feat(backup): add automatic weekly encrypted backups
A silent safety net against in-app data loss or DB corruption, with zero friction. Driven off the app lifecycle (startup + when hidden), it writes a sealed .tanemaki copy into the app's private storage once a week, keeping the newest 3 (rotating). Reuses the manual backup's encryption via the extracted ExportImportService.buildSealedBackup(); never throws, so a failed copy can't crash startup or backgrounding. Not registered on web (no file storage). Settings shows a quiet reassurance line with the date of the last automatic copy (localised via intl), hidden where no automatic backup exists.
This commit is contained in:
parent
cf6975b748
commit
9c449964fd
19 changed files with 559 additions and 29 deletions
|
|
@ -7,12 +7,14 @@ import 'package:go_router/go_router.dart';
|
|||
import 'data/species_repository.dart';
|
||||
import 'data/variety_repository.dart';
|
||||
import 'i18n/strings.g.dart';
|
||||
import 'services/auto_backup_service.dart';
|
||||
import 'services/onboarding_store.dart';
|
||||
import 'services/social_service.dart';
|
||||
import 'services/social_settings.dart';
|
||||
import 'state/inventory_cubit.dart';
|
||||
import 'state/variety_detail_cubit.dart';
|
||||
import 'ui/about_screen.dart';
|
||||
import 'ui/auto_backup_gate.dart';
|
||||
import 'ui/home_screen.dart';
|
||||
import 'ui/intro_screen.dart';
|
||||
import 'ui/inventory_list_screen.dart';
|
||||
|
|
@ -32,14 +34,15 @@ class TaneApp extends StatelessWidget {
|
|||
this.social,
|
||||
this.socialSettings,
|
||||
this.showIntro = false,
|
||||
this.autoBackup,
|
||||
super.key,
|
||||
}) : _router = _buildRouter(
|
||||
repository,
|
||||
onboarding,
|
||||
showIntro,
|
||||
social,
|
||||
socialSettings,
|
||||
);
|
||||
repository,
|
||||
onboarding,
|
||||
showIntro,
|
||||
social,
|
||||
socialSettings,
|
||||
);
|
||||
|
||||
final VarietyRepository repository;
|
||||
final SpeciesRepository species;
|
||||
|
|
@ -50,6 +53,10 @@ class TaneApp extends StatelessWidget {
|
|||
final SocialService? social;
|
||||
final SocialSettings? socialSettings;
|
||||
final bool showIntro;
|
||||
|
||||
/// Drives silent periodic backups off the app lifecycle. Null in widget tests
|
||||
/// and on platforms without file storage (web) — the gate then does nothing.
|
||||
final AutoBackupService? autoBackup;
|
||||
final GoRouter _router;
|
||||
|
||||
static GoRouter _buildRouter(
|
||||
|
|
@ -116,22 +123,25 @@ class TaneApp extends StatelessWidget {
|
|||
RepositoryProvider.value(value: repository),
|
||||
RepositoryProvider.value(value: species),
|
||||
],
|
||||
child: MaterialApp.router(
|
||||
onGenerateTitle: (context) => context.t.app.title,
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: buildTaneTheme(),
|
||||
// Let scrollables & PageViews be dragged with a mouse/trackpad on
|
||||
// desktop (Flutter disables that by default), so the photo carousel and
|
||||
// lists swipe there too.
|
||||
scrollBehavior: const _DragScrollBehavior(),
|
||||
locale: TranslationProvider.of(context).flutterLocale,
|
||||
supportedLocales: AppLocaleUtils.supportedLocales,
|
||||
localizationsDelegates: const [
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
routerConfig: _router,
|
||||
child: AutoBackupGate(
|
||||
service: autoBackup,
|
||||
child: MaterialApp.router(
|
||||
onGenerateTitle: (context) => context.t.app.title,
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: buildTaneTheme(),
|
||||
// Let scrollables & PageViews be dragged with a mouse/trackpad on
|
||||
// desktop (Flutter disables that by default), so the photo carousel and
|
||||
// lists swipe there too.
|
||||
scrollBehavior: const _DragScrollBehavior(),
|
||||
locale: TranslationProvider.of(context).flutterLocale,
|
||||
supportedLocales: AppLocaleUtils.supportedLocales,
|
||||
localizationsDelegates: const [
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
routerConfig: _router,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue