feat: sort places by distance

This commit is contained in:
Yaros
2025-04-21 12:03:28 +02:00
parent f0ff8581da
commit ba9e37bad2
6 changed files with 198 additions and 7 deletions
@@ -13,19 +13,27 @@ import 'package:immich_mobile/pages/common/large_leading_tile.dart';
import 'package:immich_mobile/providers/search/search_page_state.provider.dart';
import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/services/api.service.dart';
import 'package:immich_mobile/utils/calculate_distance.dart';
import 'package:immich_mobile/widgets/common/search_field.dart';
import 'package:immich_mobile/widgets/map/map_thumbnail.dart';
import 'package:maplibre_gl/maplibre_gl.dart';
enum FilterType {
name,
distance,
}
@RoutePage()
class PlacesCollectionPage extends HookConsumerWidget {
const PlacesCollectionPage({super.key, this.currentLocation});
final LatLng? currentLocation;
@override
Widget build(BuildContext context, WidgetRef ref) {
final places = ref.watch(getAllPlacesProvider);
final formFocus = useFocusNode();
final ValueNotifier<String?> search = useState(null);
final filterType = useState(FilterType.name);
return Scaffold(
appBar: AppBar(
@@ -52,12 +60,11 @@ class PlacesCollectionPage extends HookConsumerWidget {
body: ListView(
shrinkWrap: true,
children: [
if (search.value == null)
if (search.value == null) ...[
Padding(
padding: const EdgeInsets.all(16.0),
child: SizedBox(
height: 200,
width: context.width,
child: MapThumbnail(
onTap: (_, __) => context
.pushRoute(MapRoute(initialLocation: currentLocation)),
@@ -73,6 +80,51 @@ class PlacesCollectionPage extends HookConsumerWidget {
),
),
),
if (currentLocation != null)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Row(
spacing: 8.0,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text('sort_places_by'.tr()),
Align(
alignment: Alignment.centerLeft,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
decoration: BoxDecoration(
border: Border.all(
color: Theme.of(context)
.colorScheme
.surfaceContainerHighest,
width: 1.5,
),
borderRadius: BorderRadius.circular(8.0),
),
child: DropdownButton(
value: filterType.value,
items: [
DropdownMenuItem(
value: FilterType.name,
child: Text('name'.tr()),
),
DropdownMenuItem(
value: FilterType.distance,
child: Text('distance'.tr()),
),
],
onChanged: (e) {
filterType.value = e!;
},
isExpanded: false,
underline: const SizedBox(),
),
),
),
],
),
),
],
places.when(
data: (places) {
if (search.value != null) {
@@ -81,6 +133,26 @@ class PlacesCollectionPage extends HookConsumerWidget {
.toLowerCase()
.contains(search.value!.toLowerCase());
}).toList();
} else if (filterType.value == FilterType.distance &&
currentLocation != null) {
// Sort places by distance when filterType is distance and search is null
places = List.from(places);
places.sort((a, b) {
final double distanceA = calculateDistance(
currentLocation!.latitude,
currentLocation!.longitude,
a.latitude,
a.longitude,
);
final double distanceB = calculateDistance(
currentLocation!.latitude,
currentLocation!.longitude,
b.latitude,
b.longitude,
);
return distanceA.compareTo(distanceB);
});
}
return ListView.builder(
shrinkWrap: true,