From 01b1f7462da9911a308d6aeebf045e76dbf8f063 Mon Sep 17 00:00:00 2001 From: NaiJi Date: Wed, 11 May 2022 21:37:08 +0300 Subject: [PATCH] Implement recovery domain page frontend --- assets/translations/en.json | 7 +- lib/config/hive_config.dart | 1 + .../app_config/app_config_repository.dart | 4 + .../cubit/app_config/app_config_state.dart | 36 ++++++ .../initializing/backblaze_form_cubit.dart | 0 .../initializing/cloudflare_form_cubit.dart | 0 .../initializing/domain_cloudflare.dart | 0 .../initializing/hetzner_form_cubit.dart | 0 .../initializing/root_user_form_cubit.dart | 0 .../recovery_domain_form_cubit.dart | 51 +++++++++ lib/logic/get_it/api_config.dart | 7 ++ .../components/brand_header/brand_header.dart | 2 +- lib/ui/pages/setup/initializing.dart | 16 ++- .../setup/recovering/recovery_domain.dart | 107 +++++++++++------- 14 files changed, 177 insertions(+), 54 deletions(-) rename lib/logic/cubit/forms/{ => setup}/initializing/backblaze_form_cubit.dart (100%) rename lib/logic/cubit/forms/{ => setup}/initializing/cloudflare_form_cubit.dart (100%) rename lib/logic/cubit/forms/{ => setup}/initializing/domain_cloudflare.dart (100%) rename lib/logic/cubit/forms/{ => setup}/initializing/hetzner_form_cubit.dart (100%) rename lib/logic/cubit/forms/{ => setup}/initializing/root_user_form_cubit.dart (100%) create mode 100644 lib/logic/cubit/forms/setup/recovering/recovery_domain_form_cubit.dart diff --git a/assets/translations/en.json b/assets/translations/en.json index 7b184548..eb36af5a 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -22,7 +22,7 @@ "nickname": "Nickname", "loading": "Loading...", "later": "Skip to setup later", - "connect_to_existing": "Connect to existing server", + "connect_to_existing": "Connect to an existing server", "reset": "Reset", "details": "Details", "no_data": "No data", @@ -283,6 +283,11 @@ "finish": "Everything is initialized", "checks": "Checks have been completed \n{} ouf of {}" }, + "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" + }, "modals": { "_comment": "messages in modals", "1": "Server with such name, already exist", diff --git a/lib/config/hive_config.dart b/lib/config/hive_config.dart index e7ed84e3..9cd19459 100644 --- a/lib/config/hive_config.dart +++ b/lib/config/hive_config.dart @@ -71,4 +71,5 @@ class BNames { static String sshConfig = 'sshConfig'; static String sshPrivateKey = "sshPrivateKey"; static String sshPublicKey = "sshPublicKey"; + static String serverDomain = "serverDomain"; } diff --git a/lib/logic/cubit/app_config/app_config_repository.dart b/lib/logic/cubit/app_config/app_config_repository.dart index 78560f14..c4095cae 100644 --- a/lib/logic/cubit/app_config/app_config_repository.dart +++ b/lib/logic/cubit/app_config/app_config_repository.dart @@ -239,6 +239,10 @@ class AppConfigRepository { await getIt().storeHetznerKey(key); } + Future saveServerDomain(String domain) async { + await getIt().storeServerDomain(domain); + } + Future saveBackblazeKey(BackblazeCredential backblazeCredential) async { await getIt().storeBackblazeCredential(backblazeCredential); } diff --git a/lib/logic/cubit/app_config/app_config_state.dart b/lib/logic/cubit/app_config/app_config_state.dart index 0608d903..ac456e17 100644 --- a/lib/logic/cubit/app_config/app_config_state.dart +++ b/lib/logic/cubit/app_config/app_config_state.dart @@ -240,3 +240,39 @@ class AppConfigFinished extends AppConfigState { isServerResetedFirstTime, ]; } + +class AppRecovery extends AppConfigState { + const AppRecovery({ + required String hetznerKey, + required String cloudFlareKey, + required BackblazeCredential backblazeCredential, + required CloudFlareDomain cloudFlareDomain, + required User rootUser, + required HetznerServerDetails hetznerServer, + required bool isServerStarted, + required bool isServerResetedFirstTime, + required bool isServerResetedSecondTime, + }) : super( + hetznerKey: hetznerKey, + cloudFlareKey: cloudFlareKey, + backblazeCredential: backblazeCredential, + cloudFlareDomain: cloudFlareDomain, + rootUser: rootUser, + hetznerServer: hetznerServer, + isServerStarted: isServerStarted, + isServerResetedFirstTime: isServerResetedFirstTime, + isServerResetedSecondTime: isServerResetedSecondTime, + ); + + @override + List get props => [ + hetznerKey, + cloudFlareKey, + backblazeCredential, + cloudFlareDomain, + rootUser, + hetznerServer, + isServerStarted, + isServerResetedFirstTime, + ]; +} diff --git a/lib/logic/cubit/forms/initializing/backblaze_form_cubit.dart b/lib/logic/cubit/forms/setup/initializing/backblaze_form_cubit.dart similarity index 100% rename from lib/logic/cubit/forms/initializing/backblaze_form_cubit.dart rename to lib/logic/cubit/forms/setup/initializing/backblaze_form_cubit.dart diff --git a/lib/logic/cubit/forms/initializing/cloudflare_form_cubit.dart b/lib/logic/cubit/forms/setup/initializing/cloudflare_form_cubit.dart similarity index 100% rename from lib/logic/cubit/forms/initializing/cloudflare_form_cubit.dart rename to lib/logic/cubit/forms/setup/initializing/cloudflare_form_cubit.dart diff --git a/lib/logic/cubit/forms/initializing/domain_cloudflare.dart b/lib/logic/cubit/forms/setup/initializing/domain_cloudflare.dart similarity index 100% rename from lib/logic/cubit/forms/initializing/domain_cloudflare.dart rename to lib/logic/cubit/forms/setup/initializing/domain_cloudflare.dart diff --git a/lib/logic/cubit/forms/initializing/hetzner_form_cubit.dart b/lib/logic/cubit/forms/setup/initializing/hetzner_form_cubit.dart similarity index 100% rename from lib/logic/cubit/forms/initializing/hetzner_form_cubit.dart rename to lib/logic/cubit/forms/setup/initializing/hetzner_form_cubit.dart diff --git a/lib/logic/cubit/forms/initializing/root_user_form_cubit.dart b/lib/logic/cubit/forms/setup/initializing/root_user_form_cubit.dart similarity index 100% rename from lib/logic/cubit/forms/initializing/root_user_form_cubit.dart rename to lib/logic/cubit/forms/setup/initializing/root_user_form_cubit.dart diff --git a/lib/logic/cubit/forms/setup/recovering/recovery_domain_form_cubit.dart b/lib/logic/cubit/forms/setup/recovering/recovery_domain_form_cubit.dart new file mode 100644 index 00000000..8ab5cb88 --- /dev/null +++ b/lib/logic/cubit/forms/setup/recovering/recovery_domain_form_cubit.dart @@ -0,0 +1,51 @@ +import 'dart:async'; + +import 'package:cubit_form/cubit_form.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:selfprivacy/logic/api_maps/hetzner.dart'; +import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart'; +import 'package:selfprivacy/logic/cubit/forms/validations/validations.dart'; + +class RecoveryDomainFormCubit extends FormCubit { + RecoveryDomainFormCubit(this.initializingCubit) { + var regExp = RegExp(r"\s+|[-!$%^&*()@+|~=`{}\[\]:<>?,.\/]"); + apiKey = FieldCubit( + initalValue: '', + validations: [ + RequiredStringValidation('validations.required'.tr()), + ValidationModel( + (s) => regExp.hasMatch(s), 'validations.key_format'.tr()), + LengthStringNotEqualValidation(64) + ], + ); + + super.addFields([apiKey]); + } + + @override + FutureOr onSubmit() async { + initializingCubit.setHetznerKey(apiKey.state.value); + } + + final AppConfigCubit initializingCubit; + + late final FieldCubit apiKey; + + @override + FutureOr asyncValidation() async { + late bool isKeyValid; + HetznerApi apiClient = HetznerApi(isWithToken: false); + + try { + isKeyValid = await apiClient.isValid(apiKey.state.value); + } catch (e) { + addError(e); + } + + if (!isKeyValid) { + apiKey.setError('bad key'); + return false; + } + return true; + } +} diff --git a/lib/logic/get_it/api_config.dart b/lib/logic/get_it/api_config.dart index 1bc15eb1..5a2d622a 100644 --- a/lib/logic/get_it/api_config.dart +++ b/lib/logic/get_it/api_config.dart @@ -11,12 +11,14 @@ class ApiConfigModel { HetznerServerDetails? get hetznerServer => _hetznerServer; String? get hetznerKey => _hetznerKey; String? get cloudFlareKey => _cloudFlareKey; + String? get serverDomain => _serverDomain; BackblazeCredential? get backblazeCredential => _backblazeCredential; CloudFlareDomain? get cloudFlareDomain => _cloudFlareDomain; BackblazeBucket? get backblazeBucket => _backblazeBucket; String? _hetznerKey; String? _cloudFlareKey; + String? _serverDomain; HetznerServerDetails? _hetznerServer; BackblazeCredential? _backblazeCredential; CloudFlareDomain? _cloudFlareDomain; @@ -32,6 +34,11 @@ class ApiConfigModel { _cloudFlareKey = value; } + Future storeServerDomain(String value) async { + await _box.put(BNames.serverDomain, value); + _serverDomain = value; + } + Future storeBackblazeCredential(BackblazeCredential value) async { await _box.put(BNames.backblazeKey, value); diff --git a/lib/ui/components/brand_header/brand_header.dart b/lib/ui/components/brand_header/brand_header.dart index f9613e08..6795fdb4 100644 --- a/lib/ui/components/brand_header/brand_header.dart +++ b/lib/ui/components/brand_header/brand_header.dart @@ -6,7 +6,7 @@ import 'package:selfprivacy/ui/components/pre_styled_buttons/pre_styled_buttons. class BrandHeader extends StatelessWidget { const BrandHeader({ Key? key, - required this.title, + this.title = "", this.hasBackButton = false, this.hasFlashButton = false, }) : super(key: key); diff --git a/lib/ui/pages/setup/initializing.dart b/lib/ui/pages/setup/initializing.dart index e696e51e..d64d7c3b 100644 --- a/lib/ui/pages/setup/initializing.dart +++ b/lib/ui/pages/setup/initializing.dart @@ -4,11 +4,11 @@ import 'package:flutter/material.dart'; import 'package:selfprivacy/config/brand_theme.dart'; import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart'; import 'package:selfprivacy/logic/cubit/forms/factories/field_cubit_factory.dart'; -import 'package:selfprivacy/logic/cubit/forms/initializing/backblaze_form_cubit.dart'; -import 'package:selfprivacy/logic/cubit/forms/initializing/cloudflare_form_cubit.dart'; -import 'package:selfprivacy/logic/cubit/forms/initializing/domain_cloudflare.dart'; -import 'package:selfprivacy/logic/cubit/forms/initializing/hetzner_form_cubit.dart'; -import 'package:selfprivacy/logic/cubit/forms/initializing/root_user_form_cubit.dart'; +import 'package:selfprivacy/logic/cubit/forms/setup/initializing/backblaze_form_cubit.dart'; +import 'package:selfprivacy/logic/cubit/forms/setup/initializing/cloudflare_form_cubit.dart'; +import 'package:selfprivacy/logic/cubit/forms/setup/initializing/domain_cloudflare.dart'; +import 'package:selfprivacy/logic/cubit/forms/setup/initializing/hetzner_form_cubit.dart'; +import 'package:selfprivacy/logic/cubit/forms/setup/initializing/root_user_form_cubit.dart'; import 'package:selfprivacy/ui/components/brand_bottom_sheet/brand_bottom_sheet.dart'; import 'package:selfprivacy/ui/components/brand_button/brand_button.dart'; import 'package:selfprivacy/ui/components/brand_cards/brand_cards.dart'; @@ -104,10 +104,8 @@ class InitializingPage extends StatelessWidget { child: BrandButton.text( title: 'basis.connect_to_existing'.tr(), onPressed: () { - Navigator.of(context).pushAndRemoveUntil( - materialRoute(RecoveryDomain()), - (predicate) => false, - ); + Navigator.of(context) + .push(materialRoute(RecoveryDomain())); }, ), ) diff --git a/lib/ui/pages/setup/recovering/recovery_domain.dart b/lib/ui/pages/setup/recovering/recovery_domain.dart index ffa38085..c9546ccc 100644 --- a/lib/ui/pages/setup/recovering/recovery_domain.dart +++ b/lib/ui/pages/setup/recovering/recovery_domain.dart @@ -1,54 +1,75 @@ -import 'package:cubit_form/cubit_form.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart'; import 'package:selfprivacy/ui/components/brand_button/brand_button.dart'; -import 'package:selfprivacy/ui/pages/rootRoute.dart'; -import 'package:selfprivacy/utils/route_transitions/basic.dart'; +import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart'; -class RecoveryDomain extends StatelessWidget { +class RecoveryDomain extends StatefulWidget { + @override + State createState() => _RecoveryDomainState(); +} + +class _RecoveryDomainState extends State { @override Widget build(BuildContext context) { - var cubit = context.watch(); - return BlocListener( - listener: (context, state) { - if (cubit.state is AppConfigFinished) { - Navigator.of(context).pushReplacement(materialRoute(RootPage())); - } - }, - child: SafeArea( - child: Scaffold( - body: SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - ConstrainedBox( - constraints: BoxConstraints( - minHeight: MediaQuery.of(context).size.height - - MediaQuery.of(context).padding.top - - MediaQuery.of(context).padding.bottom - - 566, - ), - child: Container( - alignment: Alignment.center, - child: BrandButton.text( - title: cubit.state is AppConfigFinished - ? 'basis.close'.tr() - : 'basis.later'.tr(), - onPressed: () { - Navigator.of(context).pushAndRemoveUntil( - materialRoute(RootPage()), - (predicate) => false, - ); - }, - ), - ), - ), - ], - ), + return BrandHeroScreen( + children: [ + TextField( + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: "recovering.domain_recover_placeholder".tr(), ), ), + SizedBox(height: 16), + BrandButton.rised( + onPressed: () {}, + text: "more.continue".tr(), + ), + ], + heroTitle: "recovering.recovery_main_header".tr(), + heroSubtitle: "recovering.domain_recovery_description".tr(), + hasBackButton: true, + hasFlashButton: false, + heroIcon: Icons.link, + ); + } +} + +/*class RecoveryDomain extends StatelessWidget { + @override + Widget build(BuildContext context) { + return SafeArea( + child: Scaffold( + appBar: PreferredSize( + preferredSize: Size.fromHeight(52), + child: BrandHeader(hasBackButton: true), + ), + body: ListView( + padding: EdgeInsets.all(16), + children: [ + Text( + "recovering.recovery_main_header".tr(), + style: Theme.of(context).textTheme.headlineMedium, + ), + SizedBox(height: 18), + Text( + "recovering.domain_recovery_description".tr(), + style: Theme.of(context).textTheme.bodyLarge, + ), + SizedBox(height: 18), + TextField( + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: "recovering.domain_recover_placeholder".tr(), + ), + ), + SizedBox(height: 18), + BrandButton.rised( + onPressed: () {}, + text: "more.continue".tr(), + ), + ], + ), ), ); } -} +}*/ \ No newline at end of file