diff --git a/lib/pages/login/login.dart b/lib/pages/login/login.dart index 5510a9c98..cb959f47b 100644 --- a/lib/pages/login/login.dart +++ b/lib/pages/login/login.dart @@ -10,6 +10,7 @@ import 'package:fluffychat/pangea/common/constants/local.key.dart'; import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/common/utils/firebase_analytics.dart'; import 'package:fluffychat/pangea/login/pages/pangea_login_view.dart'; +import 'package:fluffychat/pangea/login/widgets/p_sso_button.dart'; import 'package:fluffychat/utils/localized_exception_extension.dart'; import 'package:fluffychat/widgets/future_loading_dialog.dart'; import 'package:fluffychat/widgets/matrix.dart'; @@ -31,7 +32,12 @@ class LoginController extends State { String? usernameError; String? passwordError; - bool loading = false; + bool loadingSignIn = false; + bool loadingAppleSSO = false; + bool loadingGoogleSSO = false; + String? appleSSOError; + String? googleSSOError; + bool showPassword = false; // #Pangea @@ -39,7 +45,7 @@ class LoginController extends State { final GlobalKey formKey = GlobalKey(); bool get enabledSignIn => - !loading && + !loadingSignIn && usernameText != null && usernameText!.isNotEmpty && passwordText != null && @@ -49,15 +55,15 @@ class LoginController extends State { void initState() { // TODO: implement initState super.initState(); - loading = true; + loadingSignIn = true; pangeaController.checkHomeServerAction().then((value) { setState(() { - loading = false; + loadingSignIn = false; }); }).catchError((e) { final String err = e.toString(); setState(() { - loading = false; + loadingSignIn = false; passwordError = err.toLocalizedString(context); }); }); @@ -77,12 +83,34 @@ class LoginController extends State { void dispose() { usernameController.dispose(); passwordController.dispose(); - loading = false; + loadingSignIn = false; usernameError = null; passwordError = null; super.dispose(); } + void setSSOError(String? error, SSOProvider provider) { + if (provider == SSOProvider.apple) { + appleSSOError = error; + googleSSOError = null; + } else if (provider == SSOProvider.google) { + googleSSOError = error; + appleSSOError = null; + } + if (mounted) setState(() {}); + } + + void setLoadingSSO(bool loading, SSOProvider provider) { + if (provider == SSOProvider.apple) { + loadingAppleSSO = loading; + loadingGoogleSSO = false; + } else if (provider == SSOProvider.google) { + loadingGoogleSSO = loading; + loadingAppleSSO = false; + } + if (mounted) setState(() {}); + } + void _setStateOnTextChange(String? oldText, String newText) { if ((oldText == null || oldText.isEmpty) && (newText.isNotEmpty)) { setState(() {}); @@ -94,7 +122,7 @@ class LoginController extends State { // Pangea# void toggleShowPassword() => - setState(() => showPassword = !loading && !showPassword); + setState(() => showPassword = !loadingSignIn && !showPassword); void login() async { // #Pangea @@ -118,7 +146,7 @@ class LoginController extends State { return; } - setState(() => loading = true); + setState(() => loadingSignIn = true); _coolDown?.cancel(); @@ -171,7 +199,7 @@ class LoginController extends State { usernameError = exception.errorMessage; }); // Pangea# - return setState(() => loading = false); + return setState(() => loadingSignIn = false); } catch (exception) { // #Pangea // setState(() => passwordError = exception.toString()); @@ -180,7 +208,7 @@ class LoginController extends State { usernameError = exception.toString(); }); // Pangea# - return setState(() => loading = false); + return setState(() => loadingSignIn = false); } // #Pangea diff --git a/lib/pages/login/login_view.dart b/lib/pages/login/login_view.dart index 5b04bbad0..265ad54db 100644 --- a/lib/pages/login/login_view.dart +++ b/lib/pages/login/login_view.dart @@ -26,9 +26,10 @@ class LoginView extends StatelessWidget { return LoginScaffold( enforceMobileMode: Matrix.of(context).client.isLogged(), appBar: AppBar( - leading: controller.loading ? null : const Center(child: BackButton()), - automaticallyImplyLeading: !controller.loading, - titleSpacing: !controller.loading ? 0 : null, + leading: + controller.loadingSignIn ? null : const Center(child: BackButton()), + automaticallyImplyLeading: !controller.loadingSignIn, + titleSpacing: !controller.loadingSignIn ? 0 : null, title: Text.rich( TextSpan( children: [ @@ -57,15 +58,16 @@ class LoginView extends StatelessWidget { Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: TextField( - readOnly: controller.loading, + readOnly: controller.loadingSignIn, autocorrect: false, autofocus: true, onChanged: controller.checkWellKnownWithCoolDown, controller: controller.usernameController, textInputAction: TextInputAction.next, keyboardType: TextInputType.emailAddress, - autofillHints: - controller.loading ? null : [AutofillHints.username], + autofillHints: controller.loadingSignIn + ? null + : [AutofillHints.username], decoration: InputDecoration( prefixIcon: const Icon(Icons.account_box_outlined), errorText: controller.usernameError, @@ -79,10 +81,11 @@ class LoginView extends StatelessWidget { Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: TextField( - readOnly: controller.loading, + readOnly: controller.loadingSignIn, autocorrect: false, - autofillHints: - controller.loading ? null : [AutofillHints.password], + autofillHints: controller.loadingSignIn + ? null + : [AutofillHints.password], controller: controller.passwordController, textInputAction: TextInputAction.go, obscureText: !controller.showPassword, @@ -113,8 +116,9 @@ class LoginView extends StatelessWidget { backgroundColor: theme.colorScheme.primary, foregroundColor: theme.colorScheme.onPrimary, ), - onPressed: controller.loading ? null : controller.login, - child: controller.loading + onPressed: + controller.loadingSignIn ? null : controller.login, + child: controller.loadingSignIn ? const LinearProgressIndicator() : Text(L10n.of(context).login), ), @@ -123,7 +127,7 @@ class LoginView extends StatelessWidget { Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: TextButton( - onPressed: controller.loading + onPressed: controller.loadingSignIn ? () {} : controller.passwordForgotten, style: TextButton.styleFrom( diff --git a/lib/pangea/login/pages/pangea_login_view.dart b/lib/pangea/login/pages/pangea_login_view.dart index 4b7bf32d1..c4e0d3702 100644 --- a/lib/pangea/login/pages/pangea_login_view.dart +++ b/lib/pangea/login/pages/pangea_login_view.dart @@ -54,7 +54,7 @@ class PangeaLoginView extends StatelessWidget { forceColor: Theme.of(context).colorScheme.onPrimary, ), onPressed: controller.enabledSignIn ? controller.login : null, - loading: controller.loading, + loading: controller.loadingSignIn, enabled: controller.enabledSignIn, ), Padding( @@ -73,10 +73,18 @@ class PangeaLoginView extends StatelessWidget { PangeaSsoButton( provider: SSOProvider.google, title: L10n.of(context).signInWithGoogle, + loading: controller.loadingGoogleSSO, + error: controller.googleSSOError, + setLoading: controller.setLoadingSSO, + setError: controller.setSSOError, ), PangeaSsoButton( provider: SSOProvider.apple, title: L10n.of(context).signInWithApple, + loading: controller.loadingAppleSSO, + error: controller.appleSSOError, + setLoading: controller.setLoadingSSO, + setError: controller.setSSOError, ), ], ), diff --git a/lib/pangea/login/pages/signup.dart b/lib/pangea/login/pages/signup.dart index 0036f492f..21ffd8661 100644 --- a/lib/pangea/login/pages/signup.dart +++ b/lib/pangea/login/pages/signup.dart @@ -7,6 +7,7 @@ import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/pangea/common/utils/firebase_analytics.dart'; import 'package:fluffychat/pangea/login/pages/signup_view.dart'; import 'package:fluffychat/pangea/login/pages/signup_with_email_view.dart'; +import 'package:fluffychat/pangea/login/widgets/p_sso_button.dart'; import 'package:fluffychat/utils/localized_exception_extension.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/widgets/matrix.dart'; @@ -32,7 +33,12 @@ class SignupPageController extends State { String? emailText; String? error; - bool loading = false; + bool loadingSignup = false; + bool loadingAppleSSO = false; + bool loadingGoogleSSO = false; + String? appleSSOError; + String? googleSSOError; + bool showPassword = false; bool noEmailWarningConfirmed = false; bool displaySecondPasswordField = false; @@ -62,13 +68,35 @@ class SignupPageController extends State { usernameController.dispose(); passwordController.dispose(); emailController.dispose(); - loading = false; + loadingSignup = false; error = null; super.dispose(); } + void setSSOError(String? error, SSOProvider provider) { + if (provider == SSOProvider.apple) { + appleSSOError = error; + googleSSOError = null; + } else if (provider == SSOProvider.google) { + googleSSOError = error; + appleSSOError = null; + } + if (mounted) setState(() {}); + } + + void setLoadingSSO(bool loading, SSOProvider provider) { + if (provider == SSOProvider.apple) { + loadingAppleSSO = loading; + loadingGoogleSSO = false; + } else if (provider == SSOProvider.google) { + loadingGoogleSSO = loading; + loadingAppleSSO = false; + } + if (mounted) setState(() {}); + } + bool get enableSignUp => - !loading && + !loadingSignup && isTnCChecked && emailController.text.isNotEmpty && usernameController.text.isNotEmpty && @@ -158,7 +186,7 @@ class SignupPageController extends State { } setState(() { - loading = true; + loadingSignup = true; }); try { @@ -216,7 +244,7 @@ class SignupPageController extends State { error = (e).toLocalizedString(context); } finally { if (mounted) { - setState(() => loading = false); + setState(() => loadingSignup = false); } } } diff --git a/lib/pangea/login/pages/signup_view.dart b/lib/pangea/login/pages/signup_view.dart index c6263a5ae..95a409047 100644 --- a/lib/pangea/login/pages/signup_view.dart +++ b/lib/pangea/login/pages/signup_view.dart @@ -30,10 +30,18 @@ class SignupPageView extends StatelessWidget { PangeaSsoButton( provider: SSOProvider.google, title: L10n.of(context).signUpWithGoogle, + setError: controller.setSSOError, + setLoading: controller.setLoadingSSO, + loading: controller.loadingGoogleSSO, + error: controller.googleSSOError, ), PangeaSsoButton( provider: SSOProvider.apple, title: L10n.of(context).signUpWithApple, + setError: controller.setSSOError, + setLoading: controller.setLoadingSSO, + loading: controller.loadingAppleSSO, + error: controller.appleSSOError, ), ], ); diff --git a/lib/pangea/login/pages/signup_with_email_view.dart b/lib/pangea/login/pages/signup_with_email_view.dart index 6016dfb19..3f64d7a15 100644 --- a/lib/pangea/login/pages/signup_with_email_view.dart +++ b/lib/pangea/login/pages/signup_with_email_view.dart @@ -59,7 +59,7 @@ class SignupWithEmailView extends StatelessWidget { ), onPressed: controller.enableSignUp ? controller.signup : null, error: controller.error, - loading: controller.loading, + loading: controller.loadingSignup, enabled: controller.enableSignUp, ), ], diff --git a/lib/pangea/login/widgets/p_sso_button.dart b/lib/pangea/login/widgets/p_sso_button.dart index 8a80cef05..a8a5e8db4 100644 --- a/lib/pangea/login/widgets/p_sso_button.dart +++ b/lib/pangea/login/widgets/p_sso_button.dart @@ -41,57 +41,34 @@ extension on SSOProvider { } } -class PangeaSsoButton extends StatefulWidget { +class PangeaSsoButton extends StatelessWidget { final String title; final SSOProvider provider; + + final Function(bool, SSOProvider) setLoading; + final Function(String?, SSOProvider) setError; + + final bool loading; + final String? error; + const PangeaSsoButton({ required this.title, required this.provider, + required this.setLoading, + required this.setError, + this.loading = false, + this.error, super.key, }); - @override - PangeaSsoButtonState createState() => PangeaSsoButtonState(); -} - -class PangeaSsoButtonState extends State { - bool _loading = false; - String? _error; - AppLifecycleListener? _listener; - - @override - void initState() { - _listener = AppLifecycleListener( - onStateChange: _onAppLifecycleChange, - ); - super.initState(); - } - - // when the SSO login launches, stop the loading indicator - void _onAppLifecycleChange(AppLifecycleState state) { - if ((state == AppLifecycleState.inactive || - state == AppLifecycleState.hidden) && - _loading) { - setState(() => _loading = false); - } - } - - @override - void dispose() { - _listener?.dispose(); - super.dispose(); - } - - Future _runSSOLogin() async { + Future _runSSOLogin(BuildContext context) async { try { - setState(() { - _loading = true; - _error = null; - }); + setLoading(true, provider); + setError(null, provider); await pangeaSSOLoginAction( IdentityProvider( - id: widget.provider.id, - name: widget.provider.name, + id: provider.id, + name: provider.name, ), Matrix.of(context).getLoginClient(), context, @@ -102,26 +79,24 @@ class PangeaSsoButtonState extends State { s: s, data: {}, ); - if (err is MatrixException) { - _error = err.errorMessage; - } else { - _error = L10n.of(context).oopsSomethingWentWrong; - } - _error = err.toString(); + final error = err is MatrixException + ? err.errorMessage + : L10n.of(context).oopsSomethingWentWrong; + setError(error, provider); } finally { - if (mounted) setState(() => _loading = false); + setLoading(false, provider); } } @override Widget build(BuildContext context) { return FullWidthButton( - depressed: _loading, - error: _error, - loading: _loading, - title: widget.title, + depressed: loading, + error: error, + loading: loading, + title: title, icon: SvgPicture.asset( - widget.provider.asset, + provider.asset, height: 20, width: 20, colorFilter: ColorFilter.mode( @@ -129,7 +104,7 @@ class PangeaSsoButtonState extends State { BlendMode.srcIn, ), ), - onPressed: _runSSOLogin, + onPressed: () => _runSSOLogin(context), ); } }