diff --git a/lib/ui/atoms/list_tiles/section_headline.dart b/lib/ui/atoms/list_tiles/section_headline.dart new file mode 100644 index 00000000..be43d871 --- /dev/null +++ b/lib/ui/atoms/list_tiles/section_headline.dart @@ -0,0 +1,27 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; + +class SectionHeadline extends StatelessWidget { + const SectionHeadline({ + required this.title, + required this.subtitle, + super.key, + }); + + final String title; + final String subtitle; + + @override + Widget build(final BuildContext context) => ListTile( + title: Text( + title, + style: Theme.of(context).textTheme.headlineSmall!.copyWith( + color: Theme.of(context).colorScheme.secondary, + ), + ), + subtitle: Text( + subtitle, + style: Theme.of(context).textTheme.labelMedium, + ), + ); +} diff --git a/lib/ui/molecules/list_items/snapshot_item.dart b/lib/ui/molecules/list_items/snapshot_item.dart new file mode 100644 index 00000000..dcad6a9e --- /dev/null +++ b/lib/ui/molecules/list_items/snapshot_item.dart @@ -0,0 +1,96 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:selfprivacy/logic/bloc/backups/backups_bloc.dart'; +import 'package:selfprivacy/logic/bloc/server_jobs/server_jobs_bloc.dart'; +import 'package:selfprivacy/logic/bloc/services/services_bloc.dart'; +import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart'; +import 'package:selfprivacy/logic/models/backup.dart'; +import 'package:selfprivacy/ui/helpers/modals.dart'; +import 'package:selfprivacy/ui/organisms/modals/backups/snapshot_modal.dart'; + +class SnapshotItem extends StatelessWidget { + const SnapshotItem({ + required this.backup, + required this.preventActions, + this.overrideColor, + super.key, + }); + + final Backup backup; + final bool preventActions; + final Color? overrideColor; + + @override + Widget build(final BuildContext context) { + final service = + context.read().state.getServiceById(backup.serviceId); + + return ListTile( + onTap: preventActions + ? null + : () { + showModalBottomSheet( + useRootNavigator: true, + context: context, + isScrollControlled: true, + builder: (final BuildContext context) => + DraggableScrollableSheet( + expand: false, + maxChildSize: 0.9, + minChildSize: 0.5, + initialChildSize: 0.7, + builder: ( + final context, + final scrollController, + ) => + SnapshotModal( + snapshot: backup, + scrollController: scrollController, + ), + ), + ); + }, + onLongPress: preventActions + ? null + : () { + showPopUpAlert( + alertTitle: 'backup.forget_snapshot'.tr(), + description: 'backup.forget_snapshot_alert'.tr(), + actionButtonTitle: 'backup.forget_snapshot'.tr(), + actionButtonOnPressed: () => context.read().add( + ForgetSnapshot( + backup.id, + ), + ), + ); + }, + title: Text( + style: TextStyle( + color: overrideColor, + ), + '${MaterialLocalizations.of(context).formatShortDate(backup.time.toLocal())} ${TimeOfDay.fromDateTime(backup.time.toLocal()).format(context)}', + ), + subtitle: Text( + style: TextStyle( + color: overrideColor, + ), + service?.displayName ?? backup.fallbackServiceName, + ), + leading: service != null + ? SvgPicture.string( + service.svgIcon, + height: 24, + width: 24, + colorFilter: ColorFilter.mode( + overrideColor ?? Theme.of(context).colorScheme.onSurface, + BlendMode.srcIn, + ), + ) + : Icon( + Icons.question_mark_outlined, + color: overrideColor, + ), + ); + } +} diff --git a/lib/ui/pages/backups/backup_details.dart b/lib/ui/pages/backups/backup_details.dart index ae6c777c..6f0c4dea 100644 --- a/lib/ui/pages/backups/backup_details.dart +++ b/lib/ui/pages/backups/backup_details.dart @@ -1,7 +1,6 @@ import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:selfprivacy/logic/bloc/backups/backups_bloc.dart'; import 'package:selfprivacy/logic/bloc/server_jobs/server_jobs_bloc.dart'; import 'package:selfprivacy/logic/bloc/services/services_bloc.dart'; @@ -13,14 +12,14 @@ import 'package:selfprivacy/logic/models/service.dart'; import 'package:selfprivacy/logic/models/state_types.dart'; import 'package:selfprivacy/ui/atoms/buttons/brand_button.dart'; import 'package:selfprivacy/ui/atoms/icons/brand_icons.dart'; -import 'package:selfprivacy/ui/helpers/modals.dart'; +import 'package:selfprivacy/ui/atoms/list_tiles/section_headline.dart'; import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart'; import 'package:selfprivacy/ui/molecules/cards/server_job_card.dart'; +import 'package:selfprivacy/ui/molecules/list_items/snapshot_item.dart'; import 'package:selfprivacy/ui/organisms/modals/backups/change_period_modal.dart'; import 'package:selfprivacy/ui/organisms/modals/backups/change_rotation_quotas_modal.dart'; import 'package:selfprivacy/ui/organisms/modals/backups/copy_encryption_key_modal.dart'; import 'package:selfprivacy/ui/organisms/modals/backups/create_backups_modal.dart'; -import 'package:selfprivacy/ui/organisms/modals/backups/snapshot_modal.dart'; import 'package:selfprivacy/ui/router/router.dart'; import 'package:selfprivacy/utils/extensions/duration.dart'; @@ -279,17 +278,9 @@ class BackupDetailsPage extends StatelessWidget { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - ListTile( - title: Text( - 'backup.latest_snapshots'.tr(), - style: Theme.of(context).textTheme.headlineSmall!.copyWith( - color: Theme.of(context).colorScheme.secondary, - ), - ), - subtitle: Text( - 'backup.latest_snapshots_subtitle'.tr(), - style: Theme.of(context).textTheme.labelMedium, - ), + SectionHeadline( + title: 'backup.latest_snapshots'.tr(), + subtitle: 'backup.latest_snapshots_subtitle'.tr(), ), if (backups.isEmpty) ListTile( @@ -306,84 +297,16 @@ class BackupDetailsPage extends StatelessWidget { ), if (backups.isNotEmpty) Column( - children: backups.take(15).map( - (final Backup backup) { - final service = context - .read() - .state - .getServiceById(backup.serviceId); - return ListTile( - onTap: preventActions - ? null - : () { - showModalBottomSheet( - useRootNavigator: true, - context: context, - isScrollControlled: true, - builder: (final BuildContext context) => - DraggableScrollableSheet( - expand: false, - maxChildSize: 0.9, - minChildSize: 0.5, - initialChildSize: 0.7, - builder: ( - final context, - final scrollController, - ) => - SnapshotModal( - snapshot: backup, - scrollController: scrollController, - ), - ), - ); - }, - onLongPress: preventActions - ? null - : () { - showPopUpAlert( - alertTitle: 'backup.forget_snapshot'.tr(), - description: - 'backup.forget_snapshot_alert'.tr(), - actionButtonTitle: - 'backup.forget_snapshot'.tr(), - actionButtonOnPressed: () => - context.read().add( - ForgetSnapshot( - backup.id, - ), - ), - ); - }, - title: Text( - style: TextStyle( - color: overrideColor, - ), - '${MaterialLocalizations.of(context).formatShortDate(backup.time.toLocal())} ${TimeOfDay.fromDateTime(backup.time.toLocal()).format(context)}', + children: backups + .take(15) + .map( + (final Backup backup) => SnapshotItem( + backup: backup, + preventActions: preventActions, + overrideColor: overrideColor, ), - subtitle: Text( - style: TextStyle( - color: overrideColor, - ), - service?.displayName ?? backup.fallbackServiceName, - ), - leading: service != null - ? SvgPicture.string( - service.svgIcon, - height: 24, - width: 24, - colorFilter: ColorFilter.mode( - overrideColor ?? - Theme.of(context).colorScheme.onSurface, - BlendMode.srcIn, - ), - ) - : Icon( - Icons.question_mark_outlined, - color: overrideColor, - ), - ); - }, - ).toList(), + ) + .toList(), ), if (backups.isNotEmpty && backups.length > 15) ListTile( diff --git a/lib/ui/pages/backups/backups_list.dart b/lib/ui/pages/backups/backups_list.dart index a4618a73..506b7f7b 100644 --- a/lib/ui/pages/backups/backups_list.dart +++ b/lib/ui/pages/backups/backups_list.dart @@ -2,14 +2,11 @@ import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_svg/svg.dart'; import 'package:selfprivacy/logic/bloc/backups/backups_bloc.dart'; -import 'package:selfprivacy/logic/bloc/services/services_bloc.dart'; import 'package:selfprivacy/logic/models/backup.dart'; import 'package:selfprivacy/logic/models/service.dart'; -import 'package:selfprivacy/ui/helpers/modals.dart'; import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart'; -import 'package:selfprivacy/ui/organisms/modals/backups/snapshot_modal.dart'; +import 'package:selfprivacy/ui/molecules/list_items/snapshot_item.dart'; @RoutePage() class BackupsListPage extends StatelessWidget { @@ -41,66 +38,10 @@ class BackupsListPage extends StatelessWidget { ) else ...backups.map( - (final Backup backup) { - final service = context - .read() - .state - .getServiceById(backup.serviceId); - return ListTile( - onTap: preventActions - ? null - : () { - showModalBottomSheet( - useRootNavigator: true, - context: context, - isScrollControlled: true, - builder: (final BuildContext context) => - DraggableScrollableSheet( - expand: false, - maxChildSize: 0.9, - minChildSize: 0.5, - initialChildSize: 0.7, - builder: (final context, final scrollController) => - SnapshotModal( - snapshot: backup, - scrollController: scrollController, - ), - ), - ); - }, - onLongPress: preventActions - ? null - : () { - showPopUpAlert( - alertTitle: 'backup.forget_snapshot'.tr(), - description: 'backup.forget_snapshot_alert'.tr(), - actionButtonTitle: 'backup.forget_snapshot'.tr(), - actionButtonOnPressed: () => context - .read() - .add(ForgetSnapshot(backup.id)), - ); - }, - title: Text( - '${MaterialLocalizations.of(context).formatShortDate(backup.time.toLocal())} ${TimeOfDay.fromDateTime(backup.time.toLocal()).format(context)}', - ), - subtitle: Text( - service?.displayName ?? backup.fallbackServiceName, - ), - leading: service != null - ? SvgPicture.string( - service.svgIcon, - height: 24, - width: 24, - colorFilter: ColorFilter.mode( - Theme.of(context).colorScheme.onSurface, - BlendMode.srcIn, - ), - ) - : const Icon( - Icons.question_mark_outlined, - ), - ); - }, + (final Backup backup) => SnapshotItem( + backup: backup, + preventActions: preventActions, + ), ), ], );