fix: convert HomeScreen to StatefulWidget with mounted checks

Prevents Duplicate GlobalKeys / wrong build scope crashes when opening
dialogs from async scanner and DB operations. The scan button is also
disabled while a query is in flight to prevent double-taps.
This commit is contained in:
Lukas Müllner 2026-02-23 08:53:04 +01:00
parent bbcacc0664
commit 16d1145efd

View file

@ -339,9 +339,16 @@ class _LoginScreenState extends State<LoginScreen> {
} }
// Home Screen // Home Screen
class HomeScreen extends StatelessWidget { class HomeScreen extends StatefulWidget {
const HomeScreen({super.key}); const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
bool _isBusy = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final user = supabase.auth.currentUser; final user = supabase.auth.currentUser;
@ -379,18 +386,20 @@ class HomeScreen extends StatelessWidget {
floatingActionButton: FloatingActionButton.extended( floatingActionButton: FloatingActionButton.extended(
icon: const Icon(Icons.camera_alt), icon: const Icon(Icons.camera_alt),
label: const Text('Scan'), label: const Text('Scan'),
onPressed: () => _openScanner(context), onPressed: _isBusy ? null : _openScanner,
), ),
); );
} }
/// Opens the scanner, gets the hw_id, then queries the DB. /// Opens the scanner, gets the hw_id, then queries the DB.
Future<void> _openScanner(BuildContext context) async { Future<void> _openScanner() async {
final hwId = await Navigator.of(context).push<String>( final hwId = await Navigator.of(context).push<String>(
MaterialPageRoute(builder: (_) => const ScannerScreen()), MaterialPageRoute(builder: (_) => const ScannerScreen()),
); );
if (hwId == null || !context.mounted) return; if (hwId == null || !mounted) return;
setState(() => _isBusy = true);
try { try {
final data = await supabase final data = await supabase
@ -399,21 +408,18 @@ class HomeScreen extends StatelessWidget {
.eq('hw_id', hwId) .eq('hw_id', hwId)
.maybeSingle(); .maybeSingle();
if (!context.mounted) return; if (!mounted) return;
setState(() => _isBusy = false);
if (data != null) { await showDialog<void>(
showDialog<void>( context: context,
context: context, builder: (_) => data != null
builder: (_) => _AlreadyExistsDialog(hwId: hwId), ? _AlreadyExistsDialog(hwId: hwId)
); : _AddCarDialog(hwId: hwId),
} else { );
showDialog<void>(
context: context,
builder: (_) => _AddCarDialog(hwId: hwId),
);
}
} catch (e) { } catch (e) {
if (!context.mounted) return; if (!mounted) return;
setState(() => _isBusy = false);
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('DB error: $e'), backgroundColor: Colors.red), SnackBar(content: Text('DB error: $e'), backgroundColor: Colors.red),
); );