From 9b87b6c835c71b4ab636b9d30c142387187647ad Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Fri, 27 Oct 2023 09:20:26 +0530 Subject: [PATCH 1/4] Fix: Avoid pushing duplicate HomeWidget during login Signed-off-by: Neeraj Gupta <254676+ua741@users.noreply.github.com> --- lib/services/user_service.dart | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/services/user_service.dart b/lib/services/user_service.dart index e67bd6112..9709f3ce4 100644 --- a/lib/services/user_service.dart +++ b/lib/services/user_service.dart @@ -13,6 +13,7 @@ import "package:photos/core/errors.dart"; import 'package:photos/core/event_bus.dart'; import 'package:photos/core/network/network.dart'; import 'package:photos/db/public_keys_db.dart'; +import "package:photos/events/account_configured_event.dart"; import 'package:photos/events/two_factor_status_change_event.dart'; import 'package:photos/events/user_details_changed_event.dart'; import "package:photos/generated/l10n.dart"; @@ -644,14 +645,19 @@ class UserService { } } await dialog.hide(); - Navigator.of(context).pushAndRemoveUntil( - MaterialPageRoute( - builder: (BuildContext context) { - return page; - }, - ), - (route) => route.isFirst, - ); + if (page is HomeWidget) { + Navigator.of(context).popUntil((route) => route.isFirst); + Bus.instance.fire(AccountConfiguredEvent()); + } else { + Navigator.of(context).pushAndRemoveUntil( + MaterialPageRoute( + builder: (BuildContext context) { + return page; + }, + ), + (route) => route.isFirst, + ); + } } else { // should never reach here throw Exception("unexpected response during email verification"); From c513957056a8c0a551d80b46cbf0ddecb98385ec Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Fri, 27 Oct 2023 09:21:04 +0530 Subject: [PATCH 2/4] Format Signed-off-by: Neeraj Gupta <254676+ua741@users.noreply.github.com> --- lib/services/user_service.dart | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/services/user_service.dart b/lib/services/user_service.dart index 9709f3ce4..391afd591 100644 --- a/lib/services/user_service.dart +++ b/lib/services/user_service.dart @@ -341,9 +341,10 @@ class UserService { } else { page = const PasswordReentryPage(); } - } else { - page = const PasswordEntryPage(mode: PasswordEntryMode.set,); + page = const PasswordEntryPage( + mode: PasswordEntryMode.set, + ); } } Navigator.of(context).pushAndRemoveUntil( @@ -530,7 +531,7 @@ class UserService { final clientM = client.calculateClientEvidenceMessage(); // ignore: unused_local_variable late Response srpCompleteResponse; - if(setKeysRequest == null) { + if (setKeysRequest == null) { srpCompleteResponse = await _enteDio.post( "/users/srp/complete", data: { @@ -551,8 +552,8 @@ class UserService { } else { throw Exception("register-srp action failed"); } - } catch (e,s) { - _logger.severe("failed to register srp" ,e,s); + } catch (e, s) { + _logger.severe("failed to register srp", e, s); rethrow; } } @@ -699,9 +700,10 @@ class UserService { } } - Future updateKeyAttributes(KeyAttributes keyAttributes, Uint8List - loginKey,) - async { + Future updateKeyAttributes( + KeyAttributes keyAttributes, + Uint8List loginKey, + ) async { try { final setKeyRequest = SetKeysRequest( kekSalt: keyAttributes.kekSalt, @@ -1131,13 +1133,14 @@ class UserService { bool hasEnabledTwoFactor() { return _preferences.getBool(keyHasEnabledTwoFactor) ?? false; } + bool hasEmailMFAEnabled() { final UserDetails? profile = getCachedUserDetails(); if (profile != null && profile.profileData != null) { return profile.profileData!.isEmailMFAEnabled; } return true; -} + } Future updateEmailMFA(bool isEnabled) async { try { @@ -1154,7 +1157,7 @@ class UserService { await _preferences.setString(keyUserDetails, profile.toJson()); } } catch (e) { - _logger.severe("Failed to update email mfa",e); + _logger.severe("Failed to update email mfa", e); rethrow; } } From f855c1b5c6e5ecac5059c6d9d19605f120795944 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Fri, 27 Oct 2023 09:31:50 +0530 Subject: [PATCH 3/4] Fix: Dispose controller during dispose of homeWidget Signed-off-by: Neeraj Gupta <254676+ua741@users.noreply.github.com> --- lib/ui/extents_page_view.dart | 24 ++++++-------------- lib/ui/home/memories/full_screen_memory.dart | 5 ++-- lib/ui/tabs/home_widget.dart | 1 + 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/lib/ui/extents_page_view.dart b/lib/ui/extents_page_view.dart index c97bee5b0..4225efa63 100644 --- a/lib/ui/extents_page_view.dart +++ b/lib/ui/extents_page_view.dart @@ -7,11 +7,6 @@ import 'package:flutter/widgets.dart' hide PageView; /// /// Based on commit 3932ffb1cd5dfa0c3891c60977ee4f9cd70ade66 on channel dev -// Having this global (mutable) page controller is a bit of a hack. We need it -// to plumb in the factory for _PagePosition, but it will end up accumulating -// a large list of scroll positions. As long as you don't try to actually -// control the scroll positions, everything should be fine. -final PageController _defaultPageController = PageController(); const PageScrollPhysics _kPagePhysics = PageScrollPhysics(); /// A scrollable list that works page by page. @@ -50,15 +45,14 @@ class ExtentsPageView extends StatefulWidget { Key? key, this.scrollDirection = Axis.horizontal, this.reverse = false, - PageController? controller, + required this.controller, this.physics, this.pageSnapping = true, this.onPageChanged, List children = const [], this.dragStartBehavior = DragStartBehavior.start, this.openDrawer, - }) : controller = controller ?? _defaultPageController, - childrenDelegate = SliverChildListDelegate(children), + }) : childrenDelegate = SliverChildListDelegate(children), extents = children.length, super(key: key); @@ -82,7 +76,7 @@ class ExtentsPageView extends StatefulWidget { Key? key, this.scrollDirection = Axis.horizontal, this.reverse = false, - PageController? controller, + required this.controller, this.physics, this.pageSnapping = true, this.onPageChanged, @@ -90,8 +84,7 @@ class ExtentsPageView extends StatefulWidget { int? itemCount, this.dragStartBehavior = DragStartBehavior.start, this.openDrawer, - }) : controller = controller ?? _defaultPageController, - childrenDelegate = + }) : childrenDelegate = SliverChildBuilderDelegate(itemBuilder, childCount: itemCount), extents = 0, super(key: key); @@ -101,7 +94,7 @@ class ExtentsPageView extends StatefulWidget { this.extents = 1, this.scrollDirection = Axis.horizontal, this.reverse = false, - PageController? controller, + required this.controller, this.physics, this.pageSnapping = true, this.onPageChanged, @@ -109,8 +102,7 @@ class ExtentsPageView extends StatefulWidget { int? itemCount, this.dragStartBehavior = DragStartBehavior.start, this.openDrawer, - }) : controller = controller ?? _defaultPageController, - childrenDelegate = SliverChildBuilderDelegate( + }) : childrenDelegate = SliverChildBuilderDelegate( itemBuilder, childCount: itemCount, addAutomaticKeepAlives: false, @@ -202,7 +194,7 @@ class ExtentsPageView extends StatefulWidget { Key? key, this.scrollDirection = Axis.horizontal, this.reverse = false, - PageController? controller, + required this.controller, this.physics, this.pageSnapping = true, this.onPageChanged, @@ -210,7 +202,6 @@ class ExtentsPageView extends StatefulWidget { this.dragStartBehavior = DragStartBehavior.start, this.openDrawer, }) : extents = 0, - controller = controller ?? _defaultPageController, super(key: key); /// The number of pages to build off screen. @@ -297,7 +288,6 @@ class _PageViewState extends State { @override void dispose() { - widget.controller.dispose(); super.dispose(); } diff --git a/lib/ui/home/memories/full_screen_memory.dart b/lib/ui/home/memories/full_screen_memory.dart index de1a43d04..3db402844 100644 --- a/lib/ui/home/memories/full_screen_memory.dart +++ b/lib/ui/home/memories/full_screen_memory.dart @@ -60,7 +60,6 @@ class _FullScreenMemoryState extends State { @override Widget build(BuildContext context) { - _pageController ??= PageController(initialPage: _index); final file = widget.memories[_index].file; return Scaffold( appBar: AppBar( @@ -292,7 +291,7 @@ class _FullScreenMemoryState extends State { debugPrint( "FullScreenbuildSwiper: $_index and total ${widget.memories.length}", ); - _pageController = PageController(initialPage: _index); + _pageController ??= PageController(initialPage: _index); return GestureDetector( behavior: HitTestBehavior.translucent, onTapDown: (TapDownDetails details) { @@ -343,7 +342,7 @@ class _FullScreenMemoryState extends State { ); }, itemCount: widget.memories.length, - controller: _pageController, + controller: _pageController!, onPageChanged: (index) async { unawaited( MemoriesService.instance.markMemoryAsSeen(widget.memories[index]), diff --git a/lib/ui/tabs/home_widget.dart b/lib/ui/tabs/home_widget.dart index 1bd6d55bc..a211c468e 100644 --- a/lib/ui/tabs/home_widget.dart +++ b/lib/ui/tabs/home_widget.dart @@ -263,6 +263,7 @@ class _HomeWidgetState extends State { _accountConfiguredEvent.cancel(); _intentDataStreamSubscription?.cancel(); _collectionUpdatedEvent.cancel(); + _pageController.dispose(); super.dispose(); } From d263bafe567dfcb793d7dad99088ac6c008869b1 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Fri, 27 Oct 2023 09:55:51 +0530 Subject: [PATCH 4/4] DebugMode: Add support to pick creds from env Signed-off-by: Neeraj Gupta <254676+ua741@users.noreply.github.com> --- lib/ui/account/login_page.dart | 66 ++++++++------ .../account/login_pwd_verification_page.dart | 87 +++++++++++-------- 2 files changed, 89 insertions(+), 64 deletions(-) diff --git a/lib/ui/account/login_page.dart b/lib/ui/account/login_page.dart index ca80a6c15..c52f461d1 100644 --- a/lib/ui/account/login_page.dart +++ b/lib/ui/account/login_page.dart @@ -1,4 +1,5 @@ import 'package:email_validator/email_validator.dart'; +import "package:flutter/foundation.dart"; import 'package:flutter/material.dart'; import "package:logging/logging.dart"; import 'package:photos/core/configuration.dart'; @@ -28,7 +29,11 @@ class _LoginPageState extends State { @override void initState() { - _email = _config.getEmail(); + if ((_config.getEmail() ?? '').isNotEmpty) { + updateEmail(_config.getEmail()!); + } else if (kDebugMode) { + updateEmail(const String.fromEnvironment("email")); + } super.initState(); } @@ -143,19 +148,12 @@ class _LoginPageState extends State { ), onChanged: (value) { setState(() { - _email = value.trim(); - _emailIsValid = EmailValidator.validate(_email!); - if (_emailIsValid) { - _emailInputFieldColor = - const Color.fromRGBO(45, 194, 98, 0.2); - } else { - _emailInputFieldColor = null; - } + updateEmail(value); }); }, autocorrect: false, keyboardType: TextInputType.emailAddress, - //initialValue: _email, + initialValue: _email, autofocus: true, ), ), @@ -179,31 +177,33 @@ class _LoginPageState extends State { .copyWith(fontSize: 12), tags: { 'u-terms': StyledTextActionTag( - (String? text, Map attrs) => Navigator.of(context).push( - MaterialPageRoute( - builder: (BuildContext context) { - return WebPage( - S.of(context).termsOfServicesTitle, - "https://ente.io/terms", - ); - }, - ), + (String? text, Map attrs) => + Navigator.of(context).push( + MaterialPageRoute( + builder: (BuildContext context) { + return WebPage( + S.of(context).termsOfServicesTitle, + "https://ente.io/terms", + ); + }, ), + ), style: const TextStyle( decoration: TextDecoration.underline, ), ), 'u-policy': StyledTextActionTag( - (String? text, Map attrs) => Navigator.of(context).push( - MaterialPageRoute( - builder: (BuildContext context) { - return WebPage( - S.of(context).privacyPolicyTitle, - "https://ente.io/privacy", - ); - }, - ), + (String? text, Map attrs) => + Navigator.of(context).push( + MaterialPageRoute( + builder: (BuildContext context) { + return WebPage( + S.of(context).privacyPolicyTitle, + "https://ente.io/privacy", + ); + }, ), + ), style: const TextStyle( decoration: TextDecoration.underline, ), @@ -226,4 +226,14 @@ class _LoginPageState extends State { ], ); } + + void updateEmail(String value) { + _email = value.trim(); + _emailIsValid = EmailValidator.validate(_email!); + if (_emailIsValid) { + _emailInputFieldColor = const Color.fromRGBO(45, 194, 98, 0.2); + } else { + _emailInputFieldColor = null; + } + } } diff --git a/lib/ui/account/login_pwd_verification_page.dart b/lib/ui/account/login_pwd_verification_page.dart index 20c04ceff..f29827a31 100644 --- a/lib/ui/account/login_pwd_verification_page.dart +++ b/lib/ui/account/login_pwd_verification_page.dart @@ -1,4 +1,4 @@ - +import "package:flutter/foundation.dart"; import 'package:flutter/material.dart'; import 'package:photos/core/configuration.dart'; import "package:photos/generated/l10n.dart"; @@ -15,14 +15,17 @@ import "package:photos/utils/dialog_util.dart"; // volatile password. class LoginPasswordVerificationPage extends StatefulWidget { final SrpAttributes srpAttributes; - const LoginPasswordVerificationPage({Key? key, required this.srpAttributes}) : super(key: key); + + const LoginPasswordVerificationPage({Key? key, required this.srpAttributes}) + : super(key: key); @override - State createState() => _LoginPasswordVerificationPageState(); + State createState() => + _LoginPasswordVerificationPageState(); } -class _LoginPasswordVerificationPageState extends -State { +class _LoginPasswordVerificationPageState + extends State { final _passwordController = TextEditingController(); final FocusNode _passwordFocusNode = FocusNode(); String? email; @@ -33,6 +36,9 @@ State { void initState() { super.initState(); email = Configuration.instance.getEmail(); + if (kDebugMode) { + _passwordController.text = const String.fromEnvironment("password"); + } _passwordFocusNode.addListener(() { setState(() { _passwordInFocus = _passwordFocusNode.hasFocus; @@ -79,9 +85,11 @@ State { buttonText: S.of(context).logInLabel, onPressedFunction: () async { FocusScope.of(context).unfocus(); - await UserService.instance.verifyEmailViaPassword(context, widget - .srpAttributes, - _passwordController.text,); + await UserService.instance.verifyEmailViaPassword( + context, + widget.srpAttributes, + _passwordController.text, + ); }, ), floatingActionButtonLocation: fabLocation(), @@ -97,17 +105,22 @@ State { child: ListView( children: [ Padding( - padding: - const EdgeInsets.only(top: 30, left: 20, right: 20), + padding: const EdgeInsets.only(top: 30, left: 20, right: 20), child: Text( S.of(context).enterPassword, style: Theme.of(context).textTheme.headlineMedium, ), ), Padding( - padding: const EdgeInsets.only(bottom: 30, left: 22, right: - 20,), - child: Text(email ?? '', style: getEnteTextTheme(context).smallMuted,), + padding: const EdgeInsets.only( + bottom: 30, + left: 22, + right: 20, + ), + child: Text( + email ?? '', + style: getEnteTextTheme(context).smallMuted, + ), ), Visibility( // hidden textForm for suggesting auto-fill service for saving @@ -138,19 +151,19 @@ State { ), suffixIcon: _passwordInFocus ? IconButton( - icon: Icon( - _passwordVisible - ? Icons.visibility - : Icons.visibility_off, - color: Theme.of(context).iconTheme.color, - size: 20, - ), - onPressed: () { - setState(() { - _passwordVisible = !_passwordVisible; - }); - }, - ) + icon: Icon( + _passwordVisible + ? Icons.visibility + : Icons.visibility_off, + color: Theme.of(context).iconTheme.color, + size: 20, + ), + onPressed: () { + setState(() { + _passwordVisible = !_passwordVisible; + }); + }, + ) : null, ), style: const TextStyle( @@ -181,9 +194,11 @@ State { GestureDetector( behavior: HitTestBehavior.opaque, onTap: () async { - await UserService.instance - .sendOtt(context, email!, - isResetPasswordScreen: true,); + await UserService.instance.sendOtt( + context, + email!, + isResetPasswordScreen: true, + ); }, child: Center( child: Text( @@ -192,9 +207,9 @@ State { .textTheme .titleMedium! .copyWith( - fontSize: 14, - decoration: TextDecoration.underline, - ), + fontSize: 14, + decoration: TextDecoration.underline, + ), ), ), ), @@ -218,9 +233,9 @@ State { .textTheme .titleMedium! .copyWith( - fontSize: 14, - decoration: TextDecoration.underline, - ), + fontSize: 14, + decoration: TextDecoration.underline, + ), ), ), ), @@ -234,4 +249,4 @@ State { ], ); } -} \ No newline at end of file +}