1
This commit is contained in:
@@ -81,6 +81,7 @@ class ModelManager extends ChangeNotifier {
|
||||
final Set<int> _downloadedIds = {};
|
||||
final Map<int, double> _progress = {};
|
||||
final Map<int, String> _errors = {};
|
||||
final Set<int> _cancelRequested = {};
|
||||
bool _activeLoaded = false;
|
||||
bool _ready = false;
|
||||
bool _refreshing = false;
|
||||
@@ -104,6 +105,12 @@ class ModelManager extends ChangeNotifier {
|
||||
/// 下载失败原因(失败后可重试)
|
||||
String? errorOf(int datasetId) => _errors[datasetId];
|
||||
|
||||
/// 中断进行中的下载:下一个数据块到达时终止(丢弃 .part),卡片恢复「使用」。
|
||||
/// 取消不记错误,可再次下载。
|
||||
void cancelDownload(int datasetId) {
|
||||
_cancelRequested.add(datasetId);
|
||||
}
|
||||
|
||||
ModelManager._({String? baseUrl, http.Client? client})
|
||||
: this(baseUrl: baseUrl, client: client);
|
||||
|
||||
@@ -209,11 +216,13 @@ class ModelManager extends ChangeNotifier {
|
||||
// 并发保护:同一数据集已有进行中的下载则直接短路(预置 0 先占位,
|
||||
// 使 onProgress 首次回调前的双击/refresh 交错也被 containsKey 拦下)
|
||||
if (_progress.containsKey(item.datasetId)) return false;
|
||||
_cancelRequested.remove(item.datasetId);
|
||||
_progress[item.datasetId] = 0;
|
||||
final dir = await _modelDir(item.datasetId);
|
||||
final file = File('${dir.path}/model.tflite');
|
||||
try {
|
||||
for (var attempt = 0; attempt < 2; attempt++) {
|
||||
if (_cancelRequested.contains(item.datasetId)) break;
|
||||
final ok = await _downloadAndVerify(item, dir, file,
|
||||
onProgress: (r, t) {
|
||||
_progress[item.datasetId] = t == 0 ? 0 : r / t;
|
||||
@@ -227,17 +236,39 @@ class ModelManager extends ChangeNotifier {
|
||||
await setActive(item.datasetId, true);
|
||||
return true;
|
||||
}
|
||||
if (_cancelRequested.contains(item.datasetId)) break;
|
||||
await file.delete().catchError((_) => file);
|
||||
await File('${dir.path}/model.tflite.part')
|
||||
.delete()
|
||||
.catchError((_) => file);
|
||||
}
|
||||
if (_cancelRequested.contains(item.datasetId)) {
|
||||
// 用户取消:清理残留,不记错误
|
||||
await file.delete().catchError((_) => file);
|
||||
await File('${dir.path}/model.tflite.part')
|
||||
.delete()
|
||||
.catchError((_) => file);
|
||||
_progress.remove(item.datasetId);
|
||||
notifyListeners();
|
||||
debugPrint('[ModelManager] 下载已取消: ${item.datasetName}');
|
||||
return false;
|
||||
}
|
||||
_progress.remove(item.datasetId);
|
||||
_errors[item.datasetId] = '下载失败,请重试';
|
||||
notifyListeners();
|
||||
debugPrint('[ModelManager] 下载失败: ${item.datasetName} ${item.version}');
|
||||
return false;
|
||||
} catch (e) {
|
||||
if (_cancelRequested.contains(item.datasetId)) {
|
||||
await file.delete().catchError((_) => file);
|
||||
await File('${dir.path}/model.tflite.part')
|
||||
.delete()
|
||||
.catchError((_) => file);
|
||||
_progress.remove(item.datasetId);
|
||||
notifyListeners();
|
||||
debugPrint('[ModelManager] 下载已取消: ${item.datasetName}');
|
||||
return false;
|
||||
}
|
||||
_progress.remove(item.datasetId);
|
||||
_errors[item.datasetId] = '下载异常:$e';
|
||||
notifyListeners();
|
||||
@@ -262,10 +293,15 @@ class ModelManager extends ChangeNotifier {
|
||||
}
|
||||
final total = res.contentLength ?? item.sizeBytes;
|
||||
await for (final chunk in res.stream) {
|
||||
if (_cancelRequested.contains(item.datasetId)) break; // 用户取消
|
||||
sink.add(chunk);
|
||||
received += chunk.length;
|
||||
onProgress?.call(received, total);
|
||||
}
|
||||
if (_cancelRequested.contains(item.datasetId)) {
|
||||
await sink.close();
|
||||
return false;
|
||||
}
|
||||
await sink.close();
|
||||
final bytes = await part.readAsBytes();
|
||||
final hex = sha256.convert(bytes).toString();
|
||||
|
||||
Reference in New Issue
Block a user