Files
Immich/mobile/lib/infrastructure/repositories/search_api.repository.dart
T
WillandCodex 1daf922555 feat(mobile): mobile tags (#30753)
* feat(mobile): mobile tags

* fix(mobile); refactoring, replaced hook

* tag provider through asset service

* make search use a tag set

* use tag action directly

* use notification listener

* untag action

* handle untag response

* fix tests and add untag action test

* fix material error from tag picker dialog

* fix(mobile): clip tag picker tiles and update tag overflow

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Santo Shakil <shakil.mezbah@gmail.com>
(cherry picked from commit 83c7ec50056bbefa10869c78457f8882c72275e2)
2026-10-14 21:24:13 +03:00

96 lines
5.1 KiB
Dart

import 'package:immich_mobile/data/server/api_repository.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart' hide AssetVisibility;
import 'package:immich_mobile/models/search/search_filter.model.dart';
import 'package:immich_mobile/utils/option.dart';
import 'package:openapi/api.dart' hide SearchFilter;
class SearchApiRepository extends ApiRepository {
final SearchApi _api;
const SearchApiRepository(this._api);
Future<SearchResponseDto?> search(SearchFilter filter, int page) {
AssetTypeEnum? type;
if (filter.mediaType.index == AssetType.image.index) {
type = AssetTypeEnum.IMAGE;
} else if (filter.mediaType.index == AssetType.video.index) {
type = AssetTypeEnum.VIDEO;
}
final tagIds = filter.tags == null
? const Optional<List<String>>.absent()
: Optional.present(filter.tags!.map((tag) => tag.id).toList());
if ((filter.context != null && filter.context!.isNotEmpty) ||
(filter.assetId != null && filter.assetId!.isNotEmpty)) {
return _api.searchSmart(
SmartSearchDto(
query: filter.context == null ? const Optional.absent() : Optional.present(filter.context),
queryAssetId: filter.assetId == null ? const Optional.absent() : Optional.present(filter.assetId),
language: filter.language == null ? const Optional.absent() : Optional.present(filter.language),
country: filter.location.country == null
? const Optional.absent()
: Optional.present(filter.location.country),
state: filter.location.state == null ? const Optional.absent() : Optional.present(filter.location.state),
city: filter.location.city == null ? const Optional.absent() : Optional.present(filter.location.city),
make: filter.camera.make == null ? const Optional.absent() : Optional.present(filter.camera.make),
model: filter.camera.model == null ? const Optional.absent() : Optional.present(filter.camera.model),
takenAfter: filter.date.takenAfter == null
? const Optional.absent()
: Optional.present(filter.date.takenAfter),
takenBefore: filter.date.takenBefore == null
? const Optional.absent()
: Optional.present(filter.date.takenBefore),
visibility: Optional.present(filter.display.isArchive ? AssetVisibility.archive : AssetVisibility.timeline),
rating: filter.rating.rating.toOptional(),
isFavorite: filter.display.isFavorite ? const Optional.present(true) : const Optional.absent(),
isNotInAlbum: filter.display.isNotInAlbum ? const Optional.present(true) : const Optional.absent(),
personIds: Optional.present(filter.people.map((e) => e.id).toList()),
tagIds: tagIds,
type: type == null ? const Optional.absent() : Optional.present(type),
page: Optional.present(page),
size: const Optional.present(100),
),
);
}
return _api.searchAssets(
MetadataSearchDto(
originalFileName: filter.filename != null && filter.filename!.isNotEmpty
? Optional.present(filter.filename)
: const Optional.absent(),
country: filter.location.country == null ? const Optional.absent() : Optional.present(filter.location.country),
description: filter.description != null && filter.description!.isNotEmpty
? Optional.present(filter.description)
: const Optional.absent(),
ocr: filter.ocr != null && filter.ocr!.isNotEmpty ? Optional.present(filter.ocr) : const Optional.absent(),
state: filter.location.state == null ? const Optional.absent() : Optional.present(filter.location.state),
city: filter.location.city == null ? const Optional.absent() : Optional.present(filter.location.city),
make: filter.camera.make == null ? const Optional.absent() : Optional.present(filter.camera.make),
model: filter.camera.model == null ? const Optional.absent() : Optional.present(filter.camera.model),
takenAfter: filter.date.takenAfter == null ? const Optional.absent() : Optional.present(filter.date.takenAfter),
takenBefore: filter.date.takenBefore == null
? const Optional.absent()
: Optional.present(filter.date.takenBefore),
visibility: Optional.present(filter.display.isArchive ? AssetVisibility.archive : AssetVisibility.timeline),
rating: filter.rating.rating.toOptional(),
isFavorite: filter.display.isFavorite ? const Optional.present(true) : const Optional.absent(),
isNotInAlbum: filter.display.isNotInAlbum ? const Optional.present(true) : const Optional.absent(),
personIds: Optional.present(filter.people.map((e) => e.id).toList()),
tagIds: tagIds,
type: type == null ? const Optional.absent() : Optional.present(type),
page: Optional.present(page),
size: const Optional.present(1000),
),
);
}
Future<List<String>?> getSearchSuggestions(
SearchSuggestionType type, {
String? country,
String? state,
String? make,
String? model,
}) => _api.getSearchSuggestions(type, country: country, state: state, make: make, model: model);
}