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); }