mirror of
https://github.com/immich-app/immich.git
synced 2025-08-11 09:16:31 -04:00
* chore: bump dart sdk to 3.8 * chore: make build * make pigeon * chore: format files --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
95 lines
3.5 KiB
Dart
95 lines
3.5 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
|
import 'package:immich_mobile/models/map/map_event.model.dart';
|
|
import 'package:immich_mobile/widgets/map/map_asset_grid.dart';
|
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
|
import 'package:immich_mobile/utils/draggable_scroll_controller.dart';
|
|
|
|
class MapBottomSheet extends HookConsumerWidget {
|
|
final Stream<MapEvent> mapEventStream;
|
|
final Function(String)? onGridAssetChanged;
|
|
final Function(String)? onZoomToAsset;
|
|
final Function()? onZoomToLocation;
|
|
final Function(bool, Set<Asset>)? onAssetsSelected;
|
|
final ValueNotifier<Set<Asset>> selectedAssets;
|
|
|
|
const MapBottomSheet({
|
|
required this.mapEventStream,
|
|
this.onGridAssetChanged,
|
|
this.onZoomToAsset,
|
|
this.onAssetsSelected,
|
|
this.onZoomToLocation,
|
|
required this.selectedAssets,
|
|
super.key,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
const sheetMinExtent = 0.1;
|
|
final sheetController = useDraggableScrollController();
|
|
final bottomSheetOffset = useValueNotifier(sheetMinExtent);
|
|
final isBottomSheetOpened = useRef(false);
|
|
|
|
void handleMapEvents(MapEvent event) async {
|
|
if (event is MapCloseBottomSheet) {
|
|
sheetController.animateTo(0.1, duration: const Duration(milliseconds: 200), curve: Curves.linearToEaseOut);
|
|
}
|
|
}
|
|
|
|
useOnStreamChange<MapEvent>(mapEventStream, onData: handleMapEvents);
|
|
|
|
bool onScrollNotification(DraggableScrollableNotification notification) {
|
|
isBottomSheetOpened.value = notification.extent > (notification.maxExtent * 0.9);
|
|
bottomSheetOffset.value = notification.extent;
|
|
// do not bubble
|
|
return true;
|
|
}
|
|
|
|
return Stack(
|
|
children: [
|
|
NotificationListener<DraggableScrollableNotification>(
|
|
onNotification: onScrollNotification,
|
|
child: DraggableScrollableSheet(
|
|
controller: sheetController,
|
|
minChildSize: sheetMinExtent,
|
|
maxChildSize: 0.8,
|
|
initialChildSize: sheetMinExtent,
|
|
snap: true,
|
|
snapSizes: [sheetMinExtent, 0.5, 0.8],
|
|
shouldCloseOnMinExtent: false,
|
|
builder: (ctx, scrollController) => MapAssetGrid(
|
|
controller: scrollController,
|
|
mapEventStream: mapEventStream,
|
|
selectedAssets: selectedAssets,
|
|
onAssetsSelected: onAssetsSelected,
|
|
// Do not bother with the event if the bottom sheet is not user scrolled
|
|
onGridAssetChanged: (assetId) => isBottomSheetOpened.value ? onGridAssetChanged?.call(assetId) : null,
|
|
onZoomToAsset: onZoomToAsset,
|
|
),
|
|
),
|
|
),
|
|
ValueListenableBuilder(
|
|
valueListenable: bottomSheetOffset,
|
|
builder: (context, value, child) {
|
|
return Positioned(
|
|
right: 0,
|
|
bottom: context.height * (value + 0.02),
|
|
child: AnimatedOpacity(
|
|
opacity: value < 0.8 ? 1 : 0,
|
|
duration: const Duration(milliseconds: 150),
|
|
child: ElevatedButton(
|
|
onPressed: onZoomToLocation,
|
|
style: ElevatedButton.styleFrom(shape: const CircleBorder()),
|
|
child: const Icon(Icons.my_location),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|