From 8ccb4f18f646d4bd9756611f37397b2e9e5757ab Mon Sep 17 00:00:00 2001 From: Kherel Date: Thu, 22 Apr 2021 20:04:24 +0200 Subject: [PATCH] done --- assets/translations/en.json | 15 ++- assets/translations/ru.json | 16 +++- .../cubit/app_config/app_config_cubit.dart | 22 +++++ .../app_config/app_config_repository.dart | 22 +++++ .../cubit/app_config/app_config_state.dart | 2 +- lib/ui/components/brand_md/brand_md.dart | 4 +- .../not_ready_card/not_ready_card.dart | 4 +- lib/ui/pages/initializing/initializing.dart | 94 +++++++++++-------- .../pages/more/app_settings/app_setting.dart | 63 ++++++++++++- 9 files changed, 186 insertions(+), 56 deletions(-) diff --git a/assets/translations/en.json b/assets/translations/en.json index f688ef13ed..2000177c4f 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -41,7 +41,9 @@ "1": "Dark Theme", "2": "Change your the app theme", "3": "Reset app config", - "4": "Reset api keys and root user" + "4": "Reset api keys and root user", + "5": "Delete Server", + "6": "This removes the Server. It will be no longer accessible" } }, "onboarding": { @@ -162,7 +164,7 @@ }, "initializing": { "_comment": "initializing page", - "1": "Connect Hetzner server", + "1": "Connect a server", "2": "Here, your data and SelfPrivacy services wiil reside", "how": "How to obtain API token", "3": "Connect CloudFlare", @@ -184,7 +186,10 @@ "18": "How to obtain Hetzner API Token", "19": "1 Go via this link ", "20": "\n", - "21": "One more restart to apply your security certificates." + "21": "One more restart to apply your security certificates.", + "22": "Create master account", + "23": "Enter a nickname and strong password" + }, "modals": { "_comment": "messages in modals", @@ -192,7 +197,9 @@ "2": "Destroy server and create a new one?", "3": "Are you sure?", "4": "Purge all authentication keys?", - "5": "Yes, purge all my tokens" + "5": "Yes, purge all my tokens", + "6": "Delete the server and volume?", + "7": "Yes" }, "timer": { "sec": "{} sec" diff --git a/assets/translations/ru.json b/assets/translations/ru.json index e8bc8f2c18..59286277d5 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -41,7 +41,9 @@ "1": "Темная тема", "2": "Сменить цветовую тему", "3": "Сброс настроек", - "4": "Сбросить API ключи а так же root пользвателя" + "4": "Сбросить API ключи а так же root пользвателя", + "5": "Удалить сервер", + "6": "Действие приведет к удалению сервера. После чего он не будет доступен." } }, "onboarding": { @@ -162,10 +164,10 @@ }, "initializing": { "_comment": "initializing page", - "1": "Подключите сервер Hetzner", + "1": "Подключите сервер", "2": "Здесь будут жить наши данные и SelfPrivacy-сервисы", "how": "Как получить API Token", - "3": "'Подключите CloudFlare'", + "3": "Подключите CloudFlare", "4": "Для управления DNS вашего домена", "5": "CloudFlare API Token", "6": "Подключите облачное хранилище Backblaze", @@ -184,7 +186,9 @@ "18": "Как получить Hetzner API Token'", "19": "1 Переходим по ссылке ", "20": "\n2 Заходим в созданный нами проект. Если такового - нет, значит создаём.\n3 Наводим мышкой на боковую панель. Она должна раскрыться, показав нам пункты меню. Нас интересует последний — Security (с иконкой ключика).\n4 Далее, в верхней части интерфейса видим примерно такой список: SSH Keys, API Tokens, Certificates, Members. Нам нужен API Tokens. Переходим по нему.\n5 В правой части интерфейса, нас будет ожидать кнопка Generate API token. Если же вы используете мобильную версию сайта, в нижнем правом углу вы увидите красный плюсик. Нажимаем на эту кнопку.\n6 В поле Description, даём нашему токену название (это может быть любое название, которые вам нравиться. Сути оно не меняет.", - "21": "Сейчас будет дополнительная перезагрузка для активации сертификатов безопастности" + "21": "Сейчас будет дополнительная перезагрузка для активации сертификатов безопастности", + "22": "Создайте главную учетную запись", + "23": "Введите никнейм и сложный пароль" }, "modals": { "_comment": "messages in modals", @@ -192,7 +196,9 @@ "2": "Уничтожить сервер и создать новый?", "3": "Вы уверенны", "4": "Сбросить все ключи?", - "5": "Да, сбросить" + "5": "Да, сбросить", + "6": "Удалить сервер и диск?", + "7": "Да, удалить" }, "timer": { "sec": "{} сек" diff --git a/lib/logic/cubit/app_config/app_config_cubit.dart b/lib/logic/cubit/app_config/app_config_cubit.dart index 6627821c2e..86b91fb557 100644 --- a/lib/logic/cubit/app_config/app_config_cubit.dart +++ b/lib/logic/cubit/app_config/app_config_cubit.dart @@ -263,6 +263,28 @@ class AppConfigCubit extends Cubit { emit(InitialAppConfigState()); } + Future serverDelete() async { + closeTimer(); + if (state.hetznerServer != null) { + await repository.deleteServer(state.cloudFlareDomain!); + } + await repository.deleteRecords(); + emit(AppConfigState( + hetznerKey: state.hetznerKey, + cloudFlareKey: state.cloudFlareKey, + backblazeCredential: state.backblazeCredential, + cloudFlareDomain: state.cloudFlareDomain, + rootUser: state.rootUser, + hetznerServer: null, + isServerStarted: false, + isServerResetedFirstTime: false, + isServerResetedSecondTime: false, + hasFinalChecked: false, + isLoading: false, + error: null, + )); + } + void setHetznerKey(String hetznerKey) async { await repository.saveHetznerKey(hetznerKey); emit(state.copyWith(hetznerKey: hetznerKey)); diff --git a/lib/logic/cubit/app_config/app_config_repository.dart b/lib/logic/cubit/app_config/app_config_repository.dart index ebbbb305ec..da9bee28b0 100644 --- a/lib/logic/cubit/app_config/app_config_repository.dart +++ b/lib/logic/cubit/app_config/app_config_repository.dart @@ -220,4 +220,26 @@ class AppConfigRepository { Future saveHasFinalChecked(bool value) async { await box.put(BNames.hasFinalChecked, value); } + + Future deleteServer(CloudFlareDomain cloudFlareDomain) async { + var hetznerApi = HetznerApi(); + var cloudFlare = CloudflareApi(); + + hetznerApi.deleteSelfprivacyServerAndAllVolumes( + domainName: cloudFlareDomain.domainName, + ); + cloudFlare.removeSimilarRecords(cloudFlareDomain: cloudFlareDomain); + } + + Future deleteRecords() async { + await box.deleteAll([ + BNames.hetznerServer, + BNames.isServerStarted, + BNames.isServerResetedFirstTime, + BNames.isServerResetedSecondTime, + BNames.hasFinalChecked, + BNames.isLoading, + ]); + getIt().init(); + } } diff --git a/lib/logic/cubit/app_config/app_config_state.dart b/lib/logic/cubit/app_config/app_config_state.dart index 50040e817a..6b9880c929 100644 --- a/lib/logic/cubit/app_config/app_config_state.dart +++ b/lib/logic/cubit/app_config/app_config_state.dart @@ -43,7 +43,7 @@ class AppConfigState extends Equatable { final bool hasFinalChecked; - final bool? isLoading; + final bool isLoading; final Exception? error; AppConfigState copyWith({ diff --git a/lib/ui/components/brand_md/brand_md.dart b/lib/ui/components/brand_md/brand_md.dart index 759852861e..c130136c72 100644 --- a/lib/ui/components/brand_md/brand_md.dart +++ b/lib/ui/components/brand_md/brand_md.dart @@ -39,7 +39,9 @@ class _BrandMarkdownState extends State { Widget build(BuildContext context) { var isDark = Theme.of(context).brightness == Brightness.dark; var markdown = MarkdownStyleSheet( - p: defaultTextStyle, + p: defaultTextStyle.copyWith( + color: isDark ? BrandColors.white : null, + ), h1: headline1Style.copyWith( color: isDark ? BrandColors.white : null, ), diff --git a/lib/ui/components/not_ready_card/not_ready_card.dart b/lib/ui/components/not_ready_card/not_ready_card.dart index d1db3047d9..7d1c6cc563 100644 --- a/lib/ui/components/not_ready_card/not_ready_card.dart +++ b/lib/ui/components/not_ready_card/not_ready_card.dart @@ -33,9 +33,7 @@ class NotReadyCard extends StatelessWidget { child: Text( 'not_ready_card.2'.tr(), style: body1Style.copyWith( - color: Theme.of(context).brightness == Brightness.dark - ? Colors.black - : BrandColors.white, + color: Colors.white, fontWeight: FontWeight.bold, decoration: TextDecoration.underline, // height: 1.1, diff --git a/lib/ui/pages/initializing/initializing.dart b/lib/ui/pages/initializing/initializing.dart index 3b966c9e4b..f675202c2c 100644 --- a/lib/ui/pages/initializing/initializing.dart +++ b/lib/ui/pages/initializing/initializing.dart @@ -1,5 +1,6 @@ import 'package:cubit_form/cubit_form.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:selfprivacy/config/brand_theme.dart'; import 'package:selfprivacy/logic/cubit/forms/initializing/backblaze_form_cubit.dart'; @@ -45,43 +46,56 @@ class InitializingPage extends StatelessWidget { }, child: SafeArea( child: Scaffold( - body: ListView( - children: [ - Padding( - padding: brandPagePadding2.copyWith(top: 10, bottom: 10), - child: ProgressBar( - steps: [ - 'Hetzner', - 'CloudFlare', - 'Backblaze', - 'Domain', - 'User', - 'Server', - ' ✅', - ' ✅', - ' ✅', - ' ✅', - ], - activeIndex: cubit.state.progress, + body: SingleChildScrollView( + child: Column( + children: [ + Padding( + padding: brandPagePadding2.copyWith(top: 10, bottom: 10), + child: ProgressBar( + steps: [ + 'Hetzner', + 'CloudFlare', + 'Backblaze', + 'Domain', + 'User', + 'Server', + ' ✅', + ' ✅', + ' ✅', + ' ✅', + ], + activeIndex: cubit.state.progress, + ), ), - ), - _addCard( - AnimatedSwitcher( - duration: Duration(milliseconds: 300), - child: actualPage, + _addCard( + AnimatedSwitcher( + duration: Duration(milliseconds: 300), + child: actualPage, + ), ), - ), - BrandButton.text( - title: cubit.state.isFullyInitilized - ? 'basis.close'.tr() - : 'basis.later'.tr(), - onPressed: () { - Navigator.of(context).pushAndRemoveUntil( - materialRoute(RootPage()), - (predicate) => false, - ); - }), - ], + 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.isFullyInitilized + ? 'basis.close'.tr() + : 'basis.later'.tr(), + onPressed: () { + Navigator.of(context).pushAndRemoveUntil( + materialRoute(RootPage()), + (predicate) => false, + ); + }, + ), + )), + ], + ), ), ), ), @@ -341,8 +355,10 @@ class InitializingPage extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Spacer(), + BrandText.h2('initializing.22'.tr()), SizedBox(height: 10), + BrandText.body2('initializing.23'.tr()), + Spacer(), CubitFormTextField( formFieldCubit: context.read().userName, textAlign: TextAlign.center, @@ -409,7 +425,7 @@ class InitializingPage extends StatelessWidget { BrandText.body2('initializing.11'.tr()), Spacer(), BrandButton.rised( - onPressed: isLoading! + onPressed: isLoading ? null : () => appConfigCubit.createServerAndSetDnsRecords(), title: isLoading ? 'basis.loading'.tr() : 'initializing.11'.tr(), @@ -446,7 +462,7 @@ class InitializingPage extends StatelessWidget { SizedBox(height: 10), BrandText.body2(text), SizedBox(height: 10), - if (!state.isLoading!) + if (!state.isLoading) Row( children: [ BrandText.body2('initializing.16'.tr()), @@ -456,7 +472,7 @@ class InitializingPage extends StatelessWidget { ) ], ), - if (state.isLoading!) BrandText.body2('initializing.17'.tr()), + if (state.isLoading) BrandText.body2('initializing.17'.tr()), Spacer( flex: 2, ), diff --git a/lib/ui/pages/more/app_settings/app_setting.dart b/lib/ui/pages/more/app_settings/app_setting.dart index 9e89d7dcde..ce857cab6e 100644 --- a/lib/ui/pages/more/app_settings/app_setting.dart +++ b/lib/ui/pages/more/app_settings/app_setting.dart @@ -27,8 +27,8 @@ class _AppSettingsPageState extends State { child: Builder(builder: (context) { return Scaffold( appBar: PreferredSize( - child: - BrandHeader(title: 'more.settings.title'.tr(), hasBackButton: true), + child: BrandHeader( + title: 'more.settings.title'.tr(), hasBackButton: true), preferredSize: Size.fromHeight(52), ), body: ListView( @@ -116,7 +116,64 @@ class _AppSettingsPageState extends State { }, ); }, - ) + ), + ], + ), + ), + Container( + padding: EdgeInsets.only(top: 20, bottom: 5), + decoration: BoxDecoration( + border: Border( + bottom: BorderSide(width: 1, color: BrandColors.dividerColor), + )), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: _TextColumn( + title: 'more.settings.5'.tr(), + value: 'more.settings.6'.tr(), + ), + ), + SizedBox(width: 5), + ElevatedButton( + style: ElevatedButton.styleFrom( + primary: BrandColors.red1, + ), + child: Text( + 'basis.delete'.tr(), + style: TextStyle( + color: BrandColors.white, + fontWeight: NamedFontWeight.demiBold, + ), + ), + onPressed: () { + showDialog( + context: context, + builder: (_) { + return BrandAlert( + title: 'modals.3'.tr(), + contentText: 'modals.6'.tr(), + acitons: [ + ActionButton( + text: 'modals.7'.tr(), + isRed: true, + onPressed: () async { + await context + .read() + .serverDelete(); + Navigator.of(context).pop(); + }), + ActionButton( + text: 'basis.cancel'.tr(), + ), + ], + ); + }, + ); + }, + ), ], ), )