import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../domain/models/sensor.dart'; import '../../providers.dart'; class SensorDetailScreen extends ConsumerStatefulWidget { const SensorDetailScreen({super.key, required this.sensorId}); final String sensorId; @override ConsumerState createState() => _SensorDetailScreenState(); } class _SensorDetailScreenState extends ConsumerState { late final int _id = int.parse(widget.sensorId); @override Widget build(BuildContext context) { final sensor = ref.watch(sensorProvider(_id)); return Scaffold( appBar: AppBar( title: Text(sensor.valueOrNull?.displayName ?? 'Sensor'), ), body: sensor.when( loading: () => const Center(child: CircularProgressIndicator()), error: (e, _) => Center(child: Text(e.toString())), data: (s) => _Body(sensor: s, id: _id, sensorId: widget.sensorId), ), ); } } class _Body extends ConsumerWidget { const _Body({required this.sensor, required this.id, required this.sensorId}); final Sensor sensor; final int id; final String sensorId; @override Widget build(BuildContext context, WidgetRef ref) { return Padding( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _InfoRow(label: 'Device ID', value: sensor.sensorId), _InfoRow( label: 'Floor position', value: sensor.isPlaced ? '(${sensor.x!.toStringAsFixed(2)}, ${sensor.y!.toStringAsFixed(2)})' : 'Not placed', ), const SizedBox(height: 24), OutlinedButton.icon( icon: const Icon(Icons.map_outlined), label: const Text('Locate on floor plan'), onPressed: () { ref.read(selectedSensorIdProvider.notifier).state = sensorId; context.go('/floorplan'); }, ), const SizedBox(height: 12), OutlinedButton.icon( icon: const Icon(Icons.edit_outlined), label: const Text('Rename'), onPressed: () => _rename(context, ref), ), const SizedBox(height: 12), OutlinedButton.icon( icon: const Icon(Icons.bluetooth), label: const Text('Re-provision WiFi'), onPressed: () {}, // TODO: show BleProvisionSheet pre-filled ), const Spacer(), TextButton( style: TextButton.styleFrom( foregroundColor: Theme.of(context).colorScheme.error, ), onPressed: () => _delete(context, ref), child: const Text('Delete sensor'), ), ], ), ); } Future _rename(BuildContext context, WidgetRef ref) async { final controller = TextEditingController(text: sensor.name); final confirmed = await showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('Rename sensor'), content: TextField( controller: controller, decoration: const InputDecoration(labelText: 'Name'), autofocus: true, onSubmitted: (_) => Navigator.of(ctx).pop(true), ), actions: [ TextButton( onPressed: () => Navigator.of(ctx).pop(false), child: const Text('Cancel'), ), FilledButton( onPressed: () => Navigator.of(ctx).pop(true), child: const Text('Save'), ), ], ), ); final name = controller.text.trim(); controller.dispose(); if (confirmed == true && name.isNotEmpty && context.mounted) { await ref.read(sensorRepositoryProvider).updateSensor(id, name: name); ref.invalidate(sensorProvider(id)); ref.invalidate(sensorsProvider); } } Future _delete(BuildContext context, WidgetRef ref) async { final confirmed = await showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('Delete sensor?'), content: const Text('This will unenrol the sensor from the system.'), actions: [ TextButton( onPressed: () => Navigator.of(ctx).pop(false), child: const Text('Cancel'), ), FilledButton( style: FilledButton.styleFrom( backgroundColor: Theme.of(context).colorScheme.error, ), onPressed: () => Navigator.of(ctx).pop(true), child: const Text('Delete'), ), ], ), ); if (confirmed == true && context.mounted) { await ref.read(sensorRepositoryProvider).deleteSensor(id); ref.invalidate(sensorsProvider); if (context.mounted) context.pop(); } } } class _InfoRow extends StatelessWidget { const _InfoRow({required this.label, required this.value}); final String label; final String value; @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Row( children: [ Expanded( child: Text(label, style: Theme.of(context).textTheme.bodySmall), ), Text(value, style: Theme.of(context).textTheme.bodyMedium), ], ), ); } }