55 lines
2.0 KiB
Dart
55 lines
2.0 KiB
Dart
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 = {};
|
||
}
|