fix: hide navigation bar in search page during multi-selection (#20616)

fix: hide navigation bar in search page during multiselect

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
shenlong 2025-08-04 23:09:40 +05:30 committed by GitHub
parent be85832b20
commit 5901c2e963
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 60 additions and 14 deletions

View File

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -137,25 +139,50 @@ void _onNavigationSelected(TabsRouter router, int index, WidgetRef ref) {
ref.read(tabProvider.notifier).state = TabEnum.values[index]; ref.read(tabProvider.notifier).state = TabEnum.values[index];
} }
class _BottomNavigationBar extends ConsumerWidget { class _BottomNavigationBar extends ConsumerStatefulWidget {
const _BottomNavigationBar({required this.tabsRouter, required this.destinations}); const _BottomNavigationBar({required this.tabsRouter, required this.destinations});
final List<Widget> destinations; final List<Widget> destinations;
final TabsRouter tabsRouter; final TabsRouter tabsRouter;
@override @override
Widget build(BuildContext context, WidgetRef ref) { ConsumerState createState() => _BottomNavigationBarState();
final isScreenLandscape = context.orientation == Orientation.landscape; }
final isMultiselectEnabled = ref.watch(multiSelectProvider.select((s) => s.isEnabled));
if (isScreenLandscape || isMultiselectEnabled) { class _BottomNavigationBarState extends ConsumerState<_BottomNavigationBar> {
bool hideNavigationBar = false;
StreamSubscription? _eventSubscription;
@override
void initState() {
super.initState();
_eventSubscription = EventStream.shared.listen<MultiSelectToggleEvent>(_onEvent);
}
void _onEvent(MultiSelectToggleEvent event) {
setState(() {
hideNavigationBar = event.isEnabled;
});
}
@override
void dispose() {
_eventSubscription?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
final isScreenLandscape = context.orientation == Orientation.landscape;
if (isScreenLandscape || hideNavigationBar) {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
return NavigationBar( return NavigationBar(
selectedIndex: tabsRouter.activeIndex, selectedIndex: widget.tabsRouter.activeIndex,
onDestinationSelected: (index) => _onNavigationSelected(tabsRouter, index, ref), onDestinationSelected: (index) => _onNavigationSelected(widget.tabsRouter, index, ref),
destinations: destinations, destinations: widget.destinations,
); );
} }
} }

View File

@ -13,6 +13,7 @@ import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart'; import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/models/search/search_filter.model.dart'; import 'package:immich_mobile/models/search/search_filter.model.dart';
import 'package:immich_mobile/presentation/pages/search/paginated_search.provider.dart'; import 'package:immich_mobile/presentation/pages/search/paginated_search.provider.dart';
import 'package:immich_mobile/presentation/widgets/bottom_sheet/general_bottom_sheet.widget.dart';
import 'package:immich_mobile/presentation/widgets/timeline/timeline.widget.dart'; import 'package:immich_mobile/presentation/widgets/timeline/timeline.widget.dart';
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart'; import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
import 'package:immich_mobile/providers/search/search_input_focus.provider.dart'; import 'package:immich_mobile/providers/search/search_input_focus.provider.dart';
@ -627,7 +628,12 @@ class _SearchResultGrid extends ConsumerWidget {
return timelineService; return timelineService;
}), }),
], ],
child: Timeline(key: ValueKey(searchResult.totalAssets), appBar: null, groupBy: GroupAssetsBy.none), child: Timeline(
key: ValueKey(searchResult.totalAssets),
groupBy: GroupAssetsBy.none,
appBar: null,
bottomSheet: const GeneralBottomSheet(minChildSize: 0.20),
),
), ),
), ),
); );

View File

@ -22,13 +22,13 @@ class BaseBottomSheet extends ConsumerStatefulWidget {
this.slivers, this.slivers,
this.controller, this.controller,
this.initialChildSize = 0.35, this.initialChildSize = 0.35,
this.minChildSize = 0.15, double? minChildSize,
this.maxChildSize = 0.65, this.maxChildSize = 0.65,
this.expand = true, this.expand = true,
this.shouldCloseOnMinExtent = true, this.shouldCloseOnMinExtent = true,
this.resizeOnScroll = true, this.resizeOnScroll = true,
this.backgroundColor, this.backgroundColor,
}); }) : minChildSize = minChildSize ?? 0.15;
@override @override
ConsumerState<BaseBottomSheet> createState() => _BaseDraggableScrollableSheetState(); ConsumerState<BaseBottomSheet> createState() => _BaseDraggableScrollableSheetState();

View File

@ -6,8 +6,8 @@ import 'package:immich_mobile/domain/models/album/album.model.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/archive_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/archive_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/delete_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_permanent_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_local_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/delete_local_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_permanent_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/download_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/download_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/edit_date_time_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/edit_date_time_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/edit_location_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/edit_location_action_button.widget.dart';
@ -26,7 +26,8 @@ import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
import 'package:immich_mobile/widgets/common/immich_toast.dart'; import 'package:immich_mobile/widgets/common/immich_toast.dart';
class GeneralBottomSheet extends ConsumerWidget { class GeneralBottomSheet extends ConsumerWidget {
const GeneralBottomSheet({super.key}); final double? minChildSize;
const GeneralBottomSheet({super.key, this.minChildSize});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@ -60,6 +61,7 @@ class GeneralBottomSheet extends ConsumerWidget {
return BaseBottomSheet( return BaseBottomSheet(
initialChildSize: 0.45, initialChildSize: 0.45,
minChildSize: minChildSize,
maxChildSize: 0.85, maxChildSize: 0.85,
shouldCloseOnMinExtent: false, shouldCloseOnMinExtent: false,
actions: [ actions: [

View File

@ -115,6 +115,8 @@ class _SliverTimelineState extends ConsumerState<_SliverTimeline> {
_baseScaleFactor = _scaleFactor; _baseScaleFactor = _scaleFactor;
}); });
}); });
ref.listenManual(multiSelectProvider.select((s) => s.isEnabled), _onMultiSelectionToggled);
} }
void _onEvent(Event event) { void _onEvent(Event event) {
@ -130,6 +132,10 @@ class _SliverTimelineState extends ConsumerState<_SliverTimeline> {
} }
} }
void _onMultiSelectionToggled(_, bool isEnabled) {
EventStream.shared.emit(MultiSelectToggleEvent(isEnabled));
}
@override @override
void dispose() { void dispose() {
_scrollController.dispose(); _scrollController.dispose();

View File

@ -1,8 +1,8 @@
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/domain/services/timeline.service.dart'; import 'package:immich_mobile/domain/services/timeline.service.dart';
import 'package:immich_mobile/domain/utils/event_stream.dart';
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart'; import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
final multiSelectProvider = NotifierProvider<MultiSelectNotifier, MultiSelectState>( final multiSelectProvider = NotifierProvider<MultiSelectNotifier, MultiSelectState>(
@ -10,6 +10,11 @@ final multiSelectProvider = NotifierProvider<MultiSelectNotifier, MultiSelectSta
dependencies: [timelineServiceProvider], dependencies: [timelineServiceProvider],
); );
class MultiSelectToggleEvent extends Event {
final bool isEnabled;
const MultiSelectToggleEvent(this.isEnabled);
}
class MultiSelectState { class MultiSelectState {
final Set<BaseAsset> selectedAssets; final Set<BaseAsset> selectedAssets;
final Set<BaseAsset> lockedSelectionAssets; final Set<BaseAsset> lockedSelectionAssets;