8d4a14150b
- Update home screen with new composer and interactions - Update settings screens with new profile flow - Update calendar share dialog - Update contacts screen - Add new shared widgets: confirm_sheet, phone_prefix_selector - Add new formatters: phone_display_formatter - Update tests for modified components
224 lines
7.3 KiB
Dart
224 lines
7.3 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import '../../../../core/theme/design_tokens.dart';
|
|
import '../../../../shared/widgets/app_pressable.dart';
|
|
import '../../../../shared/widgets/toast/toast.dart';
|
|
import '../../../../shared/widgets/toast/toast_type.dart';
|
|
import '../../../auth/presentation/bloc/auth_bloc.dart';
|
|
import '../../../auth/presentation/bloc/auth_event.dart';
|
|
import '../../../auth/presentation/bloc/auth_state.dart';
|
|
import '../../../../shared/widgets/app_button.dart';
|
|
import '../widgets/account_section_card.dart';
|
|
import '../widgets/settings_page_scaffold.dart';
|
|
|
|
class AccountScreen extends StatelessWidget {
|
|
const AccountScreen({super.key});
|
|
|
|
static const double _menuItemHeight = AppSpacing.xl * 2 + AppSpacing.md;
|
|
static const double _menuItemHorizontalPadding = AppSpacing.md;
|
|
static const double _menuIconSize = 20;
|
|
static const double _menuChevronSize = 18;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return SettingsPageScaffold(
|
|
title: '账户',
|
|
onBack: () => context.pop(),
|
|
body: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [_buildListSurface(context)],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildListSurface(BuildContext context) {
|
|
return AccountSectionCard(
|
|
backgroundColor: AppColors.white,
|
|
borderColor: AppColors.borderSecondary,
|
|
contentPadding: const EdgeInsets.symmetric(
|
|
horizontal: AppSpacing.md,
|
|
vertical: AppSpacing.sm,
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
_buildMenuItem(
|
|
icon: Icons.edit,
|
|
title: '编辑资料',
|
|
onTap: () => context.push('/edit-profile'),
|
|
),
|
|
_buildDivider(),
|
|
_buildMenuItem(
|
|
icon: Icons.logout,
|
|
title: '退出登录',
|
|
titleColor: AppColors.feedbackErrorText,
|
|
iconColor: AppColors.feedbackErrorIcon,
|
|
trailingColor: AppColors.feedbackErrorIcon,
|
|
onTap: () => _showLogoutSheet(context),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildMenuItem({
|
|
required IconData icon,
|
|
required String title,
|
|
required VoidCallback onTap,
|
|
Color titleColor = AppColors.slate900,
|
|
Color iconColor = AppColors.slate500,
|
|
Color trailingColor = AppColors.slate400,
|
|
}) {
|
|
return AppPressable(
|
|
onTap: onTap,
|
|
borderRadius: BorderRadius.circular(AppRadius.md),
|
|
child: Container(
|
|
constraints: const BoxConstraints(minHeight: _menuItemHeight),
|
|
padding: const EdgeInsets.symmetric(
|
|
horizontal: _menuItemHorizontalPadding,
|
|
vertical: AppSpacing.sm,
|
|
),
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Row(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
SizedBox(
|
|
width: _menuIconSize,
|
|
child: Icon(icon, size: _menuIconSize, color: iconColor),
|
|
),
|
|
const SizedBox(width: AppSpacing.md),
|
|
Text(
|
|
title,
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.w600,
|
|
color: titleColor,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
Icon(
|
|
Icons.chevron_right,
|
|
size: _menuChevronSize,
|
|
color: trailingColor,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildDivider() {
|
|
return Container(
|
|
height: 1,
|
|
margin: const EdgeInsets.only(
|
|
left: _menuItemHorizontalPadding + _menuIconSize + AppSpacing.md,
|
|
right: _menuItemHorizontalPadding,
|
|
),
|
|
color: AppColors.borderTertiary,
|
|
);
|
|
}
|
|
|
|
void _showLogoutSheet(BuildContext context) {
|
|
showModalBottomSheet<void>(
|
|
context: context,
|
|
backgroundColor: Colors.transparent,
|
|
isScrollControlled: true,
|
|
builder: (sheetContext) => SafeArea(
|
|
top: false,
|
|
child: Container(
|
|
margin: const EdgeInsets.fromLTRB(
|
|
AppSpacing.md,
|
|
AppSpacing.none,
|
|
AppSpacing.md,
|
|
AppSpacing.md,
|
|
),
|
|
padding: const EdgeInsets.all(AppSpacing.lg),
|
|
decoration: BoxDecoration(
|
|
color: AppColors.white,
|
|
borderRadius: BorderRadius.circular(AppRadius.xl),
|
|
border: Border.all(color: AppColors.borderSecondary),
|
|
),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
const Text(
|
|
'退出登录',
|
|
style: TextStyle(
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.w700,
|
|
color: AppColors.slate900,
|
|
),
|
|
textAlign: TextAlign.center,
|
|
),
|
|
const SizedBox(height: AppSpacing.xs),
|
|
const Text(
|
|
'确定退出当前账户吗?',
|
|
style: TextStyle(fontSize: 14, color: AppColors.slate500),
|
|
textAlign: TextAlign.center,
|
|
),
|
|
const SizedBox(height: AppSpacing.lg),
|
|
SizedBox(
|
|
height: 52,
|
|
child: GestureDetector(
|
|
onTap: () async {
|
|
Navigator.of(sheetContext).pop();
|
|
final authBloc = context.read<AuthBloc>();
|
|
authBloc.add(AuthLoggedOut());
|
|
try {
|
|
await authBloc.stream
|
|
.firstWhere((state) => state is AuthUnauthenticated)
|
|
.timeout(const Duration(seconds: 5));
|
|
} catch (_) {
|
|
if (context.mounted) {
|
|
Toast.show(
|
|
context,
|
|
'退出失败,请稍后重试',
|
|
type: ToastType.error,
|
|
);
|
|
}
|
|
return;
|
|
}
|
|
if (context.mounted) {
|
|
context.go('/');
|
|
}
|
|
},
|
|
child: Container(
|
|
decoration: BoxDecoration(
|
|
color: AppColors.feedbackErrorIcon,
|
|
borderRadius: BorderRadius.circular(AppRadius.full),
|
|
),
|
|
alignment: Alignment.center,
|
|
child: const Text(
|
|
'确认退出',
|
|
style: TextStyle(
|
|
fontSize: 15,
|
|
fontWeight: FontWeight.w700,
|
|
color: AppColors.white,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: AppSpacing.sm),
|
|
SizedBox(
|
|
height: 52,
|
|
child: AppButton(
|
|
text: '取消',
|
|
isOutlined: true,
|
|
onPressed: () => Navigator.of(sheetContext).pop(),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|