import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../providers/providers.dart'; import 'color_picker.dart'; /// Карточка одной группы ламп с управлением: /// вкл/выкл, яркость, температура, цвет, сцена. class GroupCard extends ConsumerStatefulWidget { final Map group; const GroupCard({super.key, required this.group}); @override ConsumerState createState() => _GroupCardState(); } class _GroupCardState extends ConsumerState { /// Текущий режим управления: temp (температура) или color (RGB) String _mode = 'temp'; bool _showColorPicker = false; @override Widget build(BuildContext context) { final g = widget.group; final id = g['id'].toString(); final name = g['name'] ?? 'Без имени'; final bool isOn = g['last_state']?['state'] ?? false; final int bri = g['last_state']?['brightness'] ?? 100; final int temp = g['last_state']?['temp'] ?? 4000; final int r = g['last_state']?['r'] ?? 255; final int gVal = g['last_state']?['g'] ?? 200; final int b = g['last_state']?['b'] ?? 100; // Цвет подсветки карточки зависит от режима и состояния final cardAccent = isOn ? (_mode == 'temp' ? Color.lerp(Colors.orange, Colors.blueAccent, (temp - 2700) / 3800)! : Color.fromARGB(255, r, gVal, b)) : Colors.white12; return Card( margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), child: AnimatedContainer( duration: const Duration(milliseconds: 300), decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), border: isOn ? Border.all(color: cardAccent.withOpacity(0.3), width: 1) : null, ), child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // ─── Заголовок + переключатель ─── Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Text( name, style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: isOn ? Colors.white : Colors.white54, ), ), ), // Кнопка "таймер на 4 часа" if (isOn) IconButton( icon: const Icon(Icons.timer, size: 20, color: Colors.white38), tooltip: 'Включить на 4 часа', onPressed: () => ref.read(groupsProvider.notifier).setTimer4h(id), ), Switch( value: isOn, activeColor: Colors.deepOrange, onChanged: (v) => ref.read(groupsProvider.notifier).toggleGroup(id, v), ), ], ), // ─── Управление (когда включено) ─── if (isOn) ...[ const SizedBox(height: 8), // Яркость _SliderRow( icon: Icons.sunny, value: bri.toDouble().clamp(10, 100), min: 10, max: 100, divisions: 9, label: "$bri%", activeColor: Colors.amber, onChanged: (v) => ref .read(groupsProvider.notifier) .setBrightness(id, v.toInt()), ), // Переключатель режима: температура / цвет / сцена Row( children: [ _ModeChip( label: 'Темп.', icon: Icons.wb_twilight, selected: _mode == 'temp', onTap: () => setState(() { _mode = 'temp'; _showColorPicker = false; }), ), const SizedBox(width: 8), _ModeChip( label: 'Цвет', icon: Icons.palette, selected: _mode == 'color', onTap: () => setState(() { _mode = 'color'; _showColorPicker = true; }), ), const SizedBox(width: 8), _ModeChip( label: 'Сцена', icon: Icons.auto_awesome, selected: _mode == 'scene', onTap: () => setState(() { _mode = 'scene'; _showColorPicker = false; }), ), ], ), const SizedBox(height: 8), // ─── Режим: температура ─── if (_mode == 'temp') _SliderRow( icon: Icons.wb_twilight, value: temp.toDouble().clamp(2700, 6500), min: 2700, max: 6500, divisions: 38, // шаг 100K label: "${temp}K", activeColor: Color.lerp( Colors.orange, Colors.blueAccent, (temp - 2700) / 3800), onChanged: (v) => ref .read(groupsProvider.notifier) .setTemperature(id, v.toInt()), ), // ─── Режим: цвет ─── if (_mode == 'color') SimpleColorPicker( initialColor: Color.fromARGB(255, r, gVal, b), onColorChanged: (c) => ref .read(groupsProvider.notifier) .setColor(id, c.red, c.green, c.blue), ), // ─── Режим: сцена ─── if (_mode == 'scene') _SceneSelector(groupId: id), ], ], ), ), ), ); } } /// Слайдер с иконкой и подписью class _SliderRow extends StatelessWidget { final IconData icon; final double value; final double min; final double max; final int divisions; final String label; final Color? activeColor; final ValueChanged onChanged; const _SliderRow({ required this.icon, required this.value, required this.min, required this.max, required this.divisions, required this.label, this.activeColor, required this.onChanged, }); @override Widget build(BuildContext context) { return Row( children: [ Icon(icon, size: 18, color: Colors.white54), Expanded( child: Slider( value: value, min: min, max: max, divisions: divisions, label: label, activeColor: activeColor, onChanged: onChanged, ), ), SizedBox( width: 50, child: Text( label, style: const TextStyle(fontSize: 12, color: Colors.white54), textAlign: TextAlign.right, ), ), ], ); } } /// Чип переключения режима class _ModeChip extends StatelessWidget { final String label; final IconData icon; final bool selected; final VoidCallback onTap; const _ModeChip({ required this.label, required this.icon, required this.selected, required this.onTap, }); @override Widget build(BuildContext context) { return GestureDetector( onTap: onTap, child: AnimatedContainer( duration: const Duration(milliseconds: 200), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: selected ? Colors.deepOrange.withOpacity(0.2) : Colors.white10, borderRadius: BorderRadius.circular(20), border: selected ? Border.all(color: Colors.deepOrange, width: 1) : Border.all(color: Colors.transparent), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, size: 14, color: selected ? Colors.deepOrange : Colors.white54), const SizedBox(width: 4), Text( label, style: TextStyle( fontSize: 12, color: selected ? Colors.deepOrange : Colors.white54, ), ), ], ), ), ); } } /// Выбор сцены из списка, загруженного с сервера class _SceneSelector extends ConsumerWidget { final String groupId; const _SceneSelector({required this.groupId}); @override Widget build(BuildContext context, WidgetRef ref) { final scenes = ref.watch(scenesProvider); if (scenes.isEmpty) { // Загрузить сцены при первом показе Future.microtask(() => ref.read(scenesProvider.notifier).load()); return const Padding( padding: EdgeInsets.all(8.0), child: Center( child: SizedBox( width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2), ), ), ); } return Wrap( spacing: 8, runSpacing: 4, children: scenes.map((scene) { // Сцена может быть строкой или Map с полем 'name'/'id' final sceneName = scene is String ? scene : (scene['name'] ?? scene['id'] ?? scene.toString()); final sceneId = scene is String ? scene : (scene['id'] ?? scene['name'] ?? scene.toString()); return ActionChip( label: Text(sceneName.toString(), style: const TextStyle(fontSize: 12)), backgroundColor: Colors.white10, onPressed: () => ref .read(groupsProvider.notifier) .setScene(groupId, sceneId.toString()), ); }).toList(), ); } }