mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 18:08:40 +00:00
twonly Safe is now mandatory
This commit is contained in:
parent
404aee1e18
commit
d40e33b247
14 changed files with 290 additions and 274 deletions
15
lib/app.dart
15
lib/app.dart
|
|
@ -11,6 +11,7 @@ import 'package:twonly/src/views/components/app_outdated.dart';
|
||||||
import 'package:twonly/src/views/home.view.dart';
|
import 'package:twonly/src/views/home.view.dart';
|
||||||
import 'package:twonly/src/views/onboarding/onboarding.view.dart';
|
import 'package:twonly/src/views/onboarding/onboarding.view.dart';
|
||||||
import 'package:twonly/src/views/onboarding/register.view.dart';
|
import 'package:twonly/src/views/onboarding/register.view.dart';
|
||||||
|
import 'package:twonly/src/views/settings/backup/twonly_safe_backup.view.dart';
|
||||||
import 'package:twonly/src/views/updates/62_database_migration.view.dart';
|
import 'package:twonly/src/views/updates/62_database_migration.view.dart';
|
||||||
|
|
||||||
class App extends StatefulWidget {
|
class App extends StatefulWidget {
|
||||||
|
|
@ -181,9 +182,17 @@ class _AppMainWidgetState extends State<AppMainWidget> {
|
||||||
if (_showDatabaseMigration) {
|
if (_showDatabaseMigration) {
|
||||||
child = const DatabaseMigrationView();
|
child = const DatabaseMigrationView();
|
||||||
} else if (_isUserCreated) {
|
} else if (_isUserCreated) {
|
||||||
child = HomeView(
|
if (gUser.twonlySafeBackup == null) {
|
||||||
initialPage: widget.initialPage,
|
child = TwonlyIdentityBackupView(
|
||||||
);
|
callBack: () {
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
child = HomeView(
|
||||||
|
initialPage: widget.initialPage,
|
||||||
|
);
|
||||||
|
}
|
||||||
} else if (_showOnboarding) {
|
} else if (_showOnboarding) {
|
||||||
child = OnboardingView(
|
child = OnboardingView(
|
||||||
callbackOnSuccess: () => setState(() {
|
callbackOnSuccess: () => setState(() {
|
||||||
|
|
|
||||||
|
|
@ -311,6 +311,7 @@
|
||||||
"backupLastBackupSize": "Backup-Größe",
|
"backupLastBackupSize": "Backup-Größe",
|
||||||
"backupLastBackupResult": "Ergebnis",
|
"backupLastBackupResult": "Ergebnis",
|
||||||
"deleteBackupTitle": "Bist du sicher?",
|
"deleteBackupTitle": "Bist du sicher?",
|
||||||
|
"backupNoPasswordRecovery": "Aufgrund des Sicherheitssystems von twonly gibt es (derzeit) keine Funktion zur Wiederherstellung des Passworts. Daher musst du dir dein Passwort merken oder, besser noch, aufschreiben.",
|
||||||
"deleteBackupBody": "Ohne ein Backup kannst du dein Benutzerkonto nicht wiederherstellen.",
|
"deleteBackupBody": "Ohne ein Backup kannst du dein Benutzerkonto nicht wiederherstellen.",
|
||||||
"backupData": "Daten-Backup",
|
"backupData": "Daten-Backup",
|
||||||
"backupDataDesc": "Das Daten-Backup enthält neben deiner twonly-Identität auch alle deine Mediendateien. Dieses Backup ist ebenfalls verschlüsselt, wird jedoch lokal gespeichert. Du musst es dann manuell auf deinen Laptop oder ein Gerät deiner Wahl kopieren.",
|
"backupDataDesc": "Das Daten-Backup enthält neben deiner twonly-Identität auch alle deine Mediendateien. Dieses Backup ist ebenfalls verschlüsselt, wird jedoch lokal gespeichert. Du musst es dann manuell auf deinen Laptop oder ein Gerät deiner Wahl kopieren.",
|
||||||
|
|
@ -318,18 +319,19 @@
|
||||||
"backupInsecurePasswordDesc": "Das gewählte Passwort ist sehr unsicher und kann daher leicht von Angreifern erraten werden. Bitte wähle ein sicheres Passwort.",
|
"backupInsecurePasswordDesc": "Das gewählte Passwort ist sehr unsicher und kann daher leicht von Angreifern erraten werden. Bitte wähle ein sicheres Passwort.",
|
||||||
"backupInsecurePasswordOk": "Trotzdem fortfahren",
|
"backupInsecurePasswordOk": "Trotzdem fortfahren",
|
||||||
"backupInsecurePasswordCancel": "Erneut versuchen",
|
"backupInsecurePasswordCancel": "Erneut versuchen",
|
||||||
"backupTwonlySafeLongDesc": "twonly hat keine zentralen Benutzerkonten. Während der Installation wird ein Schlüsselpaar erstellt, das aus einem öffentlichen und einem privaten Schlüssel besteht. Der private Schlüssel wird nur auf deinem Gerät gespeichert, um ihn vor unbefugtem Zugriff zu schützen. Der öffentliche Schlüssel wird auf den Server hochgeladen und mit deinem gewählten Benutzernamen verknüpft, damit andere dich finden können.\n\ntwonly Safe erstellt regelmäßig ein verschlüsseltes, anonymes Backup deines privaten Schlüssels zusammen mit deinen Kontakten und Einstellungen. Dein Benutzername und das gewählte Passwort reichen aus, um diese Daten auf einem anderen Gerät wiederherzustellen.",
|
"backupTwonlySafeLongDesc": "twonly hat keine zentralen Benutzerkonten. Während der Installation wird ein Schlüsselpaar erstellt, das aus einem öffentlichen und einem privaten Schlüssel besteht. Der private Schlüssel wird nur auf deinem Gerät gespeichert, um ihn vor unbefugtem Zugriff zu schützen. Der öffentliche Schlüssel wird auf den Server hochgeladen und mit deinem gewählten Benutzernamen verknüpft, damit andere dich finden können.\n\ntwonly Backup erstellt regelmäßig ein verschlüsseltes, anonymes Backup deines privaten Schlüssels zusammen mit deinen Kontakten und Einstellungen. Dein Benutzername und das gewählte Passwort reichen aus, um diese Daten auf einem anderen Gerät wiederherzustellen.",
|
||||||
"backupSelectStrongPassword": "Wähle ein sicheres Passwort. Dies ist erforderlich, wenn du dein twonly Safe-Backup wiederherstellen möchtest.",
|
"backupSelectStrongPassword": "Wähle ein sicheres Passwort. Dies ist erforderlich, wenn du dein twonly Backup wiederherstellen möchtest.",
|
||||||
"password": "Passwort",
|
"password": "Passwort",
|
||||||
"passwordRepeated": "Passwort wiederholen",
|
"passwordRepeated": "Passwort wiederholen",
|
||||||
"passwordRepeatedNotEqual": "Passwörter stimmen nicht überein.",
|
"passwordRepeatedNotEqual": "Passwörter stimmen nicht überein.",
|
||||||
"backupPasswordRequirement": "Das Passwort muss mindestens 8 Zeichen lang sein.",
|
"backupPasswordRequirement": "Das Passwort muss mindestens 8 Zeichen lang sein.",
|
||||||
"backupExpertSettings": "Experteneinstellungen",
|
"backupExpertSettings": "Experteneinstellungen",
|
||||||
"backupEnableBackup": "Automatische Sicherung aktivieren",
|
"backupEnableBackup": "Automatische Sicherung aktivieren",
|
||||||
"backupOwnServerDesc": "Speichere dein twonly Safe-Backups auf einem Server deiner Wahl.",
|
"backupOwnServerDesc": "Speichere dein twonly Backup auf einem Server deiner Wahl.",
|
||||||
"backupUseOwnServer": "Server verwenden",
|
"backupUseOwnServer": "Server verwenden",
|
||||||
"backupResetServer": "Standardserver verwenden",
|
"backupResetServer": "Standardserver verwenden",
|
||||||
"backupTwonlySaveNow": "Jetzt speichern",
|
"backupTwonlySaveNow": "Jetzt speichern",
|
||||||
|
"backupChangePassword": "Password ändern",
|
||||||
"inviteFriends": "Freunde einladen",
|
"inviteFriends": "Freunde einladen",
|
||||||
"inviteFriendsShareBtn": "Teilen",
|
"inviteFriendsShareBtn": "Teilen",
|
||||||
"inviteFriendsShareText": "Wechseln wir zu twonly: {url}",
|
"inviteFriendsShareText": "Wechseln wir zu twonly: {url}",
|
||||||
|
|
|
||||||
|
|
@ -457,6 +457,7 @@
|
||||||
"backupFailed": "Failed",
|
"backupFailed": "Failed",
|
||||||
"backupSuccess": "Success",
|
"backupSuccess": "Success",
|
||||||
"backupTwonlySafeDesc": "Back up your twonly identity, as this is the only way to restore your account if you uninstall the app or lose your phone.",
|
"backupTwonlySafeDesc": "Back up your twonly identity, as this is the only way to restore your account if you uninstall the app or lose your phone.",
|
||||||
|
"backupNoPasswordRecovery": "Due to twonly's security system, there is (currently) no password recovery function. Therefore, you must remember your password or, better yet, write it down.",
|
||||||
"backupServer": "Server",
|
"backupServer": "Server",
|
||||||
"backupMaxBackupSize": "max. backup size",
|
"backupMaxBackupSize": "max. backup size",
|
||||||
"backupStorageRetention": "Storage retention",
|
"backupStorageRetention": "Storage retention",
|
||||||
|
|
@ -471,20 +472,21 @@
|
||||||
"backupInsecurePasswordDesc": "The chosen password is very insecure and can therefore easily be guessed by attackers. Please choose a secure password.",
|
"backupInsecurePasswordDesc": "The chosen password is very insecure and can therefore easily be guessed by attackers. Please choose a secure password.",
|
||||||
"backupInsecurePasswordOk": "Continue anyway",
|
"backupInsecurePasswordOk": "Continue anyway",
|
||||||
"backupInsecurePasswordCancel": "Try again",
|
"backupInsecurePasswordCancel": "Try again",
|
||||||
"backupTwonlySafeLongDesc": "twonly does not have any central user accounts. A key pair is created during installation, which consists of a public and a private key. The private key is only stored on your device to protect it from unauthorized access. The public key is uploaded to the server and linked to your chosen username so that others can find you.\n\ntwonly Safe regularly creates an encrypted, anonymous backup of your private key together with your contacts and settings. Your username and chosen password are enough to restore this data on another device.",
|
"backupTwonlySafeLongDesc": "twonly does not have any central user accounts. A key pair is created during installation, which consists of a public and a private key. The private key is only stored on your device to protect it from unauthorized access. The public key is uploaded to the server and linked to your chosen username so that others can find you.\n\ntwonly Backup regularly creates an encrypted, anonymous backup of your private key together with your contacts and settings. Your username and chosen password are enough to restore this data on another device.",
|
||||||
"backupSelectStrongPassword": "Choose a secure password. This is required if you want to restore your twonly Safe backup.",
|
"backupSelectStrongPassword": "Choose a secure password. This is required if you want to restore your twonly Backup.",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
"passwordRepeated": "Repeat password",
|
"passwordRepeated": "Repeat password",
|
||||||
"passwordRepeatedNotEqual": "Passwords do not match.",
|
"passwordRepeatedNotEqual": "Passwords do not match.",
|
||||||
"backupPasswordRequirement": "Password must be at least 8 characters long.",
|
"backupPasswordRequirement": "Password must be at least 8 characters long.",
|
||||||
"backupExpertSettings": "Expert settings",
|
"backupExpertSettings": "Expert settings",
|
||||||
"backupEnableBackup": "Activate automatic backup",
|
"backupEnableBackup": "Activate automatic backup",
|
||||||
"backupOwnServerDesc": "Save your twonly safe backups at twonly or on any server of your choice.",
|
"backupOwnServerDesc": "Save your twonly Backup at twonly or on any server of your choice.",
|
||||||
"backupUseOwnServer": "Use server",
|
"backupUseOwnServer": "Use server",
|
||||||
"backupResetServer": "Use standard server",
|
"backupResetServer": "Use standard server",
|
||||||
"backupTwonlySaveNow": "Save now",
|
"backupTwonlySaveNow": "Save now",
|
||||||
|
"backupChangePassword": "Change password",
|
||||||
"twonlySafeRecoverTitle": "Recovery",
|
"twonlySafeRecoverTitle": "Recovery",
|
||||||
"twonlySafeRecoverDesc": "If you have created a backup with twonly Safe, you can restore it here.",
|
"twonlySafeRecoverDesc": "If you have created a backup with twonly Backup, you can restore it here.",
|
||||||
"twonlySafeRecoverBtn": "Restore backup",
|
"twonlySafeRecoverBtn": "Restore backup",
|
||||||
"inviteFriends": "Invite your friends",
|
"inviteFriends": "Invite your friends",
|
||||||
"inviteFriendsShareBtn": "Share",
|
"inviteFriendsShareBtn": "Share",
|
||||||
|
|
|
||||||
|
|
@ -1844,6 +1844,12 @@ abstract class AppLocalizations {
|
||||||
/// **'Back up your twonly identity, as this is the only way to restore your account if you uninstall the app or lose your phone.'**
|
/// **'Back up your twonly identity, as this is the only way to restore your account if you uninstall the app or lose your phone.'**
|
||||||
String get backupTwonlySafeDesc;
|
String get backupTwonlySafeDesc;
|
||||||
|
|
||||||
|
/// No description provided for @backupNoPasswordRecovery.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Due to twonly\'s security system, there is (currently) no password recovery function. Therefore, you must remember your password or, better yet, write it down.'**
|
||||||
|
String get backupNoPasswordRecovery;
|
||||||
|
|
||||||
/// No description provided for @backupServer.
|
/// No description provided for @backupServer.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|
@ -1931,13 +1937,13 @@ abstract class AppLocalizations {
|
||||||
/// No description provided for @backupTwonlySafeLongDesc.
|
/// No description provided for @backupTwonlySafeLongDesc.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'twonly does not have any central user accounts. A key pair is created during installation, which consists of a public and a private key. The private key is only stored on your device to protect it from unauthorized access. The public key is uploaded to the server and linked to your chosen username so that others can find you.\n\ntwonly Safe regularly creates an encrypted, anonymous backup of your private key together with your contacts and settings. Your username and chosen password are enough to restore this data on another device.'**
|
/// **'twonly does not have any central user accounts. A key pair is created during installation, which consists of a public and a private key. The private key is only stored on your device to protect it from unauthorized access. The public key is uploaded to the server and linked to your chosen username so that others can find you.\n\ntwonly Backup regularly creates an encrypted, anonymous backup of your private key together with your contacts and settings. Your username and chosen password are enough to restore this data on another device.'**
|
||||||
String get backupTwonlySafeLongDesc;
|
String get backupTwonlySafeLongDesc;
|
||||||
|
|
||||||
/// No description provided for @backupSelectStrongPassword.
|
/// No description provided for @backupSelectStrongPassword.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Choose a secure password. This is required if you want to restore your twonly Safe backup.'**
|
/// **'Choose a secure password. This is required if you want to restore your twonly Backup.'**
|
||||||
String get backupSelectStrongPassword;
|
String get backupSelectStrongPassword;
|
||||||
|
|
||||||
/// No description provided for @password.
|
/// No description provided for @password.
|
||||||
|
|
@ -1979,7 +1985,7 @@ abstract class AppLocalizations {
|
||||||
/// No description provided for @backupOwnServerDesc.
|
/// No description provided for @backupOwnServerDesc.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Save your twonly safe backups at twonly or on any server of your choice.'**
|
/// **'Save your twonly Backup at twonly or on any server of your choice.'**
|
||||||
String get backupOwnServerDesc;
|
String get backupOwnServerDesc;
|
||||||
|
|
||||||
/// No description provided for @backupUseOwnServer.
|
/// No description provided for @backupUseOwnServer.
|
||||||
|
|
@ -2000,6 +2006,12 @@ abstract class AppLocalizations {
|
||||||
/// **'Save now'**
|
/// **'Save now'**
|
||||||
String get backupTwonlySaveNow;
|
String get backupTwonlySaveNow;
|
||||||
|
|
||||||
|
/// No description provided for @backupChangePassword.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Change password'**
|
||||||
|
String get backupChangePassword;
|
||||||
|
|
||||||
/// No description provided for @twonlySafeRecoverTitle.
|
/// No description provided for @twonlySafeRecoverTitle.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|
@ -2009,7 +2021,7 @@ abstract class AppLocalizations {
|
||||||
/// No description provided for @twonlySafeRecoverDesc.
|
/// No description provided for @twonlySafeRecoverDesc.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'If you have created a backup with twonly Safe, you can restore it here.'**
|
/// **'If you have created a backup with twonly Backup, you can restore it here.'**
|
||||||
String get twonlySafeRecoverDesc;
|
String get twonlySafeRecoverDesc;
|
||||||
|
|
||||||
/// No description provided for @twonlySafeRecoverBtn.
|
/// No description provided for @twonlySafeRecoverBtn.
|
||||||
|
|
|
||||||
|
|
@ -973,6 +973,10 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
String get backupTwonlySafeDesc =>
|
String get backupTwonlySafeDesc =>
|
||||||
'Sichere deine twonly-Identität, da dies die einzige Möglichkeit ist, dein Konto wiederherzustellen, wenn du die App deinstallierst oder dein Handy verlierst.';
|
'Sichere deine twonly-Identität, da dies die einzige Möglichkeit ist, dein Konto wiederherzustellen, wenn du die App deinstallierst oder dein Handy verlierst.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupNoPasswordRecovery =>
|
||||||
|
'Aufgrund des Sicherheitssystems von twonly gibt es (derzeit) keine Funktion zur Wiederherstellung des Passworts. Daher musst du dir dein Passwort merken oder, besser noch, aufschreiben.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupServer => 'Server';
|
String get backupServer => 'Server';
|
||||||
|
|
||||||
|
|
@ -1020,11 +1024,11 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupTwonlySafeLongDesc =>
|
String get backupTwonlySafeLongDesc =>
|
||||||
'twonly hat keine zentralen Benutzerkonten. Während der Installation wird ein Schlüsselpaar erstellt, das aus einem öffentlichen und einem privaten Schlüssel besteht. Der private Schlüssel wird nur auf deinem Gerät gespeichert, um ihn vor unbefugtem Zugriff zu schützen. Der öffentliche Schlüssel wird auf den Server hochgeladen und mit deinem gewählten Benutzernamen verknüpft, damit andere dich finden können.\n\ntwonly Safe erstellt regelmäßig ein verschlüsseltes, anonymes Backup deines privaten Schlüssels zusammen mit deinen Kontakten und Einstellungen. Dein Benutzername und das gewählte Passwort reichen aus, um diese Daten auf einem anderen Gerät wiederherzustellen.';
|
'twonly hat keine zentralen Benutzerkonten. Während der Installation wird ein Schlüsselpaar erstellt, das aus einem öffentlichen und einem privaten Schlüssel besteht. Der private Schlüssel wird nur auf deinem Gerät gespeichert, um ihn vor unbefugtem Zugriff zu schützen. Der öffentliche Schlüssel wird auf den Server hochgeladen und mit deinem gewählten Benutzernamen verknüpft, damit andere dich finden können.\n\ntwonly Backup erstellt regelmäßig ein verschlüsseltes, anonymes Backup deines privaten Schlüssels zusammen mit deinen Kontakten und Einstellungen. Dein Benutzername und das gewählte Passwort reichen aus, um diese Daten auf einem anderen Gerät wiederherzustellen.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupSelectStrongPassword =>
|
String get backupSelectStrongPassword =>
|
||||||
'Wähle ein sicheres Passwort. Dies ist erforderlich, wenn du dein twonly Safe-Backup wiederherstellen möchtest.';
|
'Wähle ein sicheres Passwort. Dies ist erforderlich, wenn du dein twonly Backup wiederherstellen möchtest.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get password => 'Passwort';
|
String get password => 'Passwort';
|
||||||
|
|
@ -1047,7 +1051,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupOwnServerDesc =>
|
String get backupOwnServerDesc =>
|
||||||
'Speichere dein twonly Safe-Backups auf einem Server deiner Wahl.';
|
'Speichere dein twonly Backup auf einem Server deiner Wahl.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupUseOwnServer => 'Server verwenden';
|
String get backupUseOwnServer => 'Server verwenden';
|
||||||
|
|
@ -1058,12 +1062,15 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get backupTwonlySaveNow => 'Jetzt speichern';
|
String get backupTwonlySaveNow => 'Jetzt speichern';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupChangePassword => 'Password ändern';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get twonlySafeRecoverTitle => 'Recovery';
|
String get twonlySafeRecoverTitle => 'Recovery';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get twonlySafeRecoverDesc =>
|
String get twonlySafeRecoverDesc =>
|
||||||
'If you have created a backup with twonly Safe, you can restore it here.';
|
'If you have created a backup with twonly Backup, you can restore it here.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get twonlySafeRecoverBtn => 'Restore backup';
|
String get twonlySafeRecoverBtn => 'Restore backup';
|
||||||
|
|
|
||||||
|
|
@ -967,6 +967,10 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
String get backupTwonlySafeDesc =>
|
String get backupTwonlySafeDesc =>
|
||||||
'Back up your twonly identity, as this is the only way to restore your account if you uninstall the app or lose your phone.';
|
'Back up your twonly identity, as this is the only way to restore your account if you uninstall the app or lose your phone.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupNoPasswordRecovery =>
|
||||||
|
'Due to twonly\'s security system, there is (currently) no password recovery function. Therefore, you must remember your password or, better yet, write it down.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupServer => 'Server';
|
String get backupServer => 'Server';
|
||||||
|
|
||||||
|
|
@ -1014,11 +1018,11 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupTwonlySafeLongDesc =>
|
String get backupTwonlySafeLongDesc =>
|
||||||
'twonly does not have any central user accounts. A key pair is created during installation, which consists of a public and a private key. The private key is only stored on your device to protect it from unauthorized access. The public key is uploaded to the server and linked to your chosen username so that others can find you.\n\ntwonly Safe regularly creates an encrypted, anonymous backup of your private key together with your contacts and settings. Your username and chosen password are enough to restore this data on another device.';
|
'twonly does not have any central user accounts. A key pair is created during installation, which consists of a public and a private key. The private key is only stored on your device to protect it from unauthorized access. The public key is uploaded to the server and linked to your chosen username so that others can find you.\n\ntwonly Backup regularly creates an encrypted, anonymous backup of your private key together with your contacts and settings. Your username and chosen password are enough to restore this data on another device.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupSelectStrongPassword =>
|
String get backupSelectStrongPassword =>
|
||||||
'Choose a secure password. This is required if you want to restore your twonly Safe backup.';
|
'Choose a secure password. This is required if you want to restore your twonly Backup.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get password => 'Password';
|
String get password => 'Password';
|
||||||
|
|
@ -1041,7 +1045,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupOwnServerDesc =>
|
String get backupOwnServerDesc =>
|
||||||
'Save your twonly safe backups at twonly or on any server of your choice.';
|
'Save your twonly Backup at twonly or on any server of your choice.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupUseOwnServer => 'Use server';
|
String get backupUseOwnServer => 'Use server';
|
||||||
|
|
@ -1052,12 +1056,15 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get backupTwonlySaveNow => 'Save now';
|
String get backupTwonlySaveNow => 'Save now';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backupChangePassword => 'Change password';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get twonlySafeRecoverTitle => 'Recovery';
|
String get twonlySafeRecoverTitle => 'Recovery';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get twonlySafeRecoverDesc =>
|
String get twonlySafeRecoverDesc =>
|
||||||
'If you have created a backup with twonly Safe, you can restore it here.';
|
'If you have created a backup with twonly Backup, you can restore it here.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get twonlySafeRecoverBtn => 'Restore backup';
|
String get twonlySafeRecoverBtn => 'Restore backup';
|
||||||
|
|
|
||||||
|
|
@ -311,7 +311,9 @@ class ApiService {
|
||||||
}
|
}
|
||||||
if (res.error == ErrorCode.NewDeviceRegistered) {
|
if (res.error == ErrorCode.NewDeviceRegistered) {
|
||||||
globalCallbackNewDeviceRegistered();
|
globalCallbackNewDeviceRegistered();
|
||||||
Log.error('Device is disabled, as a newer device restore twonly Safe.');
|
Log.error(
|
||||||
|
'Device is disabled, as a newer device restore twonly Backup.',
|
||||||
|
);
|
||||||
appIsOutdated = true;
|
appIsOutdated = true;
|
||||||
await close(() {});
|
await close(() {});
|
||||||
return Result.error(ErrorCode.InternalError);
|
return Result.error(ErrorCode.InternalError);
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ Future<void> performTwonlySafeBackup({bool force = false}) async {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.info('Starting new twonly Safe-Backup!');
|
Log.info('Starting new twonly Backup!');
|
||||||
|
|
||||||
final baseDir = (await getApplicationSupportDirectory()).path;
|
final baseDir = (await getApplicationSupportDirectory()).path;
|
||||||
|
|
||||||
|
|
@ -161,7 +161,7 @@ Future<void> performTwonlySafeBackup({bool force = false}) async {
|
||||||
await encryptedBackupBytesFile.writeAsBytes(encryptedBackupBytes);
|
await encryptedBackupBytesFile.writeAsBytes(encryptedBackupBytes);
|
||||||
|
|
||||||
Log.info(
|
Log.info(
|
||||||
'Create twonly Safe backup with a size of ${encryptedBackupBytes.length} bytes.',
|
'Create twonly Backup with a size of ${encryptedBackupBytes.length} bytes.',
|
||||||
);
|
);
|
||||||
|
|
||||||
if (gUser.backupServer != null) {
|
if (gUser.backupServer != null) {
|
||||||
|
|
@ -187,7 +187,7 @@ Future<void> performTwonlySafeBackup({bool force = false}) async {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (await FileDownloader().enqueue(task)) {
|
if (await FileDownloader().enqueue(task)) {
|
||||||
Log.info('Starting upload from twonly Safe backup.');
|
Log.info('Starting upload from twonly Backup.');
|
||||||
await updateUserdata((user) {
|
await updateUserdata((user) {
|
||||||
user.twonlySafeBackup!.backupUploadState = LastBackupUploadState.pending;
|
user.twonlySafeBackup!.backupUploadState = LastBackupUploadState.pending;
|
||||||
user.twonlySafeBackup!.lastBackupDone = DateTime.now();
|
user.twonlySafeBackup!.lastBackupDone = DateTime.now();
|
||||||
|
|
@ -196,7 +196,7 @@ Future<void> performTwonlySafeBackup({bool force = false}) async {
|
||||||
});
|
});
|
||||||
gUpdateBackupView();
|
gUpdateBackupView();
|
||||||
} else {
|
} else {
|
||||||
Log.error('Error starting UploadTask for twonly Safe.');
|
Log.error('Error starting UploadTask for twonly Backup.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -204,7 +204,7 @@ Future<void> handleBackupStatusUpdate(TaskStatusUpdate update) async {
|
||||||
if (update.status == TaskStatus.failed ||
|
if (update.status == TaskStatus.failed ||
|
||||||
update.status == TaskStatus.canceled) {
|
update.status == TaskStatus.canceled) {
|
||||||
Log.error(
|
Log.error(
|
||||||
'twonly Safe upload failed. ${update.responseStatusCode} ${update.responseBody} ${update.responseHeaders} ${update.exception}',
|
'twonly Backup upload failed. ${update.responseStatusCode} ${update.responseBody} ${update.responseHeaders} ${update.exception}',
|
||||||
);
|
);
|
||||||
await updateUserdata((user) {
|
await updateUserdata((user) {
|
||||||
if (user.twonlySafeBackup != null) {
|
if (user.twonlySafeBackup != null) {
|
||||||
|
|
@ -214,7 +214,7 @@ Future<void> handleBackupStatusUpdate(TaskStatusUpdate update) async {
|
||||||
});
|
});
|
||||||
} else if (update.status == TaskStatus.complete) {
|
} else if (update.status == TaskStatus.complete) {
|
||||||
Log.error(
|
Log.error(
|
||||||
'twonly Safe uploaded with status code ${update.responseStatusCode}',
|
'twonly Backup uploaded with status code ${update.responseStatusCode}',
|
||||||
);
|
);
|
||||||
await updateUserdata((user) {
|
await updateUserdata((user) {
|
||||||
if (user.twonlySafeBackup != null) {
|
if (user.twonlySafeBackup != null) {
|
||||||
|
|
|
||||||
|
|
@ -60,13 +60,13 @@ class _BackupRecoveryViewState extends State<BackupRecoveryView> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('twonly Safe ${context.lang.twonlySafeRecoverTitle}'),
|
title: Text('twonly Backup ${context.lang.twonlySafeRecoverTitle}'),
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await showAlertDialog(
|
await showAlertDialog(
|
||||||
context,
|
context,
|
||||||
'twonly Safe',
|
'twonly Backup',
|
||||||
context.lang.backupTwonlySafeLongDesc,
|
context.lang.backupTwonlySafeLongDesc,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -166,30 +166,6 @@ class _RegisterViewState extends State<RegisterView> {
|
||||||
),
|
),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
// const SizedBox(height: 5),
|
|
||||||
// Center(
|
|
||||||
// child: Padding(
|
|
||||||
// padding: EdgeInsets.only(left: 10, right: 10),
|
|
||||||
// child: Text(
|
|
||||||
// context.lang.registerUsernameLimits,
|
|
||||||
// textAlign: TextAlign.center,
|
|
||||||
// style: const TextStyle(fontSize: 9),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// const SizedBox(height: 30),
|
|
||||||
// Center(
|
|
||||||
// child: Text(
|
|
||||||
// context.lang.registerTwonlyCodeText,
|
|
||||||
// textAlign: TextAlign.center,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// const SizedBox(height: 10),
|
|
||||||
// TextField(
|
|
||||||
// controller: inviteCodeController,
|
|
||||||
// decoration:
|
|
||||||
// getInputDecoration(context.lang.registerTwonlyCodeLabel),
|
|
||||||
// ),
|
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,8 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:twonly/globals.dart';
|
import 'package:twonly/globals.dart';
|
||||||
import 'package:twonly/src/model/json/userdata.dart';
|
import 'package:twonly/src/model/json/userdata.dart';
|
||||||
import 'package:twonly/src/services/twonly_safe/common.twonly_safe.dart';
|
|
||||||
import 'package:twonly/src/services/twonly_safe/create_backup.twonly_safe.dart';
|
import 'package:twonly/src/services/twonly_safe/create_backup.twonly_safe.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/views/components/alert_dialog.dart';
|
|
||||||
import 'package:twonly/src/views/settings/backup/twonly_safe_backup.view.dart';
|
import 'package:twonly/src/views/settings/backup/twonly_safe_backup.view.dart';
|
||||||
|
|
||||||
void Function() gUpdateBackupView = () {};
|
void Function() gUpdateBackupView = () {};
|
||||||
|
|
@ -25,8 +23,6 @@ BackupServer defaultBackupServer = BackupServer(
|
||||||
);
|
);
|
||||||
|
|
||||||
class _BackupViewState extends State<BackupView> {
|
class _BackupViewState extends State<BackupView> {
|
||||||
TwonlySafeBackup? twonlySafeBackup;
|
|
||||||
BackupServer backupServer = defaultBackupServer;
|
|
||||||
bool isLoading = false;
|
bool isLoading = false;
|
||||||
|
|
||||||
int activePageIdx = 0;
|
int activePageIdx = 0;
|
||||||
|
|
@ -47,11 +43,6 @@ class _BackupViewState extends State<BackupView> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> initAsync() async {
|
Future<void> initAsync() async {
|
||||||
twonlySafeBackup = gUser.twonlySafeBackup;
|
|
||||||
backupServer = defaultBackupServer;
|
|
||||||
if (gUser.backupServer != null) {
|
|
||||||
backupServer = gUser.backupServer!;
|
|
||||||
}
|
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,8 +59,25 @@ class _BackupViewState extends State<BackupView> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> changeTwonlySafePassword() async {
|
||||||
|
await Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) {
|
||||||
|
return const TwonlyIdentityBackupView(
|
||||||
|
isPasswordChangeOnly: true,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
setState(() {
|
||||||
|
// gUser was updated
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final backupServer = gUser.backupServer ?? defaultBackupServer;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(context.lang.settingsBackup),
|
title: Text(context.lang.settingsBackup),
|
||||||
|
|
@ -83,10 +91,13 @@ class _BackupViewState extends State<BackupView> {
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
BackupOption(
|
BackupOption(
|
||||||
title: 'twonly Safe',
|
title: 'twonly Backup',
|
||||||
description: context.lang.backupTwonlySafeDesc,
|
description: context.lang.backupTwonlySafeDesc,
|
||||||
autoBackupEnabled: twonlySafeBackup != null,
|
bottomButton: FilledButton(
|
||||||
child: (twonlySafeBackup == null)
|
onPressed: changeTwonlySafePassword,
|
||||||
|
child: Text(context.lang.backupChangePassword),
|
||||||
|
),
|
||||||
|
child: (gUser.twonlySafeBackup == null)
|
||||||
? null
|
? null
|
||||||
: Column(
|
: Column(
|
||||||
children: [
|
children: [
|
||||||
|
|
@ -114,16 +125,20 @@ class _BackupViewState extends State<BackupView> {
|
||||||
context.lang.backupLastBackupDate,
|
context.lang.backupLastBackupDate,
|
||||||
formatDateTime(
|
formatDateTime(
|
||||||
context,
|
context,
|
||||||
twonlySafeBackup!.lastBackupDone,
|
gUser.twonlySafeBackup!.lastBackupDone,
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
context.lang.backupLastBackupSize,
|
context.lang.backupLastBackupSize,
|
||||||
formatBytes(twonlySafeBackup!.lastBackupSize)
|
formatBytes(
|
||||||
|
gUser.twonlySafeBackup!.lastBackupSize,
|
||||||
|
)
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
context.lang.backupLastBackupResult,
|
context.lang.backupLastBackupResult,
|
||||||
backupStatus(twonlySafeBackup!.backupUploadState)
|
backupStatus(
|
||||||
|
gUser.twonlySafeBackup!.backupUploadState,
|
||||||
|
)
|
||||||
),
|
),
|
||||||
].map((pair) {
|
].map((pair) {
|
||||||
return TableRow(
|
return TableRow(
|
||||||
|
|
@ -134,8 +149,9 @@ class _BackupViewState extends State<BackupView> {
|
||||||
),
|
),
|
||||||
TableCell(
|
TableCell(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding:
|
padding: const EdgeInsets.symmetric(
|
||||||
const EdgeInsets.symmetric(vertical: 4),
|
vertical: 4,
|
||||||
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
pair.$2,
|
pair.$2,
|
||||||
textAlign: TextAlign.right,
|
textAlign: TextAlign.right,
|
||||||
|
|
@ -148,7 +164,7 @@ class _BackupViewState extends State<BackupView> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
FilledButton(
|
OutlinedButton(
|
||||||
onPressed: isLoading
|
onPressed: isLoading
|
||||||
? null
|
? null
|
||||||
: () async {
|
: () async {
|
||||||
|
|
@ -164,37 +180,10 @@ class _BackupViewState extends State<BackupView> {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
onTap: () async {
|
|
||||||
if (twonlySafeBackup != null) {
|
|
||||||
final disable = await showAlertDialog(
|
|
||||||
context,
|
|
||||||
context.lang.deleteBackupTitle,
|
|
||||||
context.lang.deleteBackupBody,
|
|
||||||
);
|
|
||||||
if (disable) {
|
|
||||||
await disableTwonlySafe();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setState(() {
|
|
||||||
isLoading = true;
|
|
||||||
});
|
|
||||||
await Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) {
|
|
||||||
return const TwonlyIdentityBackupView();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
await initAsync();
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
BackupOption(
|
BackupOption(
|
||||||
title: '${context.lang.backupData} (Coming Soon)',
|
title: '${context.lang.backupData} (Coming Soon)',
|
||||||
description: context.lang.backupDataDesc,
|
description: context.lang.backupDataDesc,
|
||||||
autoBackupEnabled: false,
|
|
||||||
onTap: null,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -209,7 +198,7 @@ class _BackupViewState extends State<BackupView> {
|
||||||
items: [
|
items: [
|
||||||
const BottomNavigationBarItem(
|
const BottomNavigationBarItem(
|
||||||
icon: FaIcon(FontAwesomeIcons.vault, size: 17),
|
icon: FaIcon(FontAwesomeIcons.vault, size: 17),
|
||||||
label: 'twonly Safe',
|
label: 'twonly Backup',
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: const FaIcon(FontAwesomeIcons.boxArchive, size: 17),
|
icon: const FaIcon(FontAwesomeIcons.boxArchive, size: 17),
|
||||||
|
|
@ -236,51 +225,35 @@ class BackupOption extends StatelessWidget {
|
||||||
const BackupOption({
|
const BackupOption({
|
||||||
required this.title,
|
required this.title,
|
||||||
required this.description,
|
required this.description,
|
||||||
required this.autoBackupEnabled,
|
this.bottomButton,
|
||||||
required this.onTap,
|
|
||||||
super.key,
|
super.key,
|
||||||
this.child,
|
this.child,
|
||||||
});
|
});
|
||||||
final String title;
|
final String title;
|
||||||
final String description;
|
final String description;
|
||||||
final Widget? child;
|
final Widget? child;
|
||||||
final bool autoBackupEnabled;
|
final Widget? bottomButton;
|
||||||
final void Function()? onTap;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GestureDetector(
|
return Card(
|
||||||
onTap: autoBackupEnabled ? null : onTap,
|
margin: const EdgeInsets.all(16),
|
||||||
child: Card(
|
child: Padding(
|
||||||
margin: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Padding(
|
child: Column(
|
||||||
padding: const EdgeInsets.all(16),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
child: Column(
|
children: [
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
Text(
|
||||||
children: [
|
title,
|
||||||
Text(
|
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||||
title,
|
),
|
||||||
style:
|
const SizedBox(height: 8),
|
||||||
const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
Text(description),
|
||||||
),
|
const SizedBox(height: 8),
|
||||||
const SizedBox(height: 8),
|
if (child != null) child! else Container(),
|
||||||
Text(description),
|
Expanded(child: Container()),
|
||||||
const SizedBox(height: 8),
|
if (bottomButton != null) Center(child: bottomButton),
|
||||||
if (child != null) child! else Container(),
|
],
|
||||||
Expanded(child: Container()),
|
|
||||||
Center(
|
|
||||||
child: autoBackupEnabled
|
|
||||||
? OutlinedButton(
|
|
||||||
onPressed: onTap,
|
|
||||||
child: Text(context.lang.disable),
|
|
||||||
)
|
|
||||||
: FilledButton(
|
|
||||||
onPressed: onTap,
|
|
||||||
child: Text(context.lang.enable),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,16 @@ import 'package:twonly/src/views/components/alert_dialog.dart';
|
||||||
import 'package:twonly/src/views/settings/backup/twonly_safe_server.view.dart';
|
import 'package:twonly/src/views/settings/backup/twonly_safe_server.view.dart';
|
||||||
|
|
||||||
class TwonlyIdentityBackupView extends StatefulWidget {
|
class TwonlyIdentityBackupView extends StatefulWidget {
|
||||||
const TwonlyIdentityBackupView({super.key});
|
const TwonlyIdentityBackupView({
|
||||||
|
this.isPasswordChangeOnly = false,
|
||||||
|
this.callBack,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
// in case a callback is defined the callback
|
||||||
|
// is called instead of the Navigator.pop()
|
||||||
|
final VoidCallback? callBack;
|
||||||
|
final bool isPasswordChangeOnly;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<TwonlyIdentityBackupView> createState() =>
|
State<TwonlyIdentityBackupView> createState() =>
|
||||||
|
|
@ -56,148 +65,165 @@ class _TwonlyIdentityBackupViewState extends State<TwonlyIdentityBackupView> {
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
Navigator.pop(context);
|
if (widget.callBack != null) {
|
||||||
|
widget.callBack!();
|
||||||
|
} else {
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return GestureDetector(
|
||||||
appBar: AppBar(
|
onTap: () => FocusScope.of(context).unfocus(),
|
||||||
title: const Text('twonly Safe'),
|
child: Scaffold(
|
||||||
actions: [
|
appBar: AppBar(
|
||||||
IconButton(
|
title: const Text('twonly Backup'),
|
||||||
onPressed: () async {
|
actions: [
|
||||||
await showAlertDialog(
|
IconButton(
|
||||||
context,
|
onPressed: () async {
|
||||||
'twonly Safe',
|
await showAlertDialog(
|
||||||
context.lang.backupTwonlySafeLongDesc,
|
context,
|
||||||
);
|
'twonly Backup',
|
||||||
},
|
context.lang.backupTwonlySafeLongDesc,
|
||||||
icon: const FaIcon(FontAwesomeIcons.circleInfo),
|
);
|
||||||
iconSize: 18,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
body: Padding(
|
|
||||||
padding:
|
|
||||||
const EdgeInsetsGeometry.symmetric(vertical: 40, horizontal: 40),
|
|
||||||
child: ListView(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
context.lang.backupSelectStrongPassword,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 30),
|
|
||||||
Stack(
|
|
||||||
children: [
|
|
||||||
TextField(
|
|
||||||
controller: passwordCtrl,
|
|
||||||
onChanged: (value) {
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
style: const TextStyle(fontSize: 17),
|
|
||||||
obscureText: obscureText,
|
|
||||||
decoration: getInputDecoration(
|
|
||||||
context,
|
|
||||||
context.lang.password,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Positioned(
|
|
||||||
right: 0,
|
|
||||||
top: 0,
|
|
||||||
bottom: 0,
|
|
||||||
child: IconButton(
|
|
||||||
onPressed: () {
|
|
||||||
setState(() {
|
|
||||||
obscureText = !obscureText;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
icon: FaIcon(
|
|
||||||
obscureText
|
|
||||||
? FontAwesomeIcons.eye
|
|
||||||
: FontAwesomeIcons.eyeSlash,
|
|
||||||
size: 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsetsGeometry.all(5),
|
|
||||||
child: Text(
|
|
||||||
context.lang.backupPasswordRequirement,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 13,
|
|
||||||
color: (passwordCtrl.text.length < 8 &&
|
|
||||||
passwordCtrl.text.isNotEmpty)
|
|
||||||
? Colors.red
|
|
||||||
: Colors.transparent,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 5),
|
|
||||||
TextField(
|
|
||||||
controller: repeatedPasswordCtrl,
|
|
||||||
onChanged: (value) {
|
|
||||||
setState(() {});
|
|
||||||
},
|
},
|
||||||
style: const TextStyle(fontSize: 17),
|
icon: const FaIcon(FontAwesomeIcons.circleInfo),
|
||||||
obscureText: true,
|
iconSize: 18,
|
||||||
decoration: getInputDecoration(
|
|
||||||
context,
|
|
||||||
context.lang.passwordRepeated,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsetsGeometry.all(5),
|
|
||||||
child: Text(
|
|
||||||
context.lang.passwordRepeatedNotEqual,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 13,
|
|
||||||
color: (passwordCtrl.text != repeatedPasswordCtrl.text &&
|
|
||||||
repeatedPasswordCtrl.text.isNotEmpty)
|
|
||||||
? Colors.red
|
|
||||||
: Colors.transparent,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
Center(
|
|
||||||
child: OutlinedButton(
|
|
||||||
onPressed: () async {
|
|
||||||
await Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) {
|
|
||||||
return const TwonlySafeServerView();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: Text(context.lang.backupExpertSettings),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
Center(
|
|
||||||
child: FilledButton.icon(
|
|
||||||
onPressed: (!isLoading &&
|
|
||||||
(passwordCtrl.text == repeatedPasswordCtrl.text &&
|
|
||||||
passwordCtrl.text.length >= 8 ||
|
|
||||||
kDebugMode))
|
|
||||||
? onPressedEnableTwonlySafe
|
|
||||||
: null,
|
|
||||||
icon: isLoading
|
|
||||||
? const SizedBox(
|
|
||||||
height: 12,
|
|
||||||
width: 12,
|
|
||||||
child: CircularProgressIndicator(strokeWidth: 1),
|
|
||||||
)
|
|
||||||
: const Icon(Icons.lock_clock_rounded),
|
|
||||||
label: Text(context.lang.backupEnableBackup),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
body: Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsetsGeometry.symmetric(vertical: 40, horizontal: 40),
|
||||||
|
child: ListView(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
context.lang.backupSelectStrongPassword,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 30),
|
||||||
|
Stack(
|
||||||
|
children: [
|
||||||
|
TextField(
|
||||||
|
controller: passwordCtrl,
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
style: const TextStyle(fontSize: 17),
|
||||||
|
obscureText: obscureText,
|
||||||
|
decoration: getInputDecoration(
|
||||||
|
context,
|
||||||
|
context.lang.password,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
right: 0,
|
||||||
|
top: 0,
|
||||||
|
bottom: 0,
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
obscureText = !obscureText;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
icon: FaIcon(
|
||||||
|
obscureText
|
||||||
|
? FontAwesomeIcons.eye
|
||||||
|
: FontAwesomeIcons.eyeSlash,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsetsGeometry.all(5),
|
||||||
|
child: Text(
|
||||||
|
context.lang.backupPasswordRequirement,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
color: (passwordCtrl.text.length < 8 &&
|
||||||
|
passwordCtrl.text.isNotEmpty)
|
||||||
|
? Colors.red
|
||||||
|
: Colors.transparent,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
TextField(
|
||||||
|
controller: repeatedPasswordCtrl,
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
style: const TextStyle(fontSize: 17),
|
||||||
|
obscureText: true,
|
||||||
|
decoration: getInputDecoration(
|
||||||
|
context,
|
||||||
|
context.lang.passwordRepeated,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsetsGeometry.all(5),
|
||||||
|
child: Text(
|
||||||
|
context.lang.passwordRepeatedNotEqual,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
color: (passwordCtrl.text != repeatedPasswordCtrl.text &&
|
||||||
|
repeatedPasswordCtrl.text.isNotEmpty)
|
||||||
|
? Colors.red
|
||||||
|
: Colors.transparent,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Center(
|
||||||
|
child: OutlinedButton(
|
||||||
|
onPressed: () async {
|
||||||
|
await Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) {
|
||||||
|
return const TwonlySafeServerView();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Text(context.lang.backupExpertSettings),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Text(
|
||||||
|
context.lang.backupNoPasswordRecovery,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: const TextStyle(fontSize: 12),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Center(
|
||||||
|
child: FilledButton.icon(
|
||||||
|
onPressed: (!isLoading &&
|
||||||
|
(passwordCtrl.text == repeatedPasswordCtrl.text &&
|
||||||
|
passwordCtrl.text.length >= 8 ||
|
||||||
|
kDebugMode))
|
||||||
|
? onPressedEnableTwonlySafe
|
||||||
|
: null,
|
||||||
|
icon: isLoading
|
||||||
|
? const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
width: 12,
|
||||||
|
child: CircularProgressIndicator(strokeWidth: 1),
|
||||||
|
)
|
||||||
|
: const Icon(Icons.lock_clock_rounded),
|
||||||
|
label: Text(
|
||||||
|
widget.isPasswordChangeOnly
|
||||||
|
? context.lang.backupChangePassword
|
||||||
|
: context.lang.backupEnableBackup,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ class _TwonlySafeServerViewState extends State<TwonlySafeServerView> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('twonly Safe Server'),
|
title: const Text('twonly Backup Server'),
|
||||||
),
|
),
|
||||||
body: Padding(
|
body: Padding(
|
||||||
padding: const EdgeInsets.all(40),
|
padding: const EdgeInsets.all(40),
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ if [ ! -f "pubspec.yaml" ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Definitions for twonly Safe
|
# Definitions for twonly Backup
|
||||||
GENERATED_DIR="./lib/src/model/protobuf/client/generated/"
|
GENERATED_DIR="./lib/src/model/protobuf/client/generated/"
|
||||||
CLIENT_DIR="./lib/src/model/protobuf/client/"
|
CLIENT_DIR="./lib/src/model/protobuf/client/"
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue