diff --git a/assets/translations/en.json b/assets/translations/en.json index c3245f9d..ef65c8e5 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -286,7 +286,16 @@ "recovering": { "recovery_main_header": "Connect to an existing server", "domain_recovery_description": "Enter a server domain you want to get access for", - "domain_recover_placeholder": "Your domain" + "domain_recover_placeholder": "Your domain", + "method_select_description": "Select a recovery method:", + "method_select_other_device": "I have access on another device", + "method_select_recovery_key": "I have a recovery key", + "method_select_nothing": "I don't have any of that", + "fallback_select_description": "What exactly do you have? Pick the first available option:", + "fallback_select_token_copy": "Copy of auth token from other version of the application.", + "fallback_select_root_ssh": "Root SSH access to the server.", + "fallback_select_provider_console": "Access to the server console of my prodiver.", + "fallback_select_provider_console_hint": "For example: Hetzner." }, "modals": { "_comment": "messages in modals", diff --git a/assets/translations/ru.json b/assets/translations/ru.json index 7f46b137..8503dc39 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -284,6 +284,20 @@ "finish": "Всё инициализировано.", "checks": "Проверок выполнено: \n{} / {}" }, + "recovering": { + "recovery_main_header": "Подключиться к существующему серверу", + "domain_recovery_description": "Введите домен, по которому вы хотите получить доступ к серверу:", + "domain_recover_placeholder": "Домен", + "method_select_description": "Выберите способ входа:", + "method_select_other_device": "У меня есть доступ на другом устройстве", + "method_select_recovery_key": "У меня есть ключ восстановления", + "method_select_nothing": "У меня ничего из этого нет", + "fallback_select_description": "Что у вас из этого есть? Выберите первое, что подходит:", + "fallback_select_token_copy": "Копия токена авторизации из другой версии приложения.", + "fallback_select_root_ssh": "Root доступ к серверу по SSH.", + "fallback_select_provider_console": "Доступ к консоли хостинга.", + "fallback_select_provider_console_hint": "Например, Hetzner." + }, "modals": { "_comment": "messages in modals", "1": "Сервер с таким именем уже существует", diff --git a/lib/theming/factory/app_theme_factory.dart b/lib/theming/factory/app_theme_factory.dart index c1f5903a..860dd0b2 100644 --- a/lib/theming/factory/app_theme_factory.dart +++ b/lib/theming/factory/app_theme_factory.dart @@ -39,8 +39,13 @@ abstract class AppThemeFactory { ); } - final accentColor = await SystemAccentColor(fallbackColor) - ..load(); + final accentColor = await SystemAccentColor(fallbackColor); + + try { + await accentColor.load(); + } on MissingPluginException catch (e) { + print("_createAppTheme: ${e.message}"); + } final fallbackColorScheme = ColorScheme.fromSeed( seedColor: accentColor.accent, diff --git a/lib/ui/components/brand_cards/brand_cards.dart b/lib/ui/components/brand_cards/brand_cards.dart index 398e7e89..67ad09af 100644 --- a/lib/ui/components/brand_cards/brand_cards.dart +++ b/lib/ui/components/brand_cards/brand_cards.dart @@ -67,12 +67,12 @@ class _OutlinedCard extends StatelessWidget { return Card( elevation: 0.0, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(4), + borderRadius: BorderRadius.all(Radius.circular(12)), side: BorderSide( - color: Colors.grey.withOpacity(0.2), - width: 1, + color: Theme.of(context).colorScheme.outline, ), ), + clipBehavior: Clip.antiAlias, child: child, ); } diff --git a/lib/ui/pages/setup/initializing.dart b/lib/ui/pages/setup/initializing.dart index 5048aa57..016131ae 100644 --- a/lib/ui/pages/setup/initializing.dart +++ b/lib/ui/pages/setup/initializing.dart @@ -17,7 +17,7 @@ import 'package:selfprivacy/ui/components/brand_text/brand_text.dart'; import 'package:selfprivacy/ui/components/brand_timer/brand_timer.dart'; import 'package:selfprivacy/ui/components/progress_bar/progress_bar.dart'; import 'package:selfprivacy/ui/pages/rootRoute.dart'; -import 'package:selfprivacy/ui/pages/setup/recovering/recovery_domain.dart'; +import 'package:selfprivacy/ui/pages/setup/recovering/recovery_method_select.dart'; import 'package:selfprivacy/utils/route_transitions/basic.dart'; class InitializingPage extends StatelessWidget { @@ -104,8 +104,8 @@ class InitializingPage extends StatelessWidget { child: BrandButton.text( title: 'basis.connect_to_existing'.tr(), onPressed: () { - Navigator.of(context) - .push(materialRoute(RecoveryDomain())); + Navigator.of(context).push( + materialRoute(RecoveryMethodSelect())); }, ), ) diff --git a/lib/ui/pages/setup/recovering/recovery_domain.dart b/lib/ui/pages/setup/recovering/recovery_domain.dart index 151b5314..b68d423c 100644 --- a/lib/ui/pages/setup/recovering/recovery_domain.dart +++ b/lib/ui/pages/setup/recovering/recovery_domain.dart @@ -15,33 +15,35 @@ class RecoveryDomain extends StatelessWidget { return BlocProvider( create: (context) => RecoveryDomainFormCubit(appConfig, FieldCubitFactory(context)), - child: Builder(builder: (context) { - var formCubitState = context.watch().state; + child: Builder( + builder: (context) { + var formCubitState = context.watch().state; - return BrandHeroScreen( - children: [ - CubitFormTextField( - formFieldCubit: - context.read().serverDomainField, - decoration: InputDecoration( - border: OutlineInputBorder(), - labelText: "recovering.domain_recover_placeholder".tr(), + return BrandHeroScreen( + heroTitle: "recovering.recovery_main_header".tr(), + heroSubtitle: "recovering.domain_recovery_description".tr(), + hasBackButton: true, + hasFlashButton: false, + children: [ + CubitFormTextField( + formFieldCubit: + context.read().serverDomainField, + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: "recovering.domain_recover_placeholder".tr(), + ), ), - ), - SizedBox(height: 16), - FilledButton( - title: "more.continue".tr(), - onPressed: formCubitState.isSubmitting - ? null - : () => context.read().trySubmit(), - ) - ], - heroTitle: "recovering.recovery_main_header".tr(), - heroSubtitle: "recovering.domain_recovery_description".tr(), - hasBackButton: true, - hasFlashButton: false, - ); - }), + SizedBox(height: 16), + FilledButton( + title: "more.continue".tr(), + onPressed: formCubitState.isSubmitting + ? null + : () => context.read().trySubmit(), + ) + ], + ); + }, + ), ); } } diff --git a/lib/ui/pages/setup/recovering/recovery_method_select.dart b/lib/ui/pages/setup/recovering/recovery_method_select.dart new file mode 100644 index 00000000..d71feaa0 --- /dev/null +++ b/lib/ui/pages/setup/recovering/recovery_method_select.dart @@ -0,0 +1,48 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:selfprivacy/ui/components/brand_button/brand_button.dart'; +import 'package:selfprivacy/ui/components/brand_cards/brand_cards.dart'; +import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart'; +import 'package:selfprivacy/utils/route_transitions/basic.dart'; +import 'package:selfprivacy/ui/pages/rootRoute.dart'; + +class RecoveryMethodSelect extends StatelessWidget { + @override + Widget build(BuildContext context) { + return BrandHeroScreen( + heroTitle: "recovering.recovery_main_header".tr(), + heroSubtitle: "recovering.method_select_description".tr(), + hasBackButton: true, + hasFlashButton: false, + children: [ + BrandCards.outlined( + child: ListTile( + title: Text( + "recovering.method_select_other_device".tr(), + style: Theme.of(context).textTheme.titleMedium, + ), + leading: Icon(Icons.offline_share_outlined), + onTap: () => Navigator.of(context).push(materialRoute(RootPage())), + ), + ), + SizedBox(height: 16), + BrandCards.outlined( + child: ListTile( + title: Text( + "recovering.method_select_recovery_key".tr(), + style: Theme.of(context).textTheme.titleMedium, + ), + leading: Icon(Icons.password_outlined), + onTap: () => Navigator.of(context).push(materialRoute(RootPage())), + ), + ), + SizedBox(height: 16), + BrandButton.text( + title: "recovering.method_select_nothing".tr(), + onPressed: () => + Navigator.of(context).push(materialRoute(RootPage())), + ) + ], + ); + } +}