feat: manage, account and help pages

- 管理页:单元集 / 计划 / 算法三个维度,卡片带元数据
- 账户页:资料、学习数据、竖直分组的四个功能入口
- 新增设置、文档与帮助(底部可上滑助手)、反馈、关于四个页面
- 抽出 StatBlock 与 GroupedListSection 共用组件
- 关闭 Android 预测式返回,转场改为 M3 水平滑入
This commit is contained in:
pluv committed 2026-10-24 15:21:30 +08:00
1 parent 2a307b2f48
commit 22715f7247
15 files changed
+1789 -72

No files matched your search

+30
View File
@@ -0,0 +1,30 @@
/// 账户页展示的用户资料。
class AccountProfile {
const AccountProfile({
required this.displayName,
required this.userId,
required this.stage,
required this.totalHours,
required this.streakDays,
});
final String displayName;
final String userId;
/// 学习阶段,如「大一」。
final String stage;
/// 累计学习时长(小时)。
final int totalHours;
/// 连续学习天数。
final int streakDays;
static const AccountProfile sample = AccountProfile(
displayName: 'zhiyu',
userId: 'KM-1024',
stage: '大一',
totalHours: 42,
streakDays: 4,
);
}
+146
View File
@@ -0,0 +1,146 @@
/// 管理页「单元集」列表项。
class DeckInfo {
const DeckInfo({
required this.id,
required this.title,
required this.algorithm,
required this.totalItems,
required this.activatedItems,
required this.lastStudied,
required this.description,
});
final String id;
final String title;
final String algorithm;
final int totalItems;
final int activatedItems;
/// 最近一次学习的人话描述,如「3 天前」。
final String lastStudied;
final String description;
double get progress => totalItems == 0 ? 0 : activatedItems / totalItems;
String get progressPercent => '${(progress * 100).toStringAsFixed(1)}%';
static const List<DeckInfo> samples = <DeckInfo>[
DeckInfo(
id: 'cngk-t',
title: '高考必背古诗文',
algorithm: 'NSP-0',
totalItems: 950,
activatedItems: 295,
lastStudied: '3 天前',
description: '高考古诗文 60 篇',
),
DeckInfo(
id: 'cet6-core',
title: 'CET-6 核心词汇',
algorithm: 'SM-2',
totalItems: 6204,
activatedItems: 2819,
lastStudied: '昨天',
description: '六级高频词,按词频排序',
),
DeckInfo(
id: 'linalg-formula',
title: '线性代数公式',
algorithm: 'FSRS',
totalItems: 120,
activatedItems: 0,
lastStudied: '未开始',
description: '期末复习用,含推导步骤',
),
];
}
/// 管理页「计划」列表项。
class PlanInfo {
const PlanInfo({
required this.title,
required this.newPerDay,
required this.reviewPerDay,
required this.window,
required this.enabled,
required this.description,
});
final String title;
final int newPerDay;
final int reviewPerDay;
/// 允许学习的时段,如「08:00–23:00」。
final String window;
final bool enabled;
final String description;
static const List<PlanInfo> samples = <PlanInfo>[
PlanInfo(
title: '每日计划',
newPerDay: 35,
reviewPerDay: 200,
window: '08:00–23:00',
enabled: true,
description: '默认计划,每天引入 35 条新识记',
),
PlanInfo(
title: '周末冲刺',
newPerDay: 0,
reviewPerDay: 400,
window: '09:00–22:00',
enabled: false,
description: '只复习不新增,周末启用',
),
];
}
/// 管理页「算法」列表项。
class AlgorithmInfo {
const AlgorithmInfo({
required this.name,
required this.version,
required this.description,
required this.parameters,
required this.isDefault,
});
final String name;
final String version;
final String description;
/// 关键参数摘要,如「阈值 3 · 间隔上限 365 天」。
final String parameters;
final bool isDefault;
static const List<AlgorithmInfo> samples = <AlgorithmInfo>[
AlgorithmInfo(
name: 'NSP-0',
version: '1.0',
description: '快速筛选用非间隔重复调度器',
parameters: '阈值 3 · 每日复习',
isDefault: true,
),
AlgorithmInfo(
name: 'SM-2',
version: '1.0',
description: '第二代 SuperMemo,Anki 的默认调度器',
parameters: 'EF 1.3–2.5 · 间隔倍数 1.0',
isDefault: false,
),
AlgorithmInfo(
name: 'FSRS',
version: '5.0',
description: '先进开放间隔重复调度器',
parameters: '可保留率 0.9 · 权重 19',
isDefault: false,
),
AlgorithmInfo(
name: 'SM-15M',
version: '1.0',
description: '复杂间隔重复调度器(逆向工程实现)',
parameters: '最优间隔 · 遗忘曲线拟合',
isDefault: false,
),
];
}