mirror of
				https://github.com/immich-app/immich.git
				synced 2025-10-31 02:39:03 -04:00 
			
		
		
		
	fix(mobile): show places in Search page on mobile (#9085)
* fix(mobile): show map on mobile * remove ununsed code
This commit is contained in:
		
							parent
							
								
									d52ed51aab
								
							
						
					
					
						commit
						52bcb46b42
					
				| @ -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; | ||||
|   } | ||||
| } | ||||
| @ -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; | ||||
| }); | ||||
|  | ||||
| @ -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; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -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, | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|  | ||||
| @ -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( | ||||
|  | ||||
| @ -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); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user