mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-01-08 17:11:14 +00:00
refactor(ui): Split Users modals
This commit is contained in:
parent
d9b47a4bd3
commit
8b811caa75
|
@ -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;
|
82
lib/ui/organisms/modals/new_ssh_key_modal.dart
Normal file
82
lib/ui/organisms/modals/new_ssh_key_modal.dart
Normal 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(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
83
lib/ui/organisms/modals/reset_password_modal.dart
Normal file
83
lib/ui/organisms/modals/reset_password_modal.dart
Normal 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(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
|
@ -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),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
|
|
|
@ -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';
|
||||
|
|
Loading…
Reference in a new issue