// Version: 1.0.0 | Created: 2026-07-04 // Panic button settings — choose the alert room and message. // Opened from Profile > Emergency panic button. import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:matrix/matrix.dart'; import '../../../core/network/matrix_client.dart'; import '../data/panic_repository.dart'; Future showPanicSettingsDialog(BuildContext context, WidgetRef ref) { return showDialog( context: context, builder: (_) => const _PanicSettingsDialog(), ); } class _PanicSettingsDialog extends ConsumerStatefulWidget { const _PanicSettingsDialog(); @override ConsumerState<_PanicSettingsDialog> createState() => _PanicSettingsDialogState(); } class _PanicSettingsDialogState extends ConsumerState<_PanicSettingsDialog> { String? _roomId; late final TextEditingController _messageController; bool _saving = false; @override void initState() { super.initState(); final cfg = ref.read(panicRepositoryProvider).config; _roomId = cfg?.roomId; _messageController = TextEditingController( text: cfg?.message ?? 'EMERGENCY: I need help. This is an automated alert from M8Chat.', ); } @override void dispose() { _messageController.dispose(); super.dispose(); } Future _save() async { final roomId = _roomId; if (roomId == null) return; setState(() => _saving = true); try { await ref.read(panicRepositoryProvider).saveConfig( roomId: roomId, message: _messageController.text.trim(), ); if (mounted) { Navigator.of(context).pop(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Panic button armed. Hold the alert icon ' 'on the rooms screen to trigger it.'), ), ); } } on Exception catch (e) { if (mounted) { setState(() => _saving = false); ScaffoldMessenger.of(context) .showSnackBar(SnackBar(content: Text('Could not save: $e'))); } } } Future _disable() async { setState(() => _saving = true); await ref.read(panicRepositoryProvider).clearConfig(); if (mounted) { Navigator.of(context).pop(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Panic button disabled.')), ); } } @override Widget build(BuildContext context) { final client = ref.watch(matrixClientProvider); final rooms = client.rooms .where((r) => r.membership == Membership.join) .toList() ..sort((a, b) => a .getLocalizedDisplayname() .toLowerCase() .compareTo(b.getLocalizedDisplayname().toLowerCase())); final hasConfig = ref.read(panicRepositoryProvider).config != null; return AlertDialog( title: const Text('Emergency panic button'), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'When you hold the alert icon, M8Chat sends this message ' 'and your current location to the room you choose here.', ), const SizedBox(height: 16), DropdownButtonFormField( initialValue: rooms.any((r) => r.id == _roomId) ? _roomId : null, isExpanded: true, decoration: const InputDecoration( labelText: 'Send alert to room', border: OutlineInputBorder(), ), items: [ for (final room in rooms) DropdownMenuItem( value: room.id, child: Text( room.getLocalizedDisplayname(), overflow: TextOverflow.ellipsis, ), ), ], onChanged: (v) => setState(() => _roomId = v), ), const SizedBox(height: 16), TextField( controller: _messageController, maxLines: 3, decoration: const InputDecoration( labelText: 'Alert message', border: OutlineInputBorder(), ), ), ], ), ), actions: [ if (hasConfig) TextButton( onPressed: _saving ? null : _disable, child: const Text('Disable', style: TextStyle(color: Colors.red)), ), TextButton( onPressed: _saving ? null : () => Navigator.of(context).pop(), child: const Text('Cancel'), ), FilledButton( onPressed: _saving || _roomId == null ? null : _save, child: _saving ? const SizedBox( width: 18, height: 18, child: CircularProgressIndicator(strokeWidth: 2), ) : const Text('Save'), ), ], ); } }