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

@ -132,7 +132,9 @@
"noMatches": "Nenguna simiente concasa colos filtros.",
"clearFilters": "Quitar filtros",
"uncategorized": "Ensin categoría",
"needsReproductionFilter": "Por reproducir"
"needsReproductionFilter": "Por reproducir",
"loadError": "Nun se pudo abrir el to bancu de granes. Seique taba ocupáu: prueba otra vuelta.",
"retry": "Volver probar"
},
"draft": {
"capture": "Capturar semeyes",

View file

@ -133,7 +133,9 @@
"noMatches": "No seeds match your filters.",
"clearFilters": "Clear filters",
"uncategorized": "Uncategorized",
"needsReproductionFilter": "To regrow"
"needsReproductionFilter": "To regrow",
"loadError": "Couldn't open your seed bank. It may just have been busy — try again.",
"retry": "Try again"
},
"draft": {
"capture": "Capture photos",

View file

@ -132,7 +132,9 @@
"noMatches": "Ninguna semilla coincide con los filtros.",
"clearFilters": "Quitar filtros",
"uncategorized": "Sin categoría",
"needsReproductionFilter": "Por reproducir"
"needsReproductionFilter": "Por reproducir",
"loadError": "No se pudo abrir tu banco de semillas. Quizá estaba ocupado: inténtalo de nuevo.",
"retry": "Reintentar"
},
"draft": {
"capture": "Capturar fotos",

View file

@ -133,7 +133,9 @@
"noMatches": "Nenhuma semente corresponde aos teus filtros.",
"clearFilters": "Limpar filtros",
"uncategorized": "Sem categoria",
"needsReproductionFilter": "Para reproduzir"
"needsReproductionFilter": "Para reproduzir",
"loadError": "Não foi possível abrir o teu banco de sementes. Talvez estivesse ocupado — tenta de novo.",
"retry": "Tentar de novo"
},
"draft": {
"capture": "Capturar fotos",

View file

@ -4,9 +4,9 @@
/// To regenerate, run: `dart run slang`
///
/// Locales: 4
/// Strings: 1668 (417 per locale)
/// Strings: 1676 (419 per locale)
///
/// Built on 2026-07-10 at 19:42 UTC
/// Built on 2026-07-10 at 20:10 UTC
// coverage:ignore-file
// ignore_for_file: type=lint, unused_import

View file

@ -268,6 +268,8 @@ class _Translations$inventory$ast extends Translations$inventory$en {
@override String get clearFilters => 'Quitar filtros';
@override String get uncategorized => 'Ensin categoría';
@override String get needsReproductionFilter => 'Por reproducir';
@override String get loadError => 'Nun se pudo abrir el to bancu de granes. Seique taba ocupáu: prueba otra vuelta.';
@override String get retry => 'Volver probar';
}
// Path: draft
@ -1248,6 +1250,8 @@ extension on TranslationsAst {
'inventory.clearFilters' => 'Quitar filtros',
'inventory.uncategorized' => 'Ensin categoría',
'inventory.needsReproductionFilter' => 'Por reproducir',
'inventory.loadError' => 'Nun se pudo abrir el to bancu de granes. Seique taba ocupáu: prueba otra vuelta.',
'inventory.retry' => 'Volver probar',
'draft.capture' => 'Capturar semeyes',
'draft.captured' => ({required Object n}) => '${n} capturaes por catalogar',
'draft.triageTitle' => 'Por catalogar',

View file

@ -455,6 +455,12 @@ class Translations$inventory$en {
/// en: 'To regrow'
String get needsReproductionFilter => 'To regrow';
/// en: 'Couldn't open your seed bank. It may just have been busy try again.'
String get loadError => 'Couldn\'t open your seed bank. It may just have been busy — try again.';
/// en: 'Try again'
String get retry => 'Try again';
}
// Path: draft
@ -2070,6 +2076,8 @@ extension on Translations {
'inventory.clearFilters' => 'Clear filters',
'inventory.uncategorized' => 'Uncategorized',
'inventory.needsReproductionFilter' => 'To regrow',
'inventory.loadError' => 'Couldn\'t open your seed bank. It may just have been busy — try again.',
'inventory.retry' => 'Try again',
'draft.capture' => 'Capture photos',
'draft.captured' => ({required Object n}) => '${n} captured to catalogue',
'draft.triageTitle' => 'To catalogue',

View file

@ -268,6 +268,8 @@ class _Translations$inventory$es extends Translations$inventory$en {
@override String get clearFilters => 'Quitar filtros';
@override String get uncategorized => 'Sin categoría';
@override String get needsReproductionFilter => 'Por reproducir';
@override String get loadError => 'No se pudo abrir tu banco de semillas. Quizá estaba ocupado: inténtalo de nuevo.';
@override String get retry => 'Reintentar';
}
// Path: draft
@ -1250,6 +1252,8 @@ extension on TranslationsEs {
'inventory.clearFilters' => 'Quitar filtros',
'inventory.uncategorized' => 'Sin categoría',
'inventory.needsReproductionFilter' => 'Por reproducir',
'inventory.loadError' => 'No se pudo abrir tu banco de semillas. Quizá estaba ocupado: inténtalo de nuevo.',
'inventory.retry' => 'Reintentar',
'draft.capture' => 'Capturar fotos',
'draft.captured' => ({required Object n}) => '${n} capturadas por catalogar',
'draft.triageTitle' => 'Por catalogar',

View file

@ -269,6 +269,8 @@ class _Translations$inventory$pt extends Translations$inventory$en {
@override String get clearFilters => 'Limpar filtros';
@override String get uncategorized => 'Sem categoria';
@override String get needsReproductionFilter => 'Para reproduzir';
@override String get loadError => 'Não foi possível abrir o teu banco de sementes. Talvez estivesse ocupado — tenta de novo.';
@override String get retry => 'Tentar de novo';
}
// Path: draft
@ -1248,6 +1250,8 @@ extension on TranslationsPt {
'inventory.clearFilters' => 'Limpar filtros',
'inventory.uncategorized' => 'Sem categoria',
'inventory.needsReproductionFilter' => 'Para reproduzir',
'inventory.loadError' => 'Não foi possível abrir o teu banco de sementes. Talvez estivesse ocupado — tenta de novo.',
'inventory.retry' => 'Tentar de novo',
'draft.capture' => 'Capturar fotos',
'draft.captured' => ({required Object n}) => '${n} capturadas para catalogar',
'draft.triageTitle' => 'Para catalogar',