Pause polling and show a banner when the backend is unreachable

Adds a centralized BackendReachability singleton fed by a Dio
interceptor (connection-level failures only) and connectivity_plus.
PolledValue subscribes to it and pauses on offline / reloads
immediately on reconnect, replacing the previous per-card error
cascade. MainShell renders a global OfflineBanner with Retry and
Settings actions; cards downgrade error→stale when offline so the
banner is the only red element.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
rzuasti
2026-05-31 18:21:55 -04:00
co-authored by Claude Sonnet 4.6
parent 8be65f3ffa
commit b5da90be59
15 changed files with 388 additions and 47 deletions
+25 -5
View File
@@ -8,6 +8,7 @@ import 'devices/device_list.dart';
import 'home/home_screen.dart';
import 'status/status_screen.dart';
import 'utils/pref_utils.dart';
import 'widgets/offline_banner.dart';
// M3 window size class breakpoints
const _mediumBreakpoint = 600.0;
@@ -109,9 +110,19 @@ class MainShell extends StatelessWidget {
if (width < _mediumBreakpoint) {
return Scaffold(
appBar: _buildAppBar(context),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: child,
body: Column(
children: [
const OfflineBanner(),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 12,
),
child: child,
),
),
],
),
bottomNavigationBar: NavigationBar(
selectedIndex: selectedIndex,
@@ -156,9 +167,18 @@ class MainShell extends StatelessWidget {
),
Expanded(
child: Container(
padding: const EdgeInsets.all(20),
color: Theme.of(context).colorScheme.surface,
child: child,
child: Column(
children: [
const OfflineBanner(),
Expanded(
child: Padding(
padding: const EdgeInsets.all(20),
child: child,
),
),
],
),
),
),
],