feat(auth): 登录异常改为居中弹窗
This commit is contained in:
1 parent
9b78e43702
commit
b0002abf82
14 files changed
+436
-10
No files matched your search
@@ -0,0 +1,67 @@
|
||||
// Author: fruit.com.cn
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../l10n/app_localizations.dart';
|
||||
import '../theme/app_colors.dart';
|
||||
|
||||
const Key _dialogKey = Key('centered-error-dialog');
|
||||
const Key _confirmKey = Key('centered-error-confirm');
|
||||
const double _dialogRadius = 16;
|
||||
const double _titleHorizontalInset = 24;
|
||||
const double _titleTopInset = 24;
|
||||
const double _contentHorizontalInset = 24;
|
||||
const double _contentTopInset = 12;
|
||||
const double _contentBottomInset = 8;
|
||||
const double _actionsHorizontalInset = 16;
|
||||
const double _actionsBottomInset = 12;
|
||||
const EdgeInsets _titlePadding = EdgeInsets.fromLTRB(
|
||||
_titleHorizontalInset,
|
||||
_titleTopInset,
|
||||
_titleHorizontalInset,
|
||||
0,
|
||||
);
|
||||
const EdgeInsets _contentPadding = EdgeInsets.fromLTRB(
|
||||
_contentHorizontalInset,
|
||||
_contentTopInset,
|
||||
_contentHorizontalInset,
|
||||
_contentBottomInset,
|
||||
);
|
||||
const EdgeInsets _actionsPadding = EdgeInsets.fromLTRB(
|
||||
_actionsHorizontalInset,
|
||||
0,
|
||||
_actionsHorizontalInset,
|
||||
_actionsBottomInset,
|
||||
);
|
||||
|
||||
/// Shows a reusable error dialog centered on the screen.
|
||||
Future<void> showCenteredErrorDialog(
|
||||
BuildContext context, {
|
||||
required String title,
|
||||
required String message,
|
||||
}) async {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
builder: (dialogContext) => AlertDialog(
|
||||
key: _dialogKey,
|
||||
backgroundColor: AppColors.card,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(_dialogRadius),
|
||||
),
|
||||
titlePadding: _titlePadding,
|
||||
contentPadding: _contentPadding,
|
||||
title: Text(title),
|
||||
content: Text(message),
|
||||
actionsPadding: _actionsPadding,
|
||||
actions: [
|
||||
TextButton(
|
||||
key: _confirmKey,
|
||||
onPressed: () => Navigator.of(dialogContext).pop(),
|
||||
child: Text(l10n.authErrorConfirm),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -435,6 +435,9 @@
|
||||
"authPasswordLength": "Password must be 8-64 characters",
|
||||
"authPasswordWeak": "Password needs both letters and numbers",
|
||||
"authNetworkError": "Network error, please try again",
|
||||
"authLoginFailed": "Login failed",
|
||||
"authRegisterFailed": "Registration failed",
|
||||
"authErrorConfirm": "OK",
|
||||
"authSwitchToSignUp": "New here? Create an account",
|
||||
"authSwitchToSignIn": "Already have an account? Sign in",
|
||||
"authGateTitle": "Sign in to continue",
|
||||
|
||||
@@ -409,6 +409,9 @@
|
||||
"authPasswordLength": "Kata sandi harus 8-64 karakter",
|
||||
"authPasswordWeak": "Kata sandi perlu huruf dan angka",
|
||||
"authNetworkError": "Jaringan bermasalah, coba lagi",
|
||||
"authLoginFailed": "Gagal masuk",
|
||||
"authRegisterFailed": "Pendaftaran gagal",
|
||||
"authErrorConfirm": "Mengerti",
|
||||
"authSwitchToSignUp": "Baru di sini? Buat akun",
|
||||
"authSwitchToSignIn": "Sudah punya akun? Masuk",
|
||||
"authGateTitle": "Masuk untuk melanjutkan",
|
||||
|
||||
@@ -1888,6 +1888,24 @@ abstract class AppLocalizations {
|
||||
/// **'Network error, please try again'**
|
||||
String get authNetworkError;
|
||||
|
||||
/// No description provided for @authLoginFailed.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Login failed'**
|
||||
String get authLoginFailed;
|
||||
|
||||
/// No description provided for @authRegisterFailed.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Registration failed'**
|
||||
String get authRegisterFailed;
|
||||
|
||||
/// No description provided for @authErrorConfirm.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'OK'**
|
||||
String get authErrorConfirm;
|
||||
|
||||
/// No description provided for @authSwitchToSignUp.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
||||
@@ -958,6 +958,15 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
@override
|
||||
String get authNetworkError => 'Network error, please try again';
|
||||
|
||||
@override
|
||||
String get authLoginFailed => 'Login failed';
|
||||
|
||||
@override
|
||||
String get authRegisterFailed => 'Registration failed';
|
||||
|
||||
@override
|
||||
String get authErrorConfirm => 'OK';
|
||||
|
||||
@override
|
||||
String get authSwitchToSignUp => 'New here? Create an account';
|
||||
|
||||
|
||||
@@ -962,6 +962,15 @@ class AppLocalizationsId extends AppLocalizations {
|
||||
@override
|
||||
String get authNetworkError => 'Jaringan bermasalah, coba lagi';
|
||||
|
||||
@override
|
||||
String get authLoginFailed => 'Gagal masuk';
|
||||
|
||||
@override
|
||||
String get authRegisterFailed => 'Pendaftaran gagal';
|
||||
|
||||
@override
|
||||
String get authErrorConfirm => 'Mengerti';
|
||||
|
||||
@override
|
||||
String get authSwitchToSignUp => 'Baru di sini? Buat akun';
|
||||
|
||||
|
||||
@@ -946,6 +946,15 @@ class AppLocalizationsZh extends AppLocalizations {
|
||||
@override
|
||||
String get authNetworkError => '网络异常,请稍后重试';
|
||||
|
||||
@override
|
||||
String get authLoginFailed => '登录失败';
|
||||
|
||||
@override
|
||||
String get authRegisterFailed => '注册失败';
|
||||
|
||||
@override
|
||||
String get authErrorConfirm => '知道了';
|
||||
|
||||
@override
|
||||
String get authSwitchToSignUp => '还没有账号?去注册';
|
||||
|
||||
|
||||
@@ -371,6 +371,9 @@
|
||||
"authPasswordLength": "密码长度需在 8-64 位之间",
|
||||
"authPasswordWeak": "密码需同时包含字母和数字",
|
||||
"authNetworkError": "网络异常,请稍后重试",
|
||||
"authLoginFailed": "登录失败",
|
||||
"authRegisterFailed": "注册失败",
|
||||
"authErrorConfirm": "知道了",
|
||||
"authSwitchToSignUp": "还没有账号?去注册",
|
||||
"authSwitchToSignIn": "已有账号?去登录",
|
||||
"authGateTitle": "登录后可继续",
|
||||
|
||||
@@ -12,6 +12,7 @@ import '../../core/platform/keyboard_inset.dart';
|
||||
import '../../core/theme/app_colors.dart';
|
||||
import '../../core/theme/app_dimens.dart';
|
||||
import '../../core/theme/app_theme.dart';
|
||||
import '../../core/widgets/centered_error_dialog.dart';
|
||||
import '../../core/widgets/subpage_header.dart';
|
||||
import '../../l10n/app_localizations.dart';
|
||||
import 'auth_logic.dart';
|
||||
@@ -227,6 +228,7 @@ class _AuthPageState extends State<AuthPage> {
|
||||
_logic.errorMessage = null;
|
||||
});
|
||||
final auth = context.read<AuthController>();
|
||||
String? failureMessage;
|
||||
try {
|
||||
if (_logic.signUpMode) {
|
||||
await auth.register(
|
||||
@@ -242,14 +244,18 @@ class _AuthPageState extends State<AuthPage> {
|
||||
if (!mounted) return;
|
||||
Navigator.of(context).maybePop();
|
||||
} on ApiException catch (error) {
|
||||
if (!mounted) return;
|
||||
setState(() => _logic.errorMessage = error.message);
|
||||
failureMessage = error.message;
|
||||
} catch (_) {
|
||||
if (!mounted) return;
|
||||
setState(() => _logic.errorMessage = l10n.authNetworkError);
|
||||
failureMessage = l10n.authNetworkError;
|
||||
} finally {
|
||||
if (mounted) setState(() => _logic.busy = false);
|
||||
}
|
||||
if (!mounted || failureMessage == null) return;
|
||||
await showCenteredErrorDialog(
|
||||
context,
|
||||
title: _logic.signUpMode ? l10n.authRegisterFailed : l10n.authLoginFailed,
|
||||
message: failureMessage,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -11,6 +11,7 @@ import '../../core/data/services/auth_controller.dart';
|
||||
import '../../core/platform/haptics.dart';
|
||||
import '../../core/platform/keyboard_inset.dart';
|
||||
import '../../core/theme/app_colors.dart';
|
||||
import '../../core/widgets/centered_error_dialog.dart';
|
||||
import '../../l10n/app_localizations.dart';
|
||||
|
||||
const double _fieldHeight = 52;
|
||||
@@ -164,6 +165,7 @@ class _PhoneAuthSheetState extends State<PhoneAuthSheet> {
|
||||
});
|
||||
final haptics = context.read<Haptics>();
|
||||
final auth = context.read<AuthController>();
|
||||
String? failureMessage;
|
||||
await haptics.lightImpact();
|
||||
try {
|
||||
await auth.sendOtp(
|
||||
@@ -173,16 +175,20 @@ class _PhoneAuthSheetState extends State<PhoneAuthSheet> {
|
||||
if (!mounted) return;
|
||||
_startCountdown();
|
||||
setState(() => _error = null);
|
||||
ScaffoldMessenger.of(context)
|
||||
.showSnackBar(SnackBar(content: Text(l10n.authCodeSent)));
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(SnackBar(content: Text(l10n.authCodeSent)));
|
||||
_codeFocus.requestFocus();
|
||||
} on ApiException catch (error) {
|
||||
if (mounted) setState(() => _error = error.message);
|
||||
failureMessage = error.message;
|
||||
} catch (_) {
|
||||
if (mounted) setState(() => _error = l10n.authNetworkError);
|
||||
failureMessage = l10n.authNetworkError;
|
||||
} finally {
|
||||
if (mounted) setState(() => _sending = false);
|
||||
}
|
||||
if (mounted && failureMessage != null) {
|
||||
await _showFailure(failureMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void _startCountdown() {
|
||||
@@ -212,6 +218,7 @@ class _PhoneAuthSheetState extends State<PhoneAuthSheet> {
|
||||
});
|
||||
final haptics = context.read<Haptics>();
|
||||
final auth = context.read<AuthController>();
|
||||
String? failureMessage;
|
||||
await haptics.lightImpact();
|
||||
try {
|
||||
if (_signUp) {
|
||||
@@ -221,12 +228,24 @@ class _PhoneAuthSheetState extends State<PhoneAuthSheet> {
|
||||
}
|
||||
if (mounted) Navigator.of(context).pop(true);
|
||||
} on ApiException catch (error) {
|
||||
if (mounted) setState(() => _error = error.message);
|
||||
failureMessage = error.message;
|
||||
} catch (_) {
|
||||
if (mounted) setState(() => _error = l10n.authNetworkError);
|
||||
failureMessage = l10n.authNetworkError;
|
||||
} finally {
|
||||
if (mounted) setState(() => _submitting = false);
|
||||
}
|
||||
if (mounted && failureMessage != null) {
|
||||
await _showFailure(failureMessage);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _showFailure(String message) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return showCenteredErrorDialog(
|
||||
context,
|
||||
title: _signUp ? l10n.authRegisterFailed : l10n.authLoginFailed,
|
||||
message: message,
|
||||
);
|
||||
}
|
||||
|
||||
void _switchMode() {
|
||||
|
||||
Reference in new issue
Block a user