import 'dart:async'; import 'package:flutter/foundation.dart'; import '../models/ai_model.dart'; import '../models/api_response.dart'; import '../services/http_api_service.dart'; import 'debug_provider.dart'; class ModelProvider extends ChangeNotifier { ModelProvider({ required HttpApiService httpApiService, required DebugProvider debugProvider, }) : _http = httpApiService, _debug = debugProvider; final HttpApiService _http; final DebugProvider _debug; ModelsSnapshot? _snapshot; bool _loading = false; bool _acting = false; String? _error; String? _status; Timer? _pollTimer; ModelsSnapshot? get snapshot => _snapshot; bool get isLoading => _loading; bool get isActing => _acting; String? get error => _error; String? get status => _status; Future refresh() async { _loading = true; _error = null; notifyListeners(); try { _snapshot = await _http.getModels(); _debug.addHttpLog( 'Loaded models', details: 'count=${_snapshot?.models.length ?? 0}', ); } catch (error) { _error = error.toString(); _debug.addHttpLog('Load models failed', details: _error); } finally { _loading = false; notifyListeners(); } } Future download(String modelId) async { await _runAction(() => _http.downloadModel(modelId), '下载已启动: $modelId'); _startPolling(); } Future switchTo({required String modelId, required String kind}) async { await _runAction( () => _http.switchModel(modelId: modelId, kind: kind), '已切换: $modelId', ); await refresh(); } Future delete(String modelId) async { await _runAction(() => _http.deleteModel(modelId), '已删除: $modelId'); await refresh(); } Future _runAction( Future Function() action, String okStatus, ) async { if (_acting) return; _acting = true; _error = null; notifyListeners(); try { final result = await action(); _status = result.message.isNotEmpty ? result.message : okStatus; if (!result.isOk) { _error = _status; } _debug.addHttpLog('Model action ok', details: _status); } catch (error) { _error = error.toString(); _status = _error; _debug.addHttpLog('Model action failed', details: _error); } finally { _acting = false; notifyListeners(); } } void _startPolling() { _pollTimer?.cancel(); var ticks = 0; _pollTimer = Timer.periodic(const Duration(seconds: 2), (timer) async { ticks += 1; await refresh(); final downloading = _snapshot?.models.any( (m) => m.downloadProgress > 0 && m.downloadProgress < 100 && !m.downloaded, ) ?? false; if (!downloading || ticks > 90) { timer.cancel(); } }); } @override void dispose() { _pollTimer?.cancel(); super.dispose(); } }