2020-12-30 16:13:25 +02:00
import ' package:cubit_form/cubit_form.dart ' ;
2020-12-10 22:33:19 +02:00
import ' package:flutter/material.dart ' ;
2020-12-30 16:13:25 +02:00
import ' package:flutter_bloc/flutter_bloc.dart ' ;
2021-01-27 20:33:00 +02:00
import ' package:selfprivacy/config/brand_colors.dart ' ;
2020-12-10 22:33:19 +02:00
import ' package:selfprivacy/config/brand_theme.dart ' ;
import ' package:selfprivacy/config/text_themes.dart ' ;
2021-02-03 21:51:07 +02:00
import ' package:selfprivacy/logic/cubit/forms/initializing/backblaze_form_cubit.dart ' ;
2021-01-06 19:35:57 +02:00
import ' package:selfprivacy/logic/cubit/forms/initializing/cloudflare_form_cubit.dart ' ;
2021-02-15 20:58:29 +02:00
import ' package:selfprivacy/logic/cubit/forms/initializing/domain_cloudflare.dart ' ;
2020-12-30 16:13:25 +02:00
import ' package:selfprivacy/logic/cubit/forms/initializing/hetzner_form_cubit.dart ' ;
2021-01-14 20:45:10 +02:00
import ' package:selfprivacy/logic/cubit/forms/initializing/root_user_form_cubit.dart ' ;
2021-01-06 19:35:57 +02:00
import ' package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart ' ;
2020-12-10 22:33:19 +02:00
import ' package:selfprivacy/logic/cubit/providers/providers_cubit.dart ' ;
import ' package:selfprivacy/ui/components/brand_button/brand_button.dart ' ;
import ' package:selfprivacy/ui/components/brand_card/brand_card.dart ' ;
import ' package:selfprivacy/ui/components/brand_modal_sheet/brand_modal_sheet.dart ' ;
import ' package:selfprivacy/ui/components/brand_span_button/brand_span_button.dart ' ;
import ' package:selfprivacy/ui/components/brand_text/brand_text.dart ' ;
2020-12-30 16:13:25 +02:00
import ' package:selfprivacy/ui/components/progress_bar/progress_bar.dart ' ;
import ' package:selfprivacy/ui/pages/rootRoute.dart ' ;
import ' package:selfprivacy/utils/route_transitions/basic.dart ' ;
2020-12-10 22:33:19 +02:00
2021-01-06 19:35:57 +02:00
class InitializingPage extends StatelessWidget {
2020-12-10 22:33:19 +02:00
@ override
Widget build ( BuildContext context ) {
2021-01-06 19:35:57 +02:00
var cubit = context . watch < AppConfigCubit > ( ) ;
var actualPage = [
_stepHetzner ( cubit ) ,
_stepCloudflare ( cubit ) ,
2021-02-03 21:51:07 +02:00
_stepBackblaze ( cubit ) ,
2021-01-06 19:35:57 +02:00
_stepDomain ( cubit ) ,
_stepUser ( cubit ) ,
_stepServer ( cubit ) ,
2021-01-06 21:25:53 +02:00
_stepCheck ( cubit ) ,
2021-01-06 19:35:57 +02:00
Container ( child: Text ( ' Everythigng is initialized ' ) )
2021-02-15 20:58:29 +02:00
] [ cubit . state . progress ] ;
2021-01-06 19:35:57 +02:00
return BlocListener < AppConfigCubit , AppConfigState > (
listener: ( context , state ) {
if ( state . isFullyInitilized ) {
Navigator . of ( context ) . pushReplacement ( materialRoute ( RootPage ( ) ) ) ;
}
} ,
child: SafeArea (
child: Scaffold (
body: ListView (
children: [
Padding (
padding: brandPagePadding1 ,
child: Column (
2021-02-03 21:51:07 +02:00
crossAxisAlignment: CrossAxisAlignment . center ,
2021-01-06 19:35:57 +02:00
children: [
ProgressBar (
steps: [
' Hetzner ' ,
' CloudFlare ' ,
2021-02-03 21:51:07 +02:00
' Backblaze ' ,
2021-01-06 19:35:57 +02:00
' Domain ' ,
' User ' ,
' Server ' ,
' Check '
2020-12-30 16:13:25 +02:00
] ,
2021-01-06 19:35:57 +02:00
activeIndex: cubit . state . progress ,
2020-12-30 16:13:25 +02:00
) ,
2021-01-06 19:35:57 +02:00
] ,
) ,
2020-12-30 16:13:25 +02:00
) ,
2021-01-06 19:35:57 +02:00
_addCard (
AnimatedSwitcher (
duration: Duration ( milliseconds: 300 ) ,
child: actualPage ,
) ,
2020-12-30 16:13:25 +02:00
) ,
2021-01-06 19:35:57 +02:00
BrandButton . text (
title:
cubit . state . isFullyInitilized ? ' Close ' : ' Настрою потом ' ,
onPressed: ( ) {
Navigator . of ( context ) . pushAndRemoveUntil (
materialRoute ( RootPage ( ) ) ,
( predicate ) = > predicate = = null ,
) ;
} ) ,
SizedBox ( height: 30 ) ,
] ,
) ,
2020-12-30 16:13:25 +02:00
) ,
2020-12-10 22:33:19 +02:00
) ,
) ;
}
2021-01-06 19:35:57 +02:00
Widget _stepHetzner ( AppConfigCubit initializingCubit ) {
2020-12-30 16:13:25 +02:00
return BlocProvider (
create: ( context ) = > HetznerFormCubit ( initializingCubit ) ,
child: Builder ( builder: ( context ) {
var formCubit = context . watch < HetznerFormCubit > ( ) ;
return Column (
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
2021-02-15 20:58:29 +02:00
Image . asset (
' assets/images/logos/hetzner.png ' ,
width: 150 ,
) ,
2020-12-30 16:13:25 +02:00
SizedBox ( height: 10 ) ,
BrandText . h2 ( ' Подключите сервер Hetzner ' ) ,
SizedBox ( height: 10 ) ,
BrandText . body2 (
' Здесь будут жить наши данные и SelfPrivacy-сервисы ' ) ,
Spacer ( ) ,
CubitFormTextField (
formFieldCubit: formCubit . apiKey ,
textAlign: TextAlign . center ,
scrollPadding: EdgeInsets . only ( bottom: 70 ) ,
decoration: InputDecoration (
hintText: ' Hetzner API Token ' ,
) ,
) ,
2021-01-06 19:35:57 +02:00
Spacer ( ) ,
2020-12-30 16:13:25 +02:00
BrandButton . rised (
onPressed:
formCubit . state . isSubmitting ? null : formCubit . trySubmit ,
title: ' Подключить ' ,
) ,
SizedBox ( height: 10 ) ,
BrandButton . text (
onPressed: ( ) = > _showModal ( context , _HowHetzner ( ) ) ,
title: ' Как получить API Token ' ,
) ,
] ,
) ;
} ) ,
) ;
}
2020-12-10 22:33:19 +02:00
void _showModal ( BuildContext context , Widget widget ) {
showModalBottomSheet < void > (
context: context ,
isScrollControlled: true ,
backgroundColor: Colors . transparent ,
builder: ( BuildContext context ) {
return widget ;
} ,
) ;
}
2021-01-06 19:35:57 +02:00
Widget _stepCloudflare ( AppConfigCubit initializingCubit ) {
return BlocProvider (
create: ( context ) = > CloudFlareFormCubit ( initializingCubit ) ,
child: Builder ( builder: ( context ) {
var formCubit = context . watch < CloudFlareFormCubit > ( ) ;
return Column (
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
2021-02-15 20:58:29 +02:00
Image . asset (
' assets/images/logos/cloudflare.png ' ,
width: 150 ,
) ,
SizedBox ( height: 10 ) ,
2021-01-06 19:35:57 +02:00
BrandText . h2 ( ' Подключите CloudFlare ' ) ,
SizedBox ( height: 10 ) ,
BrandText . body2 ( ' Для управления DNS вашего домена ' ) ,
Spacer ( ) ,
CubitFormTextField (
formFieldCubit: formCubit . apiKey ,
textAlign: TextAlign . center ,
scrollPadding: EdgeInsets . only ( bottom: 70 ) ,
decoration: InputDecoration (
hintText: ' CloudFlare API Token ' ,
) ,
) ,
Spacer ( ) ,
BrandButton . rised (
onPressed:
formCubit . state . isSubmitting ? null : formCubit . trySubmit ,
title: ' Подключить ' ,
) ,
SizedBox ( height: 10 ) ,
BrandButton . text (
onPressed: ( ) { } ,
title: ' Как получить API Token ' ,
) ,
] ,
) ;
} ) ,
2020-12-30 16:13:25 +02:00
) ;
}
2021-02-03 21:51:07 +02:00
Widget _stepBackblaze ( AppConfigCubit initializingCubit ) {
return BlocProvider (
create: ( context ) = > BackblazeFormCubit ( initializingCubit ) ,
child: Builder ( builder: ( context ) {
var formCubit = context . watch < BackblazeFormCubit > ( ) ;
return Column (
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
2021-02-15 20:58:29 +02:00
Image . asset (
' assets/images/logos/backblaze.png ' ,
height: 50 ,
) ,
2021-02-03 21:51:07 +02:00
SizedBox ( height: 10 ) ,
BrandText . h2 ( ' Подключите облачное хранилище Backblaze ' ) ,
SizedBox ( height: 10 ) ,
Spacer ( ) ,
CubitFormTextField (
formFieldCubit: formCubit . keyId ,
textAlign: TextAlign . center ,
scrollPadding: EdgeInsets . only ( bottom: 70 ) ,
decoration: InputDecoration (
hintText: ' KeyID ' ,
) ,
) ,
Spacer ( ) ,
CubitFormTextField (
formFieldCubit: formCubit . applicationKey ,
textAlign: TextAlign . center ,
scrollPadding: EdgeInsets . only ( bottom: 70 ) ,
decoration: InputDecoration (
hintText: ' Master Application Key ' ,
) ,
) ,
Spacer ( ) ,
BrandButton . rised (
onPressed:
formCubit . state . isSubmitting ? null : formCubit . trySubmit ,
title: ' Подключить ' ,
) ,
SizedBox ( height: 10 ) ,
BrandButton . text (
onPressed: ( ) = > _showModal ( context , _HowHetzner ( ) ) ,
title: ' Как получить API Token ' ,
) ,
] ,
) ;
} ) ,
) ;
}
2021-01-06 19:35:57 +02:00
Widget _stepDomain ( AppConfigCubit initializingCubit ) {
return BlocProvider (
2021-02-15 20:58:29 +02:00
create: ( context ) = > DomainSetupCubit ( initializingCubit ) . . load ( ) ,
2021-01-06 19:35:57 +02:00
child: Builder ( builder: ( context ) {
2021-02-15 20:58:29 +02:00
var domainSetup = context . watch < DomainSetupCubit > ( ) ;
var state = domainSetup . state ;
2021-01-06 19:35:57 +02:00
return Column (
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
2021-02-15 20:58:29 +02:00
Image . asset (
' assets/images/logos/cloudflare.png ' ,
width: 150 ,
) ,
SizedBox ( height: 30 ) ,
BrandText . h2 ( ' Домен ' ) ,
2021-01-06 19:35:57 +02:00
SizedBox ( height: 10 ) ,
2021-02-15 20:58:29 +02:00
if ( state is Empty )
BrandText . body2 ( ' Н а данный момент подлюченных доменов нет' ) ,
if ( state is Loading )
BrandText . body2 (
state . type = = LoadingTypes . loadingDomain
? ' Загружаем список доменов '
: ' Сохранение.. ' ,
2021-01-06 19:35:57 +02:00
) ,
2021-02-15 20:58:29 +02:00
if ( state is MoreThenOne )
BrandText . body2 (
' Найдено больше одного домена, для вашей безопастности, просим вам удалить не нужные домены ' ,
) ,
if ( state is Loaded ) . . . [
SizedBox ( height: 10 ) ,
Row (
mainAxisSize: MainAxisSize . min ,
mainAxisAlignment: MainAxisAlignment . end ,
crossAxisAlignment: CrossAxisAlignment . center ,
children: [
Expanded (
child: BrandText . h3 (
' ${ state . domain } ' ,
textAlign: TextAlign . center ,
) ,
) ,
Container (
width: 50 ,
child: BrandButton . rised (
onPressed: ( ) = > domainSetup . load ( ) ,
child: Row (
mainAxisAlignment: MainAxisAlignment . center ,
mainAxisSize: MainAxisSize . min ,
children: [
Icon (
Icons . refresh ,
color: Colors . white ,
) ,
] ,
) ,
) ,
) ,
] ,
)
] ,
if ( state is Empty ) . . . [
SizedBox ( height: 30 ) ,
BrandButton . rised (
onPressed: ( ) = > domainSetup . load ( ) ,
child: Row (
mainAxisAlignment: MainAxisAlignment . center ,
children: [
Icon (
Icons . refresh ,
color: Colors . white ,
) ,
SizedBox ( width: 10 ) ,
BrandText . buttonTitleText ( ' Обновить cпис о к ' ) ,
] ,
) ,
) ,
] ,
if ( state is Loaded ) . . . [
SizedBox ( height: 30 ) ,
BrandButton . rised (
onPressed: ( ) = > domainSetup . saveDomain ( ) ,
title: ' Сохранить домен ' ,
) ,
] ,
SizedBox ( height: 10 ) ,
2021-01-06 19:35:57 +02:00
Spacer ( ) ,
SizedBox ( height: 10 ) ,
BrandButton . text (
onPressed: ( ) = > _showModal ( context , _HowHetzner ( ) ) ,
title: ' Как получить API Token ' ,
) ,
] ,
) ;
} ) ,
2020-12-30 16:13:25 +02:00
) ;
}
2021-01-06 19:35:57 +02:00
Widget _stepUser ( AppConfigCubit initializingCubit ) {
return BlocProvider (
2021-01-14 20:45:10 +02:00
create: ( context ) = > RootUserFormCubit ( initializingCubit ) ,
2021-01-06 19:35:57 +02:00
child: Builder ( builder: ( context ) {
2021-01-14 20:45:10 +02:00
var formCubit = context . watch < RootUserFormCubit > ( ) ;
2021-01-06 19:35:57 +02:00
return Column (
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
Spacer ( ) ,
SizedBox ( height: 10 ) ,
CubitFormTextField (
formFieldCubit: formCubit . userName ,
textAlign: TextAlign . center ,
scrollPadding: EdgeInsets . only ( bottom: 70 ) ,
decoration: InputDecoration (
hintText: ' Никнейм ' ,
2020-12-10 22:33:19 +02:00
) ,
2021-01-06 19:35:57 +02:00
) ,
SizedBox ( height: 10 ) ,
2021-02-15 20:58:29 +02:00
BlocBuilder < FieldCubit < bool > , FieldCubitState < bool > > (
cubit: formCubit . isVisible ,
builder: ( context , state ) {
var isVisible = state . value ;
return CubitFormTextField (
obscureText: ! isVisible ,
formFieldCubit: formCubit . password ,
textAlign: TextAlign . center ,
scrollPadding: EdgeInsets . only ( bottom: 70 ) ,
decoration: InputDecoration (
hintText: ' Пароль ' ,
suffixIcon: IconButton (
icon: Icon (
isVisible ? Icons . visibility : Icons . visibility_off ,
) ,
onPressed: ( ) = > formCubit . isVisible . setValue ( ! isVisible ) ,
) ,
suffixIconConstraints: BoxConstraints ( minWidth: 60 ) ,
prefixIconConstraints: BoxConstraints ( maxWidth: 85 ) ,
prefixIcon: Container ( ) ,
) ,
) ;
} ,
2021-01-06 19:35:57 +02:00
) ,
Spacer ( ) ,
BrandButton . rised (
onPressed:
formCubit . state . isSubmitting ? null : formCubit . trySubmit ,
title: ' Подключить ' ,
) ,
SizedBox ( height: 10 ) ,
BrandButton . text (
onPressed: ( ) = > _showModal ( context , _HowHetzner ( ) ) ,
title: ' Как получить API Token ' ,
) ,
] ,
) ;
} ) ,
2020-12-30 16:13:25 +02:00
) ;
}
2020-12-10 22:33:19 +02:00
2021-01-06 19:35:57 +02:00
Widget _stepServer ( AppConfigCubit appConfigCubit ) {
var isLoading = appConfigCubit . state . isLoading ;
return Builder ( builder: ( context ) {
return Column (
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
2021-01-08 14:37:28 +02:00
Spacer ( flex: 2 ) ,
2021-01-06 19:35:57 +02:00
BrandText . h2 ( ' Создать сервер ' ) ,
SizedBox ( height: 10 ) ,
BrandText . body2 ( ' Создать сервер ' ) ,
Spacer ( ) ,
BrandButton . rised (
2021-01-21 23:01:42 +02:00
onPressed:
isLoading ? null : appConfigCubit . createServerAndSetDnsRecords ,
2021-01-06 19:35:57 +02:00
title: isLoading ? ' loading ' : ' Создать сервер ' ,
) ,
2021-01-08 14:37:28 +02:00
Spacer ( flex: 2 ) ,
2021-01-06 19:35:57 +02:00
BrandButton . text (
onPressed: ( ) = > _showModal ( context , _HowHetzner ( ) ) ,
title: ' Что это значит? ' ,
) ,
] ,
) ;
} ) ;
}
2021-01-06 21:25:53 +02:00
Widget _stepCheck ( AppConfigCubit appConfigCubit ) {
2021-02-15 20:58:29 +02:00
return Text ( ' step check ' ) ;
// var state = appConfigCubit.state as TimerState;
// var isDnsChecked = state.dataState.isDnsChecked;
// return Builder(builder: (context) {
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Spacer(flex: 2),
// SizedBox(height: 10),
// BrandText.body2(
// isDnsChecked
// ? 'Dns сервера вступили в силу, мы стартанули сервер, как только он поднимется, мы закончим инициализацию.'
// : 'Мы начали процесс инциализации сервера, раз в минуту мы будем проверять наличие DNS записей, как только они вступят в силу мы продолжим инциализацию',
// ),
// SizedBox(height: 10),
// Row(
// children: [
// BrandText.body2('До следующей проверки: '),
// BrandTimer(
// startDateTime: state.timerStart,
// duration: state.duration,
// )
// ],
// ),
// Spacer(
// flex: 2,
// ),
// BrandButton.text(
// onPressed: () => _showModal(context, _HowHetzner()),
// title: 'Что это значит?',
// ),
// ],
// );
// });
2021-01-06 21:25:53 +02:00
}
2020-12-30 16:13:25 +02:00
Widget _addCard ( Widget child ) {
2021-01-06 19:35:57 +02:00
return Container (
height: 500 ,
2020-12-30 16:13:25 +02:00
padding: brandPagePadding2 ,
2021-01-08 14:37:28 +02:00
child: BrandCard ( child: child ) ,
2020-12-30 16:13:25 +02:00
) ;
2020-12-10 22:33:19 +02:00
}
}
class _HowHetzner extends StatelessWidget {
const _HowHetzner ( {
Key key ,
} ) : super ( key: key ) ;
@ override
Widget build ( BuildContext context ) {
2021-01-27 20:33:00 +02:00
var isDark = Theme . of ( context ) . brightness = = Brightness . dark ;
2020-12-10 22:33:19 +02:00
return BrandModalSheet (
child: Padding (
padding: brandPagePadding2 ,
child: Column (
children: [
SizedBox ( height: 40 ) ,
BrandText . h2 ( ' Как получить Hetzner API Token ' ) ,
SizedBox ( height: 20 ) ,
RichText (
text: TextSpan (
children: [
TextSpan (
text: ' 1 Переходим по ссылке ' ,
2021-01-27 20:33:00 +02:00
style: body1Style . copyWith (
color: isDark ? BrandColors . white : BrandColors . black ,
) ,
2020-12-10 22:33:19 +02:00
) ,
BrandSpanButton . link (
2021-01-27 21:54:37 +02:00
text: ' hetzner.com ' ,
urlString: ' https://hetzner.com ' ,
2020-12-10 22:33:19 +02:00
) ,
TextSpan (
text: '''
2 З а х о д и м в с о з д а н н ы й н а м и п р о е к т . Е с л и т а к о в о г о - н е т , з н а ч и т с о з д а ё м .
3 Н а в о д и м м ы ш к о й н а б о к о в у ю п а н е л ь . О н а д о л ж н а р а с к р ы т ь с я , п о к а з а в н а м п у н к т ы м е н ю . Н а с и н т е р е с у е т п о с л е д н и й — Security ( с и к о н к о й к л ю ч и к а ) .
4 Д а л е е , в в е р х н е й ч а с т и и н т е р ф е й с а в и д и м п р и м е р н о т а к о й с п и с о к : SSH Keys , API Tokens , Certificates , Members . Н а м н у ж е н API Tokens . П е р е х о д и м п о н е м у .
5 В п р а в о й ч а с т и и н т е р ф е й с а , н а с б у д е т о ж и д а т ь к н о п к а Generate API token . Е с л и ж е в ы и с п о л ь з у е т е м о б и л ь н у ю в е р с и ю с а й т а , в н и ж н е м п р а в о м у г л у в ы у в и д и т е к р а с н ы й п л ю с и к . Н а ж и м а е м н а э т у к н о п к у .
6 В п о л е Description , д а ё м н а ш е м у т о к е н у н а з в а н и е ( э т о м о ж е т б ы т ь л ю б о е н а з в а н и е , к о т о р ы е в а м н р а в и т ь с я . С у т и о н о н е м е н я е т .
''' ,
2021-01-27 20:33:00 +02:00
style: body1Style . copyWith (
color: isDark ? BrandColors . white : BrandColors . black ,
) ,
2020-12-10 22:33:19 +02:00
) ,
] ,
) ,
) ,
] ,
) ,
) ,
) ;
}
}