From 6b8453463243be8163f30fbbbe767d54c2fd0200 Mon Sep 17 00:00:00 2001 From: Matthias Rupp Date: Thu, 6 Oct 2022 22:41:56 +0200 Subject: [PATCH] Get rid of home page state provider --- .../home/models/home_page_state.model.dart | 47 -------- .../providers/home_page_state.provider.dart | 91 --------------- .../home/ui/asset_grid/daily_title_text.dart | 2 - .../home/ui/asset_grid/immich_asset_grid.dart | 45 +++++--- .../{ => asset_grid}/monthly_title_text.dart | 0 .../home/ui/asset_grid/thumbnail_image.dart | 2 - .../home/ui/control_bottom_app_bar.dart | 21 ++-- .../lib/modules/home/ui/daily_title_text.dart | 109 ------------------ .../lib/modules/home/ui/delete_diaglog.dart | 13 +-- mobile/lib/modules/home/ui/image_grid.dart | 47 -------- mobile/lib/modules/home/views/home_page.dart | 43 ++++--- .../lib/shared/views/tab_controller_page.dart | 6 +- 12 files changed, 72 insertions(+), 354 deletions(-) delete mode 100644 mobile/lib/modules/home/models/home_page_state.model.dart delete mode 100644 mobile/lib/modules/home/providers/home_page_state.provider.dart rename mobile/lib/modules/home/ui/{ => asset_grid}/monthly_title_text.dart (100%) delete mode 100644 mobile/lib/modules/home/ui/daily_title_text.dart delete mode 100644 mobile/lib/modules/home/ui/image_grid.dart diff --git a/mobile/lib/modules/home/models/home_page_state.model.dart b/mobile/lib/modules/home/models/home_page_state.model.dart deleted file mode 100644 index 1701ac3ffb..0000000000 --- a/mobile/lib/modules/home/models/home_page_state.model.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'package:collection/collection.dart'; - -import 'package:openapi/api.dart'; - -class HomePageState { - final bool isMultiSelectEnable; - final Set selectedItems; - final Set selectedDateGroup; - HomePageState({ - required this.isMultiSelectEnable, - required this.selectedItems, - required this.selectedDateGroup, - }); - - HomePageState copyWith({ - bool? isMultiSelectEnable, - Set? selectedItems, - Set? selectedDateGroup, - }) { - return HomePageState( - isMultiSelectEnable: isMultiSelectEnable ?? this.isMultiSelectEnable, - selectedItems: selectedItems ?? this.selectedItems, - selectedDateGroup: selectedDateGroup ?? this.selectedDateGroup, - ); - } - - @override - String toString() => - 'HomePageState(isMultiSelectEnable: $isMultiSelectEnable, selectedItems: $selectedItems, selectedDateGroup: $selectedDateGroup)'; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - final setEquals = const DeepCollectionEquality().equals; - - return other is HomePageState && - other.isMultiSelectEnable == isMultiSelectEnable && - setEquals(other.selectedItems, selectedItems) && - setEquals(other.selectedDateGroup, selectedDateGroup); - } - - @override - int get hashCode => - isMultiSelectEnable.hashCode ^ - selectedItems.hashCode ^ - selectedDateGroup.hashCode; -} diff --git a/mobile/lib/modules/home/providers/home_page_state.provider.dart b/mobile/lib/modules/home/providers/home_page_state.provider.dart deleted file mode 100644 index ff4f8cfd93..0000000000 --- a/mobile/lib/modules/home/providers/home_page_state.provider.dart +++ /dev/null @@ -1,91 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/modules/home/models/home_page_state.model.dart'; -import 'package:immich_mobile/shared/services/share.service.dart'; -import 'package:immich_mobile/shared/ui/share_dialog.dart'; -import 'package:openapi/api.dart'; - -class HomePageStateNotifier extends StateNotifier { - - final ShareService _shareService; - - HomePageStateNotifier(this._shareService) - : super( - HomePageState( - isMultiSelectEnable: false, - selectedItems: {}, - selectedDateGroup: {}, - ), - ); - - void addSelectedDateGroup(String dateGroupTitle) { - state = state.copyWith( - selectedDateGroup: {...state.selectedDateGroup, dateGroupTitle}, - ); - } - - void removeSelectedDateGroup(String dateGroupTitle) { - var currentDateGroup = state.selectedDateGroup; - - currentDateGroup.removeWhere((e) => e == dateGroupTitle); - - state = state.copyWith(selectedDateGroup: currentDateGroup); - } - - void enableMultiSelect(Set selectedItems) { - state = - state.copyWith(isMultiSelectEnable: true, selectedItems: selectedItems); - } - - void disableMultiSelect() { - state = state.copyWith( - isMultiSelectEnable: false, - selectedItems: {}, - selectedDateGroup: {}, - ); - } - - void addSingleSelectedItem(AssetResponseDto asset) { - state = state.copyWith(selectedItems: {...state.selectedItems, asset}); - } - - void addMultipleSelectedItems(List assets) { - state = state.copyWith(selectedItems: {...state.selectedItems, ...assets}); - } - - void removeSingleSelectedItem(AssetResponseDto asset) { - Set currentList = state.selectedItems; - - currentList.removeWhere((e) => e.id == asset.id); - - state = state.copyWith(selectedItems: currentList); - } - - void removeMultipleSelectedItem(List assets) { - Set currentList = state.selectedItems; - - for (AssetResponseDto asset in assets) { - currentList.removeWhere((e) => e.id == asset.id); - } - - state = state.copyWith(selectedItems: currentList); - } - - void shareAssets(List assets, BuildContext context) { - showDialog( - context: context, - builder: (BuildContext buildContext) { - _shareService - .shareAssets(assets) - .then((_) => Navigator.of(buildContext).pop()); - return const ShareDialog(); - }, - barrierDismissible: false, - ); - } -} - -final homePageStateProvider = - StateNotifierProvider( - ((ref) => HomePageStateNotifier(ref.watch(shareServiceProvider))), -); diff --git a/mobile/lib/modules/home/ui/asset_grid/daily_title_text.dart b/mobile/lib/modules/home/ui/asset_grid/daily_title_text.dart index 6814cccb34..78e033ce59 100644 --- a/mobile/lib/modules/home/ui/asset_grid/daily_title_text.dart +++ b/mobile/lib/modules/home/ui/asset_grid/daily_title_text.dart @@ -1,8 +1,6 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/modules/home/providers/home_page_state.provider.dart'; -import 'package:openapi/api.dart'; class DailyTitleText extends ConsumerWidget { const DailyTitleText({ diff --git a/mobile/lib/modules/home/ui/asset_grid/immich_asset_grid.dart b/mobile/lib/modules/home/ui/asset_grid/immich_asset_grid.dart index 568f7ee57f..aa50b6c24b 100644 --- a/mobile/lib/modules/home/ui/asset_grid/immich_asset_grid.dart +++ b/mobile/lib/modules/home/ui/asset_grid/immich_asset_grid.dart @@ -14,12 +14,13 @@ import 'daily_title_text.dart'; import 'disable_multi_select_button.dart'; import 'draggable_scrollbar_custom.dart'; -typedef ImmichAssetGridSelectionListener = void Function(bool); +typedef ImmichAssetGridSelectionListener = void Function( + bool, Set); class ImmichAssetGridState extends State { final ItemScrollController _itemScrollController = ItemScrollController(); final ItemPositionsListener _itemPositionsListener = - ItemPositionsListener.create(); + ItemPositionsListener.create(); bool _scrolling = false; bool _multiselect = false; @@ -37,18 +38,26 @@ class ImmichAssetGridState extends State { .flattened .toList(); } - + + Set _getSelectedAssets() { + return _selectedAssets + .map((e) => _assets.firstWhereOrNull((a) => a.id == e)) + .whereNotNull() + .toSet(); + } + + void _callSelectionListener() { + widget.listener?.call(_multiselect, _getSelectedAssets()); + } + void _selectAssets(List assets) { setState(() { - - if (!_multiselect) { - _multiselect = true; - widget.listener?.call(true); - } - for (var e in assets) { _selectedAssets.add(e.id); } + + _multiselect = true; + _callSelectionListener(); }); } @@ -60,8 +69,9 @@ class ImmichAssetGridState extends State { if (_selectedAssets.isEmpty) { _multiselect = false; - widget.listener?.call(false); } + + _callSelectionListener(); }); } @@ -70,11 +80,13 @@ class ImmichAssetGridState extends State { _multiselect = false; _selectedAssets.clear(); }); - widget.listener?.call(false); + + _callSelectionListener(); } bool _allAssetsSelected(List assets) { - return _multiselect && assets.firstWhereOrNull((e) => !_selectedAssets.contains(e.id)) == null; + return _multiselect && + assets.firstWhereOrNull((e) => !_selectedAssets.contains(e.id)) == null; } double _getItemSize(BuildContext context) { @@ -113,7 +125,8 @@ class ImmichAssetGridState extends State { key: Key("asset-${asset.id}"), width: size, height: size, - margin: EdgeInsets.only(top: widget.margin, right: last ? 0.0 : widget.margin), + margin: EdgeInsets.only( + top: widget.margin, right: last ? 0.0 : widget.margin), child: _buildThumbnailOrPlaceholder(asset, scrolling), ); }).toList(), @@ -165,7 +178,8 @@ class ImmichAssetGridState extends State { Text _labelBuilder(int pos) { final date = widget.renderList[pos].date; - return Text(DateFormat.yMMMd().format(date), + return Text( + DateFormat.yMMMd().format(date), style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, @@ -231,7 +245,6 @@ class ImmichAssetGrid extends StatefulWidget { final bool showStorageIndicator; final ImmichAssetGridSelectionListener? listener; - ImmichAssetGrid({ super.key, required this.renderList, @@ -245,4 +258,4 @@ class ImmichAssetGrid extends StatefulWidget { State createState() { return ImmichAssetGridState(); } -} \ No newline at end of file +} diff --git a/mobile/lib/modules/home/ui/monthly_title_text.dart b/mobile/lib/modules/home/ui/asset_grid/monthly_title_text.dart similarity index 100% rename from mobile/lib/modules/home/ui/monthly_title_text.dart rename to mobile/lib/modules/home/ui/asset_grid/monthly_title_text.dart diff --git a/mobile/lib/modules/home/ui/asset_grid/thumbnail_image.dart b/mobile/lib/modules/home/ui/asset_grid/thumbnail_image.dart index 13533942d2..fecdf66eb5 100644 --- a/mobile/lib/modules/home/ui/asset_grid/thumbnail_image.dart +++ b/mobile/lib/modules/home/ui/asset_grid/thumbnail_image.dart @@ -1,12 +1,10 @@ import 'package:auto_route/auto_route.dart'; import 'package:cached_network_image/cached_network_image.dart'; -import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/hive_box.dart'; -import 'package:immich_mobile/modules/home/providers/home_page_state.provider.dart'; import 'package:immich_mobile/modules/login/providers/authentication.provider.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/utils/image_url_builder.dart'; diff --git a/mobile/lib/modules/home/ui/control_bottom_app_bar.dart b/mobile/lib/modules/home/ui/control_bottom_app_bar.dart index 875647e73c..dceaea4ace 100644 --- a/mobile/lib/modules/home/ui/control_bottom_app_bar.dart +++ b/mobile/lib/modules/home/ui/control_bottom_app_bar.dart @@ -1,11 +1,15 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/modules/home/providers/home_page_state.provider.dart'; import 'package:immich_mobile/modules/home/ui/delete_diaglog.dart'; class ControlBottomAppBar extends ConsumerWidget { - const ControlBottomAppBar({Key? key}) : super(key: key); + final Function onShare; + final Function onDelete; + + const ControlBottomAppBar( + {Key? key, required this.onShare, required this.onDelete}) + : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { @@ -36,7 +40,9 @@ class ControlBottomAppBar extends ConsumerWidget { showDialog( context: context, builder: (BuildContext context) { - return const DeleteDialog(); + return DeleteDialog( + onDelete: onDelete, + ); }, ); }, @@ -45,14 +51,7 @@ class ControlBottomAppBar extends ConsumerWidget { iconData: Icons.share, label: "control_bottom_app_bar_share".tr(), onPressed: () { - final homePageState = ref.watch(homePageStateProvider); - ref.watch(homePageStateProvider.notifier).shareAssets( - homePageState.selectedItems.toList(), - context, - ); - ref - .watch(homePageStateProvider.notifier) - .disableMultiSelect(); + onShare(); }, ), ], diff --git a/mobile/lib/modules/home/ui/daily_title_text.dart b/mobile/lib/modules/home/ui/daily_title_text.dart deleted file mode 100644 index f083cc6e6a..0000000000 --- a/mobile/lib/modules/home/ui/daily_title_text.dart +++ /dev/null @@ -1,109 +0,0 @@ -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/material.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/modules/home/providers/home_page_state.provider.dart'; -import 'package:openapi/api.dart'; - -class DailyTitleText extends ConsumerWidget { - const DailyTitleText({ - Key? key, - required this.isoDate, - required this.assetGroup, - }) : super(key: key); - - final String isoDate; - final List assetGroup; - - @override - Widget build(BuildContext context, WidgetRef ref) { - var currentYear = DateTime.now().year; - var groupYear = DateTime.parse(isoDate).year; - var formatDateTemplate = currentYear == groupYear - ? "daily_title_text_date".tr() - : "daily_title_text_date_year".tr(); - var dateText = DateFormat(formatDateTemplate) - .format(DateTime.parse(isoDate).toLocal()); - var isMultiSelectEnable = - ref.watch(homePageStateProvider).isMultiSelectEnable; - var selectedDateGroup = ref.watch(homePageStateProvider).selectedDateGroup; - var selectedItems = ref.watch(homePageStateProvider).selectedItems; - - void _handleTitleIconClick() { - if (isMultiSelectEnable && - selectedDateGroup.contains(dateText) && - selectedDateGroup.length == 1 && - selectedItems.length <= assetGroup.length) { - // Multi select is active - click again on the icon while it is the only active group -> disable multi select - ref.watch(homePageStateProvider.notifier).disableMultiSelect(); - } else if (isMultiSelectEnable && - selectedDateGroup.contains(dateText) && - selectedItems.length != assetGroup.length) { - // Multi select is active - click again on the icon while it is not the only active group -> remove that group from selected group/items - ref - .watch(homePageStateProvider.notifier) - .removeSelectedDateGroup(dateText); - ref - .watch(homePageStateProvider.notifier) - .removeMultipleSelectedItem(assetGroup); - } else if (isMultiSelectEnable && - selectedDateGroup.contains(dateText) && - selectedDateGroup.length > 1) { - ref - .watch(homePageStateProvider.notifier) - .removeSelectedDateGroup(dateText); - ref - .watch(homePageStateProvider.notifier) - .removeMultipleSelectedItem(assetGroup); - } else if (isMultiSelectEnable && !selectedDateGroup.contains(dateText)) { - ref - .watch(homePageStateProvider.notifier) - .addSelectedDateGroup(dateText); - ref - .watch(homePageStateProvider.notifier) - .addMultipleSelectedItems(assetGroup); - } else { - ref - .watch(homePageStateProvider.notifier) - .enableMultiSelect(assetGroup.toSet()); - ref - .watch(homePageStateProvider.notifier) - .addSelectedDateGroup(dateText); - } - } - - return SliverToBoxAdapter( - child: Padding( - padding: const EdgeInsets.only( - top: 29.0, - bottom: 29.0, - left: 12.0, - right: 12.0, - ), - child: Row( - children: [ - Text( - dateText, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ), - const Spacer(), - GestureDetector( - onTap: _handleTitleIconClick, - child: isMultiSelectEnable && selectedDateGroup.contains(dateText) - ? Icon( - Icons.check_circle_rounded, - color: Theme.of(context).primaryColor, - ) - : const Icon( - Icons.check_circle_outline_rounded, - color: Colors.grey, - ), - ) - ], - ), - ), - ); - } -} diff --git a/mobile/lib/modules/home/ui/delete_diaglog.dart b/mobile/lib/modules/home/ui/delete_diaglog.dart index 3adef135a8..cca569ee05 100644 --- a/mobile/lib/modules/home/ui/delete_diaglog.dart +++ b/mobile/lib/modules/home/ui/delete_diaglog.dart @@ -1,15 +1,14 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/shared/providers/asset.provider.dart'; -import 'package:immich_mobile/modules/home/providers/home_page_state.provider.dart'; class DeleteDialog extends ConsumerWidget { - const DeleteDialog({Key? key}) : super(key: key); + final Function onDelete; + + const DeleteDialog({Key? key, required this.onDelete}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { - final homePageState = ref.watch(homePageStateProvider); return AlertDialog( backgroundColor: Colors.grey[200], @@ -28,11 +27,7 @@ class DeleteDialog extends ConsumerWidget { ), TextButton( onPressed: () { - ref - .watch(assetProvider.notifier) - .deleteAssets(homePageState.selectedItems); - ref.watch(homePageStateProvider.notifier).disableMultiSelect(); - + onDelete(); Navigator.of(context).pop(); }, child: Text( diff --git a/mobile/lib/modules/home/ui/image_grid.dart b/mobile/lib/modules/home/ui/image_grid.dart deleted file mode 100644 index 7f0c6304ed..0000000000 --- a/mobile/lib/modules/home/ui/image_grid.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/modules/home/ui/asset_grid/thumbnail_image.dart'; -import 'package:openapi/api.dart'; - -// ignore: must_be_immutable -class ImageGrid extends ConsumerWidget { - final List assetGroup; - final List sortedAssetGroup; - final int tilesPerRow; - final bool showStorageIndicator; - - ImageGrid({ - Key? key, - required this.assetGroup, - required this.sortedAssetGroup, - this.tilesPerRow = 4, - this.showStorageIndicator = true, - }) : super(key: key); - - List imageSortedList = []; - - @override - Widget build(BuildContext context, WidgetRef ref) { - return SliverGrid( - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: tilesPerRow, - crossAxisSpacing: 5.0, - mainAxisSpacing: 5, - ), - delegate: SliverChildBuilderDelegate( - (BuildContext context, int index) { - var assetType = assetGroup[index].type; - return GestureDetector( - onTap: () {}, - child: ThumbnailImage( - asset: assetGroup[index], - assetList: sortedAssetGroup, - showStorageIndicator: showStorageIndicator, - ), - ); - }, - childCount: assetGroup.length, - ), - ); - } -} diff --git a/mobile/lib/modules/home/views/home_page.dart b/mobile/lib/modules/home/views/home_page.dart index 500e30b08d..2e38ee08f7 100644 --- a/mobile/lib/modules/home/views/home_page.dart +++ b/mobile/lib/modules/home/views/home_page.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/modules/home/providers/home_page_render_list_provider.dart'; -import 'package:immich_mobile/modules/home/providers/home_page_state.provider.dart'; import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart'; import 'package:immich_mobile/modules/home/ui/control_bottom_app_bar.dart'; import 'package:immich_mobile/modules/home/ui/immich_sliver_appbar.dart'; @@ -12,6 +11,8 @@ import 'package:immich_mobile/modules/settings/services/app_settings.service.dar import 'package:immich_mobile/shared/providers/asset.provider.dart'; import 'package:immich_mobile/shared/providers/server_info.provider.dart'; import 'package:immich_mobile/shared/providers/websocket.provider.dart'; +import 'package:immich_mobile/shared/services/share.service.dart'; +import 'package:openapi/api.dart'; class HomePage extends HookConsumerWidget { const HomePage({Key? key}) : super(key: key); @@ -22,6 +23,7 @@ class HomePage extends HookConsumerWidget { var renderList = ref.watch(renderListProvider); final multiselectEnabled = useState(false); + final selection = useState({}); useEffect( () { @@ -38,21 +40,18 @@ class HomePage extends HookConsumerWidget { } Widget buildBody() { - buildSliverAppBar() { - return multiselectEnabled.value - ? const SliverToBoxAdapter( - child: SizedBox( - height: 70, - child: null, - ), - ) - : ImmichSliverAppBar( - onPopBack: reloadAllAsset, - ); + void selectionListener( + bool multiselect, Set selectedAssets) { + multiselectEnabled.value = multiselect; + selection.value = selectedAssets; } - void selectionListener(bool multiselect) { - multiselectEnabled.value = multiselect; + void onShareAssets() { + ref.watch(shareServiceProvider).shareAssets(selection.value.toList()); + } + + void onDelete() { + ref.watch(assetProvider.notifier).deleteAssets(selection.value); } return SafeArea( @@ -62,7 +61,16 @@ class HomePage extends HookConsumerWidget { children: [ CustomScrollView( slivers: [ - buildSliverAppBar(), + multiselectEnabled.value + ? const SliverToBoxAdapter( + child: SizedBox( + height: 70, + child: null, + ), + ) + : ImmichSliverAppBar( + onPopBack: reloadAllAsset, + ), ], ), Padding( @@ -77,7 +85,10 @@ class HomePage extends HookConsumerWidget { ), ), if (multiselectEnabled.value) ...[ - const ControlBottomAppBar(), + ControlBottomAppBar( + onShare: onShareAssets, + onDelete: onDelete, + ), ], ], ), diff --git a/mobile/lib/shared/views/tab_controller_page.dart b/mobile/lib/shared/views/tab_controller_page.dart index 51a13fea5a..7fe3c2f2fa 100644 --- a/mobile/lib/shared/views/tab_controller_page.dart +++ b/mobile/lib/shared/views/tab_controller_page.dart @@ -1,8 +1,8 @@ import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/modules/home/providers/home_page_state.provider.dart'; import 'package:immich_mobile/routing/router.dart'; class TabControllerPage extends ConsumerWidget { @@ -10,8 +10,6 @@ class TabControllerPage extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - var isMultiSelectEnable = - ref.watch(homePageStateProvider).isMultiSelectEnable; return AutoTabsRouter( routes: [ @@ -32,7 +30,7 @@ class TabControllerPage extends ConsumerWidget { opacity: animation, child: child, ), - bottomNavigationBar: isMultiSelectEnable + bottomNavigationBar: false ? null : BottomNavigationBar( selectedLabelStyle: const TextStyle(