Android Feature Optimization and Updates
Build Android Release / Build Android (push) Failing after 7s
Build Android Release / Build Android (push) Failing after 7s
This commit is contained in:
@@ -5,7 +5,11 @@ import 'package:lucide_icons/lucide_icons.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../../../core/exceptions/app_exception.dart';
|
||||
import '../../../core/validators/string_validator.dart';
|
||||
import '../../../data/models/login_config_model.dart';
|
||||
import '../../providers/auth_provider.dart';
|
||||
import '../../../services/api_service.dart';
|
||||
import '../../../services/auth_service.dart';
|
||||
import '../../../services/captcha_service.dart';
|
||||
import '../../../services/server_service.dart';
|
||||
import '../../../router/app_router.dart';
|
||||
import 'forgot_password_page.dart';
|
||||
@@ -27,11 +31,15 @@ class _LoginPageState extends State<LoginPage> {
|
||||
bool _obscurePassword = true;
|
||||
bool _rememberMe = false;
|
||||
bool _isLoading = false;
|
||||
LoginConfigModel _loginConfig = const LoginConfigModel();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadRememberedInfo();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_loadLoginConfig();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -57,23 +65,59 @@ class _LoginPageState extends State<LoginPage> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _loadLoginConfig() async {
|
||||
final server = ServerService.instance.currentServer;
|
||||
if (server == null) return;
|
||||
|
||||
try {
|
||||
await ApiService.instance.setBaseUrl(server.baseUrl);
|
||||
final config = await AuthService.instance.getLoginConfig().timeout(
|
||||
const Duration(seconds: 10),
|
||||
);
|
||||
|
||||
if (!mounted) return;
|
||||
setState(() => _loginConfig = config);
|
||||
|
||||
if (config.loginCaptcha) {
|
||||
await CaptchaService.instance.loadCaptcha(server.baseUrl);
|
||||
if (mounted) setState(() {});
|
||||
} else {
|
||||
CaptchaService.instance.clearCaptcha();
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
Future<void> _login() async {
|
||||
if (!_formKey.currentState!.validate()) return;
|
||||
|
||||
final captcha = CaptchaService.instance;
|
||||
if (_loginConfig.loginCaptcha && !captcha.isWebCaptchaVerified) {
|
||||
ToastHelper.failure('请先完成人机验证');
|
||||
return;
|
||||
}
|
||||
|
||||
final navigator = Navigator.of(context);
|
||||
final authProvider = Provider.of<AuthProvider>(context, listen: false);
|
||||
|
||||
setState(() => _isLoading = true);
|
||||
|
||||
try {
|
||||
final success = await authProvider.passwordLogin(
|
||||
email: _emailController.text.trim(),
|
||||
password: _passwordController.text,
|
||||
rememberMe: _rememberMe,
|
||||
).timeout(
|
||||
const Duration(seconds: 5),
|
||||
onTimeout: () => throw Exception('请求超时'),
|
||||
);
|
||||
final captchaParams = _loginConfig.loginCaptcha
|
||||
? captcha.getCaptchaParams()
|
||||
: <String, String>{};
|
||||
|
||||
final success = await authProvider
|
||||
.passwordLogin(
|
||||
email: _emailController.text.trim(),
|
||||
password: _passwordController.text,
|
||||
rememberMe: _rememberMe,
|
||||
captcha: captchaParams['captcha'],
|
||||
ticket: captchaParams['ticket'],
|
||||
)
|
||||
.timeout(
|
||||
const Duration(seconds: 15),
|
||||
onTimeout: () => throw Exception('请求超时'),
|
||||
);
|
||||
|
||||
if (mounted) setState(() => _isLoading = false);
|
||||
|
||||
@@ -83,6 +127,11 @@ class _LoginPageState extends State<LoginPage> {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
if (mounted) navigator.pushReplacementNamed(RouteNames.home);
|
||||
} else if (mounted) {
|
||||
if (_loginConfig.loginCaptcha) {
|
||||
await captcha.refreshCaptcha();
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
final errorMessage = authProvider.errorMessage;
|
||||
if (errorMessage != null && errorMessage.isNotEmpty) {
|
||||
final errorMsg = _parseErrorMessage(errorMessage);
|
||||
@@ -99,6 +148,11 @@ class _LoginPageState extends State<LoginPage> {
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
setState(() => _isLoading = false);
|
||||
if (_loginConfig.loginCaptcha) {
|
||||
await captcha.refreshCaptcha();
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
final errorMsg = _parseErrorMessage(e.toString());
|
||||
ToastHelper.failure(errorMsg);
|
||||
}
|
||||
@@ -153,6 +207,7 @@ class _LoginPageState extends State<LoginPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final captcha = CaptchaService.instance;
|
||||
|
||||
return Scaffold(
|
||||
body: SafeArea(
|
||||
@@ -168,10 +223,7 @@ class _LoginPageState extends State<LoginPage> {
|
||||
Center(child: _buildLogo()),
|
||||
const SizedBox(height: 32),
|
||||
Center(
|
||||
child: Text(
|
||||
'公云存储',
|
||||
style: theme.textTheme.headlineMedium,
|
||||
),
|
||||
child: Text('公云存储', style: theme.textTheme.headlineMedium),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
Card(
|
||||
@@ -196,7 +248,8 @@ class _LoginPageState extends State<LoginPage> {
|
||||
hintText: '请输入邮箱地址',
|
||||
prefixIcon: Icon(LucideIcons.mail),
|
||||
),
|
||||
onFieldSubmitted: (_) => _focusNode.requestFocus(),
|
||||
onFieldSubmitted: (_) =>
|
||||
_focusNode.requestFocus(),
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
@@ -219,18 +272,27 @@ class _LoginPageState extends State<LoginPage> {
|
||||
size: 20,
|
||||
),
|
||||
onPressed: () {
|
||||
setState(() => _obscurePassword = !_obscurePassword);
|
||||
setState(
|
||||
() =>
|
||||
_obscurePassword = !_obscurePassword,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
onFieldSubmitted: (_) => _login(),
|
||||
),
|
||||
|
||||
if (_loginConfig.loginCaptcha) ...[
|
||||
const SizedBox(height: 16),
|
||||
captcha.buildCaptchaInput(context),
|
||||
],
|
||||
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// 记住我
|
||||
InkWell(
|
||||
onTap: () => setState(() => _rememberMe = !_rememberMe),
|
||||
onTap: () =>
|
||||
setState(() => _rememberMe = !_rememberMe),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@@ -240,7 +302,9 @@ class _LoginPageState extends State<LoginPage> {
|
||||
height: 24,
|
||||
child: Checkbox(
|
||||
value: _rememberMe,
|
||||
onChanged: (v) => setState(() => _rememberMe = v ?? false),
|
||||
onChanged: (v) => setState(
|
||||
() => _rememberMe = v ?? false,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
@@ -259,7 +323,10 @@ class _LoginPageState extends State<LoginPage> {
|
||||
onPressed: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const ForgotPasswordPage(),
|
||||
builder: (context) =>
|
||||
ForgotPasswordPage(
|
||||
loginConfig: _loginConfig,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -269,7 +336,9 @@ class _LoginPageState extends State<LoginPage> {
|
||||
onPressed: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const RegisterPage(),
|
||||
builder: (context) => RegisterPage(
|
||||
loginConfig: _loginConfig,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -293,7 +362,9 @@ class _LoginPageState extends State<LoginPage> {
|
||||
? const SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
),
|
||||
)
|
||||
: const Text('登录'),
|
||||
),
|
||||
@@ -356,17 +427,17 @@ class _TwoFactorDialogState extends State<_TwoFactorDialog>
|
||||
duration: const Duration(milliseconds: 400),
|
||||
vsync: this,
|
||||
);
|
||||
_shakeAnimation = TweenSequence<double>([
|
||||
TweenSequenceItem(tween: Tween(begin: 0, end: 10), weight: 1),
|
||||
TweenSequenceItem(tween: Tween(begin: 10, end: -10), weight: 1),
|
||||
TweenSequenceItem(tween: Tween(begin: -10, end: 8), weight: 1),
|
||||
TweenSequenceItem(tween: Tween(begin: 8, end: -8), weight: 1),
|
||||
TweenSequenceItem(tween: Tween(begin: -8, end: 4), weight: 1),
|
||||
TweenSequenceItem(tween: Tween(begin: 4, end: 0), weight: 1),
|
||||
]).animate(CurvedAnimation(
|
||||
parent: _shakeController,
|
||||
curve: Curves.easeInOut,
|
||||
));
|
||||
_shakeAnimation =
|
||||
TweenSequence<double>([
|
||||
TweenSequenceItem(tween: Tween(begin: 0, end: 10), weight: 1),
|
||||
TweenSequenceItem(tween: Tween(begin: 10, end: -10), weight: 1),
|
||||
TweenSequenceItem(tween: Tween(begin: -10, end: 8), weight: 1),
|
||||
TweenSequenceItem(tween: Tween(begin: 8, end: -8), weight: 1),
|
||||
TweenSequenceItem(tween: Tween(begin: -8, end: 4), weight: 1),
|
||||
TweenSequenceItem(tween: Tween(begin: 4, end: 0), weight: 1),
|
||||
]).animate(
|
||||
CurvedAnimation(parent: _shakeController, curve: Curves.easeInOut),
|
||||
);
|
||||
_controller.addListener(_onTextChanged);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_focusNode.requestFocus();
|
||||
@@ -396,16 +467,18 @@ class _TwoFactorDialogState extends State<_TwoFactorDialog>
|
||||
|
||||
final authProvider = Provider.of<AuthProvider>(context, listen: false);
|
||||
try {
|
||||
final success = await authProvider.twoFactorLogin(
|
||||
otp: code,
|
||||
sessionId: widget.sessionId,
|
||||
email: widget.email,
|
||||
password: widget.password,
|
||||
rememberMe: widget.rememberMe,
|
||||
).timeout(
|
||||
const Duration(seconds: 5),
|
||||
onTimeout: () => throw Exception('请求超时'),
|
||||
);
|
||||
final success = await authProvider
|
||||
.twoFactorLogin(
|
||||
otp: code,
|
||||
sessionId: widget.sessionId,
|
||||
email: widget.email,
|
||||
password: widget.password,
|
||||
rememberMe: widget.rememberMe,
|
||||
)
|
||||
.timeout(
|
||||
const Duration(seconds: 5),
|
||||
onTimeout: () => throw Exception('请求超时'),
|
||||
);
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
@@ -493,9 +566,7 @@ class _TwoFactorDialogState extends State<_TwoFactorDialog>
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.digitsOnly,
|
||||
],
|
||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||
onSubmitted: (_) => _submit(),
|
||||
),
|
||||
),
|
||||
@@ -503,7 +574,9 @@ class _TwoFactorDialogState extends State<_TwoFactorDialog>
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: _isSubmitting ? null : () => Navigator.of(context).pop(false),
|
||||
onPressed: _isSubmitting
|
||||
? null
|
||||
: () => Navigator.of(context).pop(false),
|
||||
child: const Text('取消'),
|
||||
),
|
||||
FilledButton(
|
||||
|
||||
Reference in New Issue
Block a user