|
@@ -1,4 +1,5 @@
|
|
|
import 'dart:async';
|
|
|
+import 'dart:io';
|
|
|
|
|
|
import 'package:easy_localization/easy_localization.dart';
|
|
|
import 'package:flutter/material.dart';
|
|
@@ -41,7 +42,7 @@ class AssetsInBoundBottomSheetState extends ConsumerState<MapPageBottomSheet> {
|
|
|
// Non-State variables
|
|
|
bool userTappedOnMap = false;
|
|
|
RenderList? _cachedRenderList;
|
|
|
- int lastAssetOffsetInSheet = -1;
|
|
|
+ int assetOffsetInSheet = -1;
|
|
|
late final DraggableScrollableController bottomSheetController;
|
|
|
late final Debounce debounce;
|
|
|
|
|
@@ -50,14 +51,16 @@ class AssetsInBoundBottomSheetState extends ConsumerState<MapPageBottomSheet> {
|
|
|
super.initState();
|
|
|
bottomSheetController = DraggableScrollableController();
|
|
|
debounce = Debounce(
|
|
|
- const Duration(milliseconds: 200),
|
|
|
+ const Duration(milliseconds: 100),
|
|
|
);
|
|
|
}
|
|
|
|
|
|
@override
|
|
|
Widget build(BuildContext context) {
|
|
|
- var isDarkMode = Theme.of(context).brightness == Brightness.dark;
|
|
|
- double maxHeight = MediaQuery.of(context).size.height;
|
|
|
+ final isDarkMode = Theme.of(context).brightness == Brightness.dark;
|
|
|
+ final bottomPadding =
|
|
|
+ Platform.isAndroid ? MediaQuery.of(context).padding.bottom - 10 : 0.0;
|
|
|
+ final maxHeight = MediaQuery.of(context).size.height - bottomPadding;
|
|
|
final isSheetScrolled = useState(false);
|
|
|
final isSheetExpanded = useState(false);
|
|
|
final assetsInBound = useState(<Asset>[]);
|
|
@@ -68,7 +71,7 @@ class AssetsInBoundBottomSheetState extends ConsumerState<MapPageBottomSheet> {
|
|
|
assetsInBound.value = event.assets;
|
|
|
} else if (event is MapPageOnTapEvent) {
|
|
|
userTappedOnMap = true;
|
|
|
- lastAssetOffsetInSheet = -1;
|
|
|
+ assetOffsetInSheet = -1;
|
|
|
bottomSheetController.animateTo(
|
|
|
0.1,
|
|
|
duration: const Duration(milliseconds: 200),
|
|
@@ -98,8 +101,8 @@ class AssetsInBoundBottomSheetState extends ConsumerState<MapPageBottomSheet> {
|
|
|
columnOffset = columnOffset < renderElement.totalCount
|
|
|
? columnOffset
|
|
|
: renderElement.totalCount - 1;
|
|
|
- lastAssetOffsetInSheet = rowOffset + columnOffset;
|
|
|
- final asset = _cachedRenderList?.allAssets?[lastAssetOffsetInSheet];
|
|
|
+ assetOffsetInSheet = rowOffset + columnOffset;
|
|
|
+ final asset = _cachedRenderList?.allAssets?[assetOffsetInSheet];
|
|
|
userTappedOnMap = false;
|
|
|
if (!userTappedOnMap && isSheetExpanded.value) {
|
|
|
widget.bottomSheetEventSC.add(
|
|
@@ -162,10 +165,10 @@ class AssetsInBoundBottomSheetState extends ConsumerState<MapPageBottomSheet> {
|
|
|
}
|
|
|
|
|
|
void onTapMapButton() {
|
|
|
- if (lastAssetOffsetInSheet != -1) {
|
|
|
+ if (assetOffsetInSheet != -1) {
|
|
|
widget.bottomSheetEventSC.add(
|
|
|
MapPageZoomToAsset(
|
|
|
- _cachedRenderList?.allAssets?[lastAssetOffsetInSheet],
|
|
|
+ _cachedRenderList?.allAssets?[assetOffsetInSheet],
|
|
|
),
|
|
|
);
|
|
|
}
|
|
@@ -176,7 +179,7 @@ class AssetsInBoundBottomSheetState extends ConsumerState<MapPageBottomSheet> {
|
|
|
? "${assetsInBound.value.length} photo${assetsInBound.value.length > 1 ? "s" : ""}"
|
|
|
: "map_no_assets_in_bounds".tr();
|
|
|
final dragHandle = Container(
|
|
|
- height: 75,
|
|
|
+ height: 60,
|
|
|
width: double.infinity,
|
|
|
decoration: BoxDecoration(
|
|
|
color: isDarkMode ? Colors.grey[900] : Colors.grey[100],
|
|
@@ -187,9 +190,9 @@ class AssetsInBoundBottomSheetState extends ConsumerState<MapPageBottomSheet> {
|
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
children: [
|
|
|
- const SizedBox(height: 12),
|
|
|
+ const SizedBox(height: 5),
|
|
|
const CustomDraggingHandle(),
|
|
|
- const SizedBox(height: 12),
|
|
|
+ const SizedBox(height: 15),
|
|
|
Text(
|
|
|
textToDisplay,
|
|
|
style: TextStyle(
|
|
@@ -199,6 +202,7 @@ class AssetsInBoundBottomSheetState extends ConsumerState<MapPageBottomSheet> {
|
|
|
),
|
|
|
),
|
|
|
Divider(
|
|
|
+ height: 10,
|
|
|
color: Theme.of(context)
|
|
|
.textTheme
|
|
|
.displayLarge
|
|
@@ -226,6 +230,7 @@ class AssetsInBoundBottomSheetState extends ConsumerState<MapPageBottomSheet> {
|
|
|
);
|
|
|
return SingleChildScrollView(
|
|
|
controller: scrollController,
|
|
|
+ physics: const ClampingScrollPhysics(),
|
|
|
child: dragHandle,
|
|
|
);
|
|
|
}
|
|
@@ -238,118 +243,125 @@ class AssetsInBoundBottomSheetState extends ConsumerState<MapPageBottomSheet> {
|
|
|
if (!sheetExtended) {
|
|
|
// reset state
|
|
|
userTappedOnMap = false;
|
|
|
- lastAssetOffsetInSheet = -1;
|
|
|
+ assetOffsetInSheet = -1;
|
|
|
isSheetScrolled.value = false;
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
},
|
|
|
- child: Stack(
|
|
|
- children: [
|
|
|
- DraggableScrollableSheet(
|
|
|
- controller: bottomSheetController,
|
|
|
- initialChildSize: 0.1,
|
|
|
- minChildSize: 0.1,
|
|
|
- maxChildSize: 0.55,
|
|
|
- snap: true,
|
|
|
- builder: (
|
|
|
- BuildContext context,
|
|
|
- ScrollController scrollController,
|
|
|
- ) {
|
|
|
- return Card(
|
|
|
- color: isDarkMode ? Colors.grey[900] : Colors.grey[100],
|
|
|
- surfaceTintColor: Colors.transparent,
|
|
|
- elevation: 18.0,
|
|
|
- margin: const EdgeInsets.all(0),
|
|
|
- child: Column(
|
|
|
- children: [
|
|
|
- buildDragHandle(scrollController),
|
|
|
- if (isSheetExpanded.value && assetsInBound.value.isNotEmpty)
|
|
|
- ref
|
|
|
- .watch(
|
|
|
- renderListProvider(
|
|
|
- assetsInBound.value,
|
|
|
- ),
|
|
|
- )
|
|
|
- .when(
|
|
|
- data: (renderList) {
|
|
|
- _cachedRenderList = renderList;
|
|
|
- final assetGrid = ImmichAssetGrid(
|
|
|
- shrinkWrap: true,
|
|
|
- renderList: renderList,
|
|
|
- showDragScroll: false,
|
|
|
- selectionActive: widget.selectionEnabled,
|
|
|
- showMultiSelectIndicator: false,
|
|
|
- listener: widget.selectionlistener,
|
|
|
- visibleItemsListener: visibleItemsListener,
|
|
|
- );
|
|
|
+ child: Padding(
|
|
|
+ padding: EdgeInsets.only(
|
|
|
+ bottom: bottomPadding,
|
|
|
+ ),
|
|
|
+ child: Stack(
|
|
|
+ children: [
|
|
|
+ DraggableScrollableSheet(
|
|
|
+ controller: bottomSheetController,
|
|
|
+ initialChildSize: 0.1,
|
|
|
+ minChildSize: 0.1,
|
|
|
+ maxChildSize: 0.55,
|
|
|
+ snap: true,
|
|
|
+ builder: (
|
|
|
+ BuildContext context,
|
|
|
+ ScrollController scrollController,
|
|
|
+ ) {
|
|
|
+ return Card(
|
|
|
+ color: isDarkMode ? Colors.grey[900] : Colors.grey[100],
|
|
|
+ surfaceTintColor: Colors.transparent,
|
|
|
+ elevation: 18.0,
|
|
|
+ margin: const EdgeInsets.all(0),
|
|
|
+ child: Column(
|
|
|
+ children: [
|
|
|
+ buildDragHandle(scrollController),
|
|
|
+ if (isSheetExpanded.value &&
|
|
|
+ assetsInBound.value.isNotEmpty)
|
|
|
+ ref
|
|
|
+ .watch(
|
|
|
+ renderListProvider(
|
|
|
+ assetsInBound.value,
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ .when(
|
|
|
+ data: (renderList) {
|
|
|
+ _cachedRenderList = renderList;
|
|
|
+ final assetGrid = ImmichAssetGrid(
|
|
|
+ shrinkWrap: true,
|
|
|
+ renderList: renderList,
|
|
|
+ showDragScroll: false,
|
|
|
+ selectionActive: widget.selectionEnabled,
|
|
|
+ showMultiSelectIndicator: false,
|
|
|
+ listener: widget.selectionlistener,
|
|
|
+ visibleItemsListener: visibleItemsListener,
|
|
|
+ );
|
|
|
|
|
|
- return Expanded(child: assetGrid);
|
|
|
- },
|
|
|
- error: (error, stackTrace) {
|
|
|
- log.warning(
|
|
|
- "Cannot get assets in the current map bounds ${error.toString()}",
|
|
|
- error,
|
|
|
- stackTrace,
|
|
|
- );
|
|
|
- return const SizedBox.shrink();
|
|
|
- },
|
|
|
- loading: () => const SizedBox.shrink(),
|
|
|
+ return Expanded(child: assetGrid);
|
|
|
+ },
|
|
|
+ error: (error, stackTrace) {
|
|
|
+ log.warning(
|
|
|
+ "Cannot get assets in the current map bounds ${error.toString()}",
|
|
|
+ error,
|
|
|
+ stackTrace,
|
|
|
+ );
|
|
|
+ return const SizedBox.shrink();
|
|
|
+ },
|
|
|
+ loading: () => const SizedBox.shrink(),
|
|
|
+ ),
|
|
|
+ if (isSheetExpanded.value && assetsInBound.value.isEmpty)
|
|
|
+ Expanded(
|
|
|
+ child: SingleChildScrollView(
|
|
|
+ child: buildNoPhotosWidget(),
|
|
|
),
|
|
|
- if (isSheetExpanded.value && assetsInBound.value.isEmpty)
|
|
|
- Expanded(
|
|
|
- child: SingleChildScrollView(
|
|
|
- child: buildNoPhotosWidget(),
|
|
|
),
|
|
|
- ),
|
|
|
- ],
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ Positioned(
|
|
|
+ bottom: maxHeight * currentExtend.value,
|
|
|
+ left: 0,
|
|
|
+ child: GestureDetector(
|
|
|
+ onTap: () => launchUrl(
|
|
|
+ Uri.parse('https://openstreetmap.org/copyright'),
|
|
|
),
|
|
|
- );
|
|
|
- },
|
|
|
- ),
|
|
|
- Positioned(
|
|
|
- bottom: maxHeight * currentExtend.value,
|
|
|
- left: 0,
|
|
|
- child: GestureDetector(
|
|
|
- onTap: () => launchUrl(
|
|
|
- Uri.parse('https://openstreetmap.org/copyright'),
|
|
|
- ),
|
|
|
- child: ColoredBox(
|
|
|
- color:
|
|
|
- (widget.isDarkTheme ? Colors.grey[900] : Colors.grey[100])!,
|
|
|
- child: Padding(
|
|
|
- padding: const EdgeInsets.all(3),
|
|
|
- child: Text(
|
|
|
- '© OpenStreetMap contributors',
|
|
|
- style: TextStyle(
|
|
|
- fontSize: 6,
|
|
|
- color: !widget.isDarkTheme
|
|
|
- ? Colors.grey[900]
|
|
|
- : Colors.grey[100],
|
|
|
+ child: ColoredBox(
|
|
|
+ color: (widget.isDarkTheme
|
|
|
+ ? Colors.grey[900]
|
|
|
+ : Colors.grey[100])!,
|
|
|
+ child: Padding(
|
|
|
+ padding: const EdgeInsets.all(3),
|
|
|
+ child: Text(
|
|
|
+ '© OpenStreetMap contributors',
|
|
|
+ style: TextStyle(
|
|
|
+ fontSize: 6,
|
|
|
+ color: !widget.isDarkTheme
|
|
|
+ ? Colors.grey[900]
|
|
|
+ : Colors.grey[100],
|
|
|
+ ),
|
|
|
),
|
|
|
),
|
|
|
),
|
|
|
),
|
|
|
),
|
|
|
- ),
|
|
|
- Positioned(
|
|
|
- bottom: maxHeight * (0.14 + (currentExtend.value - 0.1)),
|
|
|
- right: 15,
|
|
|
- child: ElevatedButton(
|
|
|
- onPressed: () =>
|
|
|
- widget.bottomSheetEventSC.add(const MapPageZoomToLocation()),
|
|
|
- style: ElevatedButton.styleFrom(
|
|
|
- shape: const CircleBorder(),
|
|
|
- padding: const EdgeInsets.all(12),
|
|
|
- ),
|
|
|
- child: const Icon(
|
|
|
- Icons.my_location,
|
|
|
- size: 22,
|
|
|
- fill: 1,
|
|
|
+ Positioned(
|
|
|
+ bottom: maxHeight * (0.14 + (currentExtend.value - 0.1)),
|
|
|
+ right: 15,
|
|
|
+ child: ElevatedButton(
|
|
|
+ onPressed: () => widget.bottomSheetEventSC
|
|
|
+ .add(const MapPageZoomToLocation()),
|
|
|
+ style: ElevatedButton.styleFrom(
|
|
|
+ shape: const CircleBorder(),
|
|
|
+ padding: const EdgeInsets.all(12),
|
|
|
+ ),
|
|
|
+ child: const Icon(
|
|
|
+ Icons.my_location,
|
|
|
+ size: 22,
|
|
|
+ fill: 1,
|
|
|
+ ),
|
|
|
),
|
|
|
),
|
|
|
- ),
|
|
|
- ],
|
|
|
+ ],
|
|
|
+ ),
|
|
|
),
|
|
|
);
|
|
|
}
|