From 52bcb46b42796e25f79c71b90b2e0cfbdddc4088 Mon Sep 17 00:00:00 2001
From: Alex <alex.tran1502@gmail.com>
Date: Fri, 26 Apr 2024 00:49:31 -0500
Subject: [PATCH] fix(mobile): show places in Search page on mobile (#9085)

* fix(mobile): show map on mobile

* remove ununsed code
---
 .../models/search_page_state.model.dart       | 81 -------------------
 .../providers/search_page_state.provider.dart | 80 +++++-------------
 .../search/services/search.service.dart       | 36 +++------
 .../search/views/curated_location_page.dart   | 17 +---
 .../lib/modules/search/views/search_page.dart | 15 +---
 .../lib/routing/tab_navigation_observer.dart  |  2 +-
 6 files changed, 40 insertions(+), 191 deletions(-)
 delete mode 100644 mobile/lib/modules/search/models/search_page_state.model.dart

diff --git a/mobile/lib/modules/search/models/search_page_state.model.dart b/mobile/lib/modules/search/models/search_page_state.model.dart
deleted file mode 100644
index e949817b98..0000000000
--- a/mobile/lib/modules/search/models/search_page_state.model.dart
+++ /dev/null
@@ -1,81 +0,0 @@
-import 'dart:convert';
-
-import 'package:collection/collection.dart';
-
-class SearchPageState {
-  final String searchTerm;
-  final bool isSearchEnabled;
-  final List<String> searchSuggestion;
-  final List<String> userSuggestedSearchTerms;
-
-  SearchPageState({
-    required this.searchTerm,
-    required this.isSearchEnabled,
-    required this.searchSuggestion,
-    required this.userSuggestedSearchTerms,
-  });
-
-  SearchPageState copyWith({
-    String? searchTerm,
-    bool? isSearchEnabled,
-    List<String>? searchSuggestion,
-    List<String>? userSuggestedSearchTerms,
-  }) {
-    return SearchPageState(
-      searchTerm: searchTerm ?? this.searchTerm,
-      isSearchEnabled: isSearchEnabled ?? this.isSearchEnabled,
-      searchSuggestion: searchSuggestion ?? this.searchSuggestion,
-      userSuggestedSearchTerms:
-          userSuggestedSearchTerms ?? this.userSuggestedSearchTerms,
-    );
-  }
-
-  Map<String, dynamic> toMap() {
-    return {
-      'searchTerm': searchTerm,
-      'isSearchEnabled': isSearchEnabled,
-      'searchSuggestion': searchSuggestion,
-      'userSuggestedSearchTerms': userSuggestedSearchTerms,
-    };
-  }
-
-  factory SearchPageState.fromMap(Map<String, dynamic> map) {
-    return SearchPageState(
-      searchTerm: map['searchTerm'] ?? '',
-      isSearchEnabled: map['isSearchEnabled'] ?? false,
-      searchSuggestion: List<String>.from(map['searchSuggestion']),
-      userSuggestedSearchTerms:
-          List<String>.from(map['userSuggestedSearchTerms']),
-    );
-  }
-
-  String toJson() => json.encode(toMap());
-
-  factory SearchPageState.fromJson(String source) =>
-      SearchPageState.fromMap(json.decode(source));
-
-  @override
-  String toString() {
-    return 'SearchPageState(searchTerm: $searchTerm, isSearchEnabled: $isSearchEnabled, searchSuggestion: $searchSuggestion, userSuggestedSearchTerms: $userSuggestedSearchTerms)';
-  }
-
-  @override
-  bool operator ==(Object other) {
-    if (identical(this, other)) return true;
-    final listEquals = const DeepCollectionEquality().equals;
-
-    return other is SearchPageState &&
-        other.searchTerm == searchTerm &&
-        other.isSearchEnabled == isSearchEnabled &&
-        listEquals(other.searchSuggestion, searchSuggestion) &&
-        listEquals(other.userSuggestedSearchTerms, userSuggestedSearchTerms);
-  }
-
-  @override
-  int get hashCode {
-    return searchTerm.hashCode ^
-        isSearchEnabled.hashCode ^
-        searchSuggestion.hashCode ^
-        userSuggestedSearchTerms.hashCode;
-  }
-}
diff --git a/mobile/lib/modules/search/providers/search_page_state.provider.dart b/mobile/lib/modules/search/providers/search_page_state.provider.dart
index 58abe2f87e..3bd346ab2d 100644
--- a/mobile/lib/modules/search/providers/search_page_state.provider.dart
+++ b/mobile/lib/modules/search/providers/search_page_state.provider.dart
@@ -1,65 +1,29 @@
 import 'package:hooks_riverpod/hooks_riverpod.dart';
-import 'package:immich_mobile/modules/search/models/search_page_state.model.dart';
+import 'package:immich_mobile/modules/search/models/curated_content.dart';
 
 import 'package:immich_mobile/modules/search/services/search.service.dart';
-import 'package:openapi/api.dart';
 
-class SearchPageStateNotifier extends StateNotifier<SearchPageState> {
-  SearchPageStateNotifier(this._searchService)
-      : super(
-          SearchPageState(
-            searchTerm: "",
-            isSearchEnabled: false,
-            searchSuggestion: [],
-            userSuggestedSearchTerms: [],
-          ),
-        );
-
-  final SearchService _searchService;
-
-  void enableSearch() {
-    state = state.copyWith(isSearchEnabled: true);
-  }
-
-  void disableSearch() {
-    state = state.copyWith(isSearchEnabled: false);
-  }
-
-  void setSearchTerm(String value) {
-    state = state.copyWith(searchTerm: value);
-
-    _getSearchSuggestion(state.searchTerm);
-  }
-
-  void _getSearchSuggestion(String searchTerm) {
-    var searchList = state.userSuggestedSearchTerms;
-
-    var newList = searchList.where((e) => e.toLowerCase().contains(searchTerm));
-
-    state = state.copyWith(searchSuggestion: [...newList]);
-
-    if (searchTerm.isEmpty) {
-      state = state.copyWith(searchSuggestion: []);
-    }
-  }
-
-  void getSuggestedSearchTerms() async {
-    var userSuggestedSearchTerms =
-        await _searchService.getUserSuggestedSearchTerms();
-
-    state = state.copyWith(userSuggestedSearchTerms: userSuggestedSearchTerms);
-  }
-}
-
-final searchPageStateProvider =
-    StateNotifierProvider<SearchPageStateNotifier, SearchPageState>((ref) {
-  return SearchPageStateNotifier(ref.watch(searchServiceProvider));
-});
-
-final getCuratedLocationProvider =
-    FutureProvider.autoDispose<List<CuratedLocationsResponseDto>>((ref) async {
+final getPlacesProvider =
+    FutureProvider.autoDispose<List<CuratedContent>>((ref) async {
   final SearchService searchService = ref.watch(searchServiceProvider);
 
-  var curatedLocation = await searchService.getCuratedLocation();
-  return curatedLocation ?? [];
+  final exploreData = await searchService.getExploreData();
+
+  if (exploreData == null) {
+    return [];
+  }
+
+  final locations =
+      exploreData.firstWhere((data) => data.fieldName == "exifInfo.city").items;
+
+  final curatedContent = locations
+      .map(
+        (l) => CuratedContent(
+          label: l.value,
+          id: l.data.id,
+        ),
+      )
+      .toList();
+
+  return curatedContent;
 });
diff --git a/mobile/lib/modules/search/services/search.service.dart b/mobile/lib/modules/search/services/search.service.dart
index 4d19657afd..c1c6493c02 100644
--- a/mobile/lib/modules/search/services/search.service.dart
+++ b/mobile/lib/modules/search/services/search.service.dart
@@ -6,6 +6,7 @@ import 'package:immich_mobile/shared/providers/api.provider.dart';
 import 'package:immich_mobile/shared/providers/db.provider.dart';
 import 'package:immich_mobile/shared/services/api.service.dart';
 import 'package:isar/isar.dart';
+import 'package:logging/logging.dart';
 import 'package:openapi/api.dart';
 
 final searchServiceProvider = Provider(
@@ -19,17 +20,9 @@ class SearchService {
   final ApiService _apiService;
   final Isar _db;
 
+  final _log = Logger("SearchService");
   SearchService(this._apiService, this._db);
 
-  Future<List<String>?> getUserSuggestedSearchTerms() async {
-    try {
-      return await _apiService.assetApi.getAssetSearchTerms();
-    } catch (e) {
-      debugPrint("[ERROR] [getUserSuggestedSearchTerms] ${e.toString()}");
-      return [];
-    }
-  }
-
   Future<List<String>?> getSearchSuggestions(
     SearchSuggestionType type, {
     String? country,
@@ -112,29 +105,18 @@ class SearchService {
 
       return _db.assets
           .getAllByRemoteId(response.assets.items.map((e) => e.id));
-    } catch (error) {
-      debugPrint("Error [search] $error");
+    } catch (error, stackTrace) {
+      _log.severe("Failed to search for assets", error, stackTrace);
     }
     return null;
   }
 
-  Future<List<CuratedLocationsResponseDto>?> getCuratedLocation() async {
+  Future<List<SearchExploreResponseDto>?> getExploreData() async {
     try {
-      var locations = await _apiService.assetApi.getCuratedLocations();
-
-      return locations;
-    } catch (e) {
-      debugPrint("Error [getCuratedLocation] ${e.toString()}");
-      return [];
-    }
-  }
-
-  Future<List<CuratedObjectsResponseDto>?> getCuratedObjects() async {
-    try {
-      return await _apiService.assetApi.getCuratedObjects();
-    } catch (e) {
-      debugPrint("Error [getCuratedObjects] ${e.toString()}");
-      return [];
+      return await _apiService.searchApi.getExploreData();
+    } catch (error, stackTrace) {
+      _log.severe("Failed to getExploreData", error, stackTrace);
     }
+    return null;
   }
 }
diff --git a/mobile/lib/modules/search/views/curated_location_page.dart b/mobile/lib/modules/search/views/curated_location_page.dart
index b216baf3ce..45067dc406 100644
--- a/mobile/lib/modules/search/views/curated_location_page.dart
+++ b/mobile/lib/modules/search/views/curated_location_page.dart
@@ -6,7 +6,6 @@ import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
 import 'package:immich_mobile/modules/search/models/curated_content.dart';
 import 'package:immich_mobile/modules/search/providers/search_page_state.provider.dart';
 import 'package:immich_mobile/modules/search/ui/explore_grid.dart';
-import 'package:openapi/api.dart';
 
 @RoutePage()
 class CuratedLocationPage extends HookConsumerWidget {
@@ -14,8 +13,7 @@ class CuratedLocationPage extends HookConsumerWidget {
 
   @override
   Widget build(BuildContext context, WidgetRef ref) {
-    AsyncValue<List<CuratedLocationsResponseDto>> curatedLocation =
-        ref.watch(getCuratedLocationProvider);
+    AsyncValue<List<CuratedContent>> places = ref.watch(getPlacesProvider);
 
     return Scaffold(
       appBar: AppBar(
@@ -27,16 +25,9 @@ class CuratedLocationPage extends HookConsumerWidget {
           icon: const Icon(Icons.arrow_back_ios_rounded),
         ),
       ),
-      body: curatedLocation.widgetWhen(
-        onData: (curatedLocations) => ExploreGrid(
-          curatedContent: curatedLocations
-              .map(
-                (l) => CuratedContent(
-                  label: l.city,
-                  id: l.id,
-                ),
-              )
-              .toList(),
+      body: places.widgetWhen(
+        onData: (data) => ExploreGrid(
+          curatedContent: data,
         ),
       ),
     );
diff --git a/mobile/lib/modules/search/views/search_page.dart b/mobile/lib/modules/search/views/search_page.dart
index d0d9f2e71d..3df614292c 100644
--- a/mobile/lib/modules/search/views/search_page.dart
+++ b/mobile/lib/modules/search/views/search_page.dart
@@ -27,7 +27,7 @@ class SearchPage extends HookConsumerWidget {
 
   @override
   Widget build(BuildContext context, WidgetRef ref) {
-    final curatedLocation = ref.watch(getCuratedLocationProvider);
+    final places = ref.watch(getPlacesProvider);
     final curatedPeople = ref.watch(getAllPeopleProvider);
     final isMapEnabled =
         ref.watch(serverInfoProvider.select((v) => v.serverFeatures.map));
@@ -87,18 +87,11 @@ class SearchPage extends HookConsumerWidget {
     buildPlaces() {
       return SizedBox(
         height: imageSize,
-        child: curatedLocation.widgetWhen(
+        child: places.widgetWhen(
           onError: (error, stack) => const ScaffoldErrorBody(withIcon: false),
-          onData: (locations) => CuratedPlacesRow(
+          onData: (data) => CuratedPlacesRow(
             isMapEnabled: isMapEnabled,
-            content: locations
-                .map(
-                  (o) => CuratedContent(
-                    id: o.id,
-                    label: o.city,
-                  ),
-                )
-                .toList(),
+            content: data,
             imageSize: imageSize,
             onTap: (content, index) {
               context.pushRoute(
diff --git a/mobile/lib/routing/tab_navigation_observer.dart b/mobile/lib/routing/tab_navigation_observer.dart
index afe87fb248..196cab1db9 100644
--- a/mobile/lib/routing/tab_navigation_observer.dart
+++ b/mobile/lib/routing/tab_navigation_observer.dart
@@ -37,7 +37,7 @@ class TabNavigationObserver extends AutoRouterObserver {
     // Perform tasks on re-visit to SearchRoute
     if (route.name == 'SearchRoute') {
       // Refresh Location State
-      ref.invalidate(getCuratedLocationProvider);
+      ref.invalidate(getPlacesProvider);
       ref.invalidate(getAllPeopleProvider);
     }