feat: 实现起卦、设置与积分系统

This commit is contained in:
qzl
2026-04-03 16:56:47 +08:00
parent 31594558eb
commit f245eec5f6
170 changed files with 20728 additions and 328 deletions
@@ -6,6 +6,9 @@ import 'package:flutter/material.dart';
import '../../../../core/logging/logger.dart';
import '../../../../core/network/api_problem.dart';
import '../../../../core/network/api_problem_mapper.dart';
import '../../../settings/presentation/models/legal_document_type.dart';
import '../../../settings/presentation/screens/legal_document_screen.dart';
import '../../../settings/presentation/utils/legal_document_assets.dart';
import '../../../../l10n/app_localizations.dart';
import '../../../../shared/theme/design_tokens.dart';
import '../../../../shared/widgets/toast/toast.dart';
@@ -171,6 +174,21 @@ class _LoginScreenState extends State<LoginScreen> {
);
}
Future<void> _openLegalDocument(LegalDocumentType type) async {
final l10n = AppLocalizations.of(context)!;
await Navigator.of(context).push<void>(
MaterialPageRoute<void>(
builder: (_) => LegalDocumentScreen(
title: legalDocumentTitle(l10n, type),
assetPath: legalDocumentAssetPath(
Localizations.localeOf(context),
type,
),
),
),
);
}
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
@@ -190,51 +208,49 @@ class _LoginScreenState extends State<LoginScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: AppSpacing.xxxl),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
l10n.welcomeLogin,
style: Theme.of(context).textTheme.headlineMedium,
),
const SizedBox(height: AppSpacing.sm),
Text(
l10n.loginSubtitleEmail,
style: Theme.of(context).textTheme.bodyLarge,
),
],
const SizedBox(height: AppSpacing.xxl),
Container(
width: double.infinity,
padding: const EdgeInsets.all(AppSpacing.xl),
decoration: BoxDecoration(
color: colors.surface,
borderRadius: BorderRadius.circular(AppRadius.lg),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
l10n.welcomeLogin,
style: Theme.of(context).textTheme.headlineMedium,
),
),
PopupMenuButton<Locale>(
icon: Icon(Icons.language, color: colors.primary),
onSelected: widget.onLocaleChanged,
itemBuilder: (context) => [
PopupMenuItem<Locale>(
value: const Locale('zh'),
child: Text(l10n.chinese),
),
PopupMenuItem<Locale>(
value: const Locale('en'),
child: Text(l10n.english),
),
],
),
],
const SizedBox(height: AppSpacing.sm),
Text(
l10n.loginSubtitleEmail,
style: Theme.of(context).textTheme.bodyLarge,
),
],
),
),
const SizedBox(height: AppSpacing.xxl),
TextField(
controller: _emailController,
keyboardType: TextInputType.emailAddress,
onChanged: (_) => setState(() {}),
decoration: InputDecoration(
hintText: l10n.emailHint,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppRadius.sm),
Container(
decoration: BoxDecoration(
color: colors.surface,
borderRadius: BorderRadius.circular(AppRadius.lg),
),
child: TextField(
controller: _emailController,
keyboardType: TextInputType.emailAddress,
onChanged: (_) => setState(() {}),
decoration: InputDecoration(
hintText: l10n.emailHint,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppRadius.lg),
borderSide: BorderSide.none,
),
contentPadding: const EdgeInsets.symmetric(
horizontal: AppSpacing.lg,
vertical: AppSpacing.lg,
),
),
),
),
@@ -242,16 +258,27 @@ class _LoginScreenState extends State<LoginScreen> {
Row(
children: [
Expanded(
child: TextField(
controller: _codeController,
keyboardType: TextInputType.number,
maxLength: 6,
onChanged: (_) => setState(() {}),
decoration: InputDecoration(
counterText: '',
hintText: l10n.codeHint,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppRadius.sm),
child: Container(
decoration: BoxDecoration(
color: colors.surface,
borderRadius: BorderRadius.circular(AppRadius.lg),
),
child: TextField(
controller: _codeController,
keyboardType: TextInputType.number,
maxLength: 6,
onChanged: (_) => setState(() {}),
decoration: InputDecoration(
counterText: '',
hintText: l10n.codeHint,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppRadius.lg),
borderSide: BorderSide.none,
),
contentPadding: const EdgeInsets.symmetric(
horizontal: AppSpacing.lg,
vertical: AppSpacing.lg,
),
),
),
),
@@ -265,7 +292,7 @@ class _LoginScreenState extends State<LoginScreen> {
backgroundColor: colors.surfaceContainerHighest,
foregroundColor: colors.primary,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadius.sm),
borderRadius: BorderRadius.circular(AppRadius.full),
),
),
onPressed: _sendCode,
@@ -288,18 +315,16 @@ class _LoginScreenState extends State<LoginScreen> {
backgroundColor: colors.primary,
foregroundColor: colors.onPrimary,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadius.sm),
borderRadius: BorderRadius.circular(AppRadius.full),
),
padding: const EdgeInsets.symmetric(
vertical: AppSpacing.md,
),
),
onPressed: canLogin ? _login : null,
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: AppSpacing.sm,
),
child: Text(
l10n.login,
style: const TextStyle(fontSize: 16),
),
child: Text(
l10n.login,
style: const TextStyle(fontSize: 16),
),
),
),
@@ -329,9 +354,8 @@ class _LoginScreenState extends State<LoginScreen> {
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()
..onTap = () => _showPolicyDialog(
l10n.privacyPolicy,
l10n.privacyContent,
..onTap = () => _openLegalDocument(
LegalDocumentType.privacyPolicy,
),
),
TextSpan(text: l10n.agreementSeparator),
@@ -342,9 +366,8 @@ class _LoginScreenState extends State<LoginScreen> {
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()
..onTap = () => _showPolicyDialog(
l10n.termsOfService,
l10n.termsContent,
..onTap = () => _openLegalDocument(
LegalDocumentType.termsOfService,
),
),
TextSpan(text: l10n.agreementAnd),