refactor(ui): Split Users modals

This commit is contained in:
Inex Code 2024-11-11 04:58:57 +03:00
parent d9b47a4bd3
commit 8b811caa75
8 changed files with 231 additions and 188 deletions

View file

@ -1,9 +1,14 @@
part of 'users.dart';
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:selfprivacy/config/brand_theme.dart';
import 'package:selfprivacy/logic/models/hive/user.dart';
import 'package:selfprivacy/ui/router/router.dart';
class _User extends StatelessWidget {
const _User({
class UserListItem extends StatelessWidget {
const UserListItem({
required this.user,
required this.isPrimaryUser,
super.key,
});
final User user;

View file

@ -0,0 +1,82 @@
import 'package:cubit_form/cubit_form.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
import 'package:selfprivacy/logic/cubit/forms/user/ssh_form_cubit.dart';
import 'package:selfprivacy/logic/models/hive/user.dart';
import 'package:selfprivacy/logic/models/job.dart';
import 'package:selfprivacy/ui/atoms/buttons/brand_button.dart';
class NewSshKeyModal extends StatelessWidget {
const NewSshKeyModal({
required this.user,
required this.scrollController,
super.key,
});
final User user;
final ScrollController scrollController;
@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);
}
},
child: ListView(
controller: scrollController,
padding: const EdgeInsets.all(16),
children: [
const Gap(16),
Text(
user.login,
style: Theme.of(context).textTheme.headlineSmall,
textAlign: TextAlign.center,
),
const Gap(16),
IntrinsicHeight(
child: CubitFormTextField(
autofocus: true,
formFieldCubit: context.read<SshFormCubit>().key,
decoration: InputDecoration(
labelText: 'ssh.input_label'.tr(),
),
),
),
const Gap(16),
BrandButton.filled(
onPressed: formCubitState.isSubmitting
? null
: () => context.read<SshFormCubit>().trySubmit(),
title: 'ssh.create'.tr(),
),
],
),
);
},
),
);
}

View file

@ -0,0 +1,83 @@
import 'package:cubit_form/cubit_form.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
import 'package:selfprivacy/logic/cubit/forms/factories/field_cubit_factory.dart';
import 'package:selfprivacy/logic/cubit/forms/user/user_form_cubit.dart';
import 'package:selfprivacy/logic/models/hive/user.dart';
import 'package:selfprivacy/ui/atoms/buttons/brand_button.dart';
class ResetPasswordModal extends StatelessWidget {
const ResetPasswordModal({
required this.user,
required this.scrollController,
super.key,
});
final User user;
final ScrollController scrollController;
@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;
return BlocListener<UserFormCubit, FormCubitState>(
listener:
(final BuildContext context, final FormCubitState state) {
if (state.isSubmitted) {
Navigator.pop(context);
}
},
child: ListView(
controller: scrollController,
padding: const EdgeInsets.all(16),
children: [
const Gap(16),
Text(
'users.reset_password'.tr(),
style: Theme.of(context).textTheme.headlineSmall,
textAlign: TextAlign.center,
),
const Gap(16),
CubitFormTextField(
autofocus: true,
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(
Icons.refresh,
color: Theme.of(context).colorScheme.secondary,
),
onPressed:
context.read<UserFormCubit>().genNewPassword,
),
),
),
),
const Gap(16),
BrandButton.filled(
onPressed: formCubitState.isSubmitting
? null
: () => context.read<UserFormCubit>().trySubmit(),
title: 'basis.apply'.tr(),
),
],
),
);
},
),
);
}

View file

@ -1,4 +1,16 @@
part of 'users.dart';
import 'package:auto_route/auto_route.dart';
import 'package:cubit_form/cubit_form.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
import 'package:selfprivacy/logic/cubit/forms/factories/field_cubit_factory.dart';
import 'package:selfprivacy/logic/cubit/forms/user/user_form_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/ui/atoms/buttons/brand_button.dart';
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
import 'package:selfprivacy/utils/platform_adapter.dart';
import 'package:selfprivacy/utils/ui_helpers.dart';
@RoutePage()
class NewUserPage extends StatelessWidget {

View file

@ -1,82 +0,0 @@
part of 'users.dart';
class ResetPassword extends StatelessWidget {
const ResetPassword({
required this.user,
super.key,
});
final User user;
@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;
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: paddingH16V0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CubitFormTextField(
autofocus: true,
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(
Icons.refresh,
color:
Theme.of(context).colorScheme.secondary,
),
onPressed: context
.read<UserFormCubit>()
.genNewPassword,
),
),
),
),
const SizedBox(height: 30),
BrandButton.filled(
onPressed: formCubitState.isSubmitting
? null
: () => context.read<UserFormCubit>().trySubmit(),
title: 'basis.apply'.tr(),
),
const SizedBox(height: 30),
],
),
),
],
),
);
},
),
);
}

View file

@ -1,4 +1,21 @@
part of 'users.dart';
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/bloc/users/users_bloc.dart';
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_detailed_info/server_detailed_info_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/models/hive/user.dart';
import 'package:selfprivacy/logic/models/job.dart';
import 'package:selfprivacy/ui/atoms/cards/filled_card.dart';
import 'package:selfprivacy/ui/atoms/list_tiles/list_tile_on_surface_variant.dart';
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
import 'package:selfprivacy/ui/molecules/info_box/info_box.dart';
import 'package:selfprivacy/ui/organisms/modals/new_ssh_key_modal.dart';
import 'package:selfprivacy/ui/organisms/modals/reset_password_modal.dart';
import 'package:selfprivacy/utils/platform_adapter.dart';
import 'package:selfprivacy/utils/ui_helpers.dart';
@RoutePage()
class UserDetailsPage extends StatelessWidget {
@ -50,9 +67,16 @@ class UserDetailsPage extends StatelessWidget {
context: context,
isScrollControlled: true,
useRootNavigator: true,
builder: (final BuildContext context) => Padding(
padding: MediaQuery.of(context).viewInsets,
child: ResetPassword(user: user),
builder: (final BuildContext context) => DraggableScrollableSheet(
expand: false,
maxChildSize: 0.9,
minChildSize: 0.3,
initialChildSize: 0.5,
builder: (final context, final scrollController) =>
ResetPasswordModal(
user: user,
scrollController: scrollController,
),
),
),
leading: const Icon(Icons.lock_reset_outlined),
@ -185,13 +209,21 @@ class _SshKeysCard extends StatelessWidget {
title: 'ssh.create'.tr(),
leadingIcon: Icons.add_circle_outline,
onTap: () {
showModalBottomSheet<void>(
showModalBottomSheet(
context: context,
isScrollControlled: true,
useRootNavigator: true,
builder: (final BuildContext context) => Padding(
padding: MediaQuery.of(context).viewInsets,
child: NewSshKey(user),
builder: (final BuildContext context) =>
DraggableScrollableSheet(
expand: false,
maxChildSize: 0.9,
minChildSize: 0.3,
initialChildSize: 0.5,
builder: (final context, final scrollController) =>
NewSshKeyModal(
user: user,
scrollController: scrollController,
),
),
);
},
@ -272,76 +304,3 @@ class _SshKeysCard extends StatelessWidget {
);
}
}
class NewSshKey extends StatelessWidget {
const NewSshKey(this.user, {super.key});
final User user;
@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);
}
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
BrandHeader(
title: user.login,
),
const SizedBox(width: 14),
Padding(
padding: paddingH16V0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
IntrinsicHeight(
child: CubitFormTextField(
autofocus: true,
formFieldCubit: context.read<SshFormCubit>().key,
decoration: InputDecoration(
labelText: 'ssh.input_label'.tr(),
),
),
),
const SizedBox(height: 30),
BrandButton.filled(
onPressed: formCubitState.isSubmitting
? null
: () => context.read<SshFormCubit>().trySubmit(),
title: 'ssh.create'.tr(),
),
const SizedBox(height: 30),
],
),
),
],
),
);
},
),
);
}

View file

@ -2,37 +2,18 @@ import 'package:auto_route/auto_route.dart';
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/config/get_it_config.dart';
import 'package:selfprivacy/logic/bloc/outdated_server_checker/outdated_server_checker_bloc.dart';
import 'package:selfprivacy/logic/bloc/users/users_bloc.dart';
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
import 'package:selfprivacy/logic/cubit/forms/factories/field_cubit_factory.dart';
import 'package:selfprivacy/logic/cubit/forms/user/ssh_form_cubit.dart';
import 'package:selfprivacy/logic/cubit/forms/user/user_form_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_detailed_info/server_detailed_info_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/models/hive/user.dart';
import 'package:selfprivacy/logic/models/job.dart';
import 'package:selfprivacy/ui/atoms/buttons/brand_button.dart';
import 'package:selfprivacy/ui/atoms/buttons/outlined_button.dart';
import 'package:selfprivacy/ui/atoms/cards/filled_card.dart';
import 'package:selfprivacy/ui/atoms/icons/brand_icons.dart';
import 'package:selfprivacy/ui/atoms/list_tiles/list_tile_on_surface_variant.dart';
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
import 'package:selfprivacy/ui/molecules/cards/server_outdated_card.dart';
import 'package:selfprivacy/ui/molecules/info_box/info_box.dart';
import 'package:selfprivacy/ui/molecules/list_items/user_list_item.dart';
import 'package:selfprivacy/ui/molecules/placeholders/empty_page_placeholder.dart';
import 'package:selfprivacy/ui/organisms/headers/brand_header.dart';
import 'package:selfprivacy/ui/router/router.dart';
import 'package:selfprivacy/utils/breakpoints.dart';
import 'package:selfprivacy/utils/platform_adapter.dart';
import 'package:selfprivacy/utils/ui_helpers.dart';
part 'new_user.dart';
part 'reset_password.dart';
part 'user.dart';
part 'user_details.dart';
@RoutePage()
class UsersPage extends StatelessWidget {
@ -131,7 +112,8 @@ class UsersPage extends StatelessWidget {
child: ListView.builder(
itemCount: users.length,
itemBuilder:
(final BuildContext context, final int index) => _User(
(final BuildContext context, final int index) =>
UserListItem(
user: users[index],
isPrimaryUser: users[index].type == UserType.primary,
),

View file

@ -31,6 +31,8 @@ import 'package:selfprivacy/ui/pages/services/service_settings.dart';
import 'package:selfprivacy/ui/pages/services/services.dart';
import 'package:selfprivacy/ui/pages/setup/initializing/initializing.dart';
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_routing.dart';
import 'package:selfprivacy/ui/pages/users/new_user.dart';
import 'package:selfprivacy/ui/pages/users/user_details.dart';
import 'package:selfprivacy/ui/pages/users/users.dart';
part 'router.gr.dart';