feat: stop other sso button loading if other sso button starts loading (#1486)
This commit is contained in:
parent
61c722c704
commit
9cb4e0e65d
7 changed files with 133 additions and 82 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue