put(Isar db) async {
diff --git a/mobile/lib/shared/models/asset.g.dart b/mobile/lib/shared/models/asset.g.dart
index d845b5353a..5912f291b5 100644
--- a/mobile/lib/shared/models/asset.g.dart
+++ b/mobile/lib/shared/models/asset.g.dart
@@ -102,19 +102,24 @@ const AssetSchema = CollectionSchema(
name: r'stackParentId',
type: IsarType.string,
),
- r'type': PropertySchema(
+ r'thumbhash': PropertySchema(
id: 17,
+ name: r'thumbhash',
+ type: IsarType.string,
+ ),
+ r'type': PropertySchema(
+ id: 18,
name: r'type',
type: IsarType.byte,
enumMap: _AssettypeEnumValueMap,
),
r'updatedAt': PropertySchema(
- id: 18,
+ id: 19,
name: r'updatedAt',
type: IsarType.dateTime,
),
r'width': PropertySchema(
- id: 19,
+ id: 20,
name: r'width',
type: IsarType.int,
)
@@ -210,6 +215,12 @@ int _assetEstimateSize(
bytesCount += 3 + value.length * 3;
}
}
+ {
+ final value = object.thumbhash;
+ if (value != null) {
+ bytesCount += 3 + value.length * 3;
+ }
+ }
return bytesCount;
}
@@ -236,9 +247,10 @@ void _assetSerialize(
writer.writeString(offsets[14], object.remoteId);
writer.writeLong(offsets[15], object.stackCount);
writer.writeString(offsets[16], object.stackParentId);
- writer.writeByte(offsets[17], object.type.index);
- writer.writeDateTime(offsets[18], object.updatedAt);
- writer.writeInt(offsets[19], object.width);
+ writer.writeString(offsets[17], object.thumbhash);
+ writer.writeByte(offsets[18], object.type.index);
+ writer.writeDateTime(offsets[19], object.updatedAt);
+ writer.writeInt(offsets[20], object.width);
}
Asset _assetDeserialize(
@@ -266,10 +278,11 @@ Asset _assetDeserialize(
remoteId: reader.readStringOrNull(offsets[14]),
stackCount: reader.readLongOrNull(offsets[15]),
stackParentId: reader.readStringOrNull(offsets[16]),
- type: _AssettypeValueEnumMap[reader.readByteOrNull(offsets[17])] ??
+ thumbhash: reader.readStringOrNull(offsets[17]),
+ type: _AssettypeValueEnumMap[reader.readByteOrNull(offsets[18])] ??
AssetType.other,
- updatedAt: reader.readDateTime(offsets[18]),
- width: reader.readIntOrNull(offsets[19]),
+ updatedAt: reader.readDateTime(offsets[19]),
+ width: reader.readIntOrNull(offsets[20]),
);
return object;
}
@@ -316,11 +329,13 @@ P _assetDeserializeProp(
case 16:
return (reader.readStringOrNull(offset)) as P;
case 17:
+ return (reader.readStringOrNull(offset)) as P;
+ case 18:
return (_AssettypeValueEnumMap[reader.readByteOrNull(offset)] ??
AssetType.other) as P;
- case 18:
- return (reader.readDateTime(offset)) as P;
case 19:
+ return (reader.readDateTime(offset)) as P;
+ case 20:
return (reader.readIntOrNull(offset)) as P;
default:
throw IsarError('Unknown property with id $propertyId');
@@ -2078,6 +2093,152 @@ extension AssetQueryFilter on QueryBuilder {
});
}
+ QueryBuilder thumbhashIsNull() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(const FilterCondition.isNull(
+ property: r'thumbhash',
+ ));
+ });
+ }
+
+ QueryBuilder thumbhashIsNotNull() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(const FilterCondition.isNotNull(
+ property: r'thumbhash',
+ ));
+ });
+ }
+
+ QueryBuilder thumbhashEqualTo(
+ String? value, {
+ bool caseSensitive = true,
+ }) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.equalTo(
+ property: r'thumbhash',
+ value: value,
+ caseSensitive: caseSensitive,
+ ));
+ });
+ }
+
+ QueryBuilder thumbhashGreaterThan(
+ String? value, {
+ bool include = false,
+ bool caseSensitive = true,
+ }) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.greaterThan(
+ include: include,
+ property: r'thumbhash',
+ value: value,
+ caseSensitive: caseSensitive,
+ ));
+ });
+ }
+
+ QueryBuilder thumbhashLessThan(
+ String? value, {
+ bool include = false,
+ bool caseSensitive = true,
+ }) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.lessThan(
+ include: include,
+ property: r'thumbhash',
+ value: value,
+ caseSensitive: caseSensitive,
+ ));
+ });
+ }
+
+ QueryBuilder thumbhashBetween(
+ String? lower,
+ String? upper, {
+ bool includeLower = true,
+ bool includeUpper = true,
+ bool caseSensitive = true,
+ }) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.between(
+ property: r'thumbhash',
+ lower: lower,
+ includeLower: includeLower,
+ upper: upper,
+ includeUpper: includeUpper,
+ caseSensitive: caseSensitive,
+ ));
+ });
+ }
+
+ QueryBuilder thumbhashStartsWith(
+ String value, {
+ bool caseSensitive = true,
+ }) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.startsWith(
+ property: r'thumbhash',
+ value: value,
+ caseSensitive: caseSensitive,
+ ));
+ });
+ }
+
+ QueryBuilder thumbhashEndsWith(
+ String value, {
+ bool caseSensitive = true,
+ }) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.endsWith(
+ property: r'thumbhash',
+ value: value,
+ caseSensitive: caseSensitive,
+ ));
+ });
+ }
+
+ QueryBuilder thumbhashContains(
+ String value,
+ {bool caseSensitive = true}) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.contains(
+ property: r'thumbhash',
+ value: value,
+ caseSensitive: caseSensitive,
+ ));
+ });
+ }
+
+ QueryBuilder thumbhashMatches(
+ String pattern,
+ {bool caseSensitive = true}) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.matches(
+ property: r'thumbhash',
+ wildcard: pattern,
+ caseSensitive: caseSensitive,
+ ));
+ });
+ }
+
+ QueryBuilder thumbhashIsEmpty() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.equalTo(
+ property: r'thumbhash',
+ value: '',
+ ));
+ });
+ }
+
+ QueryBuilder thumbhashIsNotEmpty() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.greaterThan(
+ property: r'thumbhash',
+ value: '',
+ ));
+ });
+ }
+
QueryBuilder typeEqualTo(
AssetType value) {
return QueryBuilder.apply(this, (query) {
@@ -2462,6 +2623,18 @@ extension AssetQuerySortBy on QueryBuilder {
});
}
+ QueryBuilder sortByThumbhash() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'thumbhash', Sort.asc);
+ });
+ }
+
+ QueryBuilder sortByThumbhashDesc() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'thumbhash', Sort.desc);
+ });
+ }
+
QueryBuilder sortByType() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'type', Sort.asc);
@@ -2716,6 +2889,18 @@ extension AssetQuerySortThenBy on QueryBuilder {
});
}
+ QueryBuilder thenByThumbhash() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'thumbhash', Sort.asc);
+ });
+ }
+
+ QueryBuilder thenByThumbhashDesc() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'thumbhash', Sort.desc);
+ });
+ }
+
QueryBuilder thenByType() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'type', Sort.asc);
@@ -2864,6 +3049,13 @@ extension AssetQueryWhereDistinct on QueryBuilder {
});
}
+ QueryBuilder distinctByThumbhash(
+ {bool caseSensitive = true}) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addDistinctBy(r'thumbhash', caseSensitive: caseSensitive);
+ });
+ }
+
QueryBuilder distinctByType() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'type');
@@ -2992,6 +3184,12 @@ extension AssetQueryProperty on QueryBuilder {
});
}
+ QueryBuilder thumbhashProperty() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addPropertyName(r'thumbhash');
+ });
+ }
+
QueryBuilder typeProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'type');
diff --git a/mobile/lib/shared/models/logger_message.model.dart b/mobile/lib/shared/models/logger_message.model.dart
index cb1d45a580..f657257eab 100644
--- a/mobile/lib/shared/models/logger_message.model.dart
+++ b/mobile/lib/shared/models/logger_message.model.dart
@@ -9,6 +9,7 @@ part 'logger_message.model.g.dart';
class LoggerMessage {
Id id = Isar.autoIncrement;
String message;
+ String? details;
@Enumerated(EnumType.ordinal)
LogLevel level = LogLevel.INFO;
DateTime createdAt;
@@ -17,6 +18,7 @@ class LoggerMessage {
LoggerMessage({
required this.message,
+ required this.details,
required this.level,
required this.createdAt,
required this.context1,
diff --git a/mobile/lib/shared/models/logger_message.model.g.dart b/mobile/lib/shared/models/logger_message.model.g.dart
index a6b960eece..76c823704c 100644
--- a/mobile/lib/shared/models/logger_message.model.g.dart
+++ b/mobile/lib/shared/models/logger_message.model.g.dart
@@ -32,14 +32,19 @@ const LoggerMessageSchema = CollectionSchema(
name: r'createdAt',
type: IsarType.dateTime,
),
- r'level': PropertySchema(
+ r'details': PropertySchema(
id: 3,
+ name: r'details',
+ type: IsarType.string,
+ ),
+ r'level': PropertySchema(
+ id: 4,
name: r'level',
type: IsarType.byte,
enumMap: _LoggerMessagelevelEnumValueMap,
),
r'message': PropertySchema(
- id: 4,
+ id: 5,
name: r'message',
type: IsarType.string,
)
@@ -76,6 +81,12 @@ int _loggerMessageEstimateSize(
bytesCount += 3 + value.length * 3;
}
}
+ {
+ final value = object.details;
+ if (value != null) {
+ bytesCount += 3 + value.length * 3;
+ }
+ }
bytesCount += 3 + object.message.length * 3;
return bytesCount;
}
@@ -89,8 +100,9 @@ void _loggerMessageSerialize(
writer.writeString(offsets[0], object.context1);
writer.writeString(offsets[1], object.context2);
writer.writeDateTime(offsets[2], object.createdAt);
- writer.writeByte(offsets[3], object.level.index);
- writer.writeString(offsets[4], object.message);
+ writer.writeString(offsets[3], object.details);
+ writer.writeByte(offsets[4], object.level.index);
+ writer.writeString(offsets[5], object.message);
}
LoggerMessage _loggerMessageDeserialize(
@@ -103,9 +115,10 @@ LoggerMessage _loggerMessageDeserialize(
context1: reader.readStringOrNull(offsets[0]),
context2: reader.readStringOrNull(offsets[1]),
createdAt: reader.readDateTime(offsets[2]),
- level: _LoggerMessagelevelValueEnumMap[reader.readByteOrNull(offsets[3])] ??
+ details: reader.readStringOrNull(offsets[3]),
+ level: _LoggerMessagelevelValueEnumMap[reader.readByteOrNull(offsets[4])] ??
LogLevel.ALL,
- message: reader.readString(offsets[4]),
+ message: reader.readString(offsets[5]),
);
object.id = id;
return object;
@@ -125,9 +138,11 @@ P _loggerMessageDeserializeProp(
case 2:
return (reader.readDateTime(offset)) as P;
case 3:
+ return (reader.readStringOrNull(offset)) as P;
+ case 4:
return (_LoggerMessagelevelValueEnumMap[reader.readByteOrNull(offset)] ??
LogLevel.ALL) as P;
- case 4:
+ case 5:
return (reader.readString(offset)) as P;
default:
throw IsarError('Unknown property with id $propertyId');
@@ -619,6 +634,160 @@ extension LoggerMessageQueryFilter
});
}
+ QueryBuilder
+ detailsIsNull() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(const FilterCondition.isNull(
+ property: r'details',
+ ));
+ });
+ }
+
+ QueryBuilder
+ detailsIsNotNull() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(const FilterCondition.isNotNull(
+ property: r'details',
+ ));
+ });
+ }
+
+ QueryBuilder
+ detailsEqualTo(
+ String? value, {
+ bool caseSensitive = true,
+ }) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.equalTo(
+ property: r'details',
+ value: value,
+ caseSensitive: caseSensitive,
+ ));
+ });
+ }
+
+ QueryBuilder
+ detailsGreaterThan(
+ String? value, {
+ bool include = false,
+ bool caseSensitive = true,
+ }) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.greaterThan(
+ include: include,
+ property: r'details',
+ value: value,
+ caseSensitive: caseSensitive,
+ ));
+ });
+ }
+
+ QueryBuilder
+ detailsLessThan(
+ String? value, {
+ bool include = false,
+ bool caseSensitive = true,
+ }) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.lessThan(
+ include: include,
+ property: r'details',
+ value: value,
+ caseSensitive: caseSensitive,
+ ));
+ });
+ }
+
+ QueryBuilder
+ detailsBetween(
+ String? lower,
+ String? upper, {
+ bool includeLower = true,
+ bool includeUpper = true,
+ bool caseSensitive = true,
+ }) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.between(
+ property: r'details',
+ lower: lower,
+ includeLower: includeLower,
+ upper: upper,
+ includeUpper: includeUpper,
+ caseSensitive: caseSensitive,
+ ));
+ });
+ }
+
+ QueryBuilder
+ detailsStartsWith(
+ String value, {
+ bool caseSensitive = true,
+ }) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.startsWith(
+ property: r'details',
+ value: value,
+ caseSensitive: caseSensitive,
+ ));
+ });
+ }
+
+ QueryBuilder
+ detailsEndsWith(
+ String value, {
+ bool caseSensitive = true,
+ }) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.endsWith(
+ property: r'details',
+ value: value,
+ caseSensitive: caseSensitive,
+ ));
+ });
+ }
+
+ QueryBuilder
+ detailsContains(String value, {bool caseSensitive = true}) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.contains(
+ property: r'details',
+ value: value,
+ caseSensitive: caseSensitive,
+ ));
+ });
+ }
+
+ QueryBuilder
+ detailsMatches(String pattern, {bool caseSensitive = true}) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.matches(
+ property: r'details',
+ wildcard: pattern,
+ caseSensitive: caseSensitive,
+ ));
+ });
+ }
+
+ QueryBuilder
+ detailsIsEmpty() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.equalTo(
+ property: r'details',
+ value: '',
+ ));
+ });
+ }
+
+ QueryBuilder
+ detailsIsNotEmpty() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.greaterThan(
+ property: r'details',
+ value: '',
+ ));
+ });
+ }
+
QueryBuilder idEqualTo(
Id value) {
return QueryBuilder.apply(this, (query) {
@@ -913,6 +1082,18 @@ extension LoggerMessageQuerySortBy
});
}
+ QueryBuilder sortByDetails() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'details', Sort.asc);
+ });
+ }
+
+ QueryBuilder sortByDetailsDesc() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'details', Sort.desc);
+ });
+ }
+
QueryBuilder sortByLevel() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'level', Sort.asc);
@@ -979,6 +1160,18 @@ extension LoggerMessageQuerySortThenBy
});
}
+ QueryBuilder thenByDetails() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'details', Sort.asc);
+ });
+ }
+
+ QueryBuilder thenByDetailsDesc() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'details', Sort.desc);
+ });
+ }
+
QueryBuilder thenById() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'id', Sort.asc);
@@ -1038,6 +1231,13 @@ extension LoggerMessageQueryWhereDistinct
});
}
+ QueryBuilder distinctByDetails(
+ {bool caseSensitive = true}) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addDistinctBy(r'details', caseSensitive: caseSensitive);
+ });
+ }
+
QueryBuilder distinctByLevel() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'level');
@@ -1078,6 +1278,12 @@ extension LoggerMessageQueryProperty
});
}
+ QueryBuilder detailsProperty() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addPropertyName(r'details');
+ });
+ }
+
QueryBuilder levelProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'level');
diff --git a/mobile/lib/shared/providers/websocket.provider.dart b/mobile/lib/shared/providers/websocket.provider.dart
index 6b12916d27..89f99dc6df 100644
--- a/mobile/lib/shared/providers/websocket.provider.dart
+++ b/mobile/lib/shared/providers/websocket.provider.dart
@@ -110,7 +110,8 @@ class WebsocketNotifier extends StateNotifier {
final endpoint = Uri.parse(Store.get(StoreKey.serverEndpoint));
final headers = {"x-immich-user-token": accessToken};
if (endpoint.userInfo.isNotEmpty) {
- headers["Authorization"] = "Basic ${base64.encode(utf8.encode(endpoint.userInfo))}";
+ headers["Authorization"] =
+ "Basic ${base64.encode(utf8.encode(endpoint.userInfo))}";
}
debugPrint("Attempting to connect to websocket");
@@ -161,6 +162,7 @@ class WebsocketNotifier extends StateNotifier {
socket.on('on_asset_trash', _handleServerUpdates);
socket.on('on_asset_restore', _handleServerUpdates);
socket.on('on_asset_update', _handleServerUpdates);
+ socket.on('on_asset_stack_update', _handleServerUpdates);
socket.on('on_asset_hidden', _handleOnAssetHidden);
socket.on('on_new_release', _handleReleaseUpdates);
} catch (e) {
diff --git a/mobile/lib/shared/services/asset.service.dart b/mobile/lib/shared/services/asset.service.dart
index 48f8c63524..3086ab9246 100644
--- a/mobile/lib/shared/services/asset.service.dart
+++ b/mobile/lib/shared/services/asset.service.dart
@@ -63,7 +63,7 @@ class AssetService {
/// Returns `null` if the server state did not change, else list of assets
Future?> _getRemoteAssets(User user) async {
- const int chunkSize = 5000;
+ const int chunkSize = 10000;
try {
final DateTime now = DateTime.now().toUtc();
final List allAssets = [];
@@ -90,7 +90,7 @@ class AssetService {
return allAssets;
} catch (error, stack) {
log.severe(
- 'Error while getting remote assets: ${error.toString()}',
+ 'Error while getting remote assets',
error,
stack,
);
@@ -117,7 +117,7 @@ class AssetService {
);
return true;
} catch (error, stack) {
- log.severe("Error deleteAssets ${error.toString()}", error, stack);
+ log.severe("Error while deleting assets", error, stack);
}
return false;
}
diff --git a/mobile/lib/shared/services/immich_logger.service.dart b/mobile/lib/shared/services/immich_logger.service.dart
index b66177e570..967ab2d5f2 100644
--- a/mobile/lib/shared/services/immich_logger.service.dart
+++ b/mobile/lib/shared/services/immich_logger.service.dart
@@ -12,7 +12,7 @@ import 'package:share_plus/share_plus.dart';
/// [ImmichLogger] is a custom logger that is built on top of the [logging] package.
/// The logs are written to the database and onto console, using `debugPrint` method.
///
-/// The logs are deleted when exceeding the `maxLogEntries` (default 200) property
+/// The logs are deleted when exceeding the `maxLogEntries` (default 500) property
/// in the class.
///
/// Logs can be shared by calling the `shareLogs` method, which will open a share dialog
@@ -58,6 +58,7 @@ class ImmichLogger {
debugPrint('[${record.level.name}] [${record.time}] ${record.message}');
final lm = LoggerMessage(
message: record.message,
+ details: record.error?.toString(),
level: record.level.toLogLevel(),
createdAt: record.time,
context1: record.loggerName,
diff --git a/mobile/lib/shared/services/share.service.dart b/mobile/lib/shared/services/share.service.dart
index 20ee40d588..be7c0c168d 100644
--- a/mobile/lib/shared/services/share.service.dart
+++ b/mobile/lib/shared/services/share.service.dart
@@ -2,6 +2,7 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/extensions/response_extensions.dart';
import 'package:immich_mobile/shared/models/asset.dart';
import 'package:immich_mobile/shared/providers/api.provider.dart';
import 'package:logging/logging.dart';
@@ -27,7 +28,12 @@ class ShareService {
final downloadedXFiles = [];
for (var asset in assets) {
- if (asset.isRemote) {
+ if (asset.isLocal) {
+ // Prefer local assets to share
+ File? f = await asset.local!.file;
+ downloadedXFiles.add(XFile(f!.path));
+ } else if (asset.isRemote) {
+ // Download remote asset otherwise
final tempDir = await getTemporaryDirectory();
final fileName = asset.fileName;
final tempFile = await File('${tempDir.path}/$fileName').create();
@@ -36,16 +42,14 @@ class ShareService {
if (res.statusCode != 200) {
_log.severe(
- "Asset download failed with status - ${res.statusCode} and response - ${res.body}",
+ "Asset download for ${asset.fileName} failed",
+ res.toLoggerString(),
);
continue;
}
tempFile.writeAsBytesSync(res.bodyBytes);
downloadedXFiles.add(XFile(tempFile.path));
- } else {
- File? f = await asset.local!.file;
- downloadedXFiles.add(XFile(f!.path));
}
}
@@ -66,7 +70,7 @@ class ShareService {
);
return true;
} catch (error) {
- _log.severe("Share failed with error $error");
+ _log.severe("Share failed", error);
}
return false;
}
diff --git a/mobile/lib/shared/services/sync.service.dart b/mobile/lib/shared/services/sync.service.dart
index 8d4547340e..d92145235e 100644
--- a/mobile/lib/shared/services/sync.service.dart
+++ b/mobile/lib/shared/services/sync.service.dart
@@ -127,7 +127,7 @@ class SyncService {
try {
await _db.writeTxn(() => a.put(_db));
} on IsarError catch (e) {
- _log.severe("Failed to put new asset into db: $e");
+ _log.severe("Failed to put new asset into db", e);
return false;
}
return true;
@@ -160,7 +160,7 @@ class SyncService {
}
return false;
} on IsarError catch (e) {
- _log.severe("Failed to sync remote assets to db: $e");
+ _log.severe("Failed to sync remote assets to db", e);
}
return null;
}
@@ -219,7 +219,7 @@ class SyncService {
await _db.writeTxn(() => _db.assets.deleteAll(idsToDelete));
await upsertAssetsWithExif(toAdd + toUpdate);
} on IsarError catch (e) {
- _log.severe("Failed to sync remote assets to db: $e");
+ _log.severe("Failed to sync remote assets to db", e);
}
await _updateUserAssetsETag(user, now);
return true;
@@ -351,7 +351,7 @@ class SyncService {
});
_log.info("Synced changes of remote album ${album.name} to DB");
} on IsarError catch (e) {
- _log.severe("Failed to sync remote album to database $e");
+ _log.severe("Failed to sync remote album to database", e);
}
if (album.shared || dto.shared) {
@@ -423,7 +423,7 @@ class SyncService {
assert(ok);
_log.info("Removed local album $album from DB");
} catch (e) {
- _log.severe("Failed to remove local album $album from DB");
+ _log.severe("Failed to remove local album $album from DB", e);
}
}
@@ -473,9 +473,7 @@ class SyncService {
});
_log.info("Upserted ${assets.length} assets into the DB");
} on IsarError catch (e) {
- _log.severe(
- "Failed to upsert ${assets.length} assets into the DB: ${e.toString()}",
- );
+ _log.severe("Failed to upsert ${assets.length} assets into the DB", e);
// give details on the errors
assets.sort(Asset.compareByOwnerChecksum);
final inDb = await _db.assets.getAllByOwnerIdChecksum(
diff --git a/mobile/lib/shared/services/user.service.dart b/mobile/lib/shared/services/user.service.dart
index 4d398c3a88..ae65ed31db 100644
--- a/mobile/lib/shared/services/user.service.dart
+++ b/mobile/lib/shared/services/user.service.dart
@@ -42,7 +42,7 @@ class UserService {
final dto = await _apiService.userApi.getAllUsers(isAll);
return dto?.map(User.fromUserDto).toList();
} catch (e) {
- _log.warning("Failed get all users:\n$e");
+ _log.warning("Failed get all users", e);
return null;
}
}
@@ -65,7 +65,7 @@ class UserService {
),
);
} catch (e) {
- _log.warning("Failed to upload profile image:\n$e");
+ _log.warning("Failed to upload profile image", e);
return null;
}
}
diff --git a/mobile/lib/shared/ui/delayed_loading_indicator.dart b/mobile/lib/shared/ui/delayed_loading_indicator.dart
new file mode 100644
index 0000000000..e009b660c9
--- /dev/null
+++ b/mobile/lib/shared/ui/delayed_loading_indicator.dart
@@ -0,0 +1,43 @@
+import 'package:flutter/material.dart';
+import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
+
+class DelayedLoadingIndicator extends StatelessWidget {
+ /// The delay to avoid showing the loading indicator
+ final Duration delay;
+
+ /// Defaults to using the [ImmichLoadingIndicator]
+ final Widget? child;
+
+ /// An optional fade in duration to animate the loading
+ final Duration? fadeInDuration;
+
+ const DelayedLoadingIndicator({
+ super.key,
+ this.delay = const Duration(seconds: 3),
+ this.child,
+ this.fadeInDuration,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return FutureBuilder(
+ future: Future.delayed(delay),
+ builder: (context, snapshot) {
+ late Widget c;
+ if (snapshot.connectionState == ConnectionState.done) {
+ c = child ??
+ const ImmichLoadingIndicator(
+ key: ValueKey('loading'),
+ );
+ } else {
+ c = Container(key: const ValueKey('hiding'));
+ }
+
+ return AnimatedSwitcher(
+ duration: fadeInDuration ?? Duration.zero,
+ child: c,
+ );
+ },
+ );
+ }
+}
diff --git a/mobile/lib/shared/ui/fade_in_placeholder_image.dart b/mobile/lib/shared/ui/fade_in_placeholder_image.dart
new file mode 100644
index 0000000000..e0620ea4f0
--- /dev/null
+++ b/mobile/lib/shared/ui/fade_in_placeholder_image.dart
@@ -0,0 +1,35 @@
+import 'package:flutter/material.dart';
+import 'package:immich_mobile/shared/ui/transparent_image.dart';
+
+class FadeInPlaceholderImage extends StatelessWidget {
+ final Widget placeholder;
+ final ImageProvider image;
+ final Duration duration;
+ final BoxFit fit;
+
+ const FadeInPlaceholderImage({
+ super.key,
+ required this.placeholder,
+ required this.image,
+ this.duration = const Duration(milliseconds: 100),
+ this.fit = BoxFit.cover,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return SizedBox.expand(
+ child: Stack(
+ fit: StackFit.expand,
+ children: [
+ placeholder,
+ FadeInImage(
+ fadeInDuration: duration,
+ image: image,
+ fit: fit,
+ placeholder: MemoryImage(kTransparentImage),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/mobile/lib/shared/ui/hooks/blurhash_hook.dart b/mobile/lib/shared/ui/hooks/blurhash_hook.dart
new file mode 100644
index 0000000000..24b3c25e13
--- /dev/null
+++ b/mobile/lib/shared/ui/hooks/blurhash_hook.dart
@@ -0,0 +1,17 @@
+import 'dart:convert';
+import 'dart:typed_data';
+import 'package:flutter_hooks/flutter_hooks.dart';
+import 'package:immich_mobile/shared/models/asset.dart';
+import 'package:thumbhash/thumbhash.dart' as thumbhash;
+
+ObjectRef useBlurHashRef(Asset? asset) {
+ if (asset?.thumbhash == null) {
+ return useRef(null);
+ }
+
+ final rbga = thumbhash.thumbHashToRGBA(
+ base64Decode(asset!.thumbhash!),
+ );
+
+ return useRef(thumbhash.rgbaToBmp(rbga));
+}
diff --git a/mobile/lib/shared/ui/immich_image.dart b/mobile/lib/shared/ui/immich_image.dart
index 21418d5274..f06f1726a1 100644
--- a/mobile/lib/shared/ui/immich_image.dart
+++ b/mobile/lib/shared/ui/immich_image.dart
@@ -1,15 +1,12 @@
-import 'dart:math';
-
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/modules/asset_viewer/image_providers/immich_local_image_provider.dart';
import 'package:immich_mobile/modules/asset_viewer/image_providers/immich_remote_image_provider.dart';
+import 'package:immich_mobile/modules/home/ui/asset_grid/thumbnail_placeholder.dart';
import 'package:immich_mobile/shared/models/asset.dart';
import 'package:immich_mobile/shared/models/store.dart';
import 'package:octo_image/octo_image.dart';
-import 'package:photo_manager/photo_manager.dart';
-import 'package:photo_manager_image_provider/photo_manager_image_provider.dart';
class ImmichImage extends StatelessWidget {
const ImmichImage(
@@ -17,40 +14,15 @@ class ImmichImage extends StatelessWidget {
this.width,
this.height,
this.fit = BoxFit.cover,
- this.useGrayBoxPlaceholder = false,
- this.isThumbnail = false,
- this.thumbnailSize = 250,
+ this.placeholder = const ThumbnailPlaceholder(),
super.key,
});
final Asset? asset;
- final bool useGrayBoxPlaceholder;
+ final Widget? placeholder;
final double? width;
final double? height;
final BoxFit fit;
- final bool isThumbnail;
- final int thumbnailSize;
-
- /// Factory constructor to use the thumbnail variant
- factory ImmichImage.thumbnail(
- Asset? asset, {
- BoxFit fit = BoxFit.cover,
- double? width,
- double? height,
- }) {
- // Use the width and height to derive thumbnail size
- final thumbnailSize = max(width ?? 250, height ?? 250).toInt();
-
- return ImmichImage(
- asset,
- isThumbnail: true,
- fit: fit,
- width: width,
- height: height,
- useGrayBoxPlaceholder: true,
- thumbnailSize: thumbnailSize,
- );
- }
// Helper function to return the image provider for the asset
// either by using the asset ID or the asset itself
@@ -62,8 +34,6 @@ class ImmichImage extends StatelessWidget {
static ImageProvider imageProvider({
Asset? asset,
String? assetId,
- bool isThumbnail = false,
- int thumbnailSize = 250,
}) {
if (asset == null && assetId == null) {
throw Exception('Must supply either asset or assetId');
@@ -72,67 +42,53 @@ class ImmichImage extends StatelessWidget {
if (asset == null) {
return ImmichRemoteImageProvider(
assetId: assetId!,
- isThumbnail: isThumbnail,
+ isThumbnail: false,
);
}
- if (useLocal(asset) && isThumbnail) {
- return AssetEntityImageProvider(
- asset.local!,
- isOriginal: false,
- thumbnailSize: ThumbnailSize.square(thumbnailSize),
- );
- } else if (useLocal(asset) && !isThumbnail) {
+ if (useLocal(asset)) {
return ImmichLocalImageProvider(
asset: asset,
);
} else {
return ImmichRemoteImageProvider(
assetId: asset.remoteId!,
- isThumbnail: isThumbnail,
+ isThumbnail: false,
);
}
}
+ // Whether to use the local asset image provider or a remote one
static bool useLocal(Asset asset) =>
!asset.isRemote ||
asset.isLocal && !Store.get(StoreKey.preferRemoteImage, false);
+
@override
Widget build(BuildContext context) {
-
if (asset == null) {
return Container(
- decoration: const BoxDecoration(
- color: Colors.grey,
- ),
- child: SizedBox(
- width: width,
- height: height,
- child: const Center(
- child: Icon(Icons.no_photography),
- ),
+ color: Colors.grey,
+ width: width,
+ height: height,
+ child: const Center(
+ child: Icon(Icons.no_photography),
),
);
}
return OctoImage(
fadeInDuration: const Duration(milliseconds: 0),
- fadeOutDuration: const Duration(milliseconds: 400),
+ fadeOutDuration: const Duration(milliseconds: 200),
placeholderBuilder: (context) {
- if (useGrayBoxPlaceholder) {
+ if (placeholder != null) {
// Use the gray box placeholder
- return const SizedBox.expand(
- child: DecoratedBox(
- decoration: BoxDecoration(color: Colors.grey),
- ),
- );
+ return placeholder!;
}
// No placeholder
return const SizedBox();
},
image: ImmichImage.imageProvider(
asset: asset,
- isThumbnail: isThumbnail,
),
width: width,
height: height,
diff --git a/mobile/lib/shared/ui/immich_thumbnail.dart b/mobile/lib/shared/ui/immich_thumbnail.dart
new file mode 100644
index 0000000000..77827348db
--- /dev/null
+++ b/mobile/lib/shared/ui/immich_thumbnail.dart
@@ -0,0 +1,88 @@
+import 'dart:typed_data';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_hooks/flutter_hooks.dart';
+import 'package:immich_mobile/modules/asset_viewer/image_providers/immich_local_thumbnail_provider.dart';
+import 'package:immich_mobile/modules/asset_viewer/image_providers/immich_remote_image_provider.dart';
+import 'package:immich_mobile/shared/models/asset.dart';
+import 'package:immich_mobile/shared/ui/hooks/blurhash_hook.dart';
+import 'package:immich_mobile/shared/ui/immich_image.dart';
+import 'package:immich_mobile/shared/ui/thumbhash_placeholder.dart';
+import 'package:octo_image/octo_image.dart';
+
+class ImmichThumbnail extends HookWidget {
+ const ImmichThumbnail({
+ this.asset,
+ this.width = 250,
+ this.height = 250,
+ this.fit = BoxFit.cover,
+ super.key,
+ });
+
+ final Asset? asset;
+ final double width;
+ final double height;
+ final BoxFit fit;
+
+ /// Helper function to return the image provider for the asset thumbnail
+ /// either by using the asset ID or the asset itself
+ /// [asset] is the Asset to request, or else use [assetId] to get a remote
+ /// image provider
+ static ImageProvider imageProvider({
+ Asset? asset,
+ String? assetId,
+ int thumbnailSize = 256,
+ }) {
+ if (asset == null && assetId == null) {
+ throw Exception('Must supply either asset or assetId');
+ }
+
+ if (asset == null) {
+ return ImmichRemoteImageProvider(
+ assetId: assetId!,
+ isThumbnail: true,
+ );
+ }
+
+ if (ImmichImage.useLocal(asset)) {
+ return ImmichLocalThumbnailProvider(
+ asset: asset,
+ height: thumbnailSize,
+ width: thumbnailSize,
+ );
+ } else {
+ return ImmichRemoteImageProvider(
+ assetId: asset.remoteId!,
+ isThumbnail: true,
+ );
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ Uint8List? blurhash = useBlurHashRef(asset).value;
+ if (asset == null) {
+ return Container(
+ color: Colors.grey,
+ width: width,
+ height: height,
+ child: const Center(
+ child: Icon(Icons.no_photography),
+ ),
+ );
+ }
+
+ return OctoImage.fromSet(
+ placeholderFadeInDuration: Duration.zero,
+ fadeInDuration: Duration.zero,
+ fadeOutDuration: const Duration(milliseconds: 100),
+ octoSet: blurHashOrPlaceholder(blurhash),
+ image: ImmichThumbnail.imageProvider(
+ asset: asset,
+ ),
+ width: width,
+ height: height,
+ fit: fit,
+ );
+ }
+}
diff --git a/mobile/lib/shared/ui/thumbhash_placeholder.dart b/mobile/lib/shared/ui/thumbhash_placeholder.dart
new file mode 100644
index 0000000000..0ec64d3760
--- /dev/null
+++ b/mobile/lib/shared/ui/thumbhash_placeholder.dart
@@ -0,0 +1,48 @@
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:immich_mobile/modules/home/ui/asset_grid/thumbnail_placeholder.dart';
+import 'package:immich_mobile/shared/ui/fade_in_placeholder_image.dart';
+import 'package:octo_image/octo_image.dart';
+
+/// Simple set to show [OctoPlaceholder.circularProgressIndicator] as
+/// placeholder and [OctoError.icon] as error.
+OctoSet blurHashOrPlaceholder(
+ Uint8List? blurhash, {
+ BoxFit? fit,
+ Text? errorMessage,
+}) {
+ return OctoSet(
+ placeholderBuilder: blurHashPlaceholderBuilder(blurhash, fit: fit),
+ errorBuilder: blurHashErrorBuilder(blurhash, fit: fit),
+ );
+}
+
+OctoPlaceholderBuilder blurHashPlaceholderBuilder(
+ Uint8List? blurhash, {
+ BoxFit? fit,
+}) {
+ return (context) => blurhash == null
+ ? const ThumbnailPlaceholder()
+ : FadeInPlaceholderImage(
+ placeholder: const ThumbnailPlaceholder(),
+ image: MemoryImage(blurhash),
+ fit: fit ?? BoxFit.cover,
+ );
+}
+
+OctoErrorBuilder blurHashErrorBuilder(
+ Uint8List? blurhash, {
+ BoxFit? fit,
+ Text? message,
+ IconData? icon,
+ Color? iconColor,
+ double? iconSize,
+}) {
+ return OctoError.placeholderWithErrorIcon(
+ blurHashPlaceholderBuilder(blurhash, fit: fit),
+ message: message,
+ icon: icon,
+ iconColor: iconColor,
+ iconSize: iconSize,
+ );
+}
diff --git a/mobile/lib/shared/views/app_log_detail_page.dart b/mobile/lib/shared/views/app_log_detail_page.dart
index 126f46c8ff..6b99d7f0af 100644
--- a/mobile/lib/shared/views/app_log_detail_page.dart
+++ b/mobile/lib/shared/views/app_log_detail_page.dart
@@ -15,7 +15,7 @@ class AppLogDetailPage extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
var isDarkTheme = context.isDarkTheme;
- buildStackMessage(String stackTrace) {
+ buildTextWithCopyButton(String header, String text) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
@@ -28,7 +28,7 @@ class AppLogDetailPage extends HookConsumerWidget {
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Text(
- "STACK TRACES",
+ header,
style: TextStyle(
fontSize: 12.0,
color: context.primaryColor,
@@ -38,8 +38,7 @@ class AppLogDetailPage extends HookConsumerWidget {
),
IconButton(
onPressed: () {
- Clipboard.setData(ClipboardData(text: stackTrace))
- .then((_) {
+ Clipboard.setData(ClipboardData(text: text)).then((_) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
@@ -68,73 +67,7 @@ class AppLogDetailPage extends HookConsumerWidget {
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SelectableText(
- stackTrace,
- style: const TextStyle(
- fontSize: 12.0,
- fontWeight: FontWeight.bold,
- fontFamily: "Inconsolata",
- ),
- ),
- ),
- ),
- ],
- ),
- );
- }
-
- buildLogMessage(String message) {
- return Padding(
- padding: const EdgeInsets.all(8.0),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- crossAxisAlignment: CrossAxisAlignment.center,
- children: [
- Padding(
- padding: const EdgeInsets.only(bottom: 8.0),
- child: Text(
- "MESSAGE",
- style: TextStyle(
- fontSize: 12.0,
- color: context.primaryColor,
- fontWeight: FontWeight.bold,
- ),
- ),
- ),
- IconButton(
- onPressed: () {
- Clipboard.setData(ClipboardData(text: message)).then((_) {
- ScaffoldMessenger.of(context).showSnackBar(
- SnackBar(
- content: Text(
- "Copied to clipboard",
- style: context.textTheme.bodyLarge?.copyWith(
- color: context.primaryColor,
- ),
- ),
- ),
- );
- });
- },
- icon: Icon(
- Icons.copy,
- size: 16.0,
- color: context.primaryColor,
- ),
- ),
- ],
- ),
- Container(
- decoration: BoxDecoration(
- color: isDarkTheme ? Colors.grey[900] : Colors.grey[200],
- borderRadius: BorderRadius.circular(15.0),
- ),
- child: Padding(
- padding: const EdgeInsets.all(8.0),
- child: SelectableText(
- message,
+ text,
style: const TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.bold,
@@ -194,11 +127,16 @@ class AppLogDetailPage extends HookConsumerWidget {
body: SafeArea(
child: ListView(
children: [
- buildLogMessage(logMessage.message),
+ buildTextWithCopyButton("MESSAGE", logMessage.message),
+ if (logMessage.details != null)
+ buildTextWithCopyButton("DETAILS", logMessage.details.toString()),
if (logMessage.context1 != null)
buildLogContext1(logMessage.context1.toString()),
if (logMessage.context2 != null)
- buildStackMessage(logMessage.context2.toString()),
+ buildTextWithCopyButton(
+ "STACK TRACE",
+ logMessage.context2.toString(),
+ ),
],
),
),
diff --git a/mobile/lib/shared/views/app_log_page.dart b/mobile/lib/shared/views/app_log_page.dart
index a0c4553f98..993b25c7cf 100644
--- a/mobile/lib/shared/views/app_log_page.dart
+++ b/mobile/lib/shared/views/app_log_page.dart
@@ -69,9 +69,9 @@ class AppLogPage extends HookConsumerWidget {
return Scaffold(
appBar: AppBar(
- title: Text(
- "Logs - ${logMessages.value.length}",
- style: const TextStyle(
+ title: const Text(
+ "Logs",
+ style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16.0,
),
@@ -135,29 +135,15 @@ class AppLogPage extends HookConsumerWidget {
dense: true,
tileColor: getTileColor(logMessage.level),
minLeadingWidth: 10,
- title: Text.rich(
- TextSpan(
- children: [
- TextSpan(
- text: "#$index ",
- style: TextStyle(
- color: isDarkTheme ? Colors.white70 : Colors.grey[600],
- fontSize: 14.0,
- fontWeight: FontWeight.bold,
- ),
- ),
- TextSpan(
- text: truncateLogMessage(logMessage.message, 4),
- style: const TextStyle(
- fontSize: 14.0,
- ),
- ),
- ],
+ title: Text(
+ truncateLogMessage(logMessage.message, 4),
+ style: const TextStyle(
+ fontSize: 14.0,
+ fontFamily: "Inconsolata",
),
- style: const TextStyle(fontSize: 14.0, fontFamily: "Inconsolata"),
),
subtitle: Text(
- "[${logMessage.context1}] Logged on ${DateFormat("HH:mm:ss.SSS").format(logMessage.createdAt)}",
+ "at ${DateFormat("HH:mm:ss.SSS").format(logMessage.createdAt)} in ${logMessage.context1}",
style: TextStyle(
fontSize: 12.0,
color: Colors.grey[600],
diff --git a/mobile/lib/shared/views/immich_loading_overlay.dart b/mobile/lib/shared/views/immich_loading_overlay.dart
index 85f0123ed9..c600d2a724 100644
--- a/mobile/lib/shared/views/immich_loading_overlay.dart
+++ b/mobile/lib/shared/views/immich_loading_overlay.dart
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
-import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
+import 'package:immich_mobile/shared/ui/delayed_loading_indicator.dart';
final _loadingEntry = OverlayEntry(
builder: (context) => SizedBox.square(
@@ -9,7 +9,12 @@ final _loadingEntry = OverlayEntry(
child: DecoratedBox(
decoration:
BoxDecoration(color: context.colorScheme.surface.withAlpha(200)),
- child: const Center(child: ImmichLoadingIndicator()),
+ child: const Center(
+ child: DelayedLoadingIndicator(
+ delay: Duration(seconds: 1),
+ fadeInDuration: Duration(milliseconds: 400),
+ ),
+ ),
),
),
);
@@ -27,19 +32,19 @@ class _LoadingOverlay extends Hook> {
class _LoadingOverlayState
extends HookState, _LoadingOverlay> {
- late final _isProcessing = ValueNotifier(false)..addListener(_listener);
- OverlayEntry? overlayEntry;
+ late final _isLoading = ValueNotifier(false)..addListener(_listener);
+ OverlayEntry? _loadingOverlay;
void _listener() {
setState(() {
WidgetsBinding.instance.addPostFrameCallback((_) {
- if (_isProcessing.value) {
- overlayEntry?.remove();
- overlayEntry = _loadingEntry;
+ if (_isLoading.value) {
+ _loadingOverlay?.remove();
+ _loadingOverlay = _loadingEntry;
Overlay.of(context).insert(_loadingEntry);
} else {
- overlayEntry?.remove();
- overlayEntry = null;
+ _loadingOverlay?.remove();
+ _loadingOverlay = null;
}
});
});
@@ -47,17 +52,17 @@ class _LoadingOverlayState
@override
ValueNotifier build(BuildContext context) {
- return _isProcessing;
+ return _isLoading;
}
@override
void dispose() {
- _isProcessing.dispose();
+ _isLoading.dispose();
super.dispose();
}
@override
- Object? get debugValue => _isProcessing.value;
+ Object? get debugValue => _isLoading.value;
@override
String get debugLabel => 'useProcessingOverlay<>';
diff --git a/mobile/lib/shared/views/splash_screen.dart b/mobile/lib/shared/views/splash_screen.dart
index 8dddb60aaa..3c0d65bde9 100644
--- a/mobile/lib/shared/views/splash_screen.dart
+++ b/mobile/lib/shared/views/splash_screen.dart
@@ -35,10 +35,10 @@ class SplashScreenPage extends HookConsumerWidget {
deviceIsOffline = true;
log.fine("Device seems to be offline upon launch");
} else {
- log.severe(e);
+ log.severe("Failed to resolve endpoint", e);
}
} catch (e) {
- log.severe(e);
+ log.severe("Failed to resolve endpoint", e);
}
try {
@@ -53,7 +53,7 @@ class SplashScreenPage extends HookConsumerWidget {
ref.read(authenticationProvider.notifier).logout();
log.severe(
- 'Cannot set success login info: $error',
+ 'Cannot set success login info',
error,
stackTrace,
);
diff --git a/mobile/openapi/.openapi-generator/FILES b/mobile/openapi/.openapi-generator/FILES
index aeb3d49cb4..ea413b4870 100644
--- a/mobile/openapi/.openapi-generator/FILES
+++ b/mobile/openapi/.openapi-generator/FILES
@@ -90,6 +90,7 @@ doc/MapMarkerResponseDto.md
doc/MapTheme.md
doc/MemoryLaneResponseDto.md
doc/MergePersonDto.md
+doc/MetadataSearchDto.md
doc/ModelType.md
doc/OAuthApi.md
doc/OAuthAuthorizeResponseDto.md
@@ -107,6 +108,7 @@ doc/PersonResponseDto.md
doc/PersonStatisticsResponseDto.md
doc/PersonUpdateDto.md
doc/PersonWithFacesResponseDto.md
+doc/PlacesResponseDto.md
doc/QueueStatusDto.md
doc/ReactionLevel.md
doc/ReactionType.md
@@ -137,6 +139,7 @@ doc/SharedLinkResponseDto.md
doc/SharedLinkType.md
doc/SignUpDto.md
doc/SmartInfoResponseDto.md
+doc/SmartSearchDto.md
doc/SystemConfigApi.md
doc/SystemConfigDto.md
doc/SystemConfigFFmpegDto.md
@@ -180,6 +183,9 @@ doc/UserAvatarColor.md
doc/UserDto.md
doc/UserResponseDto.md
doc/ValidateAccessTokenResponseDto.md
+doc/ValidateLibraryDto.md
+doc/ValidateLibraryImportPathResponseDto.md
+doc/ValidateLibraryResponseDto.md
doc/VideoCodec.md
git_push.sh
lib/api.dart
@@ -288,6 +294,7 @@ lib/model/map_marker_response_dto.dart
lib/model/map_theme.dart
lib/model/memory_lane_response_dto.dart
lib/model/merge_person_dto.dart
+lib/model/metadata_search_dto.dart
lib/model/model_type.dart
lib/model/o_auth_authorize_response_dto.dart
lib/model/o_auth_callback_dto.dart
@@ -302,6 +309,7 @@ lib/model/person_response_dto.dart
lib/model/person_statistics_response_dto.dart
lib/model/person_update_dto.dart
lib/model/person_with_faces_response_dto.dart
+lib/model/places_response_dto.dart
lib/model/queue_status_dto.dart
lib/model/reaction_level.dart
lib/model/reaction_type.dart
@@ -329,6 +337,7 @@ lib/model/shared_link_response_dto.dart
lib/model/shared_link_type.dart
lib/model/sign_up_dto.dart
lib/model/smart_info_response_dto.dart
+lib/model/smart_search_dto.dart
lib/model/system_config_dto.dart
lib/model/system_config_f_fmpeg_dto.dart
lib/model/system_config_job_dto.dart
@@ -368,6 +377,9 @@ lib/model/user_avatar_color.dart
lib/model/user_dto.dart
lib/model/user_response_dto.dart
lib/model/validate_access_token_response_dto.dart
+lib/model/validate_library_dto.dart
+lib/model/validate_library_import_path_response_dto.dart
+lib/model/validate_library_response_dto.dart
lib/model/video_codec.dart
pubspec.yaml
test/activity_api_test.dart
@@ -457,6 +469,7 @@ test/map_marker_response_dto_test.dart
test/map_theme_test.dart
test/memory_lane_response_dto_test.dart
test/merge_person_dto_test.dart
+test/metadata_search_dto_test.dart
test/model_type_test.dart
test/o_auth_api_test.dart
test/o_auth_authorize_response_dto_test.dart
@@ -474,6 +487,7 @@ test/person_response_dto_test.dart
test/person_statistics_response_dto_test.dart
test/person_update_dto_test.dart
test/person_with_faces_response_dto_test.dart
+test/places_response_dto_test.dart
test/queue_status_dto_test.dart
test/reaction_level_test.dart
test/reaction_type_test.dart
@@ -504,6 +518,7 @@ test/shared_link_response_dto_test.dart
test/shared_link_type_test.dart
test/sign_up_dto_test.dart
test/smart_info_response_dto_test.dart
+test/smart_search_dto_test.dart
test/system_config_api_test.dart
test/system_config_dto_test.dart
test/system_config_f_fmpeg_dto_test.dart
@@ -547,4 +562,7 @@ test/user_avatar_color_test.dart
test/user_dto_test.dart
test/user_response_dto_test.dart
test/validate_access_token_response_dto_test.dart
+test/validate_library_dto_test.dart
+test/validate_library_import_path_response_dto_test.dart
+test/validate_library_response_dto_test.dart
test/video_codec_test.dart
diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md
index 12d20ea13d..b8548c79e6 100644
--- a/mobile/openapi/README.md
+++ b/mobile/openapi/README.md
@@ -3,7 +3,7 @@ Immich API
This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
-- API version: 1.94.1
+- API version: 1.97.0
- Build package: org.openapitools.codegen.languages.DartClientCodegen
## Requirements
@@ -135,12 +135,13 @@ Class | Method | HTTP request | Description
*JobApi* | [**sendJobCommand**](doc//JobApi.md#sendjobcommand) | **PUT** /jobs/{id} |
*LibraryApi* | [**createLibrary**](doc//LibraryApi.md#createlibrary) | **POST** /library |
*LibraryApi* | [**deleteLibrary**](doc//LibraryApi.md#deletelibrary) | **DELETE** /library/{id} |
-*LibraryApi* | [**getLibraries**](doc//LibraryApi.md#getlibraries) | **GET** /library |
-*LibraryApi* | [**getLibraryInfo**](doc//LibraryApi.md#getlibraryinfo) | **GET** /library/{id} |
+*LibraryApi* | [**getAllLibraries**](doc//LibraryApi.md#getalllibraries) | **GET** /library |
+*LibraryApi* | [**getLibrary**](doc//LibraryApi.md#getlibrary) | **GET** /library/{id} |
*LibraryApi* | [**getLibraryStatistics**](doc//LibraryApi.md#getlibrarystatistics) | **GET** /library/{id}/statistics |
*LibraryApi* | [**removeOfflineFiles**](doc//LibraryApi.md#removeofflinefiles) | **POST** /library/{id}/removeOffline |
*LibraryApi* | [**scanLibrary**](doc//LibraryApi.md#scanlibrary) | **POST** /library/{id}/scan |
*LibraryApi* | [**updateLibrary**](doc//LibraryApi.md#updatelibrary) | **PUT** /library/{id} |
+*LibraryApi* | [**validate**](doc//LibraryApi.md#validate) | **POST** /library/{id}/validate |
*OAuthApi* | [**finishOAuth**](doc//OAuthApi.md#finishoauth) | **POST** /oauth/callback |
*OAuthApi* | [**linkOAuthAccount**](doc//OAuthApi.md#linkoauthaccount) | **POST** /oauth/link |
*OAuthApi* | [**redirectOAuthToMobile**](doc//OAuthApi.md#redirectoauthtomobile) | **GET** /oauth/mobile-redirect |
@@ -163,9 +164,10 @@ Class | Method | HTTP request | Description
*SearchApi* | [**getExploreData**](doc//SearchApi.md#getexploredata) | **GET** /search/explore |
*SearchApi* | [**getSearchSuggestions**](doc//SearchApi.md#getsearchsuggestions) | **GET** /search/suggestions |
*SearchApi* | [**search**](doc//SearchApi.md#search) | **GET** /search |
-*SearchApi* | [**searchMetadata**](doc//SearchApi.md#searchmetadata) | **GET** /search/metadata |
+*SearchApi* | [**searchMetadata**](doc//SearchApi.md#searchmetadata) | **POST** /search/metadata |
*SearchApi* | [**searchPerson**](doc//SearchApi.md#searchperson) | **GET** /search/person |
-*SearchApi* | [**searchSmart**](doc//SearchApi.md#searchsmart) | **GET** /search/smart |
+*SearchApi* | [**searchPlaces**](doc//SearchApi.md#searchplaces) | **GET** /search/places |
+*SearchApi* | [**searchSmart**](doc//SearchApi.md#searchsmart) | **POST** /search/smart |
*ServerInfoApi* | [**getServerConfig**](doc//ServerInfoApi.md#getserverconfig) | **GET** /server-info/config |
*ServerInfoApi* | [**getServerFeatures**](doc//ServerInfoApi.md#getserverfeatures) | **GET** /server-info/features |
*ServerInfoApi* | [**getServerInfo**](doc//ServerInfoApi.md#getserverinfo) | **GET** /server-info |
@@ -290,6 +292,7 @@ Class | Method | HTTP request | Description
- [MapTheme](doc//MapTheme.md)
- [MemoryLaneResponseDto](doc//MemoryLaneResponseDto.md)
- [MergePersonDto](doc//MergePersonDto.md)
+ - [MetadataSearchDto](doc//MetadataSearchDto.md)
- [ModelType](doc//ModelType.md)
- [OAuthAuthorizeResponseDto](doc//OAuthAuthorizeResponseDto.md)
- [OAuthCallbackDto](doc//OAuthCallbackDto.md)
@@ -304,6 +307,7 @@ Class | Method | HTTP request | Description
- [PersonStatisticsResponseDto](doc//PersonStatisticsResponseDto.md)
- [PersonUpdateDto](doc//PersonUpdateDto.md)
- [PersonWithFacesResponseDto](doc//PersonWithFacesResponseDto.md)
+ - [PlacesResponseDto](doc//PlacesResponseDto.md)
- [QueueStatusDto](doc//QueueStatusDto.md)
- [ReactionLevel](doc//ReactionLevel.md)
- [ReactionType](doc//ReactionType.md)
@@ -331,6 +335,7 @@ Class | Method | HTTP request | Description
- [SharedLinkType](doc//SharedLinkType.md)
- [SignUpDto](doc//SignUpDto.md)
- [SmartInfoResponseDto](doc//SmartInfoResponseDto.md)
+ - [SmartSearchDto](doc//SmartSearchDto.md)
- [SystemConfigDto](doc//SystemConfigDto.md)
- [SystemConfigFFmpegDto](doc//SystemConfigFFmpegDto.md)
- [SystemConfigJobDto](doc//SystemConfigJobDto.md)
@@ -370,6 +375,9 @@ Class | Method | HTTP request | Description
- [UserDto](doc//UserDto.md)
- [UserResponseDto](doc//UserResponseDto.md)
- [ValidateAccessTokenResponseDto](doc//ValidateAccessTokenResponseDto.md)
+ - [ValidateLibraryDto](doc//ValidateLibraryDto.md)
+ - [ValidateLibraryImportPathResponseDto](doc//ValidateLibraryImportPathResponseDto.md)
+ - [ValidateLibraryResponseDto](doc//ValidateLibraryResponseDto.md)
- [VideoCodec](doc//VideoCodec.md)
diff --git a/mobile/openapi/doc/AssetApi.md b/mobile/openapi/doc/AssetApi.md
index 623d88b388..c65e6a605f 100644
--- a/mobile/openapi/doc/AssetApi.md
+++ b/mobile/openapi/doc/AssetApi.md
@@ -659,7 +659,7 @@ This endpoint does not need any parameter.
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **getMapMarkers**
-> List getMapMarkers(fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite)
+> List getMapMarkers(fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite, withPartners)
@@ -686,9 +686,10 @@ final fileCreatedAfter = 2013-10-20T19:20:30+01:00; // DateTime |
final fileCreatedBefore = 2013-10-20T19:20:30+01:00; // DateTime |
final isArchived = true; // bool |
final isFavorite = true; // bool |
+final withPartners = true; // bool |
try {
- final result = api_instance.getMapMarkers(fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite);
+ final result = api_instance.getMapMarkers(fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite, withPartners);
print(result);
} catch (e) {
print('Exception when calling AssetApi->getMapMarkers: $e\n');
@@ -703,6 +704,7 @@ Name | Type | Description | Notes
**fileCreatedBefore** | **DateTime**| | [optional]
**isArchived** | **bool**| | [optional]
**isFavorite** | **bool**| | [optional]
+ **withPartners** | **bool**| | [optional]
### Return type
@@ -1034,7 +1036,7 @@ void (empty response body)
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **searchAssets**
-> List searchAssets(checksum, city, country, createdAfter, createdBefore, deviceAssetId, deviceId, encodedVideoPath, id, isArchived, isEncoded, isExternal, isFavorite, isMotion, isOffline, isReadOnly, isVisible, lensModel, libraryId, make, model, order, originalFileName, originalPath, page, resizePath, size, state, takenAfter, takenBefore, trashedAfter, trashedBefore, type, updatedAfter, updatedBefore, webpPath, withArchived, withDeleted, withExif, withPeople, withStacked)
+> List searchAssets(checksum, city, country, createdAfter, createdBefore, deviceAssetId, deviceId, encodedVideoPath, id, isArchived, isEncoded, isExternal, isFavorite, isMotion, isNotInAlbum, isOffline, isReadOnly, isVisible, lensModel, libraryId, make, model, order, originalFileName, originalPath, page, personIds, resizePath, size, state, takenAfter, takenBefore, trashedAfter, trashedBefore, type, updatedAfter, updatedBefore, webpPath, withArchived, withDeleted, withExif, withPeople, withStacked)
@@ -1071,6 +1073,7 @@ final isEncoded = true; // bool |
final isExternal = true; // bool |
final isFavorite = true; // bool |
final isMotion = true; // bool |
+final isNotInAlbum = true; // bool |
final isOffline = true; // bool |
final isReadOnly = true; // bool |
final isVisible = true; // bool |
@@ -1082,6 +1085,7 @@ final order = ; // AssetOrder |
final originalFileName = originalFileName_example; // String |
final originalPath = originalPath_example; // String |
final page = 8.14; // num |
+final personIds = []; // List |
final resizePath = resizePath_example; // String |
final size = 8.14; // num |
final state = state_example; // String |
@@ -1100,7 +1104,7 @@ final withPeople = true; // bool |
final withStacked = true; // bool |
try {
- final result = api_instance.searchAssets(checksum, city, country, createdAfter, createdBefore, deviceAssetId, deviceId, encodedVideoPath, id, isArchived, isEncoded, isExternal, isFavorite, isMotion, isOffline, isReadOnly, isVisible, lensModel, libraryId, make, model, order, originalFileName, originalPath, page, resizePath, size, state, takenAfter, takenBefore, trashedAfter, trashedBefore, type, updatedAfter, updatedBefore, webpPath, withArchived, withDeleted, withExif, withPeople, withStacked);
+ final result = api_instance.searchAssets(checksum, city, country, createdAfter, createdBefore, deviceAssetId, deviceId, encodedVideoPath, id, isArchived, isEncoded, isExternal, isFavorite, isMotion, isNotInAlbum, isOffline, isReadOnly, isVisible, lensModel, libraryId, make, model, order, originalFileName, originalPath, page, personIds, resizePath, size, state, takenAfter, takenBefore, trashedAfter, trashedBefore, type, updatedAfter, updatedBefore, webpPath, withArchived, withDeleted, withExif, withPeople, withStacked);
print(result);
} catch (e) {
print('Exception when calling AssetApi->searchAssets: $e\n');
@@ -1125,6 +1129,7 @@ Name | Type | Description | Notes
**isExternal** | **bool**| | [optional]
**isFavorite** | **bool**| | [optional]
**isMotion** | **bool**| | [optional]
+ **isNotInAlbum** | **bool**| | [optional]
**isOffline** | **bool**| | [optional]
**isReadOnly** | **bool**| | [optional]
**isVisible** | **bool**| | [optional]
@@ -1136,6 +1141,7 @@ Name | Type | Description | Notes
**originalFileName** | **String**| | [optional]
**originalPath** | **String**| | [optional]
**page** | **num**| | [optional]
+ **personIds** | [**List**](String.md)| | [optional] [default to const []]
**resizePath** | **String**| | [optional]
**size** | **num**| | [optional]
**state** | **String**| | [optional]
@@ -1147,7 +1153,7 @@ Name | Type | Description | Notes
**updatedAfter** | **DateTime**| | [optional]
**updatedBefore** | **DateTime**| | [optional]
**webpPath** | **String**| | [optional]
- **withArchived** | **bool**| | [optional]
+ **withArchived** | **bool**| | [optional] [default to false]
**withDeleted** | **bool**| | [optional]
**withExif** | **bool**| | [optional]
**withPeople** | **bool**| | [optional]
@@ -1395,7 +1401,7 @@ void (empty response body)
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **uploadFile**
-> AssetFileUploadResponseDto uploadFile(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key, duration, isArchived, isExternal, isFavorite, isOffline, isReadOnly, isVisible, libraryId, livePhotoData, sidecarData)
+> AssetFileUploadResponseDto uploadFile(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key, duration, isArchived, isFavorite, isOffline, isReadOnly, isVisible, libraryId, livePhotoData, sidecarData)
@@ -1426,7 +1432,6 @@ final fileModifiedAt = 2013-10-20T19:20:30+01:00; // DateTime |
final key = key_example; // String |
final duration = duration_example; // String |
final isArchived = true; // bool |
-final isExternal = true; // bool |
final isFavorite = true; // bool |
final isOffline = true; // bool |
final isReadOnly = true; // bool |
@@ -1436,7 +1441,7 @@ final livePhotoData = BINARY_DATA_HERE; // MultipartFile |
final sidecarData = BINARY_DATA_HERE; // MultipartFile |
try {
- final result = api_instance.uploadFile(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key, duration, isArchived, isExternal, isFavorite, isOffline, isReadOnly, isVisible, libraryId, livePhotoData, sidecarData);
+ final result = api_instance.uploadFile(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key, duration, isArchived, isFavorite, isOffline, isReadOnly, isVisible, libraryId, livePhotoData, sidecarData);
print(result);
} catch (e) {
print('Exception when calling AssetApi->uploadFile: $e\n');
@@ -1455,7 +1460,6 @@ Name | Type | Description | Notes
**key** | **String**| | [optional]
**duration** | **String**| | [optional]
**isArchived** | **bool**| | [optional]
- **isExternal** | **bool**| | [optional]
**isFavorite** | **bool**| | [optional]
**isOffline** | **bool**| | [optional]
**isReadOnly** | **bool**| | [optional]
diff --git a/mobile/openapi/doc/CreateLibraryDto.md b/mobile/openapi/doc/CreateLibraryDto.md
index 9e4859cee9..e0caf1c8a5 100644
--- a/mobile/openapi/doc/CreateLibraryDto.md
+++ b/mobile/openapi/doc/CreateLibraryDto.md
@@ -13,6 +13,7 @@ Name | Type | Description | Notes
**isVisible** | **bool** | | [optional]
**isWatched** | **bool** | | [optional]
**name** | **String** | | [optional]
+**ownerId** | **String** | | [optional]
**type** | [**LibraryType**](LibraryType.md) | |
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
diff --git a/mobile/openapi/doc/CreateUserDto.md b/mobile/openapi/doc/CreateUserDto.md
index 716571752c..0dcc8eca1f 100644
--- a/mobile/openapi/doc/CreateUserDto.md
+++ b/mobile/openapi/doc/CreateUserDto.md
@@ -9,7 +9,6 @@ import 'package:openapi/api.dart';
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**email** | **String** | |
-**externalPath** | **String** | | [optional]
**memoriesEnabled** | **bool** | | [optional]
**name** | **String** | |
**password** | **String** | |
diff --git a/mobile/openapi/doc/LibraryApi.md b/mobile/openapi/doc/LibraryApi.md
index 5ecd46503a..8a204788bb 100644
--- a/mobile/openapi/doc/LibraryApi.md
+++ b/mobile/openapi/doc/LibraryApi.md
@@ -11,12 +11,13 @@ Method | HTTP request | Description
------------- | ------------- | -------------
[**createLibrary**](LibraryApi.md#createlibrary) | **POST** /library |
[**deleteLibrary**](LibraryApi.md#deletelibrary) | **DELETE** /library/{id} |
-[**getLibraries**](LibraryApi.md#getlibraries) | **GET** /library |
-[**getLibraryInfo**](LibraryApi.md#getlibraryinfo) | **GET** /library/{id} |
+[**getAllLibraries**](LibraryApi.md#getalllibraries) | **GET** /library |
+[**getLibrary**](LibraryApi.md#getlibrary) | **GET** /library/{id} |
[**getLibraryStatistics**](LibraryApi.md#getlibrarystatistics) | **GET** /library/{id}/statistics |
[**removeOfflineFiles**](LibraryApi.md#removeofflinefiles) | **POST** /library/{id}/removeOffline |
[**scanLibrary**](LibraryApi.md#scanlibrary) | **POST** /library/{id}/scan |
[**updateLibrary**](LibraryApi.md#updatelibrary) | **PUT** /library/{id} |
+[**validate**](LibraryApi.md#validate) | **POST** /library/{id}/validate |
# **createLibrary**
@@ -128,8 +129,8 @@ void (empty response body)
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
-# **getLibraries**
-> List getLibraries()
+# **getAllLibraries**
+> List getAllLibraries(type)
@@ -152,17 +153,21 @@ import 'package:openapi/api.dart';
//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction);
final api_instance = LibraryApi();
+final type = ; // LibraryType |
try {
- final result = api_instance.getLibraries();
+ final result = api_instance.getAllLibraries(type);
print(result);
} catch (e) {
- print('Exception when calling LibraryApi->getLibraries: $e\n');
+ print('Exception when calling LibraryApi->getAllLibraries: $e\n');
}
```
### Parameters
-This endpoint does not need any parameter.
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **type** | [**LibraryType**](.md)| | [optional]
### Return type
@@ -179,8 +184,8 @@ This endpoint does not need any parameter.
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
-# **getLibraryInfo**
-> LibraryResponseDto getLibraryInfo(id)
+# **getLibrary**
+> LibraryResponseDto getLibrary(id)
@@ -206,10 +211,10 @@ final api_instance = LibraryApi();
final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
try {
- final result = api_instance.getLibraryInfo(id);
+ final result = api_instance.getLibrary(id);
print(result);
} catch (e) {
- print('Exception when calling LibraryApi->getLibraryInfo: $e\n');
+ print('Exception when calling LibraryApi->getLibrary: $e\n');
}
```
@@ -456,3 +461,60 @@ Name | Type | Description | Notes
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
+# **validate**
+> ValidateLibraryResponseDto validate(id, validateLibraryDto)
+
+
+
+### Example
+```dart
+import 'package:openapi/api.dart';
+// TODO Configure API key authorization: cookie
+//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY';
+// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
+//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer';
+// TODO Configure API key authorization: api_key
+//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY';
+// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
+//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer';
+// TODO Configure HTTP Bearer authorization: bearer
+// Case 1. Use String Token
+//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN');
+// Case 2. Use Function which generate token.
+// String yourTokenGeneratorFunction() { ... }
+//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction);
+
+final api_instance = LibraryApi();
+final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
+final validateLibraryDto = ValidateLibraryDto(); // ValidateLibraryDto |
+
+try {
+ final result = api_instance.validate(id, validateLibraryDto);
+ print(result);
+} catch (e) {
+ print('Exception when calling LibraryApi->validate: $e\n');
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **id** | **String**| |
+ **validateLibraryDto** | [**ValidateLibraryDto**](ValidateLibraryDto.md)| |
+
+### Return type
+
+[**ValidateLibraryResponseDto**](ValidateLibraryResponseDto.md)
+
+### Authorization
+
+[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer)
+
+### HTTP request headers
+
+ - **Content-Type**: application/json
+ - **Accept**: application/json
+
+[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
+
diff --git a/mobile/openapi/doc/MetadataSearchDto.md b/mobile/openapi/doc/MetadataSearchDto.md
new file mode 100644
index 0000000000..d1d098fb0e
--- /dev/null
+++ b/mobile/openapi/doc/MetadataSearchDto.md
@@ -0,0 +1,57 @@
+# openapi.model.MetadataSearchDto
+
+## Load the model package
+```dart
+import 'package:openapi/api.dart';
+```
+
+## Properties
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**checksum** | **String** | | [optional]
+**city** | **String** | | [optional]
+**country** | **String** | | [optional]
+**createdAfter** | [**DateTime**](DateTime.md) | | [optional]
+**createdBefore** | [**DateTime**](DateTime.md) | | [optional]
+**deviceAssetId** | **String** | | [optional]
+**deviceId** | **String** | | [optional]
+**encodedVideoPath** | **String** | | [optional]
+**id** | **String** | | [optional]
+**isArchived** | **bool** | | [optional]
+**isEncoded** | **bool** | | [optional]
+**isExternal** | **bool** | | [optional]
+**isFavorite** | **bool** | | [optional]
+**isMotion** | **bool** | | [optional]
+**isNotInAlbum** | **bool** | | [optional]
+**isOffline** | **bool** | | [optional]
+**isReadOnly** | **bool** | | [optional]
+**isVisible** | **bool** | | [optional]
+**lensModel** | **String** | | [optional]
+**libraryId** | **String** | | [optional]
+**make** | **String** | | [optional]
+**model** | **String** | | [optional]
+**order** | [**AssetOrder**](AssetOrder.md) | | [optional]
+**originalFileName** | **String** | | [optional]
+**originalPath** | **String** | | [optional]
+**page** | **num** | | [optional]
+**personIds** | **List** | | [optional] [default to const []]
+**resizePath** | **String** | | [optional]
+**size** | **num** | | [optional]
+**state** | **String** | | [optional]
+**takenAfter** | [**DateTime**](DateTime.md) | | [optional]
+**takenBefore** | [**DateTime**](DateTime.md) | | [optional]
+**trashedAfter** | [**DateTime**](DateTime.md) | | [optional]
+**trashedBefore** | [**DateTime**](DateTime.md) | | [optional]
+**type** | [**AssetTypeEnum**](AssetTypeEnum.md) | | [optional]
+**updatedAfter** | [**DateTime**](DateTime.md) | | [optional]
+**updatedBefore** | [**DateTime**](DateTime.md) | | [optional]
+**webpPath** | **String** | | [optional]
+**withArchived** | **bool** | | [optional] [default to false]
+**withDeleted** | **bool** | | [optional]
+**withExif** | **bool** | | [optional]
+**withPeople** | **bool** | | [optional]
+**withStacked** | **bool** | | [optional]
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
+
+
diff --git a/mobile/openapi/doc/PartnerResponseDto.md b/mobile/openapi/doc/PartnerResponseDto.md
index 46d16e6b28..ce45b32594 100644
--- a/mobile/openapi/doc/PartnerResponseDto.md
+++ b/mobile/openapi/doc/PartnerResponseDto.md
@@ -12,7 +12,6 @@ Name | Type | Description | Notes
**createdAt** | [**DateTime**](DateTime.md) | |
**deletedAt** | [**DateTime**](DateTime.md) | |
**email** | **String** | |
-**externalPath** | **String** | |
**id** | **String** | |
**inTimeline** | **bool** | | [optional]
**isAdmin** | **bool** | |
diff --git a/mobile/openapi/doc/PeopleResponseDto.md b/mobile/openapi/doc/PeopleResponseDto.md
index 2f87f19993..78f9b2207c 100644
--- a/mobile/openapi/doc/PeopleResponseDto.md
+++ b/mobile/openapi/doc/PeopleResponseDto.md
@@ -8,6 +8,7 @@ import 'package:openapi/api.dart';
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
+**hidden** | **int** | |
**people** | [**List**](PersonResponseDto.md) | | [default to const []]
**total** | **int** | |
diff --git a/mobile/openapi/doc/PlacesResponseDto.md b/mobile/openapi/doc/PlacesResponseDto.md
new file mode 100644
index 0000000000..a4bf36493c
--- /dev/null
+++ b/mobile/openapi/doc/PlacesResponseDto.md
@@ -0,0 +1,19 @@
+# openapi.model.PlacesResponseDto
+
+## Load the model package
+```dart
+import 'package:openapi/api.dart';
+```
+
+## Properties
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**admin1name** | **String** | | [optional]
+**admin2name** | **String** | | [optional]
+**latitude** | **num** | |
+**longitude** | **num** | |
+**name** | **String** | |
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
+
+
diff --git a/mobile/openapi/doc/SearchApi.md b/mobile/openapi/doc/SearchApi.md
index 8c924428f6..f63488222b 100644
--- a/mobile/openapi/doc/SearchApi.md
+++ b/mobile/openapi/doc/SearchApi.md
@@ -12,9 +12,10 @@ Method | HTTP request | Description
[**getExploreData**](SearchApi.md#getexploredata) | **GET** /search/explore |
[**getSearchSuggestions**](SearchApi.md#getsearchsuggestions) | **GET** /search/suggestions |
[**search**](SearchApi.md#search) | **GET** /search |
-[**searchMetadata**](SearchApi.md#searchmetadata) | **GET** /search/metadata |
+[**searchMetadata**](SearchApi.md#searchmetadata) | **POST** /search/metadata |
[**searchPerson**](SearchApi.md#searchperson) | **GET** /search/person |
-[**searchSmart**](SearchApi.md#searchsmart) | **GET** /search/smart |
+[**searchPlaces**](SearchApi.md#searchplaces) | **GET** /search/places |
+[**searchSmart**](SearchApi.md#searchsmart) | **POST** /search/smart |
# **getExploreData**
@@ -205,7 +206,7 @@ Name | Type | Description | Notes
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **searchMetadata**
-> SearchResponseDto searchMetadata(checksum, city, country, createdAfter, createdBefore, deviceAssetId, deviceId, encodedVideoPath, id, isArchived, isEncoded, isExternal, isFavorite, isMotion, isOffline, isReadOnly, isVisible, lensModel, libraryId, make, model, order, originalFileName, originalPath, page, resizePath, size, state, takenAfter, takenBefore, trashedAfter, trashedBefore, type, updatedAfter, updatedBefore, webpPath, withArchived, withDeleted, withExif, withPeople, withStacked)
+> SearchResponseDto searchMetadata(metadataSearchDto)
@@ -228,50 +229,10 @@ import 'package:openapi/api.dart';
//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction);
final api_instance = SearchApi();
-final checksum = checksum_example; // String |
-final city = city_example; // String |
-final country = country_example; // String |
-final createdAfter = 2013-10-20T19:20:30+01:00; // DateTime |
-final createdBefore = 2013-10-20T19:20:30+01:00; // DateTime |
-final deviceAssetId = deviceAssetId_example; // String |
-final deviceId = deviceId_example; // String |
-final encodedVideoPath = encodedVideoPath_example; // String |
-final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
-final isArchived = true; // bool |
-final isEncoded = true; // bool |
-final isExternal = true; // bool |
-final isFavorite = true; // bool |
-final isMotion = true; // bool |
-final isOffline = true; // bool |
-final isReadOnly = true; // bool |
-final isVisible = true; // bool |
-final lensModel = lensModel_example; // String |
-final libraryId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
-final make = make_example; // String |
-final model = model_example; // String |
-final order = ; // AssetOrder |
-final originalFileName = originalFileName_example; // String |
-final originalPath = originalPath_example; // String |
-final page = 8.14; // num |
-final resizePath = resizePath_example; // String |
-final size = 8.14; // num |
-final state = state_example; // String |
-final takenAfter = 2013-10-20T19:20:30+01:00; // DateTime |
-final takenBefore = 2013-10-20T19:20:30+01:00; // DateTime |
-final trashedAfter = 2013-10-20T19:20:30+01:00; // DateTime |
-final trashedBefore = 2013-10-20T19:20:30+01:00; // DateTime |
-final type = ; // AssetTypeEnum |
-final updatedAfter = 2013-10-20T19:20:30+01:00; // DateTime |
-final updatedBefore = 2013-10-20T19:20:30+01:00; // DateTime |
-final webpPath = webpPath_example; // String |
-final withArchived = true; // bool |
-final withDeleted = true; // bool |
-final withExif = true; // bool |
-final withPeople = true; // bool |
-final withStacked = true; // bool |
+final metadataSearchDto = MetadataSearchDto(); // MetadataSearchDto |
try {
- final result = api_instance.searchMetadata(checksum, city, country, createdAfter, createdBefore, deviceAssetId, deviceId, encodedVideoPath, id, isArchived, isEncoded, isExternal, isFavorite, isMotion, isOffline, isReadOnly, isVisible, lensModel, libraryId, make, model, order, originalFileName, originalPath, page, resizePath, size, state, takenAfter, takenBefore, trashedAfter, trashedBefore, type, updatedAfter, updatedBefore, webpPath, withArchived, withDeleted, withExif, withPeople, withStacked);
+ final result = api_instance.searchMetadata(metadataSearchDto);
print(result);
} catch (e) {
print('Exception when calling SearchApi->searchMetadata: $e\n');
@@ -282,47 +243,7 @@ try {
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
- **checksum** | **String**| | [optional]
- **city** | **String**| | [optional]
- **country** | **String**| | [optional]
- **createdAfter** | **DateTime**| | [optional]
- **createdBefore** | **DateTime**| | [optional]
- **deviceAssetId** | **String**| | [optional]
- **deviceId** | **String**| | [optional]
- **encodedVideoPath** | **String**| | [optional]
- **id** | **String**| | [optional]
- **isArchived** | **bool**| | [optional]
- **isEncoded** | **bool**| | [optional]
- **isExternal** | **bool**| | [optional]
- **isFavorite** | **bool**| | [optional]
- **isMotion** | **bool**| | [optional]
- **isOffline** | **bool**| | [optional]
- **isReadOnly** | **bool**| | [optional]
- **isVisible** | **bool**| | [optional]
- **lensModel** | **String**| | [optional]
- **libraryId** | **String**| | [optional]
- **make** | **String**| | [optional]
- **model** | **String**| | [optional]
- **order** | [**AssetOrder**](.md)| | [optional]
- **originalFileName** | **String**| | [optional]
- **originalPath** | **String**| | [optional]
- **page** | **num**| | [optional]
- **resizePath** | **String**| | [optional]
- **size** | **num**| | [optional]
- **state** | **String**| | [optional]
- **takenAfter** | **DateTime**| | [optional]
- **takenBefore** | **DateTime**| | [optional]
- **trashedAfter** | **DateTime**| | [optional]
- **trashedBefore** | **DateTime**| | [optional]
- **type** | [**AssetTypeEnum**](.md)| | [optional]
- **updatedAfter** | **DateTime**| | [optional]
- **updatedBefore** | **DateTime**| | [optional]
- **webpPath** | **String**| | [optional]
- **withArchived** | **bool**| | [optional]
- **withDeleted** | **bool**| | [optional]
- **withExif** | **bool**| | [optional]
- **withPeople** | **bool**| | [optional]
- **withStacked** | **bool**| | [optional]
+ **metadataSearchDto** | [**MetadataSearchDto**](MetadataSearchDto.md)| |
### Return type
@@ -334,7 +255,7 @@ Name | Type | Description | Notes
### HTTP request headers
- - **Content-Type**: Not defined
+ - **Content-Type**: application/json
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
@@ -396,8 +317,8 @@ Name | Type | Description | Notes
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
-# **searchSmart**
-> SearchResponseDto searchSmart(query, city, country, createdAfter, createdBefore, deviceId, isArchived, isEncoded, isExternal, isFavorite, isMotion, isOffline, isReadOnly, isVisible, lensModel, libraryId, make, model, page, size, state, takenAfter, takenBefore, trashedAfter, trashedBefore, type, updatedAfter, updatedBefore, withArchived, withDeleted, withExif)
+# **searchPlaces**
+> List searchPlaces(name)
@@ -420,43 +341,13 @@ import 'package:openapi/api.dart';
//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction);
final api_instance = SearchApi();
-final query = query_example; // String |
-final city = city_example; // String |
-final country = country_example; // String |
-final createdAfter = 2013-10-20T19:20:30+01:00; // DateTime |
-final createdBefore = 2013-10-20T19:20:30+01:00; // DateTime |
-final deviceId = deviceId_example; // String |
-final isArchived = true; // bool |
-final isEncoded = true; // bool |
-final isExternal = true; // bool |
-final isFavorite = true; // bool |
-final isMotion = true; // bool |
-final isOffline = true; // bool |
-final isReadOnly = true; // bool |
-final isVisible = true; // bool |
-final lensModel = lensModel_example; // String |
-final libraryId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
-final make = make_example; // String |
-final model = model_example; // String |
-final page = 8.14; // num |
-final size = 8.14; // num |
-final state = state_example; // String |
-final takenAfter = 2013-10-20T19:20:30+01:00; // DateTime |
-final takenBefore = 2013-10-20T19:20:30+01:00; // DateTime |
-final trashedAfter = 2013-10-20T19:20:30+01:00; // DateTime |
-final trashedBefore = 2013-10-20T19:20:30+01:00; // DateTime |
-final type = ; // AssetTypeEnum |
-final updatedAfter = 2013-10-20T19:20:30+01:00; // DateTime |
-final updatedBefore = 2013-10-20T19:20:30+01:00; // DateTime |
-final withArchived = true; // bool |
-final withDeleted = true; // bool |
-final withExif = true; // bool |
+final name = name_example; // String |
try {
- final result = api_instance.searchSmart(query, city, country, createdAfter, createdBefore, deviceId, isArchived, isEncoded, isExternal, isFavorite, isMotion, isOffline, isReadOnly, isVisible, lensModel, libraryId, make, model, page, size, state, takenAfter, takenBefore, trashedAfter, trashedBefore, type, updatedAfter, updatedBefore, withArchived, withDeleted, withExif);
+ final result = api_instance.searchPlaces(name);
print(result);
} catch (e) {
- print('Exception when calling SearchApi->searchSmart: $e\n');
+ print('Exception when calling SearchApi->searchPlaces: $e\n');
}
```
@@ -464,41 +355,11 @@ try {
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
- **query** | **String**| |
- **city** | **String**| | [optional]
- **country** | **String**| | [optional]
- **createdAfter** | **DateTime**| | [optional]
- **createdBefore** | **DateTime**| | [optional]
- **deviceId** | **String**| | [optional]
- **isArchived** | **bool**| | [optional]
- **isEncoded** | **bool**| | [optional]
- **isExternal** | **bool**| | [optional]
- **isFavorite** | **bool**| | [optional]
- **isMotion** | **bool**| | [optional]
- **isOffline** | **bool**| | [optional]
- **isReadOnly** | **bool**| | [optional]
- **isVisible** | **bool**| | [optional]
- **lensModel** | **String**| | [optional]
- **libraryId** | **String**| | [optional]
- **make** | **String**| | [optional]
- **model** | **String**| | [optional]
- **page** | **num**| | [optional]
- **size** | **num**| | [optional]
- **state** | **String**| | [optional]
- **takenAfter** | **DateTime**| | [optional]
- **takenBefore** | **DateTime**| | [optional]
- **trashedAfter** | **DateTime**| | [optional]
- **trashedBefore** | **DateTime**| | [optional]
- **type** | [**AssetTypeEnum**](.md)| | [optional]
- **updatedAfter** | **DateTime**| | [optional]
- **updatedBefore** | **DateTime**| | [optional]
- **withArchived** | **bool**| | [optional]
- **withDeleted** | **bool**| | [optional]
- **withExif** | **bool**| | [optional]
+ **name** | **String**| |
### Return type
-[**SearchResponseDto**](SearchResponseDto.md)
+[**List**](PlacesResponseDto.md)
### Authorization
@@ -511,3 +372,58 @@ Name | Type | Description | Notes
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
+# **searchSmart**
+> SearchResponseDto searchSmart(smartSearchDto)
+
+
+
+### Example
+```dart
+import 'package:openapi/api.dart';
+// TODO Configure API key authorization: cookie
+//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY';
+// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
+//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer';
+// TODO Configure API key authorization: api_key
+//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY';
+// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
+//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer';
+// TODO Configure HTTP Bearer authorization: bearer
+// Case 1. Use String Token
+//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN');
+// Case 2. Use Function which generate token.
+// String yourTokenGeneratorFunction() { ... }
+//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction);
+
+final api_instance = SearchApi();
+final smartSearchDto = SmartSearchDto(); // SmartSearchDto |
+
+try {
+ final result = api_instance.searchSmart(smartSearchDto);
+ print(result);
+} catch (e) {
+ print('Exception when calling SearchApi->searchSmart: $e\n');
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **smartSearchDto** | [**SmartSearchDto**](SmartSearchDto.md)| |
+
+### Return type
+
+[**SearchResponseDto**](SearchResponseDto.md)
+
+### Authorization
+
+[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer)
+
+### HTTP request headers
+
+ - **Content-Type**: application/json
+ - **Accept**: application/json
+
+[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
+
diff --git a/mobile/openapi/doc/SmartSearchDto.md b/mobile/openapi/doc/SmartSearchDto.md
new file mode 100644
index 0000000000..d5f4c40256
--- /dev/null
+++ b/mobile/openapi/doc/SmartSearchDto.md
@@ -0,0 +1,47 @@
+# openapi.model.SmartSearchDto
+
+## Load the model package
+```dart
+import 'package:openapi/api.dart';
+```
+
+## Properties
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**city** | **String** | | [optional]
+**country** | **String** | | [optional]
+**createdAfter** | [**DateTime**](DateTime.md) | | [optional]
+**createdBefore** | [**DateTime**](DateTime.md) | | [optional]
+**deviceId** | **String** | | [optional]
+**isArchived** | **bool** | | [optional]
+**isEncoded** | **bool** | | [optional]
+**isExternal** | **bool** | | [optional]
+**isFavorite** | **bool** | | [optional]
+**isMotion** | **bool** | | [optional]
+**isNotInAlbum** | **bool** | | [optional]
+**isOffline** | **bool** | | [optional]
+**isReadOnly** | **bool** | | [optional]
+**isVisible** | **bool** | | [optional]
+**lensModel** | **String** | | [optional]
+**libraryId** | **String** | | [optional]
+**make** | **String** | | [optional]
+**model** | **String** | | [optional]
+**page** | **num** | | [optional]
+**personIds** | **List** | | [optional] [default to const []]
+**query** | **String** | |
+**size** | **num** | | [optional]
+**state** | **String** | | [optional]
+**takenAfter** | [**DateTime**](DateTime.md) | | [optional]
+**takenBefore** | [**DateTime**](DateTime.md) | | [optional]
+**trashedAfter** | [**DateTime**](DateTime.md) | | [optional]
+**trashedBefore** | [**DateTime**](DateTime.md) | | [optional]
+**type** | [**AssetTypeEnum**](AssetTypeEnum.md) | | [optional]
+**updatedAfter** | [**DateTime**](DateTime.md) | | [optional]
+**updatedBefore** | [**DateTime**](DateTime.md) | | [optional]
+**withArchived** | **bool** | | [optional] [default to false]
+**withDeleted** | **bool** | | [optional]
+**withExif** | **bool** | | [optional]
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
+
+
diff --git a/mobile/openapi/doc/SystemConfigLibraryWatchDto.md b/mobile/openapi/doc/SystemConfigLibraryWatchDto.md
index baa0be6b08..43b975e21a 100644
--- a/mobile/openapi/doc/SystemConfigLibraryWatchDto.md
+++ b/mobile/openapi/doc/SystemConfigLibraryWatchDto.md
@@ -9,8 +9,6 @@ import 'package:openapi/api.dart';
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**enabled** | **bool** | |
-**interval** | **int** | |
-**usePolling** | **bool** | |
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
diff --git a/mobile/openapi/doc/SystemConfigOAuthDto.md b/mobile/openapi/doc/SystemConfigOAuthDto.md
index c02dae9b73..43694f6fc2 100644
--- a/mobile/openapi/doc/SystemConfigOAuthDto.md
+++ b/mobile/openapi/doc/SystemConfigOAuthDto.md
@@ -13,6 +13,7 @@ Name | Type | Description | Notes
**buttonText** | **String** | |
**clientId** | **String** | |
**clientSecret** | **String** | |
+**defaultStorageQuota** | **num** | |
**enabled** | **bool** | |
**issuerUrl** | **String** | |
**mobileOverrideEnabled** | **bool** | |
@@ -20,6 +21,7 @@ Name | Type | Description | Notes
**scope** | **String** | |
**signingAlgorithm** | **String** | |
**storageLabelClaim** | **String** | |
+**storageQuotaClaim** | **String** | |
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
diff --git a/mobile/openapi/doc/UpdateUserDto.md b/mobile/openapi/doc/UpdateUserDto.md
index 8c0572d1d2..ef4ebf869b 100644
--- a/mobile/openapi/doc/UpdateUserDto.md
+++ b/mobile/openapi/doc/UpdateUserDto.md
@@ -10,7 +10,6 @@ Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**avatarColor** | [**UserAvatarColor**](UserAvatarColor.md) | | [optional]
**email** | **String** | | [optional]
-**externalPath** | **String** | | [optional]
**id** | **String** | |
**isAdmin** | **bool** | | [optional]
**memoriesEnabled** | **bool** | | [optional]
diff --git a/mobile/openapi/doc/UserResponseDto.md b/mobile/openapi/doc/UserResponseDto.md
index 4ea44bb0cb..700a5b849e 100644
--- a/mobile/openapi/doc/UserResponseDto.md
+++ b/mobile/openapi/doc/UserResponseDto.md
@@ -12,7 +12,6 @@ Name | Type | Description | Notes
**createdAt** | [**DateTime**](DateTime.md) | |
**deletedAt** | [**DateTime**](DateTime.md) | |
**email** | **String** | |
-**externalPath** | **String** | |
**id** | **String** | |
**isAdmin** | **bool** | |
**memoriesEnabled** | **bool** | | [optional]
diff --git a/mobile/openapi/doc/ValidateLibraryDto.md b/mobile/openapi/doc/ValidateLibraryDto.md
new file mode 100644
index 0000000000..13c74a6a66
--- /dev/null
+++ b/mobile/openapi/doc/ValidateLibraryDto.md
@@ -0,0 +1,16 @@
+# openapi.model.ValidateLibraryDto
+
+## Load the model package
+```dart
+import 'package:openapi/api.dart';
+```
+
+## Properties
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**exclusionPatterns** | **List** | | [optional] [default to const []]
+**importPaths** | **List** | | [optional] [default to const []]
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
+
+
diff --git a/mobile/openapi/doc/ValidateLibraryImportPathResponseDto.md b/mobile/openapi/doc/ValidateLibraryImportPathResponseDto.md
new file mode 100644
index 0000000000..4601d8d2f2
--- /dev/null
+++ b/mobile/openapi/doc/ValidateLibraryImportPathResponseDto.md
@@ -0,0 +1,17 @@
+# openapi.model.ValidateLibraryImportPathResponseDto
+
+## Load the model package
+```dart
+import 'package:openapi/api.dart';
+```
+
+## Properties
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**importPath** | **String** | |
+**isValid** | **bool** | | [optional] [default to false]
+**message** | **String** | | [optional]
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
+
+
diff --git a/mobile/openapi/doc/ValidateLibraryResponseDto.md b/mobile/openapi/doc/ValidateLibraryResponseDto.md
new file mode 100644
index 0000000000..7b22fdfe90
--- /dev/null
+++ b/mobile/openapi/doc/ValidateLibraryResponseDto.md
@@ -0,0 +1,15 @@
+# openapi.model.ValidateLibraryResponseDto
+
+## Load the model package
+```dart
+import 'package:openapi/api.dart';
+```
+
+## Properties
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**importPaths** | [**List**](ValidateLibraryImportPathResponseDto.md) | | [optional] [default to const []]
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
+
+
diff --git a/mobile/openapi/lib/api.dart b/mobile/openapi/lib/api.dart
index f2903e3516..56bd907e0a 100644
--- a/mobile/openapi/lib/api.dart
+++ b/mobile/openapi/lib/api.dart
@@ -127,6 +127,7 @@ part 'model/map_marker_response_dto.dart';
part 'model/map_theme.dart';
part 'model/memory_lane_response_dto.dart';
part 'model/merge_person_dto.dart';
+part 'model/metadata_search_dto.dart';
part 'model/model_type.dart';
part 'model/o_auth_authorize_response_dto.dart';
part 'model/o_auth_callback_dto.dart';
@@ -141,6 +142,7 @@ part 'model/person_response_dto.dart';
part 'model/person_statistics_response_dto.dart';
part 'model/person_update_dto.dart';
part 'model/person_with_faces_response_dto.dart';
+part 'model/places_response_dto.dart';
part 'model/queue_status_dto.dart';
part 'model/reaction_level.dart';
part 'model/reaction_type.dart';
@@ -168,6 +170,7 @@ part 'model/shared_link_response_dto.dart';
part 'model/shared_link_type.dart';
part 'model/sign_up_dto.dart';
part 'model/smart_info_response_dto.dart';
+part 'model/smart_search_dto.dart';
part 'model/system_config_dto.dart';
part 'model/system_config_f_fmpeg_dto.dart';
part 'model/system_config_job_dto.dart';
@@ -207,6 +210,9 @@ part 'model/user_avatar_color.dart';
part 'model/user_dto.dart';
part 'model/user_response_dto.dart';
part 'model/validate_access_token_response_dto.dart';
+part 'model/validate_library_dto.dart';
+part 'model/validate_library_import_path_response_dto.dart';
+part 'model/validate_library_response_dto.dart';
part 'model/video_codec.dart';
diff --git a/mobile/openapi/lib/api/asset_api.dart b/mobile/openapi/lib/api/asset_api.dart
index 4dec34d407..786129b457 100644
--- a/mobile/openapi/lib/api/asset_api.dart
+++ b/mobile/openapi/lib/api/asset_api.dart
@@ -652,7 +652,9 @@ class AssetApi {
/// * [bool] isArchived:
///
/// * [bool] isFavorite:
- Future getMapMarkersWithHttpInfo({ DateTime? fileCreatedAfter, DateTime? fileCreatedBefore, bool? isArchived, bool? isFavorite, }) async {
+ ///
+ /// * [bool] withPartners:
+ Future getMapMarkersWithHttpInfo({ DateTime? fileCreatedAfter, DateTime? fileCreatedBefore, bool? isArchived, bool? isFavorite, bool? withPartners, }) async {
// ignore: prefer_const_declarations
final path = r'/asset/map-marker';
@@ -675,6 +677,9 @@ class AssetApi {
if (isFavorite != null) {
queryParams.addAll(_queryParams('', 'isFavorite', isFavorite));
}
+ if (withPartners != null) {
+ queryParams.addAll(_queryParams('', 'withPartners', withPartners));
+ }
const contentTypes = [];
@@ -699,8 +704,10 @@ class AssetApi {
/// * [bool] isArchived:
///
/// * [bool] isFavorite:
- Future?> getMapMarkers({ DateTime? fileCreatedAfter, DateTime? fileCreatedBefore, bool? isArchived, bool? isFavorite, }) async {
- final response = await getMapMarkersWithHttpInfo( fileCreatedAfter: fileCreatedAfter, fileCreatedBefore: fileCreatedBefore, isArchived: isArchived, isFavorite: isFavorite, );
+ ///
+ /// * [bool] withPartners:
+ Future?> getMapMarkers({ DateTime? fileCreatedAfter, DateTime? fileCreatedBefore, bool? isArchived, bool? isFavorite, bool? withPartners, }) async {
+ final response = await getMapMarkersWithHttpInfo( fileCreatedAfter: fileCreatedAfter, fileCreatedBefore: fileCreatedBefore, isArchived: isArchived, isFavorite: isFavorite, withPartners: withPartners, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
@@ -1133,6 +1140,8 @@ class AssetApi {
///
/// * [bool] isMotion:
///
+ /// * [bool] isNotInAlbum:
+ ///
/// * [bool] isOffline:
///
/// * [bool] isReadOnly:
@@ -1155,6 +1164,8 @@ class AssetApi {
///
/// * [num] page:
///
+ /// * [List] personIds:
+ ///
/// * [String] resizePath:
///
/// * [num] size:
@@ -1186,7 +1197,7 @@ class AssetApi {
/// * [bool] withPeople:
///
/// * [bool] withStacked:
- Future searchAssetsWithHttpInfo({ String? checksum, String? city, String? country, DateTime? createdAfter, DateTime? createdBefore, String? deviceAssetId, String? deviceId, String? encodedVideoPath, String? id, bool? isArchived, bool? isEncoded, bool? isExternal, bool? isFavorite, bool? isMotion, bool? isOffline, bool? isReadOnly, bool? isVisible, String? lensModel, String? libraryId, String? make, String? model, AssetOrder? order, String? originalFileName, String? originalPath, num? page, String? resizePath, num? size, String? state, DateTime? takenAfter, DateTime? takenBefore, DateTime? trashedAfter, DateTime? trashedBefore, AssetTypeEnum? type, DateTime? updatedAfter, DateTime? updatedBefore, String? webpPath, bool? withArchived, bool? withDeleted, bool? withExif, bool? withPeople, bool? withStacked, }) async {
+ Future searchAssetsWithHttpInfo({ String? checksum, String? city, String? country, DateTime? createdAfter, DateTime? createdBefore, String? deviceAssetId, String? deviceId, String? encodedVideoPath, String? id, bool? isArchived, bool? isEncoded, bool? isExternal, bool? isFavorite, bool? isMotion, bool? isNotInAlbum, bool? isOffline, bool? isReadOnly, bool? isVisible, String? lensModel, String? libraryId, String? make, String? model, AssetOrder? order, String? originalFileName, String? originalPath, num? page, List? personIds, String? resizePath, num? size, String? state, DateTime? takenAfter, DateTime? takenBefore, DateTime? trashedAfter, DateTime? trashedBefore, AssetTypeEnum? type, DateTime? updatedAfter, DateTime? updatedBefore, String? webpPath, bool? withArchived, bool? withDeleted, bool? withExif, bool? withPeople, bool? withStacked, }) async {
// ignore: prefer_const_declarations
final path = r'/assets';
@@ -1239,6 +1250,9 @@ class AssetApi {
if (isMotion != null) {
queryParams.addAll(_queryParams('', 'isMotion', isMotion));
}
+ if (isNotInAlbum != null) {
+ queryParams.addAll(_queryParams('', 'isNotInAlbum', isNotInAlbum));
+ }
if (isOffline != null) {
queryParams.addAll(_queryParams('', 'isOffline', isOffline));
}
@@ -1272,6 +1286,9 @@ class AssetApi {
if (page != null) {
queryParams.addAll(_queryParams('', 'page', page));
}
+ if (personIds != null) {
+ queryParams.addAll(_queryParams('multi', 'personIds', personIds));
+ }
if (resizePath != null) {
queryParams.addAll(_queryParams('', 'resizePath', resizePath));
}
@@ -1365,6 +1382,8 @@ class AssetApi {
///
/// * [bool] isMotion:
///
+ /// * [bool] isNotInAlbum:
+ ///
/// * [bool] isOffline:
///
/// * [bool] isReadOnly:
@@ -1387,6 +1406,8 @@ class AssetApi {
///
/// * [num] page:
///
+ /// * [List] personIds:
+ ///
/// * [String] resizePath:
///
/// * [num] size:
@@ -1418,8 +1439,8 @@ class AssetApi {
/// * [bool] withPeople:
///
/// * [bool] withStacked:
- Future?> searchAssets({ String? checksum, String? city, String? country, DateTime? createdAfter, DateTime? createdBefore, String? deviceAssetId, String? deviceId, String? encodedVideoPath, String? id, bool? isArchived, bool? isEncoded, bool? isExternal, bool? isFavorite, bool? isMotion, bool? isOffline, bool? isReadOnly, bool? isVisible, String? lensModel, String? libraryId, String? make, String? model, AssetOrder? order, String? originalFileName, String? originalPath, num? page, String? resizePath, num? size, String? state, DateTime? takenAfter, DateTime? takenBefore, DateTime? trashedAfter, DateTime? trashedBefore, AssetTypeEnum? type, DateTime? updatedAfter, DateTime? updatedBefore, String? webpPath, bool? withArchived, bool? withDeleted, bool? withExif, bool? withPeople, bool? withStacked, }) async {
- final response = await searchAssetsWithHttpInfo( checksum: checksum, city: city, country: country, createdAfter: createdAfter, createdBefore: createdBefore, deviceAssetId: deviceAssetId, deviceId: deviceId, encodedVideoPath: encodedVideoPath, id: id, isArchived: isArchived, isEncoded: isEncoded, isExternal: isExternal, isFavorite: isFavorite, isMotion: isMotion, isOffline: isOffline, isReadOnly: isReadOnly, isVisible: isVisible, lensModel: lensModel, libraryId: libraryId, make: make, model: model, order: order, originalFileName: originalFileName, originalPath: originalPath, page: page, resizePath: resizePath, size: size, state: state, takenAfter: takenAfter, takenBefore: takenBefore, trashedAfter: trashedAfter, trashedBefore: trashedBefore, type: type, updatedAfter: updatedAfter, updatedBefore: updatedBefore, webpPath: webpPath, withArchived: withArchived, withDeleted: withDeleted, withExif: withExif, withPeople: withPeople, withStacked: withStacked, );
+ Future?> searchAssets({ String? checksum, String? city, String? country, DateTime? createdAfter, DateTime? createdBefore, String? deviceAssetId, String? deviceId, String? encodedVideoPath, String? id, bool? isArchived, bool? isEncoded, bool? isExternal, bool? isFavorite, bool? isMotion, bool? isNotInAlbum, bool? isOffline, bool? isReadOnly, bool? isVisible, String? lensModel, String? libraryId, String? make, String? model, AssetOrder? order, String? originalFileName, String? originalPath, num? page, List? personIds, String? resizePath, num? size, String? state, DateTime? takenAfter, DateTime? takenBefore, DateTime? trashedAfter, DateTime? trashedBefore, AssetTypeEnum? type, DateTime? updatedAfter, DateTime? updatedBefore, String? webpPath, bool? withArchived, bool? withDeleted, bool? withExif, bool? withPeople, bool? withStacked, }) async {
+ final response = await searchAssetsWithHttpInfo( checksum: checksum, city: city, country: country, createdAfter: createdAfter, createdBefore: createdBefore, deviceAssetId: deviceAssetId, deviceId: deviceId, encodedVideoPath: encodedVideoPath, id: id, isArchived: isArchived, isEncoded: isEncoded, isExternal: isExternal, isFavorite: isFavorite, isMotion: isMotion, isNotInAlbum: isNotInAlbum, isOffline: isOffline, isReadOnly: isReadOnly, isVisible: isVisible, lensModel: lensModel, libraryId: libraryId, make: make, model: model, order: order, originalFileName: originalFileName, originalPath: originalPath, page: page, personIds: personIds, resizePath: resizePath, size: size, state: state, takenAfter: takenAfter, takenBefore: takenBefore, trashedAfter: trashedAfter, trashedBefore: trashedBefore, type: type, updatedAfter: updatedAfter, updatedBefore: updatedBefore, webpPath: webpPath, withArchived: withArchived, withDeleted: withDeleted, withExif: withExif, withPeople: withPeople, withStacked: withStacked, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
@@ -1655,8 +1676,6 @@ class AssetApi {
///
/// * [bool] isArchived:
///
- /// * [bool] isExternal:
- ///
/// * [bool] isFavorite:
///
/// * [bool] isOffline:
@@ -1670,7 +1689,7 @@ class AssetApi {
/// * [MultipartFile] livePhotoData:
///
/// * [MultipartFile] sidecarData:
- Future uploadFileWithHttpInfo(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? duration, bool? isArchived, bool? isExternal, bool? isFavorite, bool? isOffline, bool? isReadOnly, bool? isVisible, String? libraryId, MultipartFile? livePhotoData, MultipartFile? sidecarData, }) async {
+ Future uploadFileWithHttpInfo(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? duration, bool? isArchived, bool? isFavorite, bool? isOffline, bool? isReadOnly, bool? isVisible, String? libraryId, MultipartFile? livePhotoData, MultipartFile? sidecarData, }) async {
// ignore: prefer_const_declarations
final path = r'/asset/upload';
@@ -1718,10 +1737,6 @@ class AssetApi {
hasFields = true;
mp.fields[r'isArchived'] = parameterToString(isArchived);
}
- if (isExternal != null) {
- hasFields = true;
- mp.fields[r'isExternal'] = parameterToString(isExternal);
- }
if (isFavorite != null) {
hasFields = true;
mp.fields[r'isFavorite'] = parameterToString(isFavorite);
@@ -1785,8 +1800,6 @@ class AssetApi {
///
/// * [bool] isArchived:
///
- /// * [bool] isExternal:
- ///
/// * [bool] isFavorite:
///
/// * [bool] isOffline:
@@ -1800,8 +1813,8 @@ class AssetApi {
/// * [MultipartFile] livePhotoData:
///
/// * [MultipartFile] sidecarData:
- Future uploadFile(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? duration, bool? isArchived, bool? isExternal, bool? isFavorite, bool? isOffline, bool? isReadOnly, bool? isVisible, String? libraryId, MultipartFile? livePhotoData, MultipartFile? sidecarData, }) async {
- final response = await uploadFileWithHttpInfo(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key: key, duration: duration, isArchived: isArchived, isExternal: isExternal, isFavorite: isFavorite, isOffline: isOffline, isReadOnly: isReadOnly, isVisible: isVisible, libraryId: libraryId, livePhotoData: livePhotoData, sidecarData: sidecarData, );
+ Future uploadFile(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? duration, bool? isArchived, bool? isFavorite, bool? isOffline, bool? isReadOnly, bool? isVisible, String? libraryId, MultipartFile? livePhotoData, MultipartFile? sidecarData, }) async {
+ final response = await uploadFileWithHttpInfo(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key: key, duration: duration, isArchived: isArchived, isFavorite: isFavorite, isOffline: isOffline, isReadOnly: isReadOnly, isVisible: isVisible, libraryId: libraryId, livePhotoData: livePhotoData, sidecarData: sidecarData, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
diff --git a/mobile/openapi/lib/api/library_api.dart b/mobile/openapi/lib/api/library_api.dart
index 23de593eac..befd0aeeff 100644
--- a/mobile/openapi/lib/api/library_api.dart
+++ b/mobile/openapi/lib/api/library_api.dart
@@ -104,7 +104,10 @@ class LibraryApi {
}
/// Performs an HTTP 'GET /library' operation and returns the [Response].
- Future getLibrariesWithHttpInfo() async {
+ /// Parameters:
+ ///
+ /// * [LibraryType] type:
+ Future getAllLibrariesWithHttpInfo({ LibraryType? type, }) async {
// ignore: prefer_const_declarations
final path = r'/library';
@@ -115,6 +118,10 @@ class LibraryApi {
final headerParams = {};
final formParams = {};
+ if (type != null) {
+ queryParams.addAll(_queryParams('', 'type', type));
+ }
+
const contentTypes = [];
@@ -129,8 +136,11 @@ class LibraryApi {
);
}
- Future?> getLibraries() async {
- final response = await getLibrariesWithHttpInfo();
+ /// Parameters:
+ ///
+ /// * [LibraryType] type:
+ Future?> getAllLibraries({ LibraryType? type, }) async {
+ final response = await getAllLibrariesWithHttpInfo( type: type, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
@@ -151,7 +161,7 @@ class LibraryApi {
/// Parameters:
///
/// * [String] id (required):
- Future getLibraryInfoWithHttpInfo(String id,) async {
+ Future getLibraryWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/library/{id}'
.replaceAll('{id}', id);
@@ -180,8 +190,8 @@ class LibraryApi {
/// Parameters:
///
/// * [String] id (required):
- Future getLibraryInfo(String id,) async {
- final response = await getLibraryInfoWithHttpInfo(id,);
+ Future getLibrary(String id,) async {
+ final response = await getLibraryWithHttpInfo(id,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
@@ -378,4 +388,56 @@ class LibraryApi {
}
return null;
}
+
+ /// Performs an HTTP 'POST /library/{id}/validate' operation and returns the [Response].
+ /// Parameters:
+ ///
+ /// * [String] id (required):
+ ///
+ /// * [ValidateLibraryDto] validateLibraryDto (required):
+ Future validateWithHttpInfo(String id, ValidateLibraryDto validateLibraryDto,) async {
+ // ignore: prefer_const_declarations
+ final path = r'/library/{id}/validate'
+ .replaceAll('{id}', id);
+
+ // ignore: prefer_final_locals
+ Object? postBody = validateLibraryDto;
+
+ final queryParams = [];
+ final headerParams = {};
+ final formParams = {};
+
+ const contentTypes =