feat: type stats and event log models

This commit is contained in:
Artem Kokos
2026-04-23 21:05:37 +07:00
parent 0fdaf0bac4
commit 0c74748650
6 changed files with 303 additions and 96 deletions

View File

@@ -7,11 +7,13 @@ import '../app/error_message.dart';
import '../app/load_state.dart';
import '../models/api_key_info.dart';
import '../models/auth_info.dart';
import '../models/event_log_item.dart';
import '../models/ignis_device.dart';
import '../models/ignis_group.dart';
import '../models/ignis_scene.dart';
import '../models/home_config.dart';
import '../models/schedule_task.dart';
import '../models/stats_summary.dart';
import '../services/api_client.dart';
import '../services/settings_service.dart';
import '../services/geofence_worker.dart';
@@ -697,30 +699,23 @@ class TasksNotifier extends Notifier<LoadState<List<ScheduleTask>>> {
// ─── Статистика ──────────────────────────────────────────────
final statsProvider =
NotifierProvider<StatsNotifier, LoadState<Map<String, dynamic>>>(
() => StatsNotifier(),
);
final statsProvider = NotifierProvider<StatsNotifier, LoadState<StatsSummary>>(
() => StatsNotifier(),
);
class StatsNotifier extends Notifier<LoadState<Map<String, dynamic>>> {
class StatsNotifier extends Notifier<LoadState<StatsSummary>> {
@override
LoadState<Map<String, dynamic>> build() =>
const LoadState.idle(<String, dynamic>{});
LoadState<StatsSummary> build() => const LoadState.idle(StatsSummary.empty);
Future<void> load({int days = 7}) async {
state = LoadState.loading(state.data);
try {
final api = ref.read(apiProvider);
final res = await api.getStatsSummary(days: days);
final data = res.data;
if (data is! Map) {
throw FormatException('stats summary должен быть объектом');
}
final stats = Map<String, dynamic>.from(data);
final groups = stats['groups'];
final hasGroups = groups is List && groups.isNotEmpty;
state = hasGroups ? LoadState.data(stats) : LoadState.empty(stats);
final stats = StatsSummary.fromApi(res.data);
state = stats.groups.isEmpty
? LoadState.empty(stats)
: LoadState.data(stats);
} catch (e) {
state = LoadState.error(state.data, describeLoadError(e));
}
@@ -730,32 +725,21 @@ class StatsNotifier extends Notifier<LoadState<Map<String, dynamic>>> {
// ─── Лог событий ─────────────────────────────────────────────
final eventLogProvider =
NotifierProvider<EventLogNotifier, LoadState<List<dynamic>>>(
NotifierProvider<EventLogNotifier, LoadState<List<EventLogItem>>>(
() => EventLogNotifier(),
);
class EventLogNotifier extends Notifier<LoadState<List<dynamic>>> {
class EventLogNotifier extends Notifier<LoadState<List<EventLogItem>>> {
@override
LoadState<List<dynamic>> build() => const LoadState.idle(<dynamic>[]);
LoadState<List<EventLogItem>> build() =>
const LoadState.idle(<EventLogItem>[]);
Future<void> load({int limit = 100}) async {
state = LoadState.loading(state.data);
try {
final api = ref.read(apiProvider);
final res = await api.getStatsLog(limit: limit);
final data = res.data;
late final List<dynamic> events;
if (data is List) {
events = List<dynamic>.from(data);
} else if (data is Map) {
final value = data['data'] ?? data['events'] ?? data.values.toList();
if (value is! List) {
throw FormatException('stats log должен быть списком событий');
}
events = List<dynamic>.from(value);
} else {
throw FormatException('stats log должен быть списком событий');
}
final events = EventLogItem.listFromApi(res.data);
state = events.isEmpty ? LoadState.empty(events) : LoadState.data(events);
} catch (e) {