fix(inventory): recover from a stuck loading spinner

The inventory stream subscription had no onError handler, so a transient
failure at startup (e.g. the encrypted DB not yet ready) went unhandled
and left loading=true forever — the spinner that only a restart cleared.

Handle stream errors: drop out of loading, surface an error state, and
offer a retry that re-opens the stream. Add a _LoadError view (i18n en/
es/ast/pt) and cover both the failure and the retry-recovers paths.
This commit is contained in:
vjrj 2026-07-10 22:12:24 +02:00
parent bb4ee2fd89
commit f45c452615
12 changed files with 158 additions and 17 deletions

View file

@ -46,7 +46,9 @@ class InventoryListScreen extends StatelessWidget {
),
child: const Icon(Icons.add),
),
body: state.loading
body: state.error != null
? _LoadError(onRetry: context.read<InventoryCubit>().retry)
: state.loading
? const Center(child: CircularProgressIndicator())
: Column(
children: [
@ -237,6 +239,38 @@ class InventoryListScreen extends StatelessWidget {
/// A tappable banner announcing how many photo-first captures are waiting to be
/// named. Opens the "to catalogue" tray.
/// Shown when the inventory stream fails to open instead of an endless
/// spinner, offer a clear message and a way to try again.
class _LoadError extends StatelessWidget {
const _LoadError({required this.onRetry});
final VoidCallback onRetry;
@override
Widget build(BuildContext context) {
final t = context.t;
return Center(
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.cloud_off_outlined, size: 48, color: seedGreen),
const SizedBox(height: 16),
Text(t.inventory.loadError, textAlign: TextAlign.center),
const SizedBox(height: 16),
FilledButton(
key: const Key('inventory.retry'),
onPressed: onRetry,
child: Text(t.inventory.retry),
),
],
),
),
);
}
}
class _TriageBanner extends StatelessWidget {
const _TriageBanner({required this.count});