import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:mirror_ui/mirror_ui.dart'; import '../providers/ha_provider.dart'; class HaEntityPickerScreen extends ConsumerStatefulWidget { final List selectedIds; const HaEntityPickerScreen({super.key, this.selectedIds = const []}); @override ConsumerState createState() => _HaEntityPickerScreenState(); } class _HaEntityPickerScreenState extends ConsumerState { late Set _selected; String _search = ''; @override void initState() { super.initState(); _selected = Set.from(widget.selectedIds); } String _domainOf(String entityId) { final dotIndex = entityId.indexOf('.'); return dotIndex > 0 ? entityId.substring(0, dotIndex) : 'other'; } @override Widget build(BuildContext context) { final entitiesAsync = ref.watch(haEntitiesProvider); return Scaffold( appBar: AppBar( title: const Text('Select HA Entities'), backgroundColor: MirrorTheme.background, actions: [ TextButton( onPressed: () => Navigator.of(context).pop(_selected.toList()), child: Text('Done (${_selected.length})'), ), ], ), backgroundColor: MirrorTheme.background, body: entitiesAsync.when( loading: () => const Center(child: CircularProgressIndicator()), error: (e, _) => Center(child: Text('Error: $e')), data: (state) { if (state.error != null) { return Center(child: Text(state.error!)); } return _buildList(state.entities); }, ), ); } Widget _buildList(List entities) { // Filter by search final filtered = entities.where((e) { final id = e.entityId as String; final name = (e.attributes['friendly_name'] as String?) ?? id; final query = _search.toLowerCase(); return id.toLowerCase().contains(query) || name.toLowerCase().contains(query); }).toList(); // Group by domain final grouped = >{}; for (final entity in filtered) { final domain = _domainOf(entity.entityId as String); grouped.putIfAbsent(domain, () => []).add(entity); } final sortedDomains = grouped.keys.toList()..sort(); return Column( children: [ Padding( padding: const EdgeInsets.all(12), child: TextField( decoration: InputDecoration( hintText: 'Search entities...', prefixIcon: const Icon(Icons.search), filled: true, fillColor: MirrorTheme.surface, border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), ), onChanged: (v) => setState(() => _search = v), ), ), Expanded( child: ListView.builder( itemCount: sortedDomains.length, itemBuilder: (context, domainIndex) { final domain = sortedDomains[domainIndex]; final items = grouped[domain]!; return ExpansionTile( title: Text( domain, style: TextStyle(color: MirrorTheme.accent, fontWeight: FontWeight.w600), ), initiallyExpanded: items.any((e) => _selected.contains(e.entityId)), children: items.map((entity) { final id = entity.entityId as String; final name = (entity.attributes['friendly_name'] as String?) ?? id; return CheckboxListTile( title: Text(name), subtitle: Text(id, style: const TextStyle(fontSize: 12)), value: _selected.contains(id), activeColor: MirrorTheme.accent, onChanged: (checked) { setState(() { if (checked == true) { _selected.add(id); } else { _selected.remove(id); } }); }, ); }).toList(), ); }, ), ), ], ); } }