import 'package:cubit_form/cubit_form.dart'; import 'package:easy_localization/easy_localization.dart'; 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/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'; import 'package:selfprivacy/ui/components/brand_md/brand_md.dart'; 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/utils/route_transitions/basic.dart'; class InitializingPage extends StatelessWidget { @override Widget build(BuildContext context) { var cubit = context.watch(); var actualPage = [ () => _stepHetzner(cubit), () => _stepCloudflare(cubit), () => _stepBackblaze(cubit), () => _stepDomain(cubit), () => _stepUser(cubit), () => _stepServer(cubit), () => _stepCheck(cubit), () => _stepCheck(cubit), () => _stepCheck(cubit), () => Container(child: Center(child: Text('initializing.finish'.tr()))) ][cubit.state.progress](); 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: [ Padding( padding: paddingH15V0.copyWith(top: 10, bottom: 10), child: cubit.state.isFullyInitilized ? SizedBox( height: 80, ) : ProgressBar( steps: [ 'Hetzner', 'CloudFlare', 'Backblaze', 'Domain', 'User', 'Server', '✅ Check', ], activeIndex: cubit.state.porgressBar, ), ), _addCard( AnimatedSwitcher( duration: Duration(milliseconds: 300), child: actualPage, ), ), 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, ); }, ), )), ], ), ), ), ), ); } Widget _stepHetzner(AppConfigCubit initializingCubit) { return BlocProvider( create: (context) => HetznerFormCubit(initializingCubit), child: Builder(builder: (context) { var formCubitState = context.watch().state; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Image.asset( 'assets/images/logos/hetzner.png', width: 150, ), SizedBox(height: 10), BrandText.h2('initializing.1'.tr()), SizedBox(height: 10), BrandText.body2('initializing.2'.tr()), Spacer(), CubitFormTextField( formFieldCubit: context.read().apiKey, textAlign: TextAlign.center, scrollPadding: EdgeInsets.only(bottom: 70), decoration: InputDecoration( hintText: 'Hetzner API Token', ), ), Spacer(), BrandButton.rised( onPressed: formCubitState.isSubmitting ? null : () => context.read().trySubmit(), text: 'basis.connect'.tr(), ), SizedBox(height: 10), BrandButton.text( onPressed: () => _showModal(context, _HowTo(fileName: 'how_hetzner')), title: 'initializing.how'.tr(), ), ], ); }), ); } void _showModal(BuildContext context, Widget widget) { showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (BuildContext context) { return widget; }, ); } Widget _stepCloudflare(AppConfigCubit initializingCubit) { return BlocProvider( create: (context) => CloudFlareFormCubit(initializingCubit), child: Builder(builder: (context) { var formCubitState = context.watch().state; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Image.asset( 'assets/images/logos/cloudflare.png', width: 150, ), SizedBox(height: 10), BrandText.h2('initializing.3'.tr()), SizedBox(height: 10), BrandText.body2('initializing.4'.tr()), Spacer(), CubitFormTextField( formFieldCubit: context.read().apiKey, textAlign: TextAlign.center, scrollPadding: EdgeInsets.only(bottom: 70), decoration: InputDecoration( hintText: 'initializing.5'.tr(), ), ), Spacer(), BrandButton.rised( onPressed: formCubitState.isSubmitting ? null : () => context.read().trySubmit(), text: 'basis.connect'.tr(), ), SizedBox(height: 10), BrandButton.text( onPressed: () => _showModal( context, _HowTo( fileName: 'how_cloudflare', )), title: 'initializing.how'.tr(), ), ], ); }), ); } Widget _stepBackblaze(AppConfigCubit initializingCubit) { return BlocProvider( create: (context) => BackblazeFormCubit(initializingCubit), child: Builder(builder: (context) { var formCubitState = context.watch().state; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Image.asset( 'assets/images/logos/backblaze.png', height: 50, ), SizedBox(height: 10), BrandText.h2('initializing.6'.tr()), SizedBox(height: 10), Spacer(), CubitFormTextField( formFieldCubit: context.read().keyId, textAlign: TextAlign.center, scrollPadding: EdgeInsets.only(bottom: 70), decoration: InputDecoration( hintText: 'KeyID', ), ), Spacer(), CubitFormTextField( formFieldCubit: context.read().applicationKey, textAlign: TextAlign.center, scrollPadding: EdgeInsets.only(bottom: 70), decoration: InputDecoration( hintText: 'Master Application Key', ), ), Spacer(), BrandButton.rised( onPressed: formCubitState.isSubmitting ? null : () => context.read().trySubmit(), text: 'basis.connect'.tr(), ), SizedBox(height: 10), BrandButton.text( onPressed: () => _showModal( context, _HowTo( fileName: 'how_backblaze', )), title: 'initializing.how'.tr(), ), ], ); }), ); } Widget _stepDomain(AppConfigCubit initializingCubit) { return BlocProvider( create: (context) => DomainSetupCubit(initializingCubit)..load(), child: Builder(builder: (context) { DomainSetupState state = context.watch().state; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Image.asset( 'assets/images/logos/cloudflare.png', width: 150, ), SizedBox(height: 30), BrandText.h2('basis.domain'.tr()), SizedBox(height: 10), if (state is Empty) BrandText.body2('initializing.7'.tr()), if (state is Loading) BrandText.body2( state.type == LoadingTypes.loadingDomain ? 'initializing.8'.tr() : 'basis.saving'.tr(), ), if (state is MoreThenOne) BrandText.body2( 'initializing.9'.tr(), ), 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: () => context.read().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: () => context.read().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: () => context.read().saveDomain(), text: 'initializing.10'.tr(), ), ], SizedBox( height: 10, width: double.infinity, ), ], ); }), ); } Widget _stepUser(AppConfigCubit initializingCubit) { return BlocProvider( create: (context) => RootUserFormCubit(initializingCubit, FieldCubitFactory(context)), child: Builder(builder: (context) { var formCubitState = context.watch().state; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ BrandText.h2('initializing.22'.tr()), SizedBox(height: 10), BrandText.body2('initializing.23'.tr()), Spacer(), CubitFormTextField( formFieldCubit: context.read().userName, textAlign: TextAlign.center, scrollPadding: EdgeInsets.only(bottom: 70), decoration: InputDecoration( hintText: 'basis.nickname'.tr(), ), ), SizedBox(height: 10), BlocBuilder, FieldCubitState>( bloc: context.read().isVisible, builder: (context, state) { var isVisible = state.value; return CubitFormTextField( obscureText: !isVisible, formFieldCubit: context.read().password, textAlign: TextAlign.center, scrollPadding: EdgeInsets.only(bottom: 70), decoration: InputDecoration( hintText: 'basis.password'.tr(), suffixIcon: IconButton( icon: Icon( isVisible ? Icons.visibility : Icons.visibility_off, ), onPressed: () => context .read() .isVisible .setValue(!isVisible), ), suffixIconConstraints: BoxConstraints(minWidth: 60), prefixIconConstraints: BoxConstraints(maxWidth: 85), prefixIcon: Container(), ), ); }, ), Spacer(), BrandButton.rised( onPressed: formCubitState.isSubmitting ? null : () => context.read().trySubmit(), text: 'basis.connect'.tr(), ), ], ); }), ); } Widget _stepServer(AppConfigCubit appConfigCubit) { var isLoading = (appConfigCubit.state as AppConfigNotFinished).isLoading; return Builder(builder: (context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Spacer(flex: 2), BrandText.h2('initializing.final'.tr()), SizedBox(height: 10), BrandText.body2('initializing.11'.tr()), Spacer(), BrandButton.rised( onPressed: isLoading ? null : () => appConfigCubit.createServerAndSetDnsRecords(), text: isLoading ? 'basis.loading'.tr() : 'initializing.11'.tr(), ), ], ); }); } Widget _stepCheck(AppConfigCubit appConfigCubit) { assert(appConfigCubit.state is AppConfigNotFinished, 'wrong state'); var state = appConfigCubit.state as TimerState; late int doneCount; late String? text; if (state.isServerResetedSecondTime) { text = 'initializing.13'.tr(); doneCount = 3; } else if (state.isServerResetedFirstTime) { text = 'initializing.21'.tr(); doneCount = 2; } else if (state.isServerStarted) { text = 'initializing.14'.tr(); doneCount = 1; } else if (state.isServerCreated) { text = 'initializing.15'.tr(); doneCount = 0; } return Builder(builder: (context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 15), BrandText.h4( 'initializing.checks'.tr(args: [doneCount.toString(), "4"]), ), Spacer(flex: 2), SizedBox(height: 10), BrandText.body2(text), SizedBox(height: 10), if (doneCount == 0 && state.dnsMatches != null) Column( children: state.dnsMatches!.entries.map((entry) { var domain = entry.key; var isCorrect = entry.value; return Row( children: [ if (isCorrect) Icon(Icons.check, color: Colors.green), if (!isCorrect) Icon(Icons.schedule, color: Colors.amber), SizedBox(width: 10), Text(domain), ], ); }).toList(), ), SizedBox(height: 10), if (!state.isLoading) Row( children: [ BrandText.body2('initializing.16'.tr()), BrandTimer( startDateTime: state.timerStart!, duration: state.duration!, ) ], ), if (state.isLoading) BrandText.body2('initializing.17'.tr()), ], ); }); } Widget _addCard(Widget child) { return Container( height: 450, padding: paddingH15V0, child: BrandCards.big(child: child), ); } } class _HowTo extends StatelessWidget { const _HowTo({ Key? key, required this.fileName, }) : super(key: key); final String fileName; @override Widget build(BuildContext context) { return BrandBottomSheet( isExpended: true, child: Padding( padding: paddingH15V0, child: BrandMarkdown( fileName: fileName, ), ), ); } }