435 lines
15 KiB
Dart
435 lines
15 KiB
Dart
import 'dart:ui';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
import '../../providers/auth_provider.dart';
|
||
import '../../providers/family_provider.dart';
|
||
import '../../theme/colors.dart';
|
||
import '../../widgets/glass_card.dart';
|
||
|
||
class ProfileScreen extends ConsumerWidget {
|
||
const ProfileScreen({super.key});
|
||
|
||
@override
|
||
Widget build(BuildContext context, WidgetRef ref) {
|
||
final authState = ref.watch(authProvider);
|
||
final isLoggedIn = authState.isLoggedIn;
|
||
final user = authState.user;
|
||
|
||
return Scaffold(
|
||
backgroundColor: AppColors.pageBg,
|
||
body: isLoggedIn && user != null
|
||
? _LoggedInContent(user: user)
|
||
: const _LoggedOutContent(),
|
||
);
|
||
}
|
||
}
|
||
|
||
class _LoggedOutContent extends StatelessWidget {
|
||
const _LoggedOutContent();
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return SafeArea(
|
||
child: Padding(
|
||
padding: const EdgeInsets.all(20),
|
||
child: Column(
|
||
children: [
|
||
const Spacer(),
|
||
// Glass card with login prompt
|
||
GlassCard(
|
||
padding: const EdgeInsets.all(24),
|
||
child: Column(
|
||
children: [
|
||
Container(
|
||
width: 80,
|
||
height: 80,
|
||
decoration: BoxDecoration(
|
||
gradient: const LinearGradient(
|
||
begin: Alignment.topLeft,
|
||
end: Alignment.bottomRight,
|
||
colors: [AppColors.brand, AppColors.brandLight],
|
||
),
|
||
shape: BoxShape.circle,
|
||
),
|
||
child: const Icon(
|
||
Icons.person_outline,
|
||
size: 40,
|
||
color: Colors.white,
|
||
),
|
||
),
|
||
const SizedBox(height: 20),
|
||
const Text(
|
||
'登录后可同步数据',
|
||
style: TextStyle(
|
||
fontSize: 18,
|
||
fontWeight: FontWeight.bold,
|
||
color: AppColors.textPrimary,
|
||
),
|
||
),
|
||
const SizedBox(height: 8),
|
||
Text(
|
||
'管理家庭账本',
|
||
style: TextStyle(
|
||
fontSize: 14,
|
||
color: AppColors.textSecondary.withOpacity(0.8),
|
||
),
|
||
),
|
||
const SizedBox(height: 24),
|
||
// Login button
|
||
GestureDetector(
|
||
onTap: () {
|
||
Navigator.pushNamed(context, '/login');
|
||
},
|
||
child: Container(
|
||
width: double.infinity,
|
||
height: 50,
|
||
decoration: BoxDecoration(
|
||
gradient: const LinearGradient(
|
||
begin: Alignment.topLeft,
|
||
end: Alignment.bottomRight,
|
||
colors: [AppColors.brand, AppColors.brandLight],
|
||
),
|
||
borderRadius: BorderRadius.circular(25),
|
||
),
|
||
child: const Center(
|
||
child: Text(
|
||
'立即登录',
|
||
style: TextStyle(
|
||
fontSize: 16,
|
||
fontWeight: FontWeight.w600,
|
||
color: Colors.white,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
const Spacer(flex: 2),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
class _LoggedInContent extends ConsumerWidget {
|
||
final dynamic user;
|
||
|
||
const _LoggedInContent({required this.user});
|
||
|
||
@override
|
||
Widget build(BuildContext context, WidgetRef ref) {
|
||
final familiesAsync = ref.watch(familyProvider);
|
||
final nickname = user.nickname ?? '用户';
|
||
final firstLetter = nickname.isNotEmpty ? nickname[0].toUpperCase() : 'U';
|
||
|
||
return SafeArea(
|
||
child: SingleChildScrollView(
|
||
padding: const EdgeInsets.all(20),
|
||
child: Column(
|
||
children: [
|
||
// User card with orange gradient avatar
|
||
GlassCard(
|
||
padding: const EdgeInsets.all(20),
|
||
child: Column(
|
||
children: [
|
||
Row(
|
||
children: [
|
||
// Orange gradient circular avatar with first letter
|
||
Container(
|
||
width: 64,
|
||
height: 64,
|
||
decoration: const BoxDecoration(
|
||
gradient: LinearGradient(
|
||
begin: Alignment.topLeft,
|
||
end: Alignment.bottomRight,
|
||
colors: [AppColors.brand, AppColors.brandLight],
|
||
),
|
||
shape: BoxShape.circle,
|
||
),
|
||
child: Center(
|
||
child: Text(
|
||
firstLetter,
|
||
style: const TextStyle(
|
||
fontSize: 28,
|
||
fontWeight: FontWeight.bold,
|
||
color: Colors.white,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(width: 16),
|
||
Expanded(
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Text(
|
||
nickname,
|
||
style: const TextStyle(
|
||
fontSize: 20,
|
||
fontWeight: FontWeight.bold,
|
||
color: AppColors.textPrimary,
|
||
),
|
||
),
|
||
const SizedBox(height: 4),
|
||
Text(
|
||
'ID: ${user.id ?? ""}',
|
||
style: TextStyle(
|
||
fontSize: 13,
|
||
color: AppColors.textSecondary.withOpacity(0.8),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 16),
|
||
// Email status and family info
|
||
Row(
|
||
children: [
|
||
Icon(
|
||
user.email != null && user.email!.isNotEmpty
|
||
? Icons.check_circle
|
||
: Icons.warning_amber_outlined,
|
||
size: 16,
|
||
color: user.email != null && user.email!.isNotEmpty
|
||
? AppColors.income
|
||
: AppColors.expense,
|
||
),
|
||
const SizedBox(width: 6),
|
||
Text(
|
||
user.email != null && user.email!.isNotEmpty
|
||
? '邮箱已绑定'
|
||
: '未绑定邮箱',
|
||
style: TextStyle(
|
||
fontSize: 13,
|
||
color: AppColors.textSecondary.withOpacity(0.8),
|
||
),
|
||
),
|
||
const Spacer(),
|
||
familiesAsync.when(
|
||
loading: () => const SizedBox.shrink(),
|
||
error: (_, __) => const SizedBox.shrink(),
|
||
data: (families) {
|
||
if (families.isEmpty) {
|
||
return const SizedBox.shrink();
|
||
}
|
||
return Row(
|
||
children: [
|
||
const Icon(
|
||
Icons.home_outlined,
|
||
size: 16,
|
||
color: AppColors.brand,
|
||
),
|
||
const SizedBox(width: 6),
|
||
Text(
|
||
families.first.name,
|
||
style: const TextStyle(
|
||
fontSize: 13,
|
||
color: AppColors.brand,
|
||
),
|
||
),
|
||
],
|
||
);
|
||
},
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
const SizedBox(height: 24),
|
||
|
||
// Settings groups with glassmorphism
|
||
_SettingsGroup(
|
||
title: '账本管理',
|
||
items: const [
|
||
_SettingsItem(icon: '🏠', label: '我的家庭', route: '/family'),
|
||
_SettingsItem(icon: '📒', label: '账本管理', route: '/books'),
|
||
_SettingsItem(icon: '💰', label: '预算设置', route: '/budget'),
|
||
_SettingsItem(icon: '🏷️', label: '分类管理', route: '/categories'),
|
||
],
|
||
),
|
||
const SizedBox(height: 16),
|
||
|
||
_SettingsGroup(
|
||
title: '系统设置',
|
||
items: const [
|
||
_SettingsItem(icon: '🤖', label: 'AI设置', route: '/ai-settings'),
|
||
_SettingsItem(icon: '📤', label: '数据导出', route: '/export'),
|
||
_SettingsItem(icon: '🔔', label: '提醒设置', route: '/notifications'),
|
||
],
|
||
),
|
||
const SizedBox(height: 16),
|
||
|
||
_SettingsGroup(
|
||
title: '关于',
|
||
items: const [
|
||
_SettingsItem(icon: 'ℹ️', label: '关于', route: '/about'),
|
||
_SettingsItem(icon: '💬', label: '帮助与反馈', route: '/feedback'),
|
||
],
|
||
),
|
||
const SizedBox(height: 24),
|
||
|
||
// Logout button with red border
|
||
GestureDetector(
|
||
onTap: () async {
|
||
final confirmed = await showDialog<bool>(
|
||
context: context,
|
||
builder: (context) => AlertDialog(
|
||
title: const Text('确认退出'),
|
||
content: const Text('确定要退出登录吗?'),
|
||
actions: [
|
||
TextButton(
|
||
onPressed: () => Navigator.pop(context, false),
|
||
child: const Text('取消'),
|
||
),
|
||
TextButton(
|
||
onPressed: () => Navigator.pop(context, true),
|
||
child: const Text(
|
||
'退出',
|
||
style: TextStyle(color: AppColors.expense),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
if (confirmed == true) {
|
||
await ref.read(authProvider.notifier).logout();
|
||
}
|
||
},
|
||
child: Container(
|
||
width: double.infinity,
|
||
height: 50,
|
||
decoration: BoxDecoration(
|
||
color: Colors.transparent,
|
||
borderRadius: BorderRadius.circular(25),
|
||
border: Border.all(color: AppColors.expense, width: 1.5),
|
||
),
|
||
child: const Center(
|
||
child: Text(
|
||
'退出登录',
|
||
style: TextStyle(
|
||
fontSize: 16,
|
||
fontWeight: FontWeight.w600,
|
||
color: AppColors.expense,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(height: 20),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
class _SettingsGroup extends StatelessWidget {
|
||
final String title;
|
||
final List<_SettingsItem> items;
|
||
|
||
const _SettingsGroup({
|
||
required this.title,
|
||
required this.items,
|
||
});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return GlassCard(
|
||
padding: EdgeInsets.zero,
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Padding(
|
||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 8),
|
||
child: Text(
|
||
title,
|
||
style: const TextStyle(
|
||
fontSize: 14,
|
||
fontWeight: FontWeight.w600,
|
||
color: AppColors.brand,
|
||
),
|
||
),
|
||
),
|
||
...items.asMap().entries.map((entry) {
|
||
final index = entry.key;
|
||
final item = entry.value;
|
||
final isLast = index == items.length - 1;
|
||
return Column(
|
||
children: [
|
||
_SettingsTile(item: item),
|
||
if (!isLast)
|
||
Divider(
|
||
height: 1,
|
||
indent: 56,
|
||
endIndent: 16,
|
||
color: AppColors.textSecondary.withOpacity(0.1),
|
||
),
|
||
],
|
||
);
|
||
}),
|
||
const SizedBox(height: 8),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
class _SettingsItem {
|
||
final String icon;
|
||
final String label;
|
||
final String route;
|
||
|
||
const _SettingsItem({
|
||
required this.icon,
|
||
required this.label,
|
||
required this.route,
|
||
});
|
||
}
|
||
|
||
class _SettingsTile extends StatelessWidget {
|
||
final _SettingsItem item;
|
||
|
||
const _SettingsTile({required this.item});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return GestureDetector(
|
||
onTap: () {
|
||
Navigator.pushNamed(context, item.route);
|
||
},
|
||
behavior: HitTestBehavior.opaque,
|
||
child: Padding(
|
||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||
child: Row(
|
||
children: [
|
||
Text(
|
||
item.icon,
|
||
style: const TextStyle(fontSize: 20),
|
||
),
|
||
const SizedBox(width: 12),
|
||
Expanded(
|
||
child: Text(
|
||
item.label,
|
||
style: const TextStyle(
|
||
fontSize: 15,
|
||
color: AppColors.textPrimary,
|
||
),
|
||
),
|
||
),
|
||
Icon(
|
||
Icons.chevron_right,
|
||
size: 20,
|
||
color: AppColors.textSecondary.withOpacity(0.5),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
} |