1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2024-12-29 15:11:58 +00:00

refactor(mobile): map heatmap color and location picker (#6553)

* refactor(mobile): make location picker scaffold primary

* chore(mobile): update map heatmap colors

* style(mobile): map bottomsheet - only use borders on top

* fix(mobile): location picker show buttons above navigation bar

* fix: crash on iOS due to heatmap invalid color format

* disable rotate

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
shenlong 2024-02-08 03:07:43 +00:00 committed by GitHub
parent 2010c92b61
commit e0864768c2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 102 additions and 100 deletions

View file

@ -180,4 +180,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 64c9b5291666c0ca3caabdfe9865c141ac40321d
COCOAPODS: 1.12.1
COCOAPODS: 1.11.3

View file

@ -1,14 +1,14 @@
import 'package:flutter/material.dart';
extension ContextHelper on BuildContext {
// Returns the current size from MediaQuery
Size get size => MediaQuery.sizeOf(this);
// Returns the current padding from MediaQuery
EdgeInsets get padding => MediaQuery.paddingOf(this);
// Returns the current width from MediaQuery
double get width => size.width;
double get width => MediaQuery.sizeOf(this).width;
// Returns the current height from MediaQuery
double get height => size.height;
double get height => MediaQuery.sizeOf(this).height;
// Returns true if the app is running on a mobile device (!tablets)
bool get isMobile => width < 550;

View file

@ -19,17 +19,17 @@ class MapUtils {
["linear"],
["heatmap-density"],
0.0,
"rgba(246,239,247,0.0)",
0.2,
"rgb(208,209,230)",
0.4,
"rgb(166,189,219)",
0.6,
"rgb(103,169,207)",
0.8,
"rgb(28,144,153)",
"rgba(103,58,183,0.0)",
0.3,
"rgb(103,58,183)",
0.5,
"rgb(33,149,243)",
0.7,
"rgb(76,175,79)",
0.95,
"rgb(255,235,59)",
1.0,
"rgb(1,108,89)",
"rgb(255,86,34)",
],
heatmapIntensity: [
Expressions.interpolate, ["linear"], //
@ -44,6 +44,7 @@ class MapUtils {
4, 8,
9, 16,
],
heatmapOpacity: 0.7,
);
static Map<String, dynamic> _addFeature(MapMarker marker) => {

View file

@ -11,7 +11,6 @@ import 'package:immich_mobile/extensions/maplibrecontroller_extensions.dart';
import 'package:immich_mobile/modules/map/widgets/map_theme_override.dart';
import 'package:maplibre_gl/maplibre_gl.dart';
import 'package:immich_mobile/modules/map/utils/map_utils.dart';
import 'package:geolocator/geolocator.dart';
@RoutePage<LatLng?>()
class MapLocationPickerPage extends HookConsumerWidget {
@ -46,15 +45,13 @@ class MapLocationPickerPage extends HookConsumerWidget {
}
Future<void> getCurrentLocation() async {
var (currentLocation, locationPermission) =
var (currentLocation, _) =
await MapUtils.checkPermAndGetLocation(context);
if (locationPermission == LocationPermission.denied ||
locationPermission == LocationPermission.deniedForever) {
return;
}
if (currentLocation == null) {
return;
}
var currentLatLng =
LatLng(currentLocation.latitude, currentLocation.longitude);
selectedLatLng.value = currentLatLng;
@ -67,40 +64,35 @@ class MapLocationPickerPage extends HookConsumerWidget {
backgroundColor: ctx.themeData.cardColor,
appBar: _AppBar(onClose: onClose),
extendBodyBehindAppBar: true,
body: Column(
children: [
style.widgetWhen(
onData: (style) => Expanded(
child: Container(
clipBehavior: Clip.antiAliasWithSaveLayer,
decoration: const BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(40),
bottomRight: Radius.circular(40),
),
),
child: MaplibreMap(
initialCameraPosition:
CameraPosition(target: initialLatLng, zoom: 12),
styleString: style,
onMapCreated: (mapController) =>
controller.value = mapController,
onStyleLoadedCallback: onStyleLoaded,
onMapClick: onMapClick,
dragEnabled: false,
tiltGesturesEnabled: false,
myLocationEnabled: false,
attributionButtonMargins: const Point(20, 15),
),
),
primary: true,
body: style.widgetWhen(
onData: (style) => Container(
clipBehavior: Clip.antiAliasWithSaveLayer,
decoration: const BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(40),
bottomRight: Radius.circular(40),
),
),
_BottomBar(
selectedLatLng: selectedLatLng,
onUseLocation: () => onClose(selectedLatLng.value),
onGetCurrentLocation: getCurrentLocation,
child: MaplibreMap(
initialCameraPosition:
CameraPosition(target: initialLatLng, zoom: 12),
styleString: style,
onMapCreated: (mapController) =>
controller.value = mapController,
onStyleLoadedCallback: onStyleLoaded,
onMapClick: onMapClick,
dragEnabled: false,
tiltGesturesEnabled: false,
myLocationEnabled: false,
attributionButtonMargins: const Point(20, 15),
),
],
),
),
bottomNavigationBar: _BottomBar(
selectedLatLng: selectedLatLng,
onUseLocation: () => onClose(selectedLatLng.value),
onGetCurrentLocation: getCurrentLocation,
),
),
),
@ -116,17 +108,15 @@ class _AppBar extends StatelessWidget implements PreferredSizeWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(top: MediaQuery.paddingOf(context).top + 25),
child: Expanded(
child: Align(
alignment: Alignment.centerLeft,
child: ElevatedButton(
onPressed: onClose,
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
),
child: const Icon(Icons.arrow_back_ios_new_rounded),
padding: const EdgeInsets.only(top: 25),
child: Align(
alignment: Alignment.centerLeft,
child: ElevatedButton(
onPressed: onClose,
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
),
child: const Icon(Icons.arrow_back_ios_new_rounded),
),
),
);
@ -150,38 +140,42 @@ class _BottomBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SizedBox(
height: 150,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.public, size: 18),
const SizedBox(width: 15),
ValueListenableBuilder(
valueListenable: selectedLatLng,
builder: (_, value, __) => Text(
"${value.latitude.toStringAsFixed(4)}, ${value.longitude.toStringAsFixed(4)}",
height: 150 + context.padding.bottom,
child: Padding(
padding: EdgeInsets.only(bottom: context.padding.bottom),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.public, size: 18),
const SizedBox(width: 15),
ValueListenableBuilder(
valueListenable: selectedLatLng,
builder: (_, value, __) => Text(
"${value.latitude.toStringAsFixed(4)}, ${value.longitude.toStringAsFixed(4)}",
),
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: onUseLocation,
child: const Text("map_location_picker_page_use_location").tr(),
),
ElevatedButton(
onPressed: onGetCurrentLocation,
child: const Icon(Icons.my_location),
),
],
),
],
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: onUseLocation,
child:
const Text("map_location_picker_page_use_location").tr(),
),
ElevatedButton(
onPressed: onGetCurrentLocation,
child: const Icon(Icons.my_location),
),
],
),
],
),
),
);
}

View file

@ -220,10 +220,9 @@ class MapPage extends HookConsumerWidget {
}
void onZoomToLocation() async {
final location = await MapUtils.checkPermAndGetLocation(context);
if (location.$2 != null) {
if (location.$2 == LocationPermission.unableToDetermine &&
context.mounted) {
final (location, error) = await MapUtils.checkPermAndGetLocation(context);
if (error != null) {
if (error == LocationPermission.unableToDetermine && context.mounted) {
ImmichToast.show(
context: context,
gravity: ToastGravity.BOTTOM,
@ -234,10 +233,10 @@ class MapPage extends HookConsumerWidget {
return;
}
if (mapController.value != null && location.$1 != null) {
if (mapController.value != null && location != null) {
mapController.value!.animateCamera(
CameraUpdate.newLatLngZoom(
LatLng(location.$1!.latitude, location.$1!.longitude),
LatLng(location.latitude, location.longitude),
mapZoomToAssetLevel,
),
duration: const Duration(milliseconds: 800),
@ -389,6 +388,7 @@ class _MapWithMarker extends StatelessWidget {
dragEnabled: false,
myLocationEnabled: false,
attributionButtonPosition: AttributionButtonPosition.TopRight,
rotateGesturesEnabled: false,
),
),
ValueListenableBuilder(

View file

@ -231,7 +231,14 @@ class _MapSheetDragRegion extends StatelessWidget {
physics: const ClampingScrollPhysics(),
child: Card(
margin: EdgeInsets.zero,
shape: context.isMobile ? null : const BeveledRectangleBorder(),
shape: context.isMobile
? const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topRight: Radius.circular(20),
topLeft: Radius.circular(20),
),
)
: const BeveledRectangleBorder(),
elevation: 0.0,
child: Stack(
children: [