From ff83ada5765b71cb9833210b88047bd37047c5c4 Mon Sep 17 00:00:00 2001 From: rzuasti Date: Thu, 28 May 2026 19:34:42 -0400 Subject: [PATCH] Improve home screen widget UX: visual hierarchy and navigation - DeviceSummaryCard and ArpScannerCard are now tappable, navigating to the devices list and status screen respectively - Elevated "Devices" title to titleLarge; section subtitles promoted to bodyMedium/w600 while row content is demoted to bodySmall - Renamed top-level row label to "Registered in the system" Co-Authored-By: Claude Sonnet 4.6 --- frontend/lib/widgets/arp_scanner_card.dart | 55 ++++---- frontend/lib/widgets/device_summary_card.dart | 117 ++++++++++-------- 2 files changed, 95 insertions(+), 77 deletions(-) diff --git a/frontend/lib/widgets/arp_scanner_card.dart b/frontend/lib/widgets/arp_scanner_card.dart index 30eaa3a..b39740b 100644 --- a/frontend/lib/widgets/arp_scanner_card.dart +++ b/frontend/lib/widgets/arp_scanner_card.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; import '../model/arp_scanner_status.dart'; import '../utils/oott_api.dart'; @@ -76,35 +77,39 @@ class _ArpScannerCardState extends State { final (color, label, sublabel) = _resolveState(context); return Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Row( - children: [ - Icon(Icons.circle, color: color, size: 14), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'ARP Scanner', - style: Theme.of(context).textTheme.titleMedium, - ), - const SizedBox(height: 2), - Text(label, style: Theme.of(context).textTheme.bodyMedium), - if (sublabel != null) ...[ - const SizedBox(height: 2), + clipBehavior: Clip.antiAlias, + child: InkWell( + onTap: () => context.go('/status'), + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + children: [ + Icon(Icons.circle, color: color, size: 14), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ Text( - sublabel, - style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: Theme.of(context).colorScheme.outline, - ), + 'ARP Scanner', + style: Theme.of(context).textTheme.titleMedium, ), + const SizedBox(height: 2), + Text(label, style: Theme.of(context).textTheme.bodyMedium), + if (sublabel != null) ...[ + const SizedBox(height: 2), + Text( + sublabel, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of(context).colorScheme.outline, + ), + ), + ], ], - ], + ), ), - ), - ], + ], + ), ), ), ); diff --git a/frontend/lib/widgets/device_summary_card.dart b/frontend/lib/widgets/device_summary_card.dart index 91dc32d..f935831 100644 --- a/frontend/lib/widgets/device_summary_card.dart +++ b/frontend/lib/widgets/device_summary_card.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; import '../model/device_summary.dart'; import '../utils/oott_api.dart'; @@ -52,59 +53,65 @@ class _DeviceSummaryCardState extends State { @override Widget build(BuildContext context) { return Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('Devices', style: Theme.of(context).textTheme.titleMedium), - const SizedBox(height: 12), - if (_isLoading) - const Center(child: CircularProgressIndicator()) - else if (_error != null) - Text( - 'Error loading device summary', - style: TextStyle(color: Theme.of(context).colorScheme.error), - ) - else if (_summary != null) ...[ - _SummaryRow( - label: 'Registered', - value: '${_summary!.totalRegistered}', - ), - const Divider(height: 20), - Text( - 'Seen in the last 24 hours', - style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: Theme.of(context).colorScheme.outline, + clipBehavior: Clip.antiAlias, + child: InkWell( + onTap: () => context.go('/devices'), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Devices', style: Theme.of(context).textTheme.titleLarge), + const SizedBox(height: 12), + if (_isLoading) + const Center(child: CircularProgressIndicator()) + else if (_error != null) + Text( + 'Error loading device summary', + style: TextStyle(color: Theme.of(context).colorScheme.error), + ) + else if (_summary != null) ...[ + _SummaryRow( + label: 'Registered in the system', + value: '${_summary!.totalRegistered}', ), - ), - const SizedBox(height: 6), - _SummaryRow( - label: 'Registered', - value: '${_summary!.seenLastDayRegistered}', - ), - _SummaryRow( - label: 'Unregistered', - value: '${_summary!.seenLastDayUnregistered}', - ), - const Divider(height: 20), - Text( - 'Seen in the last 7 days', - style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: Theme.of(context).colorScheme.outline, + const Divider(height: 20), + Text( + 'Seen in the last 24 hours', + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: Theme.of(context).colorScheme.onSurface, + fontWeight: FontWeight.w600, + ), ), - ), - const SizedBox(height: 6), - _SummaryRow( - label: 'Registered', - value: '${_summary!.seenLastWeekRegistered}', - ), - _SummaryRow( - label: 'Unregistered', - value: '${_summary!.seenLastWeekUnregistered}', - ), + const SizedBox(height: 6), + _SummaryRow( + label: 'Registered', + value: '${_summary!.seenLastDayRegistered}', + ), + _SummaryRow( + label: 'Unregistered', + value: '${_summary!.seenLastDayUnregistered}', + ), + const Divider(height: 20), + Text( + 'Seen in the last 7 days', + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: Theme.of(context).colorScheme.onSurface, + fontWeight: FontWeight.w600, + ), + ), + const SizedBox(height: 6), + _SummaryRow( + label: 'Registered', + value: '${_summary!.seenLastWeekRegistered}', + ), + _SummaryRow( + label: 'Unregistered', + value: '${_summary!.seenLastWeekUnregistered}', + ), + ], ], - ], + ), ), ), ); @@ -124,10 +131,16 @@ class _SummaryRow extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text(label, style: Theme.of(context).textTheme.bodyMedium), + Text( + label, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), Text( value, - style: Theme.of(context).textTheme.bodyMedium?.copyWith( + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of(context).colorScheme.onSurfaceVariant, fontWeight: FontWeight.bold, ), ),