feat: stop other sso button loading if other sso button starts loading (#1486)

This commit is contained in:
ggurdin 2025-01-16 15:15:22 -05:00 committed by GitHub
parent 61c722c704
commit 9cb4e0e65d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 133 additions and 82 deletions

View file

@ -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<Login> {
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<Login> {
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
bool get enabledSignIn =>
!loading &&
!loadingSignIn &&
usernameText != null &&
usernameText!.isNotEmpty &&
passwordText != null &&
@ -49,15 +55,15 @@ class LoginController extends State<Login> {
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<Login> {
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<Login> {
// Pangea#
void toggleShowPassword() =>
setState(() => showPassword = !loading && !showPassword);
setState(() => showPassword = !loadingSignIn && !showPassword);
void login() async {
// #Pangea
@ -118,7 +146,7 @@ class LoginController extends State<Login> {
return;
}
setState(() => loading = true);
setState(() => loadingSignIn = true);
_coolDown?.cancel();
@ -171,7 +199,7 @@ class LoginController extends State<Login> {
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<Login> {
usernameError = exception.toString();
});
// Pangea#
return setState(() => loading = false);
return setState(() => loadingSignIn = false);
}
// #Pangea

View file

@ -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(

View file

@ -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,
),
],
),

View file

@ -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<SignupPage> {
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<SignupPage> {
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<SignupPage> {
}
setState(() {
loading = true;
loadingSignup = true;
});
try {
@ -216,7 +244,7 @@ class SignupPageController extends State<SignupPage> {
error = (e).toLocalizedString(context);
} finally {
if (mounted) {
setState(() => loading = false);
setState(() => loadingSignup = false);
}
}
}

View file

@ -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,
),
],
);

View file

@ -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,
),
],

View file

@ -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<PangeaSsoButton> {
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<void> _runSSOLogin() async {
Future<void> _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<PangeaSsoButton> {
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<PangeaSsoButton> {
BlendMode.srcIn,
),
),
onPressed: _runSSOLogin,
onPressed: () => _runSSOLogin(context),
);
}
}