diff --git a/lib/app.dart b/lib/app.dart index a852bf362..31d8b4f01 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -30,6 +30,7 @@ final lightThemeData = ThemeData( borderRadius: BorderRadius.circular(8), ), padding: EdgeInsets.fromLTRB(50, 16, 50, 16), + alignment: Alignment.center, textStyle: TextStyle( fontWeight: FontWeight.w600, fontFamily: 'Inter-SemiBold', @@ -64,11 +65,23 @@ final lightThemeData = ThemeData( iconTheme: IconThemeData(color: Colors.black)), //https://api.flutter.dev/flutter/material/TextTheme-class.html textTheme: TextTheme().copyWith( + headline4: TextStyle( + fontFamily: 'Inter-SemiBold', + color: Colors.black, + fontSize: 32, + fontWeight: FontWeight.w600), headline6: TextStyle( color: Colors.black, fontSize: 18, fontWeight: FontWeight.w600), subtitle1: TextStyle( - fontFamily: 'Inter-Medium', - color: Colors.black, fontSize: 16, fontWeight: FontWeight.w500), + fontFamily: 'Inter-Medium', + color: Colors.black, + fontSize: 16, + fontWeight: FontWeight.w500), + bodyText1: TextStyle( + fontFamily: 'Inter-Medium', + color: Colors.black, + fontSize: 16, + fontWeight: FontWeight.w400), caption: TextStyle(color: Colors.black.withOpacity(0.7), fontSize: 14), overline: TextStyle(color: Colors.black.withOpacity(0.8), fontSize: 12)), @@ -107,10 +120,23 @@ final darkThemeData = ThemeData( ), // primaryColor: Colors.red, textTheme: TextTheme().copyWith( + headline4: TextStyle( + fontFamily: 'Inter-SemiBold', + color: Colors.white, + fontSize: 32, + fontWeight: FontWeight.w600), headline6: TextStyle( color: Colors.white, fontSize: 18, fontWeight: FontWeight.w600), subtitle1: TextStyle( - color: Colors.white, fontFamily: 'Inter-Medium', fontSize: 16, fontWeight: FontWeight.w500), + color: Colors.white, + fontFamily: 'Inter-Medium', + fontSize: 16, + fontWeight: FontWeight.w500), + bodyText1: TextStyle( + fontFamily: 'Inter-Medium', + color: Colors.white, + fontSize: 16, + fontWeight: FontWeight.w400), caption: TextStyle( color: Colors.white.withOpacity(0.6), fontSize: 14, @@ -125,6 +151,7 @@ final darkThemeData = ThemeData( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), + alignment: Alignment.center, padding: EdgeInsets.fromLTRB(50, 16, 50, 16), textStyle: TextStyle( fontWeight: FontWeight.w600, diff --git a/lib/ui/backup_folder_selection_page.dart b/lib/ui/backup_folder_selection_page.dart index 787c99b9d..65217b33d 100644 --- a/lib/ui/backup_folder_selection_page.dart +++ b/lib/ui/backup_folder_selection_page.dart @@ -135,7 +135,7 @@ class _BackupFolderSelectionPageState extends State { child: Container( width: double.infinity, padding: EdgeInsets.only( - left: 24, right:24, bottom: Platform.isIOS ? 60 : 32), + left: 24, right: 24, bottom: Platform.isIOS ? 60 : 32), child: OutlinedButton( child: Text(widget.buttonText), onPressed: _selectedFolders.isEmpty @@ -278,11 +278,7 @@ class _BackupFolderSelectionPageState extends State { fontSize: 12, color: isSelected ? Colors.white - - : Theme.of(context) - .colorScheme - .onSurface - , + : Theme.of(context).colorScheme.onSurface, ), ), ], diff --git a/lib/ui/recovery_key_page.dart b/lib/ui/recovery_key_page.dart new file mode 100644 index 000000000..09f75e44b --- /dev/null +++ b/lib/ui/recovery_key_page.dart @@ -0,0 +1,79 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:photos/core/configuration.dart'; +import 'package:photos/ui/settings/account_section_widget.dart'; +import 'package:photos/ui/settings/app_version_widget.dart'; +import 'package:photos/ui/settings/backup_section_widget.dart'; +import 'package:photos/ui/settings/danger_section_widget.dart'; +import 'package:photos/ui/settings/debug_section_widget.dart'; +import 'package:photos/ui/settings/details_section_widget.dart'; +import 'package:photos/ui/settings/info_section_widget.dart'; +import 'package:photos/ui/settings/security_section_widget.dart'; +import 'package:photos/ui/settings/social_section_widget.dart'; +import 'package:photos/ui/settings/support_section_widget.dart'; +import 'package:photos/ui/settings/theme_switch_widget.dart'; +import 'package:photos/utils/dialog_util.dart'; + +class RecoveryKeyPage extends StatelessWidget { + const RecoveryKeyPage({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: _getBody(context), + ); + } + + Widget _getBody(BuildContext context) { + final hasLoggedIn = Configuration.instance.getToken() != null; + final List contents = []; + contents.add(Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.center, + children: const [ThemeSwitchWidget()])); + final sectionDivider = Divider( + height: 10, + color: Theme.of(context).colorScheme.onSurface.withOpacity(0.4), + ); + if (hasLoggedIn) { + contents.addAll([ + DetailsSectionWidget(), + sectionDivider, + BackupSectionWidget(), + sectionDivider, + AccountSectionWidget(), + sectionDivider, + ]); + } + contents.addAll([ + SecuritySectionWidget(), + sectionDivider, + test(), + sectionDivider, + SupportSectionWidget(), + sectionDivider, + SocialSectionWidget(), + sectionDivider, + InfoSectionWidget(), + ]); + if (hasLoggedIn) { + contents.addAll([ + sectionDivider, + DangerSectionWidget(), + ]); + } + contents.add(AppVersionWidget()); + if (kDebugMode && hasLoggedIn) { + contents.add(DebugSectionWidget()); + } + return SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + children: contents, + ), + ), + ); + } +} diff --git a/lib/ui/recovery_page.dart b/lib/ui/recovery_page.dart index 91c27932f..15b0dd33e 100644 --- a/lib/ui/recovery_page.dart +++ b/lib/ui/recovery_page.dart @@ -6,9 +6,11 @@ import 'package:photos/ui/common_elements.dart'; import 'package:photos/ui/password_entry_page.dart'; import 'package:photos/utils/dialog_util.dart'; import 'package:photos/utils/toast_util.dart'; +import 'package:dotted_border/dotted_border.dart'; class RecoveryPage extends StatefulWidget { - const RecoveryPage({Key key}) : super(key: key); + final bool showAppBar; + const RecoveryPage({Key key, @required this.showAppBar}) : super(key: key); @override _RecoveryPageState createState() => _RecoveryPageState(); @@ -20,108 +22,71 @@ class _RecoveryPageState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: Text( - "recover account", - style: TextStyle( - fontSize: 18, - ), - ), - ), - body: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(60, 0, 60, 0), - child: TextFormField( - decoration: InputDecoration( - hintText: "enter your recovery key", - contentPadding: EdgeInsets.all(20), - ), - style: TextStyle( - fontSize: 14, - fontFeatures: [FontFeature.tabularFigures()], - ), - controller: _recoveryKey, - autofocus: false, - autocorrect: false, - keyboardType: TextInputType.multiline, - maxLines: null, - onChanged: (_) { - setState(() {}); - }, + appBar: widget.showAppBar + ? AppBar( + title: Text(""), + ) + : null, + body: Padding( + padding: const EdgeInsets.fromLTRB(20, 40, 20, 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + // mainAxisAlignment: MainAxisAlignment.center, + + mainAxisSize: MainAxisSize.max, + children: [ + Text("Recovery Key", style: Theme.of(context).textTheme.headline4), + Padding(padding: EdgeInsets.all(12)), + Text( + "If you forget your password, the only way you can recover your data is with this key.", + style: Theme.of(context).textTheme.subtitle1, ), - ), - Padding(padding: EdgeInsets.all(12)), - Container( - padding: const EdgeInsets.fromLTRB(80, 0, 80, 0), - width: double.infinity, - height: 64, - child: button( - "recover", - fontSize: 18, - onPressed: _recoveryKey.text.isNotEmpty - ? () async { - final dialog = - createProgressDialog(context, "decrypting..."); - await dialog.show(); - try { - await Configuration.instance - .recover(_recoveryKey.text.trim()); - await dialog.hide(); - showToast("recovery successful!"); - Navigator.of(context).pushReplacement( - MaterialPageRoute( - builder: (BuildContext context) { - return WillPopScope( - onWillPop: () async => false, - child: PasswordEntryPage( - mode: PasswordEntryMode.reset, - ), - ); - }, + Padding(padding: EdgeInsets.only(top: 24)), + DottedBorder( + color: Color.fromRGBO(17, 127, 56, 1), //color of dotted/dash line + strokeWidth: 1, //thickness of dash/dots + dashPattern: const [6, 6], + radius: Radius.circular(8), + //dash patterns, 10 is dash width, 6 is space width + child: SizedBox( + //inner container + height: 200, //height of inner container + width: + double.infinity, //width to 100% match to parent container. + // ignore: prefer_const_literals_to_create_immutables + child: Column( + children: [ + Container( + decoration: BoxDecoration( + border: Border.all( + color: Color.fromRGBO(49, 155, 86, .2), + ), + borderRadius: BorderRadius.all( + Radius.circular(12), + ), + color: Color.fromRGBO(49, 155, 86, .2), + ), + // color: Color.fromRGBO(49, 155, 86, .2), + height: 120, + width: double.infinity, + child: const Text('1'), + ), + SizedBox( + height: 80, + width: double.infinity, + child: Padding( + child: Text( + "we don’t store this key, please save this in a safe place", + style: Theme.of(context).textTheme.bodyText1, ), - ); - } catch (e) { - await dialog.hide(); - String errMessage = - 'the recovery key you entered is incorrect'; - if (e is AssertionError) { - errMessage = '$errMessage : ${e.message}'; - } - showErrorDialog( - context, "incorrect recovery key", errMessage); - } - } - : null, - ), - ), - GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () { - showErrorDialog( - context, - "sorry", - "due to the nature of our end-to-end encryption protocol, your data cannot be decrypted without your password or recovery key", - ); - }, - child: Container( - padding: EdgeInsets.all(40), - child: Center( - child: Text( - "no recovery key?", - style: TextStyle( - decoration: TextDecoration.underline, - fontSize: 12, - color: Colors.white.withOpacity(0.9), - ), + padding: EdgeInsets.all(20)), + ), + ], ), ), - ), - ), - ], + ) + ], + ), ), ); } diff --git a/lib/ui/settings/backup_section_widget.dart b/lib/ui/settings/backup_section_widget.dart index c6fc9b638..df54901ee 100644 --- a/lib/ui/settings/backup_section_widget.dart +++ b/lib/ui/settings/backup_section_widget.dart @@ -10,6 +10,7 @@ import 'package:photos/services/sync_service.dart'; import 'package:photos/ui/backup_folder_selection_page.dart'; import 'package:photos/ui/deduplicate_page.dart'; import 'package:photos/ui/free_space_page.dart'; +import 'package:photos/ui/recovery_page.dart'; import 'package:photos/ui/settings/common_settings.dart'; import 'package:photos/ui/settings/settings_section_title.dart'; import 'package:photos/ui/settings/settings_text_item.dart'; @@ -44,11 +45,14 @@ class BackupSectionWidgetState extends State { behavior: HitTestBehavior.translucent, onTap: () async { routeToPage( - context, - BackupFolderSelectionPage( - buttonText: "Backup", - ), - ); + context, + RecoveryPage( + showAppBar: true, + ) + // BackupFolderSelectionPage( + // buttonText: "Backup", + // ), + ); }, child: SettingsTextItem( text: "Backed up folders", icon: Icons.navigate_next), @@ -59,7 +63,10 @@ class BackupSectionWidgetState extends State { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text("Backup over mobile data", style: Theme.of(context).textTheme.subtitle1,), + Text( + "Backup over mobile data", + style: Theme.of(context).textTheme.subtitle1, + ), Switch.adaptive( value: Configuration.instance.shouldBackupOverMobileData(), onChanged: (value) async { @@ -76,7 +83,10 @@ class BackupSectionWidgetState extends State { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text("Backup videos", style: Theme.of(context).textTheme.subtitle1,), + Text( + "Backup videos", + style: Theme.of(context).textTheme.subtitle1, + ), Switch.adaptive( value: Configuration.instance.shouldBackupVideos(), onChanged: (value) async { diff --git a/lib/ui/settings_page.dart b/lib/ui/settings_page.dart index 2e877190f..5fb5b456a 100644 --- a/lib/ui/settings_page.dart +++ b/lib/ui/settings_page.dart @@ -1,6 +1,5 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:photos/core/configuration.dart'; import 'package:photos/ui/settings/account_section_widget.dart'; import 'package:photos/ui/settings/app_version_widget.dart'; diff --git a/lib/utils/dialog_util.dart b/lib/utils/dialog_util.dart index 29ab033f9..8463c1d92 100644 --- a/lib/utils/dialog_util.dart +++ b/lib/utils/dialog_util.dart @@ -101,3 +101,128 @@ Future showConfettiDialog({ routeSettings: routeSettings, ); } + +Widget test() { + return Container( + width: 355, + height: 236, + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 355, + height: 236, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Color(0x4c000000), + ), + padding: const EdgeInsets.only( + top: 20, + bottom: 16, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + width: 234, + child: Text( + "Are you sure you want to logout?", + style: TextStyle( + color: Colors.white, + fontSize: 24, + fontFamily: "SF Pro Display", + fontWeight: FontWeight.w600, + ), + ), + ), + SizedBox(height: 16), + Container( + width: 323, + height: 48, + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 323, + height: 48, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Color(0x4c000000), + ), + padding: const EdgeInsets.only( + left: 135, + right: 136, + ), + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + "Cancel", + style: TextStyle( + color: Colors.white, + fontSize: 16, + fontFamily: "SF Pro Text", + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ), + ], + ), + ), + SizedBox(height: 16), + Container( + width: 323, + height: 48, + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 323, + height: 48, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Colors.white, + ), + padding: const EdgeInsets.symmetric( + horizontal: 120, + vertical: 12, + ), + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + "Yes Logout", + style: TextStyle( + color: Colors.black, + fontSize: 16, + fontFamily: "SF Pro Text", + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ), + ], + ), + ), + ], + ), + ), + ], + ), + ); +} diff --git a/pubspec.lock b/pubspec.lock index 22968e3c1..1e4dda053 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -232,6 +232,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.0" + dotted_border: + dependency: "direct main" + description: + name: dotted_border + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0+2" email_validator: dependency: "direct main" description: @@ -786,6 +793,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.0" + path_drawing: + dependency: transitive + description: + name: path_drawing + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + path_parsing: + dependency: transitive + description: + name: path_parsing + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" path_provider: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 9021b84e8..b6797767f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,6 +33,7 @@ dependencies: device_info: ^2.0.2 dio: ^4.0.0 dots_indicator: ^2.0.0 + dotted_border: ^2.0.0+2 email_validator: ^2.0.1 event_bus: ^2.0.0 exif: ^3.0.0 diff --git a/thirdparty/extended_image b/thirdparty/extended_image new file mode 160000 index 000000000..112cc8be0 --- /dev/null +++ b/thirdparty/extended_image @@ -0,0 +1 @@ +Subproject commit 112cc8be0c2f07129edd7575003a3f9ddb62ae3f