From e0fe9c3e0df3bf26a9161f3dc7bc31b802172c69 Mon Sep 17 00:00:00 2001 From: braniii Date: Fri, 29 Mar 2024 13:08:07 +0100 Subject: [PATCH 1/7] Add backup interval class and add to preference backend, --- CHANGELOG.md | 2 ++ app/lib/core/backupInterval.dart | 50 ++++++++++++++++++++++++++++++++ app/lib/core/preferences.dart | 17 +++++++++++ app/lib/l10n/app_en.arb | 16 ++++++++++ 4 files changed, 85 insertions(+) create mode 100644 app/lib/core/backupInterval.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index c8390aaf..6b3111f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Other changes: +- Add backup reminder, see settings for more options ## [0.6.1] - 2024-03-21 diff --git a/app/lib/core/backupInterval.dart b/app/lib/core/backupInterval.dart new file mode 100644 index 00000000..175d05b1 --- /dev/null +++ b/app/lib/core/backupInterval.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + + +/// Enum with all available backup intervals +enum BackupInterval { + /// never + never, + /// weekly + weekly, + /// bi-weekly + biweekly, + /// monthly + monthly, +} + +/// extend interpolation strength +extension BackupIntervalExtension on BackupInterval { + /// get the length [days] + int get inDays => { + BackupInterval.never: -1, + BackupInterval.weekly: 7, + BackupInterval.biweekly: 14, + BackupInterval.monthly: 28, + }[this]!; + + /// get international name + String nameLong (BuildContext context) => { + BackupInterval.never: AppLocalizations.of(context)!.never, + BackupInterval.weekly: AppLocalizations.of(context)!.weekly, + BackupInterval.biweekly: AppLocalizations.of(context)!.biweekly, + BackupInterval.monthly: AppLocalizations.of(context)!.monthly, + }[this]!; + + /// get string expression + String get name => toString().split('.').last; +} + +/// convert string to interpolation strength +extension BackupIntervalParsing on String { + /// convert string to interpolation strength + BackupInterval? toBackupInterval() { + for (final BackupInterval interval in BackupInterval.values) { + if (this == interval.name) { + return interval; + } + } + return null; + } +} diff --git a/app/lib/core/preferences.dart b/app/lib/core/preferences.dart index 6c57e8c5..d87ec59f 100644 --- a/app/lib/core/preferences.dart +++ b/app/lib/core/preferences.dart @@ -1,4 +1,5 @@ import 'package:shared_preferences/shared_preferences.dart'; +import 'package:trale/core/backupInterval.dart'; import 'package:trale/core/interpolation.dart'; import 'package:trale/core/language.dart'; @@ -70,6 +71,9 @@ class Preferences { /// default zoomLevel final ZoomLevel defaultZoomLevel = ZoomLevel.all; + /// default backup interval + final BackupInterval defaultBackupInterval = BackupInterval.weekly; + /// getter and setter for all preferences /// set user name set userName(String name) => prefs.setString('userName', name); @@ -149,6 +153,16 @@ class Preferences { 'interpolStrength', strength.name, ); + /// get backup frequency + BackupInterval get backupInterval => + prefs.getString('backupInverval')!.toBackupInterval()!; + + /// set interpolation strength mode + set backupInterval(BackupInterval interval) => + prefs.setString( + 'backupInterval', interval.name, + ); + /// get zoom level ZoomLevel get zoomLevel => prefs.getInt('zoomLevel')!.toZoomLevel()!; @@ -194,6 +208,9 @@ class Preferences { if (override || !prefs.containsKey('zoomLevel')) { zoomLevel = defaultZoomLevel; } + if (override || !prefs.containsKey('backupInterval')) { + backupInterval = defaultBackupInterval; + } } /// reset all settings diff --git a/app/lib/l10n/app_en.arb b/app/lib/l10n/app_en.arb index 9ec1c59d..6cab43de 100644 --- a/app/lib/l10n/app_en.arb +++ b/app/lib/l10n/app_en.arb @@ -4,6 +4,22 @@ "@achievements": { "description": "achievements" }, + "never": "never", + "@never": { + "description": "Frequency of backup interval" + }, + "weekly": "weekly", + "@weekly": { + "description": "Frequency of backup interval" + }, + "biweekly": "biweekly", + "@biweekly": { + "description": "Frequency of backup interval" + }, + "monthly": "monthly", + "@monthly": { + "description": "Frequency of backup interval" + }, "stats": "Statistics", "@stats": { "description": "Header for statistics section" From 6d71ad4ed9e5a7f0e79428eb842c0e79de91c325 Mon Sep 17 00:00:00 2001 From: braniii Date: Fri, 29 Mar 2024 13:30:51 +0100 Subject: [PATCH 2/7] Add listtile for backup setting. --- app/lib/core/traleNotifier.dart | 13 +++++++++- app/lib/l10n/app_en.arb | 4 +++ app/lib/pages/settings.dart | 46 +++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/app/lib/core/traleNotifier.dart b/app/lib/core/traleNotifier.dart index 57b7c80f..b8e5cc33 100644 --- a/app/lib/core/traleNotifier.dart +++ b/app/lib/core/traleNotifier.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:intl/date_time_patterns.dart'; import 'package:intl/intl.dart'; +import 'package:trale/core/backupInterval.dart'; import 'package:trale/core/interpolation.dart'; import 'package:trale/core/language.dart'; import 'package:trale/core/measurementDatabase.dart'; @@ -59,7 +60,17 @@ class TraleNotifier with ChangeNotifier { prefs.zoomLevel = newLevel; notifyListeners(); } -} + } + + /// get backup frequency + BackupInterval get backupInterval => prefs.backupInterval; + /// setter backup frequency + set backupInterval(BackupInterval newInterval) { + if (backupInterval != newInterval) { + prefs.backupInterval = newInterval; + notifyListeners(); + } + } /// getter Language get language => prefs.language; diff --git a/app/lib/l10n/app_en.arb b/app/lib/l10n/app_en.arb index 6cab43de..ca0c7ee9 100644 --- a/app/lib/l10n/app_en.arb +++ b/app/lib/l10n/app_en.arb @@ -20,6 +20,10 @@ "@monthly": { "description": "Frequency of backup interval" }, + "backupInterval": "Backups", + "@backupInterval": { + "description": "Frequency of backup interval" + }, "stats": "Statistics", "@stats": { "description": "Header for statistics section" diff --git a/app/lib/pages/settings.dart b/app/lib/pages/settings.dart index 10ae3370..e7f1bbd3 100644 --- a/app/lib/pages/settings.dart +++ b/app/lib/pages/settings.dart @@ -8,6 +8,7 @@ import 'package:intl/intl.dart'; import 'package:path_provider/path_provider.dart'; import 'package:provider/provider.dart'; import 'package:share_plus/share_plus.dart'; +import 'package:trale/core/backupInterval.dart'; import 'package:trale/core/icons.dart'; import 'package:trale/core/interpolation.dart'; @@ -484,6 +485,50 @@ class UnitsListTile extends StatelessWidget { } } +/// ListTile for changing units settings +class BackupIntervalListTile extends StatelessWidget { + /// constructor + const BackupIntervalListTile({super.key}); + + @override + Widget build(BuildContext context) { + return ListTile( + contentPadding: EdgeInsets.symmetric( + horizontal: 2 * TraleTheme.of(context)!.padding, + vertical: 0.5 * TraleTheme.of(context)!.padding, + ), + title: AutoSizeText( + AppLocalizations.of(context)!.backupInterval, + style: Theme.of(context).textTheme.bodyLarge, + maxLines: 1, + ), + trailing: DropdownMenu( + initialSelection: Provider.of(context).backupInterval, + label: AutoSizeText( + AppLocalizations.of(context)!.backupInterval, + style: Theme.of(context).textTheme.bodyLarge, + maxLines: 1, + ), + dropdownMenuEntries: >[ + for (final BackupInterval interval in BackupInterval.values) + DropdownMenuEntry( + value: interval, + label: interval.name, + ) + ], + onSelected: (BackupInterval? newInterval) async { + if (newInterval != null) { + Provider.of( + context, listen: false + ).backupInterval = newInterval; + } + }, + ), + ); + } +} + + /// ListTile for changing dark mode settings class DarkModeListTile extends StatelessWidget { @@ -751,6 +796,7 @@ class _Settings extends State { const LanguageListTile(), const UnitsListTile(), const InterpolationListTile(), + const BackupIntervalListTile(), Divider( height: 2 * TraleTheme.of(context)!.padding, ), From 91370c1fc4646e4bf2426b22c29770a525e34eed Mon Sep 17 00:00:00 2001 From: braniii Date: Mon, 27 May 2024 19:06:42 +0200 Subject: [PATCH 3/7] Fix typo in saving backupInterval. --- app/lib/core/preferences.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/core/preferences.dart b/app/lib/core/preferences.dart index d87ec59f..ffb4e771 100644 --- a/app/lib/core/preferences.dart +++ b/app/lib/core/preferences.dart @@ -155,7 +155,7 @@ class Preferences { /// get backup frequency BackupInterval get backupInterval => - prefs.getString('backupInverval')!.toBackupInterval()!; + prefs.getString('backupInterval')!.toBackupInterval()!; /// set interpolation strength mode set backupInterval(BackupInterval interval) => From 3a1835f0d3154767b92b7dbd6903517cf57731fc Mon Sep 17 00:00:00 2001 From: braniii Date: Mon, 27 May 2024 23:54:59 +0200 Subject: [PATCH 4/7] Add quarterly backups. --- app/lib/core/backupInterval.dart | 6 +++++- app/lib/l10n/app_en.arb | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/lib/core/backupInterval.dart b/app/lib/core/backupInterval.dart index 175d05b1..73de5f73 100644 --- a/app/lib/core/backupInterval.dart +++ b/app/lib/core/backupInterval.dart @@ -12,6 +12,8 @@ enum BackupInterval { biweekly, /// monthly monthly, + /// quarterly + quarterly, } /// extend interpolation strength @@ -21,7 +23,8 @@ extension BackupIntervalExtension on BackupInterval { BackupInterval.never: -1, BackupInterval.weekly: 7, BackupInterval.biweekly: 14, - BackupInterval.monthly: 28, + BackupInterval.monthly: 30, + BackupInterval.quarterly: 90, }[this]!; /// get international name @@ -30,6 +33,7 @@ extension BackupIntervalExtension on BackupInterval { BackupInterval.weekly: AppLocalizations.of(context)!.weekly, BackupInterval.biweekly: AppLocalizations.of(context)!.biweekly, BackupInterval.monthly: AppLocalizations.of(context)!.monthly, + BackupInterval.quarterly: AppLocalizations.of(context)!.quarterly, }[this]!; /// get string expression diff --git a/app/lib/l10n/app_en.arb b/app/lib/l10n/app_en.arb index ca0c7ee9..ee0ff3fe 100644 --- a/app/lib/l10n/app_en.arb +++ b/app/lib/l10n/app_en.arb @@ -20,6 +20,10 @@ "@monthly": { "description": "Frequency of backup interval" }, + "quarterly": "quarterly", + "@quarterly": { + "description": "Frequency of backup interval" + }, "backupInterval": "Backups", "@backupInterval": { "description": "Frequency of backup interval" From 2289f8f459d6fd60d7dc1b7480d3fb605f9df850 Mon Sep 17 00:00:00 2001 From: braniii Date: Mon, 27 May 2024 23:56:05 +0200 Subject: [PATCH 5/7] Add latest backup date. --- app/lib/core/preferences.dart | 22 ++++++++++++++++++++-- app/lib/core/theme.dart | 4 ++++ app/lib/core/traleNotifier.dart | 19 +++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/app/lib/core/preferences.dart b/app/lib/core/preferences.dart index ffb4e771..3552ebd2 100644 --- a/app/lib/core/preferences.dart +++ b/app/lib/core/preferences.dart @@ -72,7 +72,12 @@ class Preferences { final ZoomLevel defaultZoomLevel = ZoomLevel.all; /// default backup interval - final BackupInterval defaultBackupInterval = BackupInterval.weekly; + final BackupInterval defaultBackupInterval = BackupInterval.monthly; + + /// latest backup date + final DateTime defaultLatestBackupDate = DateTime.fromMillisecondsSinceEpoch( + 0, + ); /// getter and setter for all preferences /// set user name @@ -157,12 +162,22 @@ class Preferences { BackupInterval get backupInterval => prefs.getString('backupInterval')!.toBackupInterval()!; - /// set interpolation strength mode + /// set backup frequency set backupInterval(BackupInterval interval) => prefs.setString( 'backupInterval', interval.name, ); + /// get latest backup date + DateTime get latestBackupDate => + DateTime.parse(prefs.getString('latestBackupDate')!); + + /// set latest backup date + set latestBackupDate(DateTime date) => + prefs.setString( + 'latestBackupDate', date.toString(), + ); + /// get zoom level ZoomLevel get zoomLevel => prefs.getInt('zoomLevel')!.toZoomLevel()!; @@ -211,6 +226,9 @@ class Preferences { if (override || !prefs.containsKey('backupInterval')) { backupInterval = defaultBackupInterval; } + if (override || !prefs.containsKey('latestBackupDate')) { + latestBackupDate = defaultLatestBackupDate; + } } /// reset all settings diff --git a/app/lib/core/theme.dart b/app/lib/core/theme.dart index e7fe39a1..0ec554f3 100644 --- a/app/lib/core/theme.dart +++ b/app/lib/core/theme.dart @@ -102,9 +102,13 @@ class TraleTheme { /// Get border radius double get borderRadius => 16; + /// get transition durations final TransitionDuration transitionDuration = TransitionDuration(100, 200, 500); + /// get duration of snackbar + final Duration snackbarDuration = Duration(seconds: 5); + /// get background gradient LinearGradient get bgGradient => LinearGradient( begin: Alignment.topCenter, diff --git a/app/lib/core/traleNotifier.dart b/app/lib/core/traleNotifier.dart index b8e5cc33..261ba0b7 100644 --- a/app/lib/core/traleNotifier.dart +++ b/app/lib/core/traleNotifier.dart @@ -72,6 +72,25 @@ class TraleNotifier with ChangeNotifier { } } + /// get latest backup date + DateTime? get latestBackupDate { + if (prefs.defaultLatestBackupDate.sameDay(prefs.latestBackupDate)) { + return null; + } + return prefs.latestBackupDate; + } + + /// set latest backup date + set latestBackupDate(DateTime? newDate) { + if (latestBackupDate != newDate) { + if (newDate == null) { + prefs.latestBackupDate = prefs.defaultLatestBackupDate; + } else { + prefs.latestBackupDate = newDate; + } + } + } + /// getter Language get language => prefs.language; /// setter From 08902a873b95b8ed0a6b719ed348e9affa75ba7d Mon Sep 17 00:00:00 2001 From: braniii Date: Mon, 27 May 2024 23:57:46 +0200 Subject: [PATCH 6/7] Unify backup code and call snackbar if backup interval is exceeded. --- app/lib/l10n/app_en.arb | 12 +++++ app/lib/pages/overview.dart | 29 +++++++++++ app/lib/pages/settings.dart | 98 ++----------------------------------- 3 files changed, 44 insertions(+), 95 deletions(-) diff --git a/app/lib/l10n/app_en.arb b/app/lib/l10n/app_en.arb index ee0ff3fe..7a2acae4 100644 --- a/app/lib/l10n/app_en.arb +++ b/app/lib/l10n/app_en.arb @@ -24,6 +24,18 @@ "@quarterly": { "description": "Frequency of backup interval" }, + "backupReminder": "Please back up regularly", + "@backupReminder": { + "description": "Please remember to back up your data regularly." + }, + "backupReminderButton": "back up now", + "@backupReminderButton": { + "description": "Back up now" + }, + "backupSuccess": "Backup successfully exported", + "@backupSuccess": { + "description": "Back successfully exported" + }, "backupInterval": "Backups", "@backupInterval": { "description": "Frequency of backup interval" diff --git a/app/lib/pages/overview.dart b/app/lib/pages/overview.dart index f77c56e4..9dd94977 100644 --- a/app/lib/pages/overview.dart +++ b/app/lib/pages/overview.dart @@ -1,10 +1,16 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:provider/provider.dart'; +import 'package:trale/core/backupInterval.dart'; + +import 'package:trale/core/backupInterval.dart'; import 'package:trale/core/icons.dart'; import 'package:trale/core/measurement.dart'; import 'package:trale/core/measurementDatabase.dart'; import 'package:trale/core/theme.dart'; +import 'package:trale/core/traleNotifier.dart'; import 'package:trale/widget/animate_in_effect.dart'; +import 'package:trale/widget/backupDialog.dart'; import 'package:trale/widget/emptyChart.dart'; import 'package:trale/widget/fade_in_effect.dart'; import 'package:trale/widget/linechart.dart'; @@ -30,6 +36,29 @@ class _OverviewScreen extends State { WidgetsBinding.instance.addPostFrameCallback((_) { if (loadedFirst) { loadedFirst = false; + TraleNotifier traleNotifier = Provider.of( + context, listen: false, + ); + if ( + traleNotifier.latestBackupDate != null && + traleNotifier.backupInterval != BackupInterval.never && + traleNotifier.latestBackupDate!.difference( + DateTime.now() + ).inDays > traleNotifier.backupInterval.inDays + ) { + final ScaffoldMessengerState sm = ScaffoldMessenger.of(context); + sm.showSnackBar( + SnackBar( + content: Text(AppLocalizations.of(context)!.backupReminder), + behavior: SnackBarBehavior.fixed, + duration: TraleTheme.of(context)!.snackbarDuration, + action: SnackBarAction( + label: AppLocalizations.of(context)!.backupReminderButton, + onPressed: () => backupDialog(context), + ), + ), + ); + } setState(() {}); } }); diff --git a/app/lib/pages/settings.dart b/app/lib/pages/settings.dart index e7f1bbd3..94f1c05c 100644 --- a/app/lib/pages/settings.dart +++ b/app/lib/pages/settings.dart @@ -4,10 +4,7 @@ import 'package:auto_size_text/auto_size_text.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import 'package:intl/intl.dart'; -import 'package:path_provider/path_provider.dart'; import 'package:provider/provider.dart'; -import 'package:share_plus/share_plus.dart'; import 'package:trale/core/backupInterval.dart'; import 'package:trale/core/icons.dart'; @@ -19,6 +16,7 @@ import 'package:trale/core/stringExtension.dart'; import 'package:trale/core/theme.dart'; import 'package:trale/core/traleNotifier.dart'; import 'package:trale/core/units.dart'; +import 'package:trale/widget/backupDialog.dart'; import 'package:trale/widget/coloredContainer.dart'; import 'package:trale/widget/customSliverAppBar.dart'; @@ -30,7 +28,6 @@ class ExportListTile extends StatelessWidget { @override Widget build(BuildContext context) { final ScaffoldMessengerState sm = ScaffoldMessenger.of(context); - const Duration duration = Duration(seconds: 5); return ListTile( dense: true, title: AutoSizeText( @@ -47,95 +44,7 @@ class ExportListTile extends StatelessWidget { ), trailing: IconButton( icon: const Icon(CustomIcons.export_icon), - onPressed: () async { - final bool accepted = await showDialog( - context: context, - builder: (BuildContext context) => AlertDialog( - title: Text( - AppLocalizations.of(context)!.export, - style: Theme.of(context).textTheme.titleLarge, - ), - content: Text( - AppLocalizations.of(context)!.exportDialog, - style: Theme.of(context).textTheme.bodyLarge, - ), - actions: [ - TextButton( - style: ButtonStyle( - foregroundColor: MaterialStateProperty.all( - Theme.of(context).colorScheme.onBackground, - ), - ), - onPressed: () => Navigator.pop(context, false), - child: Container( - padding: EdgeInsets.symmetric( - vertical: TraleTheme.of(context)!.padding / 2, - horizontal: TraleTheme.of(context)!.padding, - ), - child: Text(AppLocalizations.of(context)!.abort) - ), - ), - TextButton( - style: ButtonStyle( - backgroundColor: MaterialStateProperty.all( - Theme.of(context).colorScheme.primary, - ), - foregroundColor: MaterialStateProperty.all( - Theme.of(context).colorScheme.onPrimary, - ), - ), - onPressed: () => Navigator.pop(context, true), - child: Container( - padding: EdgeInsets.symmetric( - vertical: TraleTheme.of(context)!.padding / 2, - horizontal: TraleTheme.of(context)!.padding, - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon(CustomIcons.done), - SizedBox(width: TraleTheme.of(context)!.padding), - Text(AppLocalizations.of(context)!.yes), - ], - ) - ) - ), - ], - ), - ) ?? false; - if (accepted) { - final Directory localPath = await getTemporaryDirectory(); - final DateFormat formatter = DateFormat('yyyy-MM-dd'); - final String filename = - 'trale_${formatter.format(DateTime.now())}.txt'; - final String path = '${localPath.path}/$filename'; - final File file = File(path); - final MeasurementDatabase db = MeasurementDatabase(); - file.writeAsString(db.exportString, mode: FileMode.write); - final ShareResult sharingResult = await Share.shareXFiles( - [XFile(path)], - text: 'trale backup', - subject: 'trale backup', - ); - if (sharingResult.status == ShareResultStatus.success) { - sm.showSnackBar( - const SnackBar( - content: Text('File successfully exported'), - behavior: SnackBarBehavior.floating, - duration: duration, - ), - ); - } - await file.delete(); - //sm.showSnackBar( - // const SnackBar( - // content: Text('Missing write permission.'), - // behavior: SnackBarBehavior.floating, - // duration: duration, - // ), - //); - } - }, + onPressed: () => backupDialog(context), ), ); } @@ -151,7 +60,6 @@ class ImportListTile extends StatelessWidget { Widget build(BuildContext context) { final ScaffoldMessengerState sm = ScaffoldMessenger.of(context); final MeasurementDatabase db = MeasurementDatabase(); - const Duration duration = Duration(seconds: 5); return ListTile( dense: true, title: AutoSizeText( @@ -254,7 +162,7 @@ class ImportListTile extends StatelessWidget { SnackBar( content: Text('$measurementCounts measurements added'), behavior: SnackBarBehavior.floating, - duration: duration, + duration: TraleTheme.of(context)!.snackbarDuration, ), ); } else { From ed1e5f1f643a527998966e4100f62112ad4b6883 Mon Sep 17 00:00:00 2001 From: braniii Date: Sat, 21 Sep 2024 16:57:53 +0200 Subject: [PATCH 7/7] Fix missing backup dialog. --- app/lib/pages/overview.dart | 2 - app/lib/widget/backupDialog.dart | 105 +++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 app/lib/widget/backupDialog.dart diff --git a/app/lib/pages/overview.dart b/app/lib/pages/overview.dart index 0a48c35f..764583f2 100644 --- a/app/lib/pages/overview.dart +++ b/app/lib/pages/overview.dart @@ -1,8 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:provider/provider.dart'; -import 'package:trale/core/backupInterval.dart'; - import 'package:trale/core/backupInterval.dart'; import 'package:trale/core/icons.dart'; import 'package:trale/core/measurement.dart'; diff --git a/app/lib/widget/backupDialog.dart b/app/lib/widget/backupDialog.dart new file mode 100644 index 00000000..a0d1feb5 --- /dev/null +++ b/app/lib/widget/backupDialog.dart @@ -0,0 +1,105 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:intl/intl.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:provider/provider.dart'; +import 'package:share_plus/share_plus.dart'; + +import 'package:trale/core/icons.dart'; +import 'package:trale/core/measurementDatabase.dart'; +import 'package:trale/core/theme.dart'; +import 'package:trale/core/traleNotifier.dart'; + + +/// Backup dialog +Future backupDialog(BuildContext context) async { + final ScaffoldMessengerState sm = ScaffoldMessenger.of(context); + final TraleNotifier traleNotifier = Provider.of( + context, listen: false, + ); + + final bool accepted = await showDialog( + context: context, + builder: (BuildContext context) => AlertDialog( + title: Text( + AppLocalizations.of(context)!.export, + style: Theme.of(context).textTheme.titleLarge, + ), + content: Text( + AppLocalizations.of(context)!.exportDialog, + style: Theme.of(context).textTheme.bodyLarge, + ), + actions: [ + TextButton( + style: ButtonStyle( + foregroundColor: WidgetStateProperty.all( + Theme.of(context).colorScheme.onSurface, + ), + ), + onPressed: () => Navigator.pop(context, false), + child: Container( + padding: EdgeInsets.symmetric( + vertical: TraleTheme.of(context)!.padding / 2, + horizontal: TraleTheme.of(context)!.padding, + ), + child: Text(AppLocalizations.of(context)!.abort) + ), + ), + TextButton( + style: ButtonStyle( + backgroundColor: WidgetStateProperty.all( + Theme.of(context).colorScheme.primary, + ), + foregroundColor: WidgetStateProperty.all( + Theme.of(context).colorScheme.onPrimary, + ), + ), + onPressed: () => Navigator.pop(context, true), + child: Container( + padding: EdgeInsets.symmetric( + vertical: TraleTheme.of(context)!.padding / 2, + horizontal: TraleTheme.of(context)!.padding, + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(CustomIcons.done), + SizedBox(width: TraleTheme.of(context)!.padding), + Text(AppLocalizations.of(context)!.yes), + ], + ) + ) + ), + ], + ), + ) ?? false; + if (accepted) { + final Directory localPath = await getTemporaryDirectory(); + final DateFormat formatter = DateFormat('yyyy-MM-dd'); + final String filename = + 'trale_${formatter.format(DateTime.now())}.txt'; + final String path = '${localPath.path}/$filename'; + final File file = File(path); + final MeasurementDatabase db = MeasurementDatabase(); + file.writeAsString(db.exportString, mode: FileMode.write); + final ShareResult sharingResult = await Share.shareXFiles( + [XFile(path)], + text: 'trale backup', + subject: 'trale backup', + ); + if (sharingResult.status == ShareResultStatus.success) { + sm.showSnackBar( + SnackBar( + content: Text(AppLocalizations.of(context)!.backupSuccess), + behavior: SnackBarBehavior.floating, + duration: TraleTheme.of(context)!.snackbarDuration, + ), + ); +// set latest backup date + traleNotifier.latestBackupDate = DateTime.now(); + } + await file.delete(); + } +} \ No newline at end of file