diff --git a/lib/src/localization/app_en.arb b/lib/src/localization/app_en.arb index 0c0b161..cd9d451 100644 --- a/lib/src/localization/app_en.arb +++ b/lib/src/localization/app_en.arb @@ -418,5 +418,6 @@ "tutorialChatMessagesReopenMessageDesc": "If your friend has sent you a picture or video with infinite display time, you can open it again at any time until you restart the app. To do this, simply double-click on the message. Your friend will then receive a notification that you have viewed the picture again.", "memoriesEmpty": "As soon as you save pictures or videos, they end up here in your memories.", "deleteImageTitle": "Are you sure?", - "deleteImageBody": "The image will be irrevocably deleted." + "deleteImageBody": "The image will be irrevocably deleted.", + "settingsBackup": "Backup" } \ No newline at end of file diff --git a/lib/src/localization/generated/app_localizations.dart b/lib/src/localization/generated/app_localizations.dart index 809fe79..6145355 100644 --- a/lib/src/localization/generated/app_localizations.dart +++ b/lib/src/localization/generated/app_localizations.dart @@ -1573,6 +1573,12 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'The image will be irrevocably deleted.'** String get deleteImageBody; + + /// No description provided for @settingsBackup. + /// + /// In en, this message translates to: + /// **'Backup'** + String get settingsBackup; } class _AppLocalizationsDelegate diff --git a/lib/src/localization/generated/app_localizations_de.dart b/lib/src/localization/generated/app_localizations_de.dart index 8e7f3a5..94064e1 100644 --- a/lib/src/localization/generated/app_localizations_de.dart +++ b/lib/src/localization/generated/app_localizations_de.dart @@ -833,4 +833,7 @@ class AppLocalizationsDe extends AppLocalizations { @override String get deleteImageBody => 'Das Bild wird unwiderruflich gelöscht.'; + + @override + String get settingsBackup => 'Backup'; } diff --git a/lib/src/localization/generated/app_localizations_en.dart b/lib/src/localization/generated/app_localizations_en.dart index a02ddff..b116e3d 100644 --- a/lib/src/localization/generated/app_localizations_en.dart +++ b/lib/src/localization/generated/app_localizations_en.dart @@ -827,4 +827,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String get deleteImageBody => 'The image will be irrevocably deleted.'; + + @override + String get settingsBackup => 'Backup'; } diff --git a/lib/src/views/settings/backup/backup.view.dart b/lib/src/views/settings/backup/backup.view.dart new file mode 100644 index 0000000..8c361aa --- /dev/null +++ b/lib/src/views/settings/backup/backup.view.dart @@ -0,0 +1,138 @@ +import 'package:flutter/material.dart'; +import 'package:twonly/src/utils/misc.dart'; +import 'package:twonly/src/views/settings/backup/twonly_identity_backup.view.dart'; + +class BackupView extends StatefulWidget { + const BackupView({super.key}); + + @override + State createState() => _BackupViewState(); +} + +class _BackupViewState extends State { + bool _twonlyIdBackupEnabled = false; + DateTime? _twonlyIdLastBackup; + bool _dataBackupEnabled = false; + DateTime? _dataBackupLastBackup; + + @override + void initState() { + initAsync(); + super.initState(); + } + + Future initAsync() async { + setState(() { + _twonlyIdBackupEnabled = true; + _dataBackupEnabled = false; + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(context.lang.settingsBackup), + ), + body: ListView( + children: [ + BackupOption( + title: 'twonly-Identity Backup', + description: + 'Back up your twonly identity, as this is the only way to restore your account if you uninstall or lose your phone.', + lastBackup: _twonlyIdLastBackup, + autoBackupEnabled: _twonlyIdBackupEnabled, + onTap: () async { + await Navigator.push(context, + MaterialPageRoute(builder: (context) { + return TwonlyIdentityBackupView(); + })); + initAsync(); + }, + ), + BackupOption( + title: 'Daten-Backup', + description: + 'This backup contains besides of your twonly-Identity also all of your media files. This backup will also be encrypted using a password chosen by the user but stored locally on the smartphone. You then have to ensure to manually copy it onto your laptop or device of your choice.', + autoBackupEnabled: _dataBackupEnabled, + onTap: () {}, + lastBackup: _dataBackupLastBackup, + ), + ], + ), + ); + } +} + +class BackupOption extends StatelessWidget { + final String title; + final String description; + final bool autoBackupEnabled; + final DateTime? lastBackup; + final Function() onTap; + + const BackupOption({ + super.key, + required this.title, + required this.description, + required this.autoBackupEnabled, + required this.lastBackup, + required this.onTap, + }); + + String formatDateTime(DateTime? dateTime) { + if (dateTime == null) { + return "Never"; + } + final now = DateTime.now(); + final difference = now.difference(dateTime); + + if (difference.inDays == 0) { + return 'Today'; + } else if (difference.inDays == 1) { + return 'Yesterday'; + } else { + return '${difference.inDays} Days ago'; + } + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onTap, + child: Card( + margin: EdgeInsets.all(8.0), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + SizedBox(height: 8.0), + Text(description), + SizedBox(height: 8.0), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('Last backup: ${formatDateTime(lastBackup)}'), + (autoBackupEnabled) + ? OutlinedButton( + onPressed: onTap, + child: Text("Disable"), + ) + : FilledButton( + onPressed: onTap, + child: Text("Enable"), + ) + ], + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/src/views/settings/backup/twonly_identity_backup.view.dart b/lib/src/views/settings/backup/twonly_identity_backup.view.dart new file mode 100644 index 0000000..81de328 --- /dev/null +++ b/lib/src/views/settings/backup/twonly_identity_backup.view.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; + +class TwonlyIdentityBackupView extends StatefulWidget { + const TwonlyIdentityBackupView({super.key}); + + @override + State createState() => + _TwonlyIdentityBackupViewState(); +} + +class _TwonlyIdentityBackupViewState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("twonly-Identity Backup"), + ), + body: ListView(children: [ + Text( + 'Backup of your twonly-Identity. As twonly does not have any second factor like your phone number or email, this backup contains your twonly-Identity. If you lose your device, the only option to recover is with the twonly-ID Backup. This backup will be protected by a password chosen by you in the next step and anonymously uploaded to the twonly servers. Read more [here](https://twonly.eu/s/backup).'), + ]), + ); + } +} diff --git a/lib/src/views/settings/settings_main.view.dart b/lib/src/views/settings/settings_main.view.dart index 2b93c44..2d20e3e 100644 --- a/lib/src/views/settings/settings_main.view.dart +++ b/lib/src/views/settings/settings_main.view.dart @@ -120,6 +120,16 @@ class _SettingsMainViewState extends State { })); }, ), + // BetterListTile( + // icon: Icons.lock_clock_rounded, + // text: context.lang.settingsBackup, + // onTap: () { + // Navigator.push(context, + // MaterialPageRoute(builder: (context) { + // return BackupView(); + // })); + // }, + // ), const Divider(), BetterListTile( icon: FontAwesomeIcons.sun,