feat: surface device and scene load errors
This commit is contained in:
@@ -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 'color_picker.dart';
|
||||
|
||||
@@ -90,14 +91,12 @@ class _GroupCardState extends ConsumerState<GroupCard> {
|
||||
color: Colors.white38,
|
||||
),
|
||||
tooltip: 'Включить на 4 часа',
|
||||
onPressed: () =>
|
||||
ref.read(groupsProvider.notifier).setTimer4h(id),
|
||||
onPressed: () => _setTimer4h(id),
|
||||
),
|
||||
Switch(
|
||||
value: isOn,
|
||||
activeThumbColor: Colors.deepOrange,
|
||||
onChanged: (v) =>
|
||||
ref.read(groupsProvider.notifier).toggleGroup(id, v),
|
||||
onChanged: (v) => _toggleGroup(id, v),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -204,6 +203,32 @@ class _GroupCardState extends ConsumerState<GroupCard> {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _toggleGroup(String id, bool value) async {
|
||||
try {
|
||||
await ref.read(groupsProvider.notifier).toggleGroup(id, value);
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Ошибка управления группой: ${describeLoadError(e)}'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _setTimer4h(String id) async {
|
||||
try {
|
||||
await ref.read(groupsProvider.notifier).setTimer4h(id);
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Ошибка создания таймера: ${describeLoadError(e)}'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Слайдер с иконкой и подписью
|
||||
@@ -324,16 +349,18 @@ class _SceneSelector extends ConsumerStatefulWidget {
|
||||
}
|
||||
|
||||
class _SceneSelectorState extends ConsumerState<_SceneSelector> {
|
||||
bool _loadStarted = false;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
Future.microtask(() => ref.read(scenesProvider.notifier).load());
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scenes = ref.watch(scenesProvider);
|
||||
final scenesState = ref.watch(scenesProvider);
|
||||
final scenes = scenesState.data;
|
||||
|
||||
if (scenes.isEmpty && !_loadStarted) {
|
||||
// Загрузить сцены при первом показе
|
||||
_loadStarted = true;
|
||||
Future.microtask(() => ref.read(scenesProvider.notifier).load());
|
||||
if ((scenesState.isIdle || scenesState.isLoading) && scenes.isEmpty) {
|
||||
return const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Center(
|
||||
@@ -346,6 +373,34 @@ class _SceneSelectorState extends ConsumerState<_SceneSelector> {
|
||||
);
|
||||
}
|
||||
|
||||
if (scenesState.hasError && scenes.isEmpty) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Не удалось загрузить сцены',
|
||||
style: const TextStyle(color: Colors.white54, fontSize: 12),
|
||||
),
|
||||
if (scenesState.errorMessage != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 4),
|
||||
child: Text(
|
||||
scenesState.errorMessage!,
|
||||
style: const TextStyle(color: Colors.white30, fontSize: 11),
|
||||
),
|
||||
),
|
||||
TextButton.icon(
|
||||
onPressed: _loadScenes,
|
||||
icon: const Icon(Icons.refresh, size: 16),
|
||||
label: const Text('Повторить'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (scenes.isEmpty) {
|
||||
return const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
@@ -356,34 +411,75 @@ class _SceneSelectorState extends ConsumerState<_SceneSelector> {
|
||||
);
|
||||
}
|
||||
|
||||
return Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 4,
|
||||
children: scenes.map((scene) {
|
||||
String sceneName;
|
||||
String sceneId;
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (scenesState.hasError)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.warning_amber_rounded,
|
||||
size: 16,
|
||||
color: Colors.deepOrange,
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
const Expanded(
|
||||
child: Text(
|
||||
'Сцены не обновились',
|
||||
style: TextStyle(color: Colors.white38, fontSize: 12),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
tooltip: 'Повторить',
|
||||
onPressed: _loadScenes,
|
||||
icon: const Icon(Icons.refresh, size: 16),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 4,
|
||||
children: scenes.map((scene) {
|
||||
String sceneName;
|
||||
String sceneId;
|
||||
|
||||
if (scene is String) {
|
||||
sceneName = scene;
|
||||
sceneId = scene;
|
||||
} else if (scene is Map) {
|
||||
sceneName = (scene['name'] ?? scene['id'] ?? scene.toString())
|
||||
.toString();
|
||||
sceneId = (scene['id'] ?? scene['name'] ?? scene.toString())
|
||||
.toString();
|
||||
} else {
|
||||
sceneName = scene.toString();
|
||||
sceneId = scene.toString();
|
||||
}
|
||||
if (scene is String) {
|
||||
sceneName = scene;
|
||||
sceneId = scene;
|
||||
} else if (scene is Map) {
|
||||
sceneName = (scene['name'] ?? scene['id'] ?? scene.toString())
|
||||
.toString();
|
||||
sceneId = (scene['id'] ?? scene['name'] ?? scene.toString())
|
||||
.toString();
|
||||
} else {
|
||||
sceneName = scene.toString();
|
||||
sceneId = scene.toString();
|
||||
}
|
||||
|
||||
return ActionChip(
|
||||
label: Text(sceneName, style: const TextStyle(fontSize: 12)),
|
||||
backgroundColor: Colors.white10,
|
||||
onPressed: () => ref
|
||||
.read(groupsProvider.notifier)
|
||||
.setScene(widget.groupId, sceneId),
|
||||
);
|
||||
}).toList(),
|
||||
return ActionChip(
|
||||
label: Text(sceneName, style: const TextStyle(fontSize: 12)),
|
||||
backgroundColor: Colors.white10,
|
||||
onPressed: () => _setScene(sceneId),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _loadScenes() => ref.read(scenesProvider.notifier).load();
|
||||
|
||||
Future<void> _setScene(String sceneId) async {
|
||||
try {
|
||||
await ref.read(groupsProvider.notifier).setScene(widget.groupId, sceneId);
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Ошибка сцены: ${describeLoadError(e)}')),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user