mirror of
				https://github.com/immich-app/immich.git
				synced 2025-10-31 10:49:11 -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: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:immich_mobile/modules/search/services/search.service.dart'; | ||||||
| import 'package:openapi/api.dart'; |  | ||||||
| 
 | 
 | ||||||
| class SearchPageStateNotifier extends StateNotifier<SearchPageState> { | final getPlacesProvider = | ||||||
|   SearchPageStateNotifier(this._searchService) |     FutureProvider.autoDispose<List<CuratedContent>>((ref) async { | ||||||
|       : 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 SearchService searchService = ref.watch(searchServiceProvider); |   final SearchService searchService = ref.watch(searchServiceProvider); | ||||||
| 
 | 
 | ||||||
|   var curatedLocation = await searchService.getCuratedLocation(); |   final exploreData = await searchService.getExploreData(); | ||||||
|   return curatedLocation ?? []; | 
 | ||||||
|  |   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/providers/db.provider.dart'; | ||||||
| import 'package:immich_mobile/shared/services/api.service.dart'; | import 'package:immich_mobile/shared/services/api.service.dart'; | ||||||
| import 'package:isar/isar.dart'; | import 'package:isar/isar.dart'; | ||||||
|  | import 'package:logging/logging.dart'; | ||||||
| import 'package:openapi/api.dart'; | import 'package:openapi/api.dart'; | ||||||
| 
 | 
 | ||||||
| final searchServiceProvider = Provider( | final searchServiceProvider = Provider( | ||||||
| @ -19,17 +20,9 @@ class SearchService { | |||||||
|   final ApiService _apiService; |   final ApiService _apiService; | ||||||
|   final Isar _db; |   final Isar _db; | ||||||
| 
 | 
 | ||||||
|  |   final _log = Logger("SearchService"); | ||||||
|   SearchService(this._apiService, this._db); |   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( |   Future<List<String>?> getSearchSuggestions( | ||||||
|     SearchSuggestionType type, { |     SearchSuggestionType type, { | ||||||
|     String? country, |     String? country, | ||||||
| @ -112,29 +105,18 @@ class SearchService { | |||||||
| 
 | 
 | ||||||
|       return _db.assets |       return _db.assets | ||||||
|           .getAllByRemoteId(response.assets.items.map((e) => e.id)); |           .getAllByRemoteId(response.assets.items.map((e) => e.id)); | ||||||
|     } catch (error) { |     } catch (error, stackTrace) { | ||||||
|       debugPrint("Error [search] $error"); |       _log.severe("Failed to search for assets", error, stackTrace); | ||||||
|     } |     } | ||||||
|     return null; |     return null; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   Future<List<CuratedLocationsResponseDto>?> getCuratedLocation() async { |   Future<List<SearchExploreResponseDto>?> getExploreData() async { | ||||||
|     try { |     try { | ||||||
|       var locations = await _apiService.assetApi.getCuratedLocations(); |       return await _apiService.searchApi.getExploreData(); | ||||||
| 
 |     } catch (error, stackTrace) { | ||||||
|       return locations; |       _log.severe("Failed to getExploreData", error, stackTrace); | ||||||
|     } 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 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/models/curated_content.dart'; | ||||||
| import 'package:immich_mobile/modules/search/providers/search_page_state.provider.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:immich_mobile/modules/search/ui/explore_grid.dart'; | ||||||
| import 'package:openapi/api.dart'; |  | ||||||
| 
 | 
 | ||||||
| @RoutePage() | @RoutePage() | ||||||
| class CuratedLocationPage extends HookConsumerWidget { | class CuratedLocationPage extends HookConsumerWidget { | ||||||
| @ -14,8 +13,7 @@ class CuratedLocationPage extends HookConsumerWidget { | |||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context, WidgetRef ref) { |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|     AsyncValue<List<CuratedLocationsResponseDto>> curatedLocation = |     AsyncValue<List<CuratedContent>> places = ref.watch(getPlacesProvider); | ||||||
|         ref.watch(getCuratedLocationProvider); |  | ||||||
| 
 | 
 | ||||||
|     return Scaffold( |     return Scaffold( | ||||||
|       appBar: AppBar( |       appBar: AppBar( | ||||||
| @ -27,16 +25,9 @@ class CuratedLocationPage extends HookConsumerWidget { | |||||||
|           icon: const Icon(Icons.arrow_back_ios_rounded), |           icon: const Icon(Icons.arrow_back_ios_rounded), | ||||||
|         ), |         ), | ||||||
|       ), |       ), | ||||||
|       body: curatedLocation.widgetWhen( |       body: places.widgetWhen( | ||||||
|         onData: (curatedLocations) => ExploreGrid( |         onData: (data) => ExploreGrid( | ||||||
|           curatedContent: curatedLocations |           curatedContent: data, | ||||||
|               .map( |  | ||||||
|                 (l) => CuratedContent( |  | ||||||
|                   label: l.city, |  | ||||||
|                   id: l.id, |  | ||||||
|                 ), |  | ||||||
|               ) |  | ||||||
|               .toList(), |  | ||||||
|         ), |         ), | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|  | |||||||
| @ -27,7 +27,7 @@ class SearchPage extends HookConsumerWidget { | |||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context, WidgetRef ref) { |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|     final curatedLocation = ref.watch(getCuratedLocationProvider); |     final places = ref.watch(getPlacesProvider); | ||||||
|     final curatedPeople = ref.watch(getAllPeopleProvider); |     final curatedPeople = ref.watch(getAllPeopleProvider); | ||||||
|     final isMapEnabled = |     final isMapEnabled = | ||||||
|         ref.watch(serverInfoProvider.select((v) => v.serverFeatures.map)); |         ref.watch(serverInfoProvider.select((v) => v.serverFeatures.map)); | ||||||
| @ -87,18 +87,11 @@ class SearchPage extends HookConsumerWidget { | |||||||
|     buildPlaces() { |     buildPlaces() { | ||||||
|       return SizedBox( |       return SizedBox( | ||||||
|         height: imageSize, |         height: imageSize, | ||||||
|         child: curatedLocation.widgetWhen( |         child: places.widgetWhen( | ||||||
|           onError: (error, stack) => const ScaffoldErrorBody(withIcon: false), |           onError: (error, stack) => const ScaffoldErrorBody(withIcon: false), | ||||||
|           onData: (locations) => CuratedPlacesRow( |           onData: (data) => CuratedPlacesRow( | ||||||
|             isMapEnabled: isMapEnabled, |             isMapEnabled: isMapEnabled, | ||||||
|             content: locations |             content: data, | ||||||
|                 .map( |  | ||||||
|                   (o) => CuratedContent( |  | ||||||
|                     id: o.id, |  | ||||||
|                     label: o.city, |  | ||||||
|                   ), |  | ||||||
|                 ) |  | ||||||
|                 .toList(), |  | ||||||
|             imageSize: imageSize, |             imageSize: imageSize, | ||||||
|             onTap: (content, index) { |             onTap: (content, index) { | ||||||
|               context.pushRoute( |               context.pushRoute( | ||||||
|  | |||||||
| @ -37,7 +37,7 @@ class TabNavigationObserver extends AutoRouterObserver { | |||||||
|     // Perform tasks on re-visit to SearchRoute |     // Perform tasks on re-visit to SearchRoute | ||||||
|     if (route.name == 'SearchRoute') { |     if (route.name == 'SearchRoute') { | ||||||
|       // Refresh Location State |       // Refresh Location State | ||||||
|       ref.invalidate(getCuratedLocationProvider); |       ref.invalidate(getPlacesProvider); | ||||||
|       ref.invalidate(getAllPeopleProvider); |       ref.invalidate(getAllPeopleProvider); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user