refactor(ui): Update recovery flow to use new support drawer

pull/203/head
Inex Code 2023-04-04 17:31:35 +03:00 committed by Gitea
parent d242f5141e
commit a9d7a27e9d
17 changed files with 335 additions and 322 deletions

View File

@ -0,0 +1,113 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
class ProgressDrawer extends StatelessWidget {
/// A [Drawer] that displays a list of steps and the current step.
/// Used in setup wizards. The [trailing] widget is displayed at the bottom.
/// The [steps] are translated using [EasyLocalization].
const ProgressDrawer({
required this.steps,
required this.currentStep,
required this.constraints,
required this.trailing,
required this.title,
super.key,
});
final List<String> steps;
final int currentStep;
final Widget trailing;
final BoxConstraints constraints;
final String title;
@override
Widget build(final BuildContext context) => SizedBox(
width: 300,
height: constraints.maxHeight,
child: Drawer(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
title,
style: Theme.of(context).textTheme.titleLarge,
),
),
Flexible(
fit: FlexFit.tight,
child: SingleChildScrollView(
child: Column(
children: [
...steps.map((final step) {
final index = steps.indexOf(step);
return _StepIndicator(
title: step.tr(),
isCurrent: index == currentStep,
isCompleted: index < currentStep,
);
}),
],
),
),
),
// const Spacer(),
Padding(
padding: const EdgeInsets.all(16.0),
child: trailing,
),
],
),
),
);
}
class _StepIndicator extends StatelessWidget {
const _StepIndicator({
required this.title,
required this.isCompleted,
required this.isCurrent,
});
final String title;
final bool isCompleted;
final bool isCurrent;
@override
Widget build(final BuildContext context) => ListTile(
selected: isCurrent,
leading: isCurrent
? const _StepCurrentIcon()
: isCompleted
? const _StepCompletedIcon()
: const _StepPendingIcon(),
title: Text(
title,
),
textColor: Theme.of(context).colorScheme.onSurfaceVariant,
iconColor: Theme.of(context).colorScheme.onSurfaceVariant,
);
}
class _StepCompletedIcon extends StatelessWidget {
const _StepCompletedIcon();
@override
Widget build(final BuildContext context) => const Icon(Icons.check_circle);
}
class _StepPendingIcon extends StatelessWidget {
const _StepPendingIcon();
@override
Widget build(final BuildContext context) => const Icon(Icons.circle_outlined);
}
class _StepCurrentIcon extends StatelessWidget {
const _StepCurrentIcon();
@override
Widget build(final BuildContext context) =>
const Icon(Icons.build_circle_outlined);
}

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:ionicons/ionicons.dart';
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
import 'package:selfprivacy/ui/components/jobs_content/jobs_content.dart';
import 'package:selfprivacy/ui/components/drawers/support_drawer.dart';
import 'package:selfprivacy/ui/helpers/widget_size.dart';
import 'package:selfprivacy/utils/breakpoints.dart';
@ -18,6 +19,8 @@ class BrandHeroScreen extends StatelessWidget {
this.heroSubtitle,
this.onBackButtonPressed,
this.bodyPadding = const EdgeInsets.all(16.0),
this.ignoreBreakpoints = false,
this.hasSupportDrawer = false,
});
final List<Widget> children;
@ -30,6 +33,15 @@ class BrandHeroScreen extends StatelessWidget {
final VoidCallback? onBackButtonPressed;
final EdgeInsetsGeometry bodyPadding;
/// On non-mobile screens the buttons of the app bar are hidden.
/// This is because this widget implies that it is nested inside a bigger layout.
/// If it is not nested, set this to true.
final bool ignoreBreakpoints;
/// Usually support drawer is provided by the parent layout.
/// If it is not provided, set this to true.
final bool hasSupportDrawer;
@override
Widget build(final BuildContext context) {
final Widget heroIconWidget = this.heroIconWidget ??
@ -41,6 +53,8 @@ class BrandHeroScreen extends StatelessWidget {
final bool hasHeroIcon = heroIcon != null || this.heroIconWidget != null;
return Scaffold(
endDrawerEnableOpenDragGesture: false,
endDrawer: hasSupportDrawer ? const SupportDrawer() : null,
body: CustomScrollView(
slivers: [
HeroSliverAppBar(
@ -50,6 +64,7 @@ class BrandHeroScreen extends StatelessWidget {
onBackButtonPressed: onBackButtonPressed,
heroIconWidget: heroIconWidget,
hasFlashButton: hasFlashButton,
ignoreBreakpoints: ignoreBreakpoints,
),
if (heroSubtitle != null)
SliverPadding(
@ -89,6 +104,7 @@ class HeroSliverAppBar extends StatefulWidget {
required this.onBackButtonPressed,
required this.heroIconWidget,
required this.hasFlashButton,
required this.ignoreBreakpoints,
super.key,
});
@ -98,6 +114,7 @@ class HeroSliverAppBar extends StatefulWidget {
final bool hasFlashButton;
final VoidCallback? onBackButtonPressed;
final Widget heroIconWidget;
final bool ignoreBreakpoints;
@override
State<HeroSliverAppBar> createState() => _HeroSliverAppBarState();
@ -107,7 +124,8 @@ class _HeroSliverAppBarState extends State<HeroSliverAppBar> {
Size _size = Size.zero;
@override
Widget build(final BuildContext context) {
final isMobile = Breakpoints.small.isActive(context);
final isMobile =
widget.ignoreBreakpoints ? true : Breakpoints.small.isActive(context);
final isJobsListEmpty = context.watch<JobsCubit>().state is JobsStateEmpty;
return SliverAppBar(
expandedHeight:
@ -127,8 +145,7 @@ class _HeroSliverAppBarState extends State<HeroSliverAppBar> {
onPressed: () {
showModalBottomSheet(
context: context,
builder: (final BuildContext context) =>
const JobsContent(),
builder: (final BuildContext context) => const JobsContent(),
);
},
icon: Icon(
@ -139,6 +156,7 @@ class _HeroSliverAppBarState extends State<HeroSliverAppBar> {
: Theme.of(context).colorScheme.primary,
),
),
const SizedBox.shrink(),
],
flexibleSpace: FlexibleSpaceBar(
title: LayoutBuilder(

View File

@ -1,7 +1,7 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:selfprivacy/ui/components/pre_styled_buttons/flash_fab.dart';
import 'package:selfprivacy/ui/components/support_drawer/support_drawer.dart';
import 'package:selfprivacy/ui/components/drawers/support_drawer.dart';
import 'package:selfprivacy/ui/router/root_destinations.dart';
import 'package:selfprivacy/utils/breakpoints.dart';

View File

@ -182,8 +182,7 @@ class _ServicesMigrationPageState extends State<ServicesMigrationPage> {
);
showModalBottomSheet(
context: context,
builder: (final BuildContext context) =>
const JobsContent(),
builder: (final BuildContext context) => const JobsContent(),
);
},
),

View File

@ -13,8 +13,9 @@ import 'package:selfprivacy/logic/cubit/support_system/support_system_cubit.dart
import 'package:selfprivacy/ui/components/buttons/brand_button.dart';
import 'package:selfprivacy/ui/components/buttons/outlined_button.dart';
import 'package:selfprivacy/ui/components/brand_timer/brand_timer.dart';
import 'package:selfprivacy/ui/components/drawers/progress_drawer.dart';
import 'package:selfprivacy/ui/components/progress_bar/progress_bar.dart';
import 'package:selfprivacy/ui/components/support_drawer/support_drawer.dart';
import 'package:selfprivacy/ui/components/drawers/support_drawer.dart';
import 'package:selfprivacy/ui/layouts/responsive_layout_with_infobox.dart';
import 'package:selfprivacy/ui/pages/setup/initializing/server_provider_picker.dart';
import 'package:selfprivacy/ui/pages/setup/initializing/server_type_picker.dart';
@ -113,10 +114,42 @@ class InitializingPage extends StatelessWidget {
builder: (final context, final constraints) => Row(
children: [
if (Breakpoints.large.isActive(context))
_ProgressDrawer(
ProgressDrawer(
steps: steps,
cubit: cubit,
currentStep: cubit.state.progress.index,
title: 'more_page.configuration_wizard'.tr(),
constraints: constraints,
trailing: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (cubit.state is ServerInstallationEmpty ||
cubit.state is ServerInstallationNotFinished)
Container(
alignment: Alignment.center,
child: BrandButton.filled(
text: 'basis.connect_to_existing'.tr(),
onPressed: () {
context.router.replace(const RecoveryRoute());
},
),
),
ConstrainedBox(
constraints: const BoxConstraints(
minWidth: double.infinity,
),
child: OutlinedButton(
child: Text(
cubit.state is ServerInstallationFinished
? 'basis.close'.tr()
: 'basis.later'.tr(),
),
onPressed: () {
context.router.popUntilRoot();
},
),
),
],
),
),
SizedBox(
width: constraints.maxWidth -
@ -625,136 +658,3 @@ class InitializingPage extends StatelessWidget {
);
}
}
class _ProgressDrawer extends StatelessWidget {
const _ProgressDrawer({
required this.steps,
required this.cubit,
required this.constraints,
});
final List<String> steps;
final ServerInstallationCubit cubit;
final BoxConstraints constraints;
@override
Widget build(final BuildContext context) => SizedBox(
width: 300,
height: constraints.maxHeight,
child: Drawer(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'more_page.configuration_wizard'.tr(),
style: Theme.of(context).textTheme.titleLarge,
),
),
Flexible(
fit: FlexFit.tight,
child: SingleChildScrollView(
child: Column(
children: [
...steps.map((final step) {
final index = steps.indexOf(step);
return _StepIndicator(
title: step.tr(),
isCurrent: index == cubit.state.progress.index,
isCompleted: index < cubit.state.progress.index,
);
}),
],
),
),
),
// const Spacer(),
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (cubit.state is ServerInstallationEmpty ||
cubit.state is ServerInstallationNotFinished)
Container(
alignment: Alignment.center,
child: BrandButton.filled(
text: 'basis.connect_to_existing'.tr(),
onPressed: () {
context.router.replace(const RecoveryRoute());
},
),
),
ConstrainedBox(
constraints: const BoxConstraints(
minWidth: double.infinity,
),
child: OutlinedButton(
child: Text(
cubit.state is ServerInstallationFinished
? 'basis.close'.tr()
: 'basis.later'.tr(),
),
onPressed: () {
context.router.popUntilRoot();
},
),
),
],
),
),
],
),
),
);
}
class _StepIndicator extends StatelessWidget {
const _StepIndicator({
required this.title,
required this.isCompleted,
required this.isCurrent,
});
final String title;
final bool isCompleted;
final bool isCurrent;
@override
Widget build(final BuildContext context) => ListTile(
selected: isCurrent,
leading: isCurrent
? const _StepCurrentIcon()
: isCompleted
? const _StepCompletedIcon()
: const _StepPendingIcon(),
title: Text(
title,
),
textColor: Theme.of(context).colorScheme.onSurfaceVariant,
iconColor: Theme.of(context).colorScheme.onSurfaceVariant,
);
}
class _StepCompletedIcon extends StatelessWidget {
const _StepCompletedIcon();
@override
Widget build(final BuildContext context) => const Icon(Icons.check_circle);
}
class _StepPendingIcon extends StatelessWidget {
const _StepPendingIcon();
@override
Widget build(final BuildContext context) => const Icon(Icons.circle_outlined);
}
class _StepCurrentIcon extends StatelessWidget {
const _StepCurrentIcon();
@override
Widget build(final BuildContext context) =>
const Icon(Icons.build_circle_outlined);
}

View File

@ -17,6 +17,7 @@ class RecoverByNewDeviceKeyInstruction extends StatelessWidget {
heroSubtitle: 'recovering.method_device_description'.tr(),
hasBackButton: true,
hasFlashButton: false,
ignoreBreakpoints: true,
onBackButtonPressed:
context.read<ServerInstallationCubit>().revertRecoveryStep,
children: [
@ -61,6 +62,7 @@ class RecoverByNewDeviceKeyInput extends StatelessWidget {
heroSubtitle: 'recovering.method_device_input_description'.tr(),
hasBackButton: true,
hasFlashButton: false,
ignoreBreakpoints: true,
children: [
CubitFormTextField(
formFieldCubit:

View File

@ -28,6 +28,7 @@ class RecoverByOldTokenInstruction extends StatelessWidget {
heroTitle: 'recovering.recovery_main_header'.tr(),
hasBackButton: true,
hasFlashButton: false,
ignoreBreakpoints: true,
onBackButtonPressed:
context.read<ServerInstallationCubit>().revertRecoveryStep,
children: [
@ -72,6 +73,7 @@ class RecoverByOldToken extends StatelessWidget {
heroSubtitle: 'recovering.method_device_input_description'.tr(),
hasBackButton: true,
hasFlashButton: false,
ignoreBreakpoints: true,
children: [
CubitFormTextField(
formFieldCubit:

View File

@ -31,6 +31,7 @@ class RecoverByRecoveryKey extends StatelessWidget {
heroSubtitle: 'recovering.method_recovery_input_description'.tr(),
hasBackButton: true,
hasFlashButton: false,
ignoreBreakpoints: true,
onBackButtonPressed:
context.read<ServerInstallationCubit>().revertRecoveryStep,
children: [

View File

@ -1,12 +1,11 @@
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/forms/setup/initializing/backblaze_form_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/cubit/support_system/support_system_cubit.dart';
import 'package:selfprivacy/ui/components/buttons/brand_button.dart';
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
import 'package:selfprivacy/ui/components/brand_md/brand_md.dart';
class RecoveryConfirmBackblaze extends StatelessWidget {
const RecoveryConfirmBackblaze({super.key});
@ -27,6 +26,8 @@ class RecoveryConfirmBackblaze extends StatelessWidget {
heroTitle: 'recovering.confirm_backblaze'.tr(),
heroSubtitle: 'recovering.confirm_backblaze_description'.tr(),
hasBackButton: true,
ignoreBreakpoints: true,
hasSupportDrawer: true,
onBackButtonPressed: () {
Navigator.of(context).popUntil((final route) => route.isFirst);
},
@ -56,24 +57,15 @@ class RecoveryConfirmBackblaze extends StatelessWidget {
text: 'basis.connect'.tr(),
),
const SizedBox(height: 16),
BrandButton.text(
onPressed: () => showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (final BuildContext context) => Padding(
padding: paddingH15V0,
child: ListView(
padding: const EdgeInsets.symmetric(vertical: 16),
children: const [
BrandMarkdown(
fileName: 'how_backblaze',
Builder(
builder: (final context) => BrandButton.text(
onPressed: () =>
context.read<SupportSystemCubit>().showArticle(
article: 'how_backblaze',
context: context,
),
],
),
),
title: 'initializing.how'.tr(),
),
title: 'initializing.how'.tr(),
),
],
);

View File

@ -1,12 +1,11 @@
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/forms/setup/initializing/dns_provider_form_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/cubit/support_system/support_system_cubit.dart';
import 'package:selfprivacy/ui/components/buttons/brand_button.dart';
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
import 'package:selfprivacy/ui/components/brand_md/brand_md.dart';
class RecoveryConfirmCloudflare extends StatelessWidget {
const RecoveryConfirmCloudflare({super.key});
@ -30,6 +29,8 @@ class RecoveryConfirmCloudflare extends StatelessWidget {
),
hasBackButton: true,
hasFlashButton: false,
ignoreBreakpoints: true,
hasSupportDrawer: true,
onBackButtonPressed:
context.read<ServerInstallationCubit>().revertRecoveryStep,
children: [
@ -48,24 +49,15 @@ class RecoveryConfirmCloudflare extends StatelessWidget {
text: 'basis.connect'.tr(),
),
const SizedBox(height: 16),
BrandButton.text(
onPressed: () => showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (final BuildContext context) => Padding(
padding: paddingH15V0,
child: ListView(
padding: const EdgeInsets.symmetric(vertical: 16),
children: const [
BrandMarkdown(
fileName: 'how_cloudflare',
),
],
),
),
Builder(
builder: (final context) => BrandButton.text(
onPressed: () =>
context.read<SupportSystemCubit>().showArticle(
article: 'how_cloudflare',
context: context,
),
title: 'initializing.how'.tr(),
),
title: 'initializing.how'.tr(),
),
],
);

View File

@ -38,6 +38,7 @@ class _RecoveryConfirmServerState extends State<RecoveryConfirmServer> {
? 'recovering.choose_server_description'.tr()
: 'recovering.confirm_server_description'.tr(),
hasBackButton: true,
ignoreBreakpoints: true,
onBackButtonPressed: () {
Navigator.of(context).popUntil((final route) => route.isFirst);
},

View File

@ -17,6 +17,7 @@ class RecoveryMethodSelect extends StatelessWidget {
heroSubtitle: 'recovering.method_select_description'.tr(),
hasBackButton: true,
hasFlashButton: false,
ignoreBreakpoints: true,
onBackButtonPressed:
context.read<ServerInstallationCubit>().revertRecoveryStep,
children: [
@ -74,6 +75,7 @@ class RecoveryFallbackMethodSelect extends StatelessWidget {
heroSubtitle: 'recovering.fallback_select_description'.tr(),
hasBackButton: true,
hasFlashButton: false,
ignoreBreakpoints: true,
children: [
OutlinedCard(
child: ListTile(

View File

@ -112,6 +112,7 @@ class SelectDomainToRecover extends StatelessWidget {
heroSubtitle: 'recovering.domain_recovery_description'.tr(),
hasBackButton: true,
hasFlashButton: false,
ignoreBreakpoints: true,
onBackButtonPressed: () {
Navigator.of(context).pushAndRemoveUntil(
materialRoute(const RootPage()),

View File

@ -1,12 +1,11 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:selfprivacy/config/brand_theme.dart';
import 'package:selfprivacy/logic/cubit/forms/setup/initializing/provider_form_cubit.dart';
import 'package:selfprivacy/logic/cubit/support_system/support_system_cubit.dart';
import 'package:selfprivacy/ui/components/buttons/brand_button.dart';
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
import 'package:cubit_form/cubit_form.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/ui/components/brand_md/brand_md.dart';
class RecoveryServerProviderConnected extends StatelessWidget {
const RecoveryServerProviderConnected({super.key});
@ -30,6 +29,8 @@ class RecoveryServerProviderConnected extends StatelessWidget {
),
hasBackButton: true,
hasFlashButton: false,
ignoreBreakpoints: true,
hasSupportDrawer: true,
onBackButtonPressed: () {
Navigator.of(context).popUntil((final route) => route.isFirst);
},
@ -50,23 +51,14 @@ class RecoveryServerProviderConnected extends StatelessWidget {
child: Text('basis.continue'.tr()),
),
const SizedBox(height: 16),
BrandButton.text(
title: 'initializing.how'.tr(),
onPressed: () => showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (final BuildContext context) => Padding(
padding: paddingH15V0,
child: ListView(
padding: const EdgeInsets.symmetric(vertical: 16),
children: const [
BrandMarkdown(
fileName: 'how_hetzner',
),
],
),
),
Builder(
builder: (final context) => BrandButton.text(
title: 'initializing.how'.tr(),
onPressed: () =>
context.read<SupportSystemCubit>().showArticle(
article: 'how_hetzner',
context: context,
),
),
),
],

View File

@ -10,73 +10,72 @@ class ResetPassword extends StatelessWidget {
@override
Widget build(final BuildContext context) => BlocProvider(
create: (final BuildContext context) => UserFormCubit(
jobsCubit: context.read<JobsCubit>(),
fieldFactory: FieldCubitFactory(context),
initialUser: user,
),
child: Builder(
builder: (final BuildContext context) {
final FormCubitState formCubitState =
context.watch<UserFormCubit>().state;
create: (final BuildContext context) => UserFormCubit(
jobsCubit: context.read<JobsCubit>(),
fieldFactory: FieldCubitFactory(context),
initialUser: user,
),
child: Builder(
builder: (final BuildContext context) {
final FormCubitState formCubitState =
context.watch<UserFormCubit>().state;
return BlocListener<UserFormCubit, FormCubitState>(
listener:
(final BuildContext context, final FormCubitState state) {
if (state.isSubmitted) {
Navigator.pop(context);
}
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
BrandHeader(
title: 'users.reset_password'.tr(),
),
const SizedBox(width: 14),
Padding(
padding: paddingH15V0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CubitFormTextField(
formFieldCubit:
context.read<UserFormCubit>().password,
decoration: InputDecoration(
alignLabelWithHint: false,
labelText: 'basis.password'.tr(),
suffixIcon: Padding(
padding: const EdgeInsets.only(right: 8),
child: IconButton(
icon: Icon(
BrandIcons.refresh,
color:
Theme.of(context).colorScheme.secondary,
return BlocListener<UserFormCubit, FormCubitState>(
listener:
(final BuildContext context, final FormCubitState state) {
if (state.isSubmitted) {
Navigator.pop(context);
}
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
BrandHeader(
title: 'users.reset_password'.tr(),
),
const SizedBox(width: 14),
Padding(
padding: paddingH15V0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CubitFormTextField(
formFieldCubit:
context.read<UserFormCubit>().password,
decoration: InputDecoration(
alignLabelWithHint: false,
labelText: 'basis.password'.tr(),
suffixIcon: Padding(
padding: const EdgeInsets.only(right: 8),
child: IconButton(
icon: Icon(
BrandIcons.refresh,
color:
Theme.of(context).colorScheme.secondary,
),
onPressed: context
.read<UserFormCubit>()
.genNewPassword,
),
),
onPressed: context
.read<UserFormCubit>()
.genNewPassword,
),
),
),
const SizedBox(height: 30),
BrandButton.rised(
onPressed: formCubitState.isSubmitting
? null
: () => context.read<UserFormCubit>().trySubmit(),
text: 'basis.apply'.tr(),
),
const SizedBox(height: 30),
],
),
const SizedBox(height: 30),
BrandButton.rised(
onPressed: formCubitState.isSubmitting
? null
: () =>
context.read<UserFormCubit>().trySubmit(),
text: 'basis.apply'.tr(),
),
const SizedBox(height: 30),
],
),
),
],
),
],
),
);
},
),
);
);
},
),
);
}

View File

@ -255,69 +255,68 @@ class NewSshKey extends StatelessWidget {
@override
Widget build(final BuildContext context) => BlocProvider(
create: (final context) {
final jobCubit = context.read<JobsCubit>();
final jobState = jobCubit.state;
if (jobState is JobsStateWithJobs) {
final jobs = jobState.clientJobList;
for (final job in jobs) {
if (job is CreateSSHKeyJob && job.user.login == user.login) {
user.sshKeys.add(job.publicKey);
}
}
}
return SshFormCubit(
jobsCubit: jobCubit,
user: user,
);
},
child: Builder(
builder: (final context) {
final formCubitState = context.watch<SshFormCubit>().state;
return BlocListener<SshFormCubit, FormCubitState>(
listener: (final context, final state) {
if (state.isSubmitted) {
Navigator.pop(context);
create: (final context) {
final jobCubit = context.read<JobsCubit>();
final jobState = jobCubit.state;
if (jobState is JobsStateWithJobs) {
final jobs = jobState.clientJobList;
for (final job in jobs) {
if (job is CreateSSHKeyJob && job.user.login == user.login) {
user.sshKeys.add(job.publicKey);
}
}
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
BrandHeader(
title: user.login,
),
const SizedBox(width: 14),
Padding(
padding: paddingH15V0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
IntrinsicHeight(
child: CubitFormTextField(
formFieldCubit: context.read<SshFormCubit>().key,
decoration: InputDecoration(
labelText: 'ssh.input_label'.tr(),
}
return SshFormCubit(
jobsCubit: jobCubit,
user: user,
);
},
child: Builder(
builder: (final context) {
final formCubitState = context.watch<SshFormCubit>().state;
return BlocListener<SshFormCubit, FormCubitState>(
listener: (final context, final state) {
if (state.isSubmitted) {
Navigator.pop(context);
}
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
BrandHeader(
title: user.login,
),
const SizedBox(width: 14),
Padding(
padding: paddingH15V0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
IntrinsicHeight(
child: CubitFormTextField(
formFieldCubit: context.read<SshFormCubit>().key,
decoration: InputDecoration(
labelText: 'ssh.input_label'.tr(),
),
),
),
),
const SizedBox(height: 30),
BrandButton.rised(
onPressed: formCubitState.isSubmitting
? null
: () => context.read<SshFormCubit>().trySubmit(),
text: 'ssh.create'.tr(),
),
const SizedBox(height: 30),
],
),
const SizedBox(height: 30),
BrandButton.rised(
onPressed: formCubitState.isSubmitting
? null
: () =>
context.read<SshFormCubit>().trySubmit(),
text: 'ssh.create'.tr(),
),
const SizedBox(height: 30),
],
),
),
],
),
],
),
);
},
),
);
);
},
),
);
}