feat(apps): 重构 UI 架构为 presentation 层并新增 l10n 国际化支持
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import 'package:social_app/core/api/i_api_client.dart';
|
||||
import 'package:social_app/core/network/i_api_client.dart';
|
||||
import 'models/signup_request.dart';
|
||||
import 'models/login_request.dart';
|
||||
import 'models/auth_response.dart';
|
||||
|
||||
@@ -3,10 +3,11 @@ import 'dart:async';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:formz/formz.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import '../../../../core/api/api_exception.dart';
|
||||
import '../../../../core/network/api_exception.dart';
|
||||
import '../../../../core/l10n/l10n.dart';
|
||||
import '../../data/auth_repository.dart';
|
||||
import '../../data/models/auth_response.dart';
|
||||
import '../../../../core/form_inputs/form_inputs.dart';
|
||||
import '../../../../shared/forms/inputs.dart';
|
||||
|
||||
class LoginState extends Equatable {
|
||||
static const defaultDialCode = '+86';
|
||||
@@ -121,7 +122,7 @@ class LoginCubit extends Cubit<LoginState> {
|
||||
|
||||
Future<bool> sendCode() async {
|
||||
if (!state.phone.isValid) {
|
||||
emit(state.copyWith(errorMessage: '请输入有效手机号'));
|
||||
emit(state.copyWith(errorMessage: L10n.current.authInvalidPhone));
|
||||
return false;
|
||||
}
|
||||
if (!state.canSendCode) {
|
||||
@@ -152,7 +153,9 @@ class LoginCubit extends Cubit<LoginState> {
|
||||
if (isClosed) {
|
||||
return false;
|
||||
}
|
||||
final message = e is ApiException ? e.message : '验证码发送失败';
|
||||
final message = e is ApiException
|
||||
? e.message
|
||||
: L10n.current.authSendCodeFailed;
|
||||
emit(state.copyWith(isSendingCode: false, errorMessage: message));
|
||||
return false;
|
||||
}
|
||||
|
||||
+19
-17
@@ -4,8 +4,9 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:formz/formz.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../../../core/di/injection.dart';
|
||||
import '../../../../core/router/app_routes.dart';
|
||||
import '../../../../app/di/injection.dart';
|
||||
import '../../../../app/router/app_routes.dart';
|
||||
import '../../../../core/l10n/l10n.dart';
|
||||
import '../../../../core/theme/design_tokens.dart';
|
||||
import '../../../../shared/widgets/app_button.dart';
|
||||
import '../../../../shared/widgets/banner/app_banner.dart';
|
||||
@@ -85,12 +86,13 @@ class _LoginViewState extends State<LoginView> {
|
||||
}
|
||||
|
||||
Future<bool> _showAgreementDialog() async {
|
||||
final l10n = context.l10n;
|
||||
return await showConfirmSheet(
|
||||
context,
|
||||
title: '请先同意协议',
|
||||
message: '在使用我们的服务之前,请先阅读并同意《用户协议》和《隐私政策》。\n\n只有您同意上述协议,我们才能为您提供服务。',
|
||||
confirmText: '确认',
|
||||
cancelText: '取消',
|
||||
title: l10n.authAgreementTitle,
|
||||
message: l10n.authAgreementMessage,
|
||||
confirmText: l10n.commonConfirm,
|
||||
cancelText: l10n.commonCancel,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -101,7 +103,7 @@ class _LoginViewState extends State<LoginView> {
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Semantics(
|
||||
label: '同意用户协议与隐私政策',
|
||||
label: context.l10n.authAgreementSemantics,
|
||||
checked: _agreedToTerms,
|
||||
button: true,
|
||||
child: InkWell(
|
||||
@@ -143,17 +145,17 @@ class _LoginViewState extends State<LoginView> {
|
||||
text: TextSpan(
|
||||
style: const TextStyle(fontSize: 13, color: AppColors.slate600),
|
||||
children: [
|
||||
const TextSpan(text: '我已同意'),
|
||||
TextSpan(text: context.l10n.authAgreementPrefix),
|
||||
TextSpan(
|
||||
text: '《用户协议》',
|
||||
text: context.l10n.authAgreementTerms,
|
||||
style: const TextStyle(
|
||||
color: AppColors.blue600,
|
||||
decoration: TextDecoration.underline,
|
||||
),
|
||||
),
|
||||
const TextSpan(text: '与'),
|
||||
TextSpan(text: context.l10n.authAgreementAnd),
|
||||
TextSpan(
|
||||
text: '《隐私政策》',
|
||||
text: context.l10n.authAgreementPrivacy,
|
||||
style: const TextStyle(
|
||||
color: AppColors.blue600,
|
||||
decoration: TextDecoration.underline,
|
||||
@@ -213,7 +215,7 @@ class _LoginViewState extends State<LoginView> {
|
||||
CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
AuthField(
|
||||
hint: '输入手机号',
|
||||
hint: context.l10n.authPhoneHint,
|
||||
controller: _phoneController,
|
||||
onChanged: (value) {
|
||||
context.read<LoginCubit>().phoneChanged(
|
||||
@@ -237,7 +239,7 @@ class _LoginViewState extends State<LoginView> {
|
||||
),
|
||||
SizedBox(height: AppSpacing.lg),
|
||||
AuthField(
|
||||
hint: '输入验证码',
|
||||
hint: context.l10n.authCodeHint,
|
||||
controller: _codeController,
|
||||
onChanged: (value) {
|
||||
context.read<LoginCubit>().codeChanged(
|
||||
@@ -256,7 +258,7 @@ class _LoginViewState extends State<LoginView> {
|
||||
child: LinkButton(
|
||||
text: state.resendCooldownSeconds > 0
|
||||
? '${state.resendCooldownSeconds}s'
|
||||
: '发送验证码',
|
||||
: context.l10n.authSendCode,
|
||||
onTap: state.canSendCode
|
||||
? _handleSendCode
|
||||
: null,
|
||||
@@ -276,8 +278,8 @@ class _LoginViewState extends State<LoginView> {
|
||||
? ToastType.error
|
||||
: ToastType.warning,
|
||||
title: state.errorMessage != null
|
||||
? '登录失败'
|
||||
: '请检查输入',
|
||||
? context.l10n.authLoginFailed
|
||||
: context.l10n.authCheckInput,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -285,7 +287,7 @@ class _LoginViewState extends State<LoginView> {
|
||||
),
|
||||
SizedBox(height: AppSpacing.xxl),
|
||||
AppButton(
|
||||
text: '登录/注册',
|
||||
text: context.l10n.authLoginOrRegister,
|
||||
onPressed:
|
||||
state.status ==
|
||||
FormzSubmissionStatus.inProgress
|
||||
+2
-2
@@ -146,8 +146,8 @@ class AuthHeroHeader extends StatelessWidget {
|
||||
borderRadius: BorderRadius.circular(AppRadius.full),
|
||||
child: Image.asset(
|
||||
'assets/images/logo.png',
|
||||
width: 58,
|
||||
height: 58,
|
||||
width: 88,
|
||||
height: 88,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
+4
-1
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../../core/l10n/l10n.dart';
|
||||
import '../../../../core/theme/design_tokens.dart';
|
||||
import 'auth_field.dart';
|
||||
|
||||
@@ -40,7 +41,9 @@ class _PasswordFieldState extends State<PasswordField> {
|
||||
onChanged: widget.onChanged,
|
||||
suffixIcon: IconButton(
|
||||
onPressed: _toggleVisibility,
|
||||
tooltip: _obscured ? '显示密码' : '隐藏密码',
|
||||
tooltip: _obscured
|
||||
? context.l10n.authShowPassword
|
||||
: context.l10n.authHidePassword,
|
||||
icon: Icon(
|
||||
_obscured ? Icons.visibility_off_rounded : Icons.visibility_rounded,
|
||||
color: AppColors.authInputIcon,
|
||||
Reference in New Issue
Block a user