Files
yanting/lib/features/profile/profile_page.dart
T
2026-06-05 17:54:46 +08:00

228 lines
6.9 KiB
Dart

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
import '../../data/api/report_data_source.dart';
import '../../theme/app_icons.dart';
import '../../routing/app_routes.dart';
import '../../theme/yanting_text.dart';
import '../../theme/yanting_tokens.dart';
import '../../widgets/app_buttons.dart';
import '../../widgets/app_card.dart';
import '../../widgets/page_header.dart';
import '../../widgets/sheets.dart';
import '../../widgets/states.dart';
class ProfilePage extends StatelessWidget {
const ProfilePage({required this.dataSource, super.key});
final ReportDataSource dataSource;
@override
Widget build(BuildContext context) {
final colors = ShadTheme.of(context).colorScheme;
return ListView(
padding: const EdgeInsets.fromLTRB(
YantingSpacing.screenX,
4,
YantingSpacing.screenX,
16,
),
children: [
const PageHeader(title: '我的'),
AppCard(
color: colors.secondary,
child: Row(
children: [
CircleAvatar(
radius: 27,
backgroundColor: colors.background,
foregroundColor: colors.mutedForeground,
child: const Icon(AppIcons.user, size: 28),
),
const SizedBox(width: 15),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'未登录',
style: YantingText.cardTitle.copyWith(
fontSize: 18,
color: colors.foreground,
),
),
const SizedBox(height: 5),
Text(
'登录后同步收藏、历史和听单',
style: YantingText.meta.copyWith(
height: 1.5,
color: colors.mutedForeground,
),
),
],
),
),
],
),
),
const SizedBox(height: YantingSpacing.x3),
AppButton(
label: '登录 / 注册',
expand: true,
onPressed: () => showLoginSheet(context),
),
const SizedBox(height: 18),
_MenuGroup(
children: [
_MenuRow(
icon: AppIcons.history,
title: '本地浏览记录',
trailing: '0 条 · 本地临时',
onTap: () => showAppToast(context, '历史同步接口待接入'),
),
],
),
const SizedBox(height: YantingSpacing.x3),
_MenuGroup(
children: [
_MenuRow(
icon: AppIcons.settings,
title: '设置',
onTap: () => context.push(AppRoutes.settings),
),
_MenuRow(
icon: AppIcons.fileList,
title: '用户协议',
onTap: () => showOutboundSheet(context, title: '用户协议'),
),
_MenuRow(
icon: AppIcons.shield,
title: '隐私政策',
onTap: () => showOutboundSheet(context, title: '隐私政策'),
),
],
),
const SizedBox(height: YantingSpacing.x3),
AppCard(
color: colors.secondary,
onTap: () => showOutboundSheet(context, title: '相关服务'),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
'了解相关服务',
style: YantingText.body.copyWith(
color: colors.foreground,
fontWeight: FontWeight.w600,
),
),
const SizedBox(width: 3),
const Icon(AppIcons.arrowRight, size: 18),
],
),
const SizedBox(height: 6),
Text(
'与你关注主题相关的延伸服务,内容不构成投资建议。',
style: YantingText.meta.copyWith(
height: 1.5,
color: colors.mutedForeground,
),
),
],
),
),
const SizedBox(height: 22),
Text(
'研听 · 全球机构研报中文解读\n登录不阻断游客完整收听第一期 · 内容不构成投资建议',
textAlign: TextAlign.center,
style: YantingText.meta.copyWith(fontSize: 12, height: 1.7),
),
],
);
}
}
class _MenuGroup extends StatelessWidget {
const _MenuGroup({required this.children});
final List<Widget> children;
@override
Widget build(BuildContext context) {
final colors = ShadTheme.of(context).colorScheme;
return AppCard(
padding: EdgeInsets.zero,
child: Column(
children: [
for (var index = 0; index < children.length; index++) ...[
children[index],
if (index != children.length - 1)
Divider(height: 1, thickness: 1, color: colors.border),
],
],
),
);
}
}
class _MenuRow extends StatelessWidget {
const _MenuRow({
required this.icon,
required this.title,
required this.onTap,
this.trailing,
});
final IconData icon;
final String title;
final String? trailing;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
final colors = ShadTheme.of(context).colorScheme;
return InkWell(
onTap: onTap,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 15),
child: Row(
children: [
Icon(icon, size: 20, color: colors.foreground),
const SizedBox(width: 13),
Expanded(child: Text(title, style: YantingText.body)),
if (trailing != null)
DecoratedBox(
decoration: BoxDecoration(
color: colors.secondary,
borderRadius: BorderRadius.circular(YantingRadius.pill),
),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 3,
),
child: Text(
trailing!,
style: YantingText.meta.copyWith(
fontSize: 11.5,
color: colors.secondaryForeground,
),
),
),
)
else
Icon(
AppIcons.arrowRight,
color: colors.mutedForeground,
size: 20,
),
],
),
),
);
}
}