fix: report group control failures
This commit is contained in:
@@ -278,7 +278,7 @@ class GroupsLoadStateNotifier extends Notifier<GroupsLoadState> {
|
||||
}
|
||||
|
||||
void setError(Object error) =>
|
||||
state = GroupsLoadState.error(error.toString());
|
||||
state = GroupsLoadState.error(describeLoadError(error));
|
||||
}
|
||||
|
||||
class GroupsNotifier extends Notifier<List<dynamic>> {
|
||||
@@ -432,7 +432,6 @@ class GroupsNotifier extends Notifier<List<dynamic>> {
|
||||
state = updatedList;
|
||||
ref.read(groupsLoadStateProvider.notifier).setData(updatedList);
|
||||
} catch (e) {
|
||||
debugPrint("Ошибка глобального опроса: $e");
|
||||
if (_isActiveGeneration(generation)) {
|
||||
ref.read(groupsLoadStateProvider.notifier).setError(e);
|
||||
}
|
||||
@@ -474,6 +473,7 @@ class GroupsNotifier extends Notifier<List<dynamic>> {
|
||||
void _debouncedControl(
|
||||
String id,
|
||||
String key,
|
||||
String action,
|
||||
Map<String, dynamic> localPatch,
|
||||
Map<String, dynamic> apiParams,
|
||||
) {
|
||||
@@ -489,7 +489,8 @@ class GroupsNotifier extends Notifier<List<dynamic>> {
|
||||
await _api.controlGroup(id, apiParams);
|
||||
} catch (e) {
|
||||
_lockUntil.remove(id);
|
||||
refresh();
|
||||
await refresh();
|
||||
ref.read(groupControlErrorProvider.notifier).report(id, action, e);
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -513,6 +514,7 @@ class GroupsNotifier extends Notifier<List<dynamic>> {
|
||||
_debouncedControl(
|
||||
id,
|
||||
'brightness',
|
||||
'яркость',
|
||||
{'brightness': value},
|
||||
{'brightness': value},
|
||||
);
|
||||
@@ -520,7 +522,13 @@ class GroupsNotifier extends Notifier<List<dynamic>> {
|
||||
|
||||
/// Установить цветовую температуру (2700-6500K) -- с debounce
|
||||
void setTemperature(String id, int value) {
|
||||
_debouncedControl(id, 'temp', {'temp': value}, {'temp': value});
|
||||
_debouncedControl(
|
||||
id,
|
||||
'temp',
|
||||
'температуру',
|
||||
{'temp': value},
|
||||
{'temp': value},
|
||||
);
|
||||
}
|
||||
|
||||
/// Установить RGB-цвет -- с debounce
|
||||
@@ -528,6 +536,7 @@ class GroupsNotifier extends Notifier<List<dynamic>> {
|
||||
_debouncedControl(
|
||||
id,
|
||||
'color',
|
||||
'цвет',
|
||||
{'r': r, 'g': g, 'b': b},
|
||||
{'r': r, 'g': g, 'b': b},
|
||||
);
|
||||
@@ -558,6 +567,41 @@ class GroupsNotifier extends Notifier<List<dynamic>> {
|
||||
}
|
||||
}
|
||||
|
||||
class GroupControlError {
|
||||
final String groupId;
|
||||
final String action;
|
||||
final String message;
|
||||
final int sequence;
|
||||
|
||||
const GroupControlError({
|
||||
required this.groupId,
|
||||
required this.action,
|
||||
required this.message,
|
||||
required this.sequence,
|
||||
});
|
||||
}
|
||||
|
||||
final groupControlErrorProvider =
|
||||
NotifierProvider<GroupControlErrorNotifier, GroupControlError?>(
|
||||
() => GroupControlErrorNotifier(),
|
||||
);
|
||||
|
||||
class GroupControlErrorNotifier extends Notifier<GroupControlError?> {
|
||||
int _sequence = 0;
|
||||
|
||||
@override
|
||||
GroupControlError? build() => null;
|
||||
|
||||
void report(String groupId, String action, Object error) {
|
||||
state = GroupControlError(
|
||||
groupId: groupId,
|
||||
action: action,
|
||||
message: describeLoadError(error),
|
||||
sequence: ++_sequence,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Устройства (для создания групп) ─────────────────────────
|
||||
|
||||
final devicesProvider =
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../app/error_message.dart';
|
||||
import '../providers/providers.dart';
|
||||
import '../widgets/group_card.dart';
|
||||
import 'homes_screen.dart';
|
||||
@@ -191,8 +192,7 @@ class _RemoteScreenState extends ConsumerState<RemoteScreen> {
|
||||
),
|
||||
child: const Icon(Icons.delete, color: Colors.redAccent),
|
||||
),
|
||||
confirmDismiss: (_) => _confirmDeleteGroup(context, g),
|
||||
onDismissed: (_) => _deleteGroup(g['id'].toString()),
|
||||
confirmDismiss: (_) => _confirmAndDeleteGroup(context, g),
|
||||
child: GroupCard(group: g),
|
||||
);
|
||||
},
|
||||
@@ -201,12 +201,13 @@ class _RemoteScreenState extends ConsumerState<RemoteScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
/// Подтверждение удаления группы свайпом
|
||||
Future<bool> _confirmDeleteGroup(
|
||||
Future<bool> _confirmAndDeleteGroup(
|
||||
BuildContext context,
|
||||
Map<String, dynamic> g,
|
||||
) async {
|
||||
return await showDialog<bool>(
|
||||
final messenger = ScaffoldMessenger.of(context);
|
||||
final confirmed =
|
||||
await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: const Text('Удалить группу?'),
|
||||
@@ -227,18 +228,20 @@ class _RemoteScreenState extends ConsumerState<RemoteScreen> {
|
||||
),
|
||||
) ??
|
||||
false;
|
||||
}
|
||||
|
||||
Future<void> _deleteGroup(String id) async {
|
||||
if (!confirmed) return false;
|
||||
|
||||
try {
|
||||
await ref.read(apiProvider).deleteGroup(id);
|
||||
await ref.read(apiProvider).deleteGroup(g['id'].toString());
|
||||
await ref.read(groupsProvider.notifier).refresh();
|
||||
return true;
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(SnackBar(content: Text('Ошибка удаления: $e')));
|
||||
messenger.showSnackBar(
|
||||
SnackBar(content: Text('Ошибка удаления: ${describeLoadError(e)}')),
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,17 @@ class _GroupCardState extends ConsumerState<GroupCard> {
|
||||
final int gVal = g['last_state']?['g'] ?? 200;
|
||||
final int b = g['last_state']?['b'] ?? 100;
|
||||
|
||||
ref.listen<GroupControlError?>(groupControlErrorProvider, (previous, next) {
|
||||
if (next == null || next.groupId != id) return;
|
||||
if (previous?.sequence == next.sequence) return;
|
||||
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Не удалось применить ${next.action}: ${next.message}'),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
// Значения слайдеров: локальные (если тянем) или серверные
|
||||
final briValue = (_localBrightness ?? bri.toDouble()).clamp(10.0, 100.0);
|
||||
final tempValue = (_localTemp ?? temp.toDouble()).clamp(2700.0, 6500.0);
|
||||
|
||||
Reference in New Issue
Block a user