flutter架 构项目基础

This commit is contained in:
崔宝新
2026-09-04 15:22:20 +08:00
parent 70967229d0
commit 0c5aee59c0
265 changed files with 35484 additions and 0 deletions
+54
View File
@@ -0,0 +1,54 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:new_learn/core/storage/stores/answer_record_store.dart';
/// ============================================================
/// 【answerProvider】答题状态 —— Riverpod 内存主状态
///
/// 一、架构定位(对应方案分析结论):
/// 答案主状态必须住内存(每题作答高频读写、交卷即弃),
/// Isar 只是"备份恢复层":每次作答同步写一条 AnswerRecord,
/// 进程杀掉后下次进卷按 paperId 读回 restore() 续答。
///
/// 二、数据结构:`Map<questionId, String>`
/// key 用服务器题号(Question.questionId),不依赖本地自增 id,
/// 这样续答恢复时即使题目重新拉取也能对上。
///
/// 三、持久化为什么 fire-and-forget:
/// put 走 Isar 毫秒级完成,没必要阻塞 UI 作答回调;
/// web 端 store 是空实现(打印跳过),行为自动降级为纯内存。
/// ============================================================
/// Demo 试卷 id(真实项目由试卷对象传入,如 paper.paperId)
const int demoPaperId = 1001;
final answerProvider =
NotifierProvider<AnswerNotifier, Map<int, String>>(AnswerNotifier.new);
class AnswerNotifier extends Notifier<Map<int, String>> {
@override
Map<int, String> build() => {};
/// 【作答】更新内存 + 同步落盘(续答持久化)
void answer(int questionId, String value) {
state = {...state, questionId: value};
// fire-and-forget:写库毫秒级,不阻塞作答回调
unawaited(
AnswerRecordStore.instance.put(
paperId: demoPaperId,
questionId: questionId,
answer: value,
),
);
}
/// 【续答恢复】进卷时从 Isar 读回,整体注入(只恢复本卷存在的题)
void restore(Map<int, String> saved) {
if (saved.isEmpty) return;
state = {...state, ...saved};
}
/// 【交卷清理】清空内存状态(Isar 记录由页面调 deleteByPaper)
void clear() => state = {};
}