Initial project

This commit is contained in:
Cody
2026-03-06 14:56:17 +08:00
parent 977b627b15
commit bf9e099747
1180 changed files with 50973 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../presentation/settings_view_model.dart';
/// 设置页
///
/// 所有用户操作通过 [SettingsViewModel] 处理View 不直接调用路由。
class SettingsPage extends ConsumerWidget {
const SettingsPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
appBar: AppBar(
title: const Text('设置'),
),
body: ListView(
children: [
ListTile(
title: const Text('主题'),
trailing: const Icon(Icons.chevron_right),
onTap: () => ref
.read(settingsViewModelProvider.notifier)
.navigateToTheme(context),
),
],
),
);
}
}

View File

@@ -0,0 +1,53 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../presentation/theme_view_model.dart';
import 'widgets/settings_section_header.dart';
import 'widgets/theme_option_tile.dart';
/// 主题选择页
///
/// 通过 [ThemeViewModel] 读写主题状态,不直接感知 app 级 Provider。
class ThemeView extends ConsumerWidget {
const ThemeView({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final current = ref.watch(themeViewModelProvider);
return Scaffold(
appBar: AppBar(
title: const Text('主题'),
),
body: ListView(
children: [
const SettingsSectionHeader(title: '外观'),
ThemeOptionTile(
label: '跟随系统',
mode: ThemeMode.system,
current: current,
onTap: () => ref
.read(themeViewModelProvider.notifier)
.setMode(ThemeMode.system),
),
ThemeOptionTile(
label: '黑色模式',
mode: ThemeMode.dark,
current: current,
onTap: () => ref
.read(themeViewModelProvider.notifier)
.setMode(ThemeMode.dark),
),
ThemeOptionTile(
label: '白色模式',
mode: ThemeMode.light,
current: current,
onTap: () => ref
.read(themeViewModelProvider.notifier)
.setMode(ThemeMode.light),
),
],
),
);
}
}

View File

@@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
import '../../../../../core/ui/base/context_theme_ext.dart';
/// 设置页分组标题
///
/// 用于在列表中区分配置分组,如「外观」、「通知」。
/// 文字颜色跟随 [ColorScheme.primary],自带上下留白。
///
/// 用法:
/// ```dart
/// const SettingsSectionHeader(title: '外观')
/// ```
class SettingsSectionHeader extends StatelessWidget {
const SettingsSectionHeader({
super.key,
required this.title,
});
final String title;
@override
Widget build(BuildContext context) {
final s = context.styles;
return Padding(
padding: const EdgeInsets.fromLTRB(16, 24, 16, 4),
child: Text(title, style: s.sectionLabel),
);
}
}

View File

@@ -0,0 +1,44 @@
import 'package:flutter/material.dart';
import '../../../../../core/ui/base/context_theme_ext.dart';
/// 单个主题选项行
///
/// 纯展示 + 事件透传,不感知任何 Provider。
/// 由父级传入 [current] 判断选中状态,[onTap] 处理切换。
///
/// 用法:
/// ```dart
/// ThemeOptionTile(
/// label: '黑色模式',
/// mode: ThemeMode.dark,
/// current: current,
/// onTap: () => ref.read(themeViewModelProvider.notifier).setMode(ThemeMode.dark),
/// )
/// ```
class ThemeOptionTile extends StatelessWidget {
const ThemeOptionTile({
super.key,
required this.label,
required this.mode,
required this.current,
required this.onTap,
});
final String label;
final ThemeMode mode;
final ThemeMode current;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
final s = context.styles;
final isSelected = current == mode;
return ListTile(
title: Text(label),
trailing: isSelected ? Icon(Icons.check, color: s.primary) : null,
onTap: onTap,
);
}
}