> allOffsets,
) {
final object = Album(
- createdAt: reader.readDateTime(offsets[0]),
- endDate: reader.readDateTimeOrNull(offsets[1]),
- lastModifiedAssetTimestamp: reader.readDateTimeOrNull(offsets[2]),
- localId: reader.readStringOrNull(offsets[3]),
- modifiedAt: reader.readDateTime(offsets[4]),
- name: reader.readString(offsets[5]),
- remoteId: reader.readStringOrNull(offsets[6]),
- shared: reader.readBool(offsets[7]),
- startDate: reader.readDateTimeOrNull(offsets[8]),
+ activityEnabled: reader.readBool(offsets[0]),
+ createdAt: reader.readDateTime(offsets[1]),
+ endDate: reader.readDateTimeOrNull(offsets[2]),
+ lastModifiedAssetTimestamp: reader.readDateTimeOrNull(offsets[3]),
+ localId: reader.readStringOrNull(offsets[4]),
+ modifiedAt: reader.readDateTime(offsets[5]),
+ name: reader.readString(offsets[6]),
+ remoteId: reader.readStringOrNull(offsets[7]),
+ shared: reader.readBool(offsets[8]),
+ startDate: reader.readDateTimeOrNull(offsets[9]),
);
object.id = id;
return object;
@@ -197,22 +204,24 @@ P _albumDeserializeProp(
) {
switch (propertyId) {
case 0:
- return (reader.readDateTime(offset)) as P;
+ return (reader.readBool(offset)) as P;
case 1:
- return (reader.readDateTimeOrNull(offset)) as P;
+ return (reader.readDateTime(offset)) as P;
case 2:
return (reader.readDateTimeOrNull(offset)) as P;
case 3:
- return (reader.readStringOrNull(offset)) as P;
+ return (reader.readDateTimeOrNull(offset)) as P;
case 4:
- return (reader.readDateTime(offset)) as P;
- case 5:
- return (reader.readString(offset)) as P;
- case 6:
return (reader.readStringOrNull(offset)) as P;
+ case 5:
+ return (reader.readDateTime(offset)) as P;
+ case 6:
+ return (reader.readString(offset)) as P;
case 7:
- return (reader.readBool(offset)) as P;
+ return (reader.readStringOrNull(offset)) as P;
case 8:
+ return (reader.readBool(offset)) as P;
+ case 9:
return (reader.readDateTimeOrNull(offset)) as P;
default:
throw IsarError('Unknown property with id $propertyId');
@@ -442,6 +451,16 @@ extension AlbumQueryWhere on QueryBuilder {
}
extension AlbumQueryFilter on QueryBuilder {
+ QueryBuilder activityEnabledEqualTo(
+ bool value) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.equalTo(
+ property: r'activityEnabled',
+ value: value,
+ ));
+ });
+ }
+
QueryBuilder createdAtEqualTo(
DateTime value) {
return QueryBuilder.apply(this, (query) {
@@ -1385,6 +1404,18 @@ extension AlbumQueryLinks on QueryBuilder {
}
extension AlbumQuerySortBy on QueryBuilder {
+ QueryBuilder sortByActivityEnabled() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'activityEnabled', Sort.asc);
+ });
+ }
+
+ QueryBuilder sortByActivityEnabledDesc() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'activityEnabled', Sort.desc);
+ });
+ }
+
QueryBuilder sortByCreatedAt() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'createdAt', Sort.asc);
@@ -1496,6 +1527,18 @@ extension AlbumQuerySortBy on QueryBuilder {
}
extension AlbumQuerySortThenBy on QueryBuilder {
+ QueryBuilder thenByActivityEnabled() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'activityEnabled', Sort.asc);
+ });
+ }
+
+ QueryBuilder thenByActivityEnabledDesc() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'activityEnabled', Sort.desc);
+ });
+ }
+
QueryBuilder thenByCreatedAt() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'createdAt', Sort.asc);
@@ -1619,6 +1662,12 @@ extension AlbumQuerySortThenBy on QueryBuilder {
}
extension AlbumQueryWhereDistinct on QueryBuilder {
+ QueryBuilder distinctByActivityEnabled() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addDistinctBy(r'activityEnabled');
+ });
+ }
+
QueryBuilder distinctByCreatedAt() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'createdAt');
@@ -1684,6 +1733,12 @@ extension AlbumQueryProperty on QueryBuilder {
});
}
+ QueryBuilder activityEnabledProperty() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addPropertyName(r'activityEnabled');
+ });
+ }
+
QueryBuilder createdAtProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'createdAt');
diff --git a/mobile/lib/shared/models/asset.dart b/mobile/lib/shared/models/asset.dart
index e1a3f24cd..31b243e4d 100644
--- a/mobile/lib/shared/models/asset.dart
+++ b/mobile/lib/shared/models/asset.dart
@@ -6,7 +6,7 @@ import 'package:immich_mobile/utils/hash.dart';
import 'package:isar/isar.dart';
import 'package:openapi/api.dart';
import 'package:photo_manager/photo_manager.dart';
-import 'package:immich_mobile/utils/builtin_extensions.dart';
+import 'package:immich_mobile/extensions/string_extensions.dart';
import 'package:path/path.dart' as p;
part 'asset.g.dart';
@@ -419,12 +419,12 @@ class Asset {
"type": "$type",
"fileName": "$fileName",
"isFavorite": $isFavorite,
- "isRemote: $isRemote,
+ "isRemote": $isRemote,
"storage": "$storage",
"width": ${width ?? "N/A"},
"height": ${height ?? "N/A"},
"isArchived": $isArchived,
- "isTrashed": $isTrashed,
+ "isTrashed": $isTrashed
}""";
}
}
diff --git a/mobile/lib/shared/models/server_info/server_config.model.dart b/mobile/lib/shared/models/server_info/server_config.model.dart
index 227625dcb..cdb99987e 100644
--- a/mobile/lib/shared/models/server_info/server_config.model.dart
+++ b/mobile/lib/shared/models/server_info/server_config.model.dart
@@ -2,43 +2,35 @@ import 'package:openapi/api.dart';
class ServerConfig {
final int trashDays;
- final String mapTileUrl;
const ServerConfig({
required this.trashDays,
- required this.mapTileUrl,
});
ServerConfig copyWith({
int? trashDays,
- String? mapTileUrl,
}) {
return ServerConfig(
trashDays: trashDays ?? this.trashDays,
- mapTileUrl: mapTileUrl ?? this.mapTileUrl,
);
}
@override
String toString() {
- return 'ServerConfig(trashDays: $trashDays, mapTileUrl: $mapTileUrl)';
+ return 'ServerConfig(trashDays: $trashDays)';
}
- ServerConfig.fromDto(ServerConfigDto dto)
- : trashDays = dto.trashDays,
- mapTileUrl = dto.mapTileUrl;
+ ServerConfig.fromDto(ServerConfigDto dto) : trashDays = dto.trashDays;
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
- return other is ServerConfig &&
- other.trashDays == trashDays &&
- other.mapTileUrl == mapTileUrl;
+ return other is ServerConfig && other.trashDays == trashDays;
}
@override
int get hashCode {
- return trashDays.hashCode ^ mapTileUrl.hashCode;
+ return trashDays.hashCode;
}
}
diff --git a/mobile/lib/shared/models/store.dart b/mobile/lib/shared/models/store.dart
index 8f24899f1..40258f304 100644
--- a/mobile/lib/shared/models/store.dart
+++ b/mobile/lib/shared/models/store.dart
@@ -156,6 +156,7 @@ enum StoreKey {
accessToken(11, type: String),
serverEndpoint(12, type: String),
autoBackup(13, type: bool),
+ backgroundBackup(14, type: bool),
// user settings from [AppSettingsEnum] below:
loadPreview(100, type: bool),
loadOriginal(101, type: bool),
diff --git a/mobile/lib/shared/providers/server_info.provider.dart b/mobile/lib/shared/providers/server_info.provider.dart
index b0bcf89b1..3c66fe76d 100644
--- a/mobile/lib/shared/providers/server_info.provider.dart
+++ b/mobile/lib/shared/providers/server_info.provider.dart
@@ -23,7 +23,6 @@ class ServerInfoNotifier extends StateNotifier {
trash: true,
),
serverConfig: const ServerConfig(
- mapTileUrl: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
trashDays: 30,
),
serverDiskInfo: const ServerDiskInfo(
diff --git a/mobile/lib/shared/services/api.service.dart b/mobile/lib/shared/services/api.service.dart
index 7c1dfc8fc..656de826c 100644
--- a/mobile/lib/shared/services/api.service.dart
+++ b/mobile/lib/shared/services/api.service.dart
@@ -22,6 +22,8 @@ class ApiService {
late PersonApi personApi;
late AuditApi auditApi;
late SharedLinkApi sharedLinkApi;
+ late SystemConfigApi systemConfigApi;
+ late ActivityApi activityApi;
ApiService() {
final endpoint = Store.tryGet(StoreKey.serverEndpoint);
@@ -47,6 +49,8 @@ class ApiService {
personApi = PersonApi(_apiClient);
auditApi = AuditApi(_apiClient);
sharedLinkApi = SharedLinkApi(_apiClient);
+ systemConfigApi = SystemConfigApi(_apiClient);
+ activityApi = ActivityApi(_apiClient);
}
Future resolveAndSetEndpoint(String serverUrl) async {
diff --git a/mobile/lib/shared/services/asset.service.dart b/mobile/lib/shared/services/asset.service.dart
index 488395b16..8b1ee6a33 100644
--- a/mobile/lib/shared/services/asset.service.dart
+++ b/mobile/lib/shared/services/asset.service.dart
@@ -62,20 +62,31 @@ class AssetService {
/// Returns `null` if the server state did not change, else list of assets
Future?> _getRemoteAssets(User user) async {
+ const int chunkSize = 5000;
try {
- final List? assets =
- await _apiService.assetApi.getAllAssets(
- userId: user.id,
- );
- if (assets == null) {
- return null;
- } else if (assets.isNotEmpty && assets.first.ownerId != user.id) {
- log.warning("Make sure that server and app versions match!"
- " The server returned assets for user ${assets.first.ownerId}"
- " while requesting assets of user ${user.id}");
- return null;
+ final DateTime now = DateTime.now().toUtc();
+ final List allAssets = [];
+ for (int i = 0;; i += chunkSize) {
+ final List? assets =
+ await _apiService.assetApi.getAllAssets(
+ userId: user.id,
+ // updatedBefore is important! without it we could
+ // a) get the same Asset multiple times in different versions (when
+ // the asset is modified while the chunks are loaded from the server)
+ // b) miss assets when new assets are inserted in between the calls
+ updatedBefore: now,
+ skip: i,
+ take: chunkSize,
+ );
+ if (assets == null) {
+ return null;
+ }
+ allAssets.addAll(assets.map(Asset.remote));
+ if (assets.length < chunkSize) {
+ break;
+ }
}
- return assets.map(Asset.remote).toList();
+ return allAssets;
} catch (error, stack) {
log.severe(
'Error while getting remote assets: ${error.toString()}',
diff --git a/mobile/lib/shared/services/hash.service.dart b/mobile/lib/shared/services/hash.service.dart
index ee272cf5f..914c8bc28 100644
--- a/mobile/lib/shared/services/hash.service.dart
+++ b/mobile/lib/shared/services/hash.service.dart
@@ -10,7 +10,7 @@ import 'package:immich_mobile/shared/models/asset.dart';
import 'package:immich_mobile/shared/models/device_asset.dart';
import 'package:immich_mobile/shared/models/ios_device_asset.dart';
import 'package:immich_mobile/shared/providers/db.provider.dart';
-import 'package:immich_mobile/utils/builtin_extensions.dart';
+import 'package:immich_mobile/extensions/string_extensions.dart';
import 'package:isar/isar.dart';
import 'package:logging/logging.dart';
import 'package:photo_manager/photo_manager.dart';
diff --git a/mobile/lib/shared/services/sync.service.dart b/mobile/lib/shared/services/sync.service.dart
index 34d84401a..fb9888258 100644
--- a/mobile/lib/shared/services/sync.service.dart
+++ b/mobile/lib/shared/services/sync.service.dart
@@ -11,7 +11,7 @@ import 'package:immich_mobile/shared/models/user.dart';
import 'package:immich_mobile/shared/providers/db.provider.dart';
import 'package:immich_mobile/shared/services/hash.service.dart';
import 'package:immich_mobile/utils/async_mutex.dart';
-import 'package:immich_mobile/utils/builtin_extensions.dart';
+import 'package:immich_mobile/extensions/collection_extensions.dart';
import 'package:immich_mobile/utils/diff.dart';
import 'package:isar/isar.dart';
import 'package:logging/logging.dart';
@@ -197,7 +197,7 @@ class SyncService {
User user,
FutureOr?> Function(User user) loadAssets,
) async {
- final DateTime now = DateTime.now();
+ final DateTime now = DateTime.now().toUtc();
final List? remote = await loadAssets(user);
if (remote == null) {
return false;
@@ -210,6 +210,10 @@ class SyncService {
assert(inDb.isSorted(Asset.compareByChecksum), "inDb not sorted!");
remote.sort(Asset.compareByChecksum);
+
+ // filter our duplicates that might be introduced by the chunked retrieval
+ remote.uniqueConsecutive(compare: Asset.compareByChecksum);
+
final (toAdd, toUpdate, toRemove) = _diffAssets(remote, inDb, remote: true);
if (toAdd.isEmpty && toUpdate.isEmpty && toRemove.isEmpty) {
await _updateUserAssetsETag(user, now);
@@ -759,6 +763,12 @@ class SyncService {
final List toAdd = [];
final List toUpdate = [];
final List toRemove = [];
+ if (assets.isEmpty || inDb.isEmpty) {
+ // fast path for trivial cases: halfes memory usage during initial sync
+ return assets.isEmpty
+ ? (toAdd, toUpdate, inDb) // remove all from DB
+ : (assets, toUpdate, toRemove); // add all assets
+ }
diffSortedListsSync(
inDb,
assets,
diff --git a/mobile/lib/shared/ui/app_bar_dialog/app_bar_dialog.dart b/mobile/lib/shared/ui/app_bar_dialog/app_bar_dialog.dart
index ede113837..60ee135b8 100644
--- a/mobile/lib/shared/ui/app_bar_dialog/app_bar_dialog.dart
+++ b/mobile/lib/shared/ui/app_bar_dialog/app_bar_dialog.dart
@@ -1,8 +1,8 @@
-import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/modules/backup/models/backup_state.model.dart';
import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
import 'package:immich_mobile/modules/backup/providers/manual_upload.provider.dart';
@@ -22,9 +22,8 @@ class ImmichAppBarDialog extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
BackUpState backupState = ref.watch(backupProvider);
- final theme = Theme.of(context);
- bool isDarkTheme = theme.brightness == Brightness.dark;
- bool isHorizontal = MediaQuery.of(context).size.width > 600;
+ final theme = context.themeData;
+ bool isHorizontal = !context.isMobile;
final horizontalPadding = isHorizontal ? 100.0 : 20.0;
final user = ref.watch(currentUserProvider);
@@ -40,7 +39,7 @@ class ImmichAppBarDialog extends HookConsumerWidget {
return Row(
children: [
InkWell(
- onTap: () => Navigator.of(context).pop(),
+ onTap: () => context.pop(),
child: const Icon(
Icons.close,
size: 20,
@@ -54,7 +53,7 @@ class ImmichAppBarDialog extends HookConsumerWidget {
style: TextStyle(
fontFamily: 'SnowburstOne',
fontWeight: FontWeight.bold,
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
fontSize: 15,
),
),
@@ -90,7 +89,7 @@ class ImmichAppBarDialog extends HookConsumerWidget {
return buildActionButton(
Icons.settings_rounded,
"profile_drawer_settings",
- () => AutoRouter.of(context).push(const SettingsRoute()),
+ () => context.autoPush(const SettingsRoute()),
);
}
@@ -98,7 +97,7 @@ class ImmichAppBarDialog extends HookConsumerWidget {
return buildActionButton(
Icons.assignment_outlined,
"profile_drawer_app_logs",
- () => AutoRouter.of(context).push(const AppLogRoute()),
+ () => context.autoPush(const AppLogRoute()),
);
}
@@ -121,7 +120,7 @@ class ImmichAppBarDialog extends HookConsumerWidget {
ref.watch(backupProvider.notifier).cancelBackup();
ref.watch(assetProvider.notifier).clearAllAsset();
ref.watch(websocketProvider.notifier).disconnect();
- AutoRouter.of(context).replace(const LoginRoute());
+ context.autoReplace(const LoginRoute());
},
);
},
@@ -136,8 +135,8 @@ class ImmichAppBarDialog extends HookConsumerWidget {
child: Container(
padding: const EdgeInsets.symmetric(vertical: 4),
decoration: BoxDecoration(
- color: isDarkTheme
- ? Theme.of(context).scaffoldBackgroundColor
+ color: context.isDarkTheme
+ ? context.scaffoldBackgroundColor
: const Color.fromARGB(255, 225, 229, 240),
),
child: ListTile(
@@ -191,7 +190,7 @@ class ImmichAppBarDialog extends HookConsumerWidget {
children: [
InkWell(
onTap: () {
- Navigator.of(context).pop();
+ context.pop();
launchUrl(
Uri.parse('https://immich.app'),
mode: LaunchMode.externalApplication,
@@ -199,7 +198,7 @@ class ImmichAppBarDialog extends HookConsumerWidget {
},
child: Text(
"profile_drawer_documentation",
- style: Theme.of(context).textTheme.bodySmall,
+ style: context.textTheme.bodySmall,
).tr(),
),
const SizedBox(
@@ -211,7 +210,7 @@ class ImmichAppBarDialog extends HookConsumerWidget {
),
InkWell(
onTap: () {
- Navigator.of(context).pop();
+ context.pop();
launchUrl(
Uri.parse('https://github.com/immich-app/immich'),
mode: LaunchMode.externalApplication,
@@ -219,7 +218,7 @@ class ImmichAppBarDialog extends HookConsumerWidget {
},
child: Text(
"profile_drawer_github",
- style: Theme.of(context).textTheme.bodySmall,
+ style: context.textTheme.bodySmall,
).tr(),
),
],
diff --git a/mobile/lib/shared/ui/app_bar_dialog/app_bar_profile_info.dart b/mobile/lib/shared/ui/app_bar_dialog/app_bar_profile_info.dart
index d58699d5c..4f1f7db86 100644
--- a/mobile/lib/shared/ui/app_bar_dialog/app_bar_profile_info.dart
+++ b/mobile/lib/shared/ui/app_bar_dialog/app_bar_profile_info.dart
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:image_picker/image_picker.dart';
+import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/modules/home/providers/upload_profile_image.provider.dart';
import 'package:immich_mobile/shared/models/store.dart';
import 'package:immich_mobile/shared/ui/user_circle_avatar.dart';
@@ -18,7 +19,6 @@ class AppBarProfileInfoBox extends HookConsumerWidget {
AuthenticationState authState = ref.watch(authenticationProvider);
final uploadProfileImageStatus =
ref.watch(uploadProfileImageProvider).status;
- final isDarkMode = Theme.of(context).brightness == Brightness.dark;
final user = Store.tryGet(StoreKey.currentUser);
buildUserProfileImage() {
@@ -91,8 +91,8 @@ class AppBarProfileInfoBox extends HookConsumerWidget {
child: Container(
width: double.infinity,
decoration: BoxDecoration(
- color: Theme.of(context).brightness == Brightness.dark
- ? Theme.of(context).scaffoldBackgroundColor
+ color: context.isDarkTheme
+ ? context.scaffoldBackgroundColor
: const Color.fromARGB(255, 225, 229, 240),
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(10),
@@ -111,7 +111,9 @@ class AppBarProfileInfoBox extends HookConsumerWidget {
bottom: -5,
right: -8,
child: Material(
- color: isDarkMode ? Colors.blueGrey[800] : Colors.white,
+ color: context.isDarkTheme
+ ? Colors.blueGrey[800]
+ : Colors.white,
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0),
@@ -120,7 +122,7 @@ class AppBarProfileInfoBox extends HookConsumerWidget {
padding: const EdgeInsets.all(5.0),
child: Icon(
Icons.camera_alt_outlined,
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
size: 14,
),
),
@@ -132,16 +134,16 @@ class AppBarProfileInfoBox extends HookConsumerWidget {
title: Text(
"${authState.firstName} ${authState.lastName}",
style: TextStyle(
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
subtitle: Text(
authState.userEmail,
- style: Theme.of(context).textTheme.labelMedium?.copyWith(
- fontSize: 12,
- ),
+ style: context.textTheme.labelMedium?.copyWith(
+ fontSize: 12,
+ ),
),
),
),
diff --git a/mobile/lib/shared/ui/app_bar_dialog/app_bar_server_info.dart b/mobile/lib/shared/ui/app_bar_dialog/app_bar_server_info.dart
index fa4a73536..fef9e1daa 100644
--- a/mobile/lib/shared/ui/app_bar_dialog/app_bar_server_info.dart
+++ b/mobile/lib/shared/ui/app_bar_dialog/app_bar_server_info.dart
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/shared/models/server_info/server_info.model.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:immich_mobile/shared/providers/server_info.provider.dart';
@@ -39,8 +40,8 @@ class AppBarServerInfo extends HookConsumerWidget {
padding: const EdgeInsets.only(left: 10.0, right: 10.0, bottom: 10.0),
child: Container(
decoration: BoxDecoration(
- color: Theme.of(context).brightness == Brightness.dark
- ? Theme.of(context).scaffoldBackgroundColor
+ color: context.isDarkTheme
+ ? context.scaffoldBackgroundColor
: const Color.fromARGB(255, 225, 229, 240),
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(10),
@@ -61,7 +62,7 @@ class AppBarServerInfo extends HookConsumerWidget {
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 11,
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
fontWeight: FontWeight.w600,
),
),
@@ -83,7 +84,7 @@ class AppBarServerInfo extends HookConsumerWidget {
"server_info_box_app_version".tr(),
style: TextStyle(
fontSize: 11,
- color: Theme.of(context).textTheme.labelSmall?.color,
+ color: context.textTheme.labelSmall?.color,
fontWeight: FontWeight.bold,
),
),
@@ -97,10 +98,7 @@ class AppBarServerInfo extends HookConsumerWidget {
"${appInfo.value["version"]} build.${appInfo.value["buildNumber"]}",
style: TextStyle(
fontSize: 11,
- color: Theme.of(context)
- .textTheme
- .labelSmall
- ?.color
+ color: context.textTheme.labelSmall?.color
?.withOpacity(0.5),
fontWeight: FontWeight.bold,
),
@@ -126,7 +124,7 @@ class AppBarServerInfo extends HookConsumerWidget {
"server_info_box_server_version".tr(),
style: TextStyle(
fontSize: 11,
- color: Theme.of(context).textTheme.labelSmall?.color,
+ color: context.textTheme.labelSmall?.color,
fontWeight: FontWeight.bold,
),
),
@@ -142,10 +140,7 @@ class AppBarServerInfo extends HookConsumerWidget {
: "?",
style: TextStyle(
fontSize: 11,
- color: Theme.of(context)
- .textTheme
- .labelSmall
- ?.color
+ color: context.textTheme.labelSmall?.color
?.withOpacity(0.5),
fontWeight: FontWeight.bold,
),
@@ -171,7 +166,7 @@ class AppBarServerInfo extends HookConsumerWidget {
"server_info_box_server_url".tr(),
style: TextStyle(
fontSize: 11,
- color: Theme.of(context).textTheme.labelSmall?.color,
+ color: context.textTheme.labelSmall?.color,
fontWeight: FontWeight.bold,
),
),
@@ -185,14 +180,12 @@ class AppBarServerInfo extends HookConsumerWidget {
child: Tooltip(
verticalOffset: 0,
decoration: BoxDecoration(
- color:
- Theme.of(context).primaryColor.withOpacity(0.9),
+ color: context.primaryColor.withOpacity(0.9),
borderRadius: BorderRadius.circular(10),
),
textStyle: TextStyle(
- color: Theme.of(context).brightness == Brightness.dark
- ? Colors.black
- : Colors.white,
+ color:
+ context.isDarkTheme ? Colors.black : Colors.white,
fontWeight: FontWeight.bold,
),
message: getServerUrl() ?? '--',
@@ -202,10 +195,7 @@ class AppBarServerInfo extends HookConsumerWidget {
getServerUrl() ?? '--',
style: TextStyle(
fontSize: 11,
- color: Theme.of(context)
- .textTheme
- .labelSmall
- ?.color
+ color: context.textTheme.labelSmall?.color
?.withOpacity(0.5),
fontWeight: FontWeight.bold,
overflow: TextOverflow.ellipsis,
diff --git a/mobile/lib/shared/ui/confirm_dialog.dart b/mobile/lib/shared/ui/confirm_dialog.dart
index ca5fee7ec..1fd255a15 100644
--- a/mobile/lib/shared/ui/confirm_dialog.dart
+++ b/mobile/lib/shared/ui/confirm_dialog.dart
@@ -1,5 +1,6 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
+import 'package:immich_mobile/extensions/build_context_extensions.dart';
class ConfirmDialog extends StatelessWidget {
final Function onOk;
@@ -30,11 +31,11 @@ class ConfirmDialog extends StatelessWidget {
).tr(),
actions: [
TextButton(
- onPressed: () => Navigator.of(context).pop(false),
+ onPressed: () => context.pop(false),
child: Text(
cancel,
style: TextStyle(
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
fontWeight: FontWeight.bold,
),
).tr(),
@@ -42,7 +43,7 @@ class ConfirmDialog extends StatelessWidget {
TextButton(
onPressed: () {
onOk();
- Navigator.of(context).pop(true);
+ context.pop(true);
},
child: Text(
ok,
diff --git a/mobile/lib/shared/ui/immich_app_bar.dart b/mobile/lib/shared/ui/immich_app_bar.dart
index 3510931f6..bbf5a48a0 100644
--- a/mobile/lib/shared/ui/immich_app_bar.dart
+++ b/mobile/lib/shared/ui/immich_app_bar.dart
@@ -1,6 +1,6 @@
-import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/shared/models/store.dart';
import 'package:immich_mobile/shared/ui/app_bar_dialog/app_bar_dialog.dart';
import 'package:immich_mobile/shared/ui/user_circle_avatar.dart';
@@ -28,7 +28,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
final ServerInfo serverInfoState = ref.watch(serverInfoProvider);
AuthenticationState authState = ref.watch(authenticationProvider);
final user = Store.tryGet(StoreKey.currentUser);
- final isDarkMode = Theme.of(context).brightness == Brightness.dark;
+ final isDarkTheme = context.isDarkTheme;
const widgetSize = 30.0;
buildProfileIndicator() {
@@ -70,7 +70,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
}
getBackupBadgeIcon() {
- final iconColor = isDarkMode ? Colors.white : Colors.black;
+ final iconColor = isDarkTheme ? Colors.white : Colors.black;
if (isEnableAutoBackup) {
if (backupState.backupProgress == BackUpProgressEnum.inProgress) {
@@ -104,10 +104,10 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
buildBackupIndicator() {
final indicatorIcon = getBackupBadgeIcon();
- final badgeBackground = isDarkMode ? Colors.blueGrey[800] : Colors.white;
+ final badgeBackground = isDarkTheme ? Colors.blueGrey[800] : Colors.white;
return InkWell(
- onTap: () => AutoRouter.of(context).push(const BackupControllerRoute()),
+ onTap: () => context.autoPush(const BackupControllerRoute()),
borderRadius: BorderRadius.circular(12),
child: Badge(
label: Container(
@@ -116,7 +116,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
decoration: BoxDecoration(
color: badgeBackground,
border: Border.all(
- color: isDarkMode ? Colors.black : Colors.grey,
+ color: isDarkTheme ? Colors.black : Colors.grey,
),
borderRadius: BorderRadius.circular(widgetSize / 2),
),
@@ -129,14 +129,14 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
child: Icon(
Icons.backup_rounded,
size: widgetSize,
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
),
),
);
}
return AppBar(
- backgroundColor: Theme.of(context).appBarTheme.backgroundColor,
+ backgroundColor: context.themeData.appBarTheme.backgroundColor,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(5),
diff --git a/mobile/lib/shared/ui/immich_image.dart b/mobile/lib/shared/ui/immich_image.dart
index 8b505f556..985219d6e 100644
--- a/mobile/lib/shared/ui/immich_image.dart
+++ b/mobile/lib/shared/ui/immich_image.dart
@@ -2,6 +2,7 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
+import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/shared/models/asset.dart';
import 'package:immich_mobile/shared/models/store.dart';
import 'package:immich_mobile/utils/image_url_builder.dart';
@@ -86,7 +87,7 @@ class ImmichImage extends StatelessWidget {
}
return Icon(
Icons.image_not_supported_outlined,
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
);
},
);
@@ -137,7 +138,7 @@ class ImmichImage extends StatelessWidget {
}
return Icon(
Icons.image_not_supported_outlined,
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
);
},
);
diff --git a/mobile/lib/shared/ui/immich_loading_indicator.dart b/mobile/lib/shared/ui/immich_loading_indicator.dart
index 98ddb8f47..db5dd3c19 100644
--- a/mobile/lib/shared/ui/immich_loading_indicator.dart
+++ b/mobile/lib/shared/ui/immich_loading_indicator.dart
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
+import 'package:immich_mobile/extensions/build_context_extensions.dart';
class ImmichLoadingIndicator extends StatelessWidget {
final double? borderRadius;
@@ -14,7 +15,7 @@ class ImmichLoadingIndicator extends StatelessWidget {
height: 60,
width: 60,
decoration: BoxDecoration(
- color: Theme.of(context).primaryColor.withAlpha(200),
+ color: context.primaryColor.withAlpha(200),
borderRadius: BorderRadius.circular(borderRadius ?? 10),
),
padding: const EdgeInsets.all(15),
diff --git a/mobile/lib/shared/ui/immich_title_text.dart b/mobile/lib/shared/ui/immich_title_text.dart
index 7f633a0e6..3ef0501dd 100644
--- a/mobile/lib/shared/ui/immich_title_text.dart
+++ b/mobile/lib/shared/ui/immich_title_text.dart
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
+import 'package:immich_mobile/extensions/build_context_extensions.dart';
class ImmichTitleText extends StatelessWidget {
final double fontSize;
@@ -18,9 +19,8 @@ class ImmichTitleText extends StatelessWidget {
fontFamily: 'SnowburstOne',
fontWeight: FontWeight.bold,
fontSize: fontSize,
- color: color ?? Theme.of(context).primaryColor,
+ color: color ?? context.primaryColor,
),
);
}
-
}
diff --git a/mobile/lib/shared/ui/immich_toast.dart b/mobile/lib/shared/ui/immich_toast.dart
index 3f15c13a2..25a0e65fa 100644
--- a/mobile/lib/shared/ui/immich_toast.dart
+++ b/mobile/lib/shared/ui/immich_toast.dart
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
+import 'package:immich_mobile/extensions/build_context_extensions.dart';
enum ToastType { info, success, error }
@@ -11,14 +12,13 @@ class ImmichToast {
ToastGravity gravity = ToastGravity.TOP,
int durationInSecond = 3,
}) {
- final isDarkTheme = Theme.of(context).brightness == Brightness.dark;
final fToast = FToast();
fToast.init(context);
Color getColor(ToastType type, BuildContext context) {
switch (type) {
case ToastType.info:
- return Theme.of(context).primaryColor;
+ return context.primaryColor;
case ToastType.success:
return const Color.fromARGB(255, 78, 140, 124);
case ToastType.error:
@@ -31,7 +31,7 @@ class ImmichToast {
case ToastType.info:
return Icon(
Icons.info_outline_rounded,
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
);
case ToastType.success:
return const Icon(
@@ -51,7 +51,7 @@ class ImmichToast {
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 12.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
- color: isDarkTheme ? Colors.grey[900] : Colors.grey[50],
+ color: context.isDarkTheme ? Colors.grey[900] : Colors.grey[50],
border: Border.all(
color: Colors.black12,
width: 1,
diff --git a/mobile/lib/shared/ui/user_avatar.dart b/mobile/lib/shared/ui/user_avatar.dart
index c736e8f90..382e44eff 100644
--- a/mobile/lib/shared/ui/user_avatar.dart
+++ b/mobile/lib/shared/ui/user_avatar.dart
@@ -1,5 +1,6 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
+import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/shared/models/store.dart';
import 'package:immich_mobile/shared/models/user.dart';
@@ -10,7 +11,7 @@ Widget userAvatar(BuildContext context, User u, {double? radius}) {
final lastNameFirstLetter = u.lastName.isNotEmpty ? u.lastName[0] : "";
return CircleAvatar(
radius: radius,
- backgroundColor: Theme.of(context).primaryColor.withAlpha(50),
+ backgroundColor: context.primaryColor.withAlpha(50),
foregroundImage: CachedNetworkImageProvider(
url,
headers: {"Authorization": "Bearer ${Store.get(StoreKey.accessToken)}"},
diff --git a/mobile/lib/shared/ui/user_circle_avatar.dart b/mobile/lib/shared/ui/user_circle_avatar.dart
index b70566d88..98df36265 100644
--- a/mobile/lib/shared/ui/user_circle_avatar.dart
+++ b/mobile/lib/shared/ui/user_circle_avatar.dart
@@ -3,6 +3,7 @@ import 'dart:math';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/shared/models/store.dart';
import 'package:immich_mobile/shared/models/user.dart';
import 'package:immich_mobile/shared/ui/transparent_image.dart';
@@ -40,19 +41,21 @@ class UserCircleAvatar extends ConsumerWidget {
final profileImageUrl =
'${Store.get(StoreKey.serverEndpoint)}/user/profile-image/${user.id}?d=${Random().nextInt(1024)}';
+
+ final textIcon = Text(
+ user.firstName[0].toUpperCase(),
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ color: context.isDarkTheme ? Colors.black : Colors.white,
+ ),
+ );
return CircleAvatar(
backgroundColor: useRandomBackgroundColor
? randomColors[Random().nextInt(randomColors.length)]
- : Theme.of(context).primaryColor,
+ : context.primaryColor,
radius: radius,
child: user.profileImagePath == ""
- ? Text(
- user.firstName[0].toUpperCase(),
- style: const TextStyle(
- fontWeight: FontWeight.bold,
- color: Colors.black,
- ),
- )
+ ? textIcon
: ClipRRect(
borderRadius: BorderRadius.circular(50),
child: CachedNetworkImage(
@@ -66,8 +69,7 @@ class UserCircleAvatar extends ConsumerWidget {
"Authorization": "Bearer ${Store.get(StoreKey.accessToken)}",
},
fadeInDuration: const Duration(milliseconds: 300),
- errorWidget: (context, error, stackTrace) =>
- Image.memory(kTransparentImage),
+ errorWidget: (context, error, stackTrace) => textIcon,
),
),
);
diff --git a/mobile/lib/shared/views/app_log_detail_page.dart b/mobile/lib/shared/views/app_log_detail_page.dart
index 0963605b4..f8ddf5191 100644
--- a/mobile/lib/shared/views/app_log_detail_page.dart
+++ b/mobile/lib/shared/views/app_log_detail_page.dart
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/shared/models/logger_message.model.dart';
import 'package:flutter/services.dart';
@@ -10,7 +11,7 @@ class AppLogDetailPage extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
- var isDarkMode = Theme.of(context).brightness == Brightness.dark;
+ var isDarkTheme = context.isDarkTheme;
buildStackMessage(String stackTrace) {
return Padding(
@@ -28,7 +29,7 @@ class AppLogDetailPage extends HookConsumerWidget {
"STACK TRACES",
style: TextStyle(
fontSize: 12.0,
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
fontWeight: FontWeight.bold,
),
),
@@ -45,14 +46,14 @@ class AppLogDetailPage extends HookConsumerWidget {
icon: Icon(
Icons.copy,
size: 16.0,
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
),
),
],
),
Container(
decoration: BoxDecoration(
- color: isDarkMode ? Colors.grey[900] : Colors.grey[200],
+ color: isDarkTheme ? Colors.grey[900] : Colors.grey[200],
borderRadius: BorderRadius.circular(15.0),
),
child: Padding(
@@ -88,7 +89,7 @@ class AppLogDetailPage extends HookConsumerWidget {
"MESSAGE",
style: TextStyle(
fontSize: 12.0,
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
fontWeight: FontWeight.bold,
),
),
@@ -104,14 +105,14 @@ class AppLogDetailPage extends HookConsumerWidget {
icon: Icon(
Icons.copy,
size: 16.0,
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
),
),
],
),
Container(
decoration: BoxDecoration(
- color: isDarkMode ? Colors.grey[900] : Colors.grey[200],
+ color: isDarkTheme ? Colors.grey[900] : Colors.grey[200],
borderRadius: BorderRadius.circular(15.0),
),
child: Padding(
@@ -143,14 +144,14 @@ class AppLogDetailPage extends HookConsumerWidget {
"FROM",
style: TextStyle(
fontSize: 12.0,
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
fontWeight: FontWeight.bold,
),
),
),
Container(
decoration: BoxDecoration(
- color: isDarkMode ? Colors.grey[900] : Colors.grey[200],
+ color: isDarkTheme ? Colors.grey[900] : Colors.grey[200],
borderRadius: BorderRadius.circular(15.0),
),
child: Padding(
diff --git a/mobile/lib/shared/views/app_log_page.dart b/mobile/lib/shared/views/app_log_page.dart
index a8dfc6ec4..9d1dca19f 100644
--- a/mobile/lib/shared/views/app_log_page.dart
+++ b/mobile/lib/shared/views/app_log_page.dart
@@ -1,7 +1,7 @@
-import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/shared/models/logger_message.model.dart';
import 'package:immich_mobile/shared/services/immich_logger.service.dart';
@@ -16,6 +16,7 @@ class AppLogPage extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final immichLogger = ImmichLogger();
final logMessages = useState(immichLogger.messages);
+ final isDarkTheme = context.isDarkTheme;
Widget colorStatusIndicator(Color color) {
return Column(
@@ -36,7 +37,7 @@ class AppLogPage extends HookConsumerWidget {
Widget buildLeadingIcon(LogLevel level) {
switch (level) {
case LogLevel.INFO:
- return colorStatusIndicator(Theme.of(context).primaryColor);
+ return colorStatusIndicator(context.primaryColor);
case LogLevel.SEVERE:
return colorStatusIndicator(Colors.redAccent);
@@ -52,15 +53,15 @@ class AppLogPage extends HookConsumerWidget {
case LogLevel.INFO:
return Colors.transparent;
case LogLevel.SEVERE:
- return Theme.of(context).brightness == Brightness.dark
+ return isDarkTheme
? Colors.redAccent.withOpacity(0.25)
: Colors.redAccent.withOpacity(0.075);
case LogLevel.WARNING:
- return Theme.of(context).brightness == Brightness.dark
+ return isDarkTheme
? Colors.orangeAccent.withOpacity(0.25)
: Colors.orangeAccent.withOpacity(0.075);
default:
- return Theme.of(context).primaryColor.withOpacity(0.1);
+ return context.primaryColor.withOpacity(0.1);
}
}
@@ -79,7 +80,7 @@ class AppLogPage extends HookConsumerWidget {
IconButton(
icon: Icon(
Icons.delete_outline_rounded,
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
semanticLabel: "Clear logs",
size: 20.0,
),
@@ -91,7 +92,7 @@ class AppLogPage extends HookConsumerWidget {
IconButton(
icon: Icon(
Icons.share_rounded,
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
semanticLabel: "Share logs",
size: 20.0,
),
@@ -102,7 +103,7 @@ class AppLogPage extends HookConsumerWidget {
],
leading: IconButton(
onPressed: () {
- AutoRouter.of(context).pop();
+ context.autoPop();
},
icon: const Icon(
Icons.arrow_back_ios_new_rounded,
@@ -115,16 +116,14 @@ class AppLogPage extends HookConsumerWidget {
separatorBuilder: (context, index) {
return Divider(
height: 0,
- color: Theme.of(context).brightness == Brightness.dark
- ? Colors.white70
- : Colors.grey[600],
+ color: isDarkTheme ? Colors.white70 : Colors.grey[600],
);
},
itemCount: logMessages.value.length,
itemBuilder: (context, index) {
var logMessage = logMessages.value[index];
return ListTile(
- onTap: () => AutoRouter.of(context).push(
+ onTap: () => context.autoPush(
AppLogDetailRoute(
logMessage: logMessage,
),
@@ -140,9 +139,7 @@ class AppLogPage extends HookConsumerWidget {
TextSpan(
text: "#$index ",
style: TextStyle(
- color: Theme.of(context).brightness == Brightness.dark
- ? Colors.white70
- : Colors.grey[600],
+ color: isDarkTheme ? Colors.white70 : Colors.grey[600],
fontSize: 14.0,
fontWeight: FontWeight.bold,
),
@@ -170,7 +167,7 @@ class AppLogPage extends HookConsumerWidget {
),
);
}
-
+
/// Truncate the log message to a certain number of lines
/// @param int maxLines - Max number of lines to truncate
String truncateLogMessage(String message, int maxLines) {
diff --git a/mobile/lib/shared/views/splash_screen.dart b/mobile/lib/shared/views/splash_screen.dart
index bd419bc02..2f493d16a 100644
--- a/mobile/lib/shared/views/splash_screen.dart
+++ b/mobile/lib/shared/views/splash_screen.dart
@@ -1,7 +1,7 @@
-import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
import 'package:immich_mobile/modules/onboarding/providers/gallery_permission.provider.dart';
@@ -51,7 +51,7 @@ class SplashScreenPage extends HookConsumerWidget {
// If the device is offline and there is a currentUser stored locallly
// Proceed into the app
if (deviceIsOffline && Store.tryGet(StoreKey.currentUser) != null) {
- AutoRouter.of(context).replace(const TabControllerRoute());
+ context.autoReplace(const TabControllerRoute());
} else if (isSuccess) {
// If device was able to login through the internet successfully
final hasPermission =
@@ -60,10 +60,10 @@ class SplashScreenPage extends HookConsumerWidget {
// Resume backup (if enable) then navigate
ref.watch(backupProvider.notifier).resumeBackup();
}
- AutoRouter.of(context).replace(const TabControllerRoute());
+ context.autoReplace(const TabControllerRoute());
} else {
// User was unable to login through either offline or online methods
- AutoRouter.of(context).replace(const LoginRoute());
+ context.autoReplace(const LoginRoute());
}
}
@@ -72,7 +72,7 @@ class SplashScreenPage extends HookConsumerWidget {
if (serverUrl != null && accessToken != null) {
performLoggingIn();
} else {
- AutoRouter.of(context).replace(const LoginRoute());
+ context.autoReplace(const LoginRoute());
}
return null;
},
diff --git a/mobile/lib/shared/views/tab_controller_page.dart b/mobile/lib/shared/views/tab_controller_page.dart
index 8e72ce900..2b9d62565 100644
--- a/mobile/lib/shared/views/tab_controller_page.dart
+++ b/mobile/lib/shared/views/tab_controller_page.dart
@@ -3,6 +3,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/modules/asset_viewer/providers/scroll_notifier.provider.dart';
import 'package:immich_mobile/modules/home/providers/multiselect.provider.dart';
import 'package:immich_mobile/routing/router.dart';
@@ -31,7 +32,7 @@ class TabControllerPage extends HookConsumerWidget {
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation(
- Theme.of(context).primaryColor,
+ context.primaryColor,
),
),
),
@@ -55,10 +56,10 @@ class TabControllerPage extends HookConsumerWidget {
ref.read(tabProvider.notifier).state = TabEnum.values[index];
},
selectedIconTheme: IconThemeData(
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
),
selectedLabelTextStyle: TextStyle(
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
),
useIndicator: false,
destinations: [
@@ -116,7 +117,7 @@ class TabControllerPage extends HookConsumerWidget {
selectedIcon: buildIcon(
Icon(
Icons.photo_library,
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
),
),
),
@@ -127,7 +128,7 @@ class TabControllerPage extends HookConsumerWidget {
),
selectedIcon: Icon(
Icons.search,
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
),
),
NavigationDestination(
@@ -137,7 +138,7 @@ class TabControllerPage extends HookConsumerWidget {
),
selectedIcon: Icon(
Icons.group,
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
),
),
NavigationDestination(
@@ -148,7 +149,7 @@ class TabControllerPage extends HookConsumerWidget {
selectedIcon: buildIcon(
Icon(
Icons.photo_album_rounded,
- color: Theme.of(context).primaryColor,
+ color: context.primaryColor,
),
),
),
diff --git a/mobile/lib/utils/capitalize.dart b/mobile/lib/utils/capitalize.dart
deleted file mode 100644
index 80b10cc58..000000000
--- a/mobile/lib/utils/capitalize.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-extension StringExtension on String {
- String capitalize() {
- return split(" ")
- .map(
- (str) => str.isEmpty ? str : str[0].toUpperCase() + str.substring(1),
- )
- .join(" ");
- }
-}
diff --git a/mobile/lib/utils/selection_handlers.dart b/mobile/lib/utils/selection_handlers.dart
index 511dcf81e..5d13d20a2 100644
--- a/mobile/lib/utils/selection_handlers.dart
+++ b/mobile/lib/utils/selection_handlers.dart
@@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/shared/models/asset.dart';
import 'package:immich_mobile/shared/providers/asset.provider.dart';
import 'package:immich_mobile/shared/services/share.service.dart';
@@ -26,7 +27,7 @@ void handleShareAssets(
gravity: ToastGravity.BOTTOM,
);
}
- Navigator.of(buildContext).pop();
+ context.pop();
},
);
return const ShareDialog();
diff --git a/mobile/openapi/.openapi-generator/FILES b/mobile/openapi/.openapi-generator/FILES
index 52b863a6f..57854e1b7 100644
--- a/mobile/openapi/.openapi-generator/FILES
+++ b/mobile/openapi/.openapi-generator/FILES
@@ -13,7 +13,6 @@ doc/ActivityCreateDto.md
doc/ActivityResponseDto.md
doc/ActivityStatisticsResponseDto.md
doc/AddUsersDto.md
-doc/AdminSignupResponseDto.md
doc/AlbumApi.md
doc/AlbumCountResponseDto.md
doc/AlbumResponseDto.md
@@ -82,6 +81,7 @@ doc/LoginCredentialDto.md
doc/LoginResponseDto.md
doc/LogoutResponseDto.md
doc/MapMarkerResponseDto.md
+doc/MapTheme.md
doc/MemoryLaneResponseDto.md
doc/MergePersonDto.md
doc/ModelType.md
@@ -101,6 +101,7 @@ doc/PersonResponseDto.md
doc/PersonStatisticsResponseDto.md
doc/PersonUpdateDto.md
doc/QueueStatusDto.md
+doc/ReactionLevel.md
doc/ReactionType.md
doc/RecognitionConfig.md
doc/ScanLibraryDto.md
@@ -198,7 +199,6 @@ lib/model/activity_create_dto.dart
lib/model/activity_response_dto.dart
lib/model/activity_statistics_response_dto.dart
lib/model/add_users_dto.dart
-lib/model/admin_signup_response_dto.dart
lib/model/album_count_response_dto.dart
lib/model/album_response_dto.dart
lib/model/all_job_status_response_dto.dart
@@ -265,6 +265,7 @@ lib/model/login_credential_dto.dart
lib/model/login_response_dto.dart
lib/model/logout_response_dto.dart
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/model_type.dart
@@ -281,6 +282,7 @@ lib/model/person_response_dto.dart
lib/model/person_statistics_response_dto.dart
lib/model/person_update_dto.dart
lib/model/queue_status_dto.dart
+lib/model/reaction_level.dart
lib/model/reaction_type.dart
lib/model/recognition_config.dart
lib/model/scan_library_dto.dart
@@ -347,7 +349,6 @@ test/activity_create_dto_test.dart
test/activity_response_dto_test.dart
test/activity_statistics_response_dto_test.dart
test/add_users_dto_test.dart
-test/admin_signup_response_dto_test.dart
test/album_api_test.dart
test/album_count_response_dto_test.dart
test/album_response_dto_test.dart
@@ -421,6 +422,7 @@ test/login_credential_dto_test.dart
test/login_response_dto_test.dart
test/logout_response_dto_test.dart
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/model_type_test.dart
@@ -440,6 +442,7 @@ test/person_response_dto_test.dart
test/person_statistics_response_dto_test.dart
test/person_update_dto_test.dart
test/queue_status_dto_test.dart
+test/reaction_level_test.dart
test/reaction_type_test.dart
test/recognition_config_test.dart
test/scan_library_dto_test.dart
diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md
index 70ef217a5..0bc2cc1e3 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.84.0
+- API version: 1.85.0
- Build package: org.openapitools.codegen.languages.DartClientCodegen
## Requirements
@@ -181,6 +181,7 @@ Class | Method | HTTP request | Description
*SharedLinkApi* | [**updateSharedLink**](doc//SharedLinkApi.md#updatesharedlink) | **PATCH** /shared-link/{id} |
*SystemConfigApi* | [**getConfig**](doc//SystemConfigApi.md#getconfig) | **GET** /system-config |
*SystemConfigApi* | [**getConfigDefaults**](doc//SystemConfigApi.md#getconfigdefaults) | **GET** /system-config/defaults |
+*SystemConfigApi* | [**getMapStyle**](doc//SystemConfigApi.md#getmapstyle) | **GET** /system-config/map/style.json |
*SystemConfigApi* | [**getStorageTemplateOptions**](doc//SystemConfigApi.md#getstoragetemplateoptions) | **GET** /system-config/storage-template-options |
*SystemConfigApi* | [**updateConfig**](doc//SystemConfigApi.md#updateconfig) | **PUT** /system-config |
*TagApi* | [**createTag**](doc//TagApi.md#createtag) | **POST** /tag |
@@ -212,7 +213,6 @@ Class | Method | HTTP request | Description
- [ActivityResponseDto](doc//ActivityResponseDto.md)
- [ActivityStatisticsResponseDto](doc//ActivityStatisticsResponseDto.md)
- [AddUsersDto](doc//AddUsersDto.md)
- - [AdminSignupResponseDto](doc//AdminSignupResponseDto.md)
- [AlbumCountResponseDto](doc//AlbumCountResponseDto.md)
- [AlbumResponseDto](doc//AlbumResponseDto.md)
- [AllJobStatusResponseDto](doc//AllJobStatusResponseDto.md)
@@ -275,6 +275,7 @@ Class | Method | HTTP request | Description
- [LoginResponseDto](doc//LoginResponseDto.md)
- [LogoutResponseDto](doc//LogoutResponseDto.md)
- [MapMarkerResponseDto](doc//MapMarkerResponseDto.md)
+ - [MapTheme](doc//MapTheme.md)
- [MemoryLaneResponseDto](doc//MemoryLaneResponseDto.md)
- [MergePersonDto](doc//MergePersonDto.md)
- [ModelType](doc//ModelType.md)
@@ -291,6 +292,7 @@ Class | Method | HTTP request | Description
- [PersonStatisticsResponseDto](doc//PersonStatisticsResponseDto.md)
- [PersonUpdateDto](doc//PersonUpdateDto.md)
- [QueueStatusDto](doc//QueueStatusDto.md)
+ - [ReactionLevel](doc//ReactionLevel.md)
- [ReactionType](doc//ReactionType.md)
- [RecognitionConfig](doc//RecognitionConfig.md)
- [ScanLibraryDto](doc//ScanLibraryDto.md)
diff --git a/mobile/openapi/doc/ActivityApi.md b/mobile/openapi/doc/ActivityApi.md
index 1af3f1f49..6221ef5e4 100644
--- a/mobile/openapi/doc/ActivityApi.md
+++ b/mobile/openapi/doc/ActivityApi.md
@@ -125,7 +125,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)
# **getActivities**
-> List getActivities(albumId, assetId, type, userId)
+> List getActivities(albumId, assetId, type, level, userId)
@@ -151,10 +151,11 @@ final api_instance = ActivityApi();
final albumId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
final assetId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
final type = ; // ReactionType |
+final level = ; // ReactionLevel |
final userId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
try {
- final result = api_instance.getActivities(albumId, assetId, type, userId);
+ final result = api_instance.getActivities(albumId, assetId, type, level, userId);
print(result);
} catch (e) {
print('Exception when calling ActivityApi->getActivities: $e\n');
@@ -168,6 +169,7 @@ Name | Type | Description | Notes
**albumId** | **String**| |
**assetId** | **String**| | [optional]
**type** | [**ReactionType**](.md)| | [optional]
+ **level** | [**ReactionLevel**](.md)| | [optional]
**userId** | **String**| | [optional]
### Return type
diff --git a/mobile/openapi/doc/AlbumResponseDto.md b/mobile/openapi/doc/AlbumResponseDto.md
index 93620b9fc..bc00d30af 100644
--- a/mobile/openapi/doc/AlbumResponseDto.md
+++ b/mobile/openapi/doc/AlbumResponseDto.md
@@ -17,6 +17,7 @@ Name | Type | Description | Notes
**endDate** | [**DateTime**](DateTime.md) | | [optional]
**hasSharedLink** | **bool** | |
**id** | **String** | |
+**isActivityEnabled** | **bool** | |
**lastModifiedAssetTimestamp** | [**DateTime**](DateTime.md) | | [optional]
**owner** | [**UserResponseDto**](UserResponseDto.md) | |
**ownerId** | **String** | |
diff --git a/mobile/openapi/doc/AssetApi.md b/mobile/openapi/doc/AssetApi.md
index cf50f659d..811841947 100644
--- a/mobile/openapi/doc/AssetApi.md
+++ b/mobile/openapi/doc/AssetApi.md
@@ -374,7 +374,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)
# **getAllAssets**
-> List getAllAssets(userId, isFavorite, isArchived, skip, updatedAfter, ifNoneMatch)
+> List getAllAssets(skip, take, userId, isFavorite, isArchived, updatedAfter, updatedBefore, ifNoneMatch)
@@ -399,15 +399,17 @@ import 'package:openapi/api.dart';
//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction);
final api_instance = AssetApi();
+final skip = 56; // int |
+final take = 56; // int |
final userId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
final isFavorite = true; // bool |
final isArchived = true; // bool |
-final skip = 8.14; // num |
final updatedAfter = 2013-10-20T19:20:30+01:00; // DateTime |
+final updatedBefore = 2013-10-20T19:20:30+01:00; // DateTime |
final ifNoneMatch = ifNoneMatch_example; // String | ETag of data already cached on the client
try {
- final result = api_instance.getAllAssets(userId, isFavorite, isArchived, skip, updatedAfter, ifNoneMatch);
+ final result = api_instance.getAllAssets(skip, take, userId, isFavorite, isArchived, updatedAfter, updatedBefore, ifNoneMatch);
print(result);
} catch (e) {
print('Exception when calling AssetApi->getAllAssets: $e\n');
@@ -418,11 +420,13 @@ try {
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
+ **skip** | **int**| | [optional]
+ **take** | **int**| | [optional]
**userId** | **String**| | [optional]
**isFavorite** | **bool**| | [optional]
**isArchived** | **bool**| | [optional]
- **skip** | **num**| | [optional]
**updatedAfter** | **DateTime**| | [optional]
+ **updatedBefore** | **DateTime**| | [optional]
**ifNoneMatch** | **String**| ETag of data already cached on the client | [optional]
### Return type
@@ -1696,7 +1700,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, isFavorite, key, duration, isArchived, isExternal, isOffline, isReadOnly, isVisible, libraryId, livePhotoData, sidecarData)
+> AssetFileUploadResponseDto uploadFile(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key, duration, isArchived, isExternal, isFavorite, isOffline, isReadOnly, isVisible, libraryId, livePhotoData, sidecarData)
@@ -1724,11 +1728,11 @@ final deviceAssetId = deviceAssetId_example; // String |
final deviceId = deviceId_example; // String |
final fileCreatedAt = 2013-10-20T19:20:30+01:00; // DateTime |
final fileModifiedAt = 2013-10-20T19:20:30+01:00; // DateTime |
-final isFavorite = true; // bool |
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 |
final isVisible = true; // bool |
@@ -1737,7 +1741,7 @@ final livePhotoData = BINARY_DATA_HERE; // MultipartFile |
final sidecarData = BINARY_DATA_HERE; // MultipartFile |
try {
- final result = api_instance.uploadFile(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, key, duration, isArchived, isExternal, isOffline, isReadOnly, isVisible, libraryId, livePhotoData, sidecarData);
+ final result = api_instance.uploadFile(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key, duration, isArchived, isExternal, isFavorite, isOffline, isReadOnly, isVisible, libraryId, livePhotoData, sidecarData);
print(result);
} catch (e) {
print('Exception when calling AssetApi->uploadFile: $e\n');
@@ -1753,11 +1757,11 @@ Name | Type | Description | Notes
**deviceId** | **String**| |
**fileCreatedAt** | **DateTime**| |
**fileModifiedAt** | **DateTime**| |
- **isFavorite** | **bool**| |
**key** | **String**| | [optional]
**duration** | **String**| | [optional]
**isArchived** | **bool**| | [optional]
**isExternal** | **bool**| | [optional]
+ **isFavorite** | **bool**| | [optional]
**isOffline** | **bool**| | [optional]
**isReadOnly** | **bool**| | [optional]
**isVisible** | **bool**| | [optional]
diff --git a/mobile/openapi/doc/AuthenticationApi.md b/mobile/openapi/doc/AuthenticationApi.md
index c56f88228..9521568e9 100644
--- a/mobile/openapi/doc/AuthenticationApi.md
+++ b/mobile/openapi/doc/AuthenticationApi.md
@@ -322,7 +322,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)
# **signUpAdmin**
-> AdminSignupResponseDto signUpAdmin(signUpDto)
+> UserResponseDto signUpAdmin(signUpDto)
@@ -349,7 +349,7 @@ Name | Type | Description | Notes
### Return type
-[**AdminSignupResponseDto**](AdminSignupResponseDto.md)
+[**UserResponseDto**](UserResponseDto.md)
### Authorization
diff --git a/mobile/openapi/doc/ImportAssetDto.md b/mobile/openapi/doc/ImportAssetDto.md
index c9a5f25d2..3f2747edc 100644
--- a/mobile/openapi/doc/ImportAssetDto.md
+++ b/mobile/openapi/doc/ImportAssetDto.md
@@ -16,7 +16,7 @@ Name | Type | Description | Notes
**fileModifiedAt** | [**DateTime**](DateTime.md) | |
**isArchived** | **bool** | | [optional]
**isExternal** | **bool** | | [optional]
-**isFavorite** | **bool** | |
+**isFavorite** | **bool** | | [optional]
**isOffline** | **bool** | | [optional]
**isReadOnly** | **bool** | | [optional] [default to true]
**isVisible** | **bool** | | [optional]
diff --git a/mobile/openapi/doc/LoginResponseDto.md b/mobile/openapi/doc/LoginResponseDto.md
index ad3592eff..e344ef124 100644
--- a/mobile/openapi/doc/LoginResponseDto.md
+++ b/mobile/openapi/doc/LoginResponseDto.md
@@ -8,14 +8,14 @@ import 'package:openapi/api.dart';
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
-**accessToken** | **String** | | [readonly]
-**firstName** | **String** | | [readonly]
-**isAdmin** | **bool** | | [readonly]
-**lastName** | **String** | | [readonly]
-**profileImagePath** | **String** | | [readonly]
-**shouldChangePassword** | **bool** | | [readonly]
-**userEmail** | **String** | | [readonly]
-**userId** | **String** | | [readonly]
+**accessToken** | **String** | |
+**firstName** | **String** | |
+**isAdmin** | **bool** | |
+**lastName** | **String** | |
+**profileImagePath** | **String** | |
+**shouldChangePassword** | **bool** | |
+**userEmail** | **String** | |
+**userId** | **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/AdminSignupResponseDto.md b/mobile/openapi/doc/MapTheme.md
similarity index 62%
rename from mobile/openapi/doc/AdminSignupResponseDto.md
rename to mobile/openapi/doc/MapTheme.md
index 08d3d8bfa..29fd8d998 100644
--- a/mobile/openapi/doc/AdminSignupResponseDto.md
+++ b/mobile/openapi/doc/MapTheme.md
@@ -1,4 +1,4 @@
-# openapi.model.AdminSignupResponseDto
+# openapi.model.MapTheme
## Load the model package
```dart
@@ -8,11 +8,6 @@ import 'package:openapi/api.dart';
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
-**createdAt** | [**DateTime**](DateTime.md) | |
-**email** | **String** | |
-**firstName** | **String** | |
-**id** | **String** | |
-**lastName** | **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/ReactionLevel.md b/mobile/openapi/doc/ReactionLevel.md
new file mode 100644
index 000000000..a53955cb0
--- /dev/null
+++ b/mobile/openapi/doc/ReactionLevel.md
@@ -0,0 +1,14 @@
+# openapi.model.ReactionLevel
+
+## Load the model package
+```dart
+import 'package:openapi/api.dart';
+```
+
+## Properties
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+
+[[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/ServerConfigDto.md b/mobile/openapi/doc/ServerConfigDto.md
index cbe56d2f4..fd543257b 100644
--- a/mobile/openapi/doc/ServerConfigDto.md
+++ b/mobile/openapi/doc/ServerConfigDto.md
@@ -10,7 +10,6 @@ Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**isInitialized** | **bool** | |
**loginPageMessage** | **String** | |
-**mapTileUrl** | **String** | |
**oauthButtonText** | **String** | |
**trashDays** | **int** | |
diff --git a/mobile/openapi/doc/SystemConfigApi.md b/mobile/openapi/doc/SystemConfigApi.md
index 9377b6e0b..e782265b4 100644
--- a/mobile/openapi/doc/SystemConfigApi.md
+++ b/mobile/openapi/doc/SystemConfigApi.md
@@ -11,6 +11,7 @@ Method | HTTP request | Description
------------- | ------------- | -------------
[**getConfig**](SystemConfigApi.md#getconfig) | **GET** /system-config |
[**getConfigDefaults**](SystemConfigApi.md#getconfigdefaults) | **GET** /system-config/defaults |
+[**getMapStyle**](SystemConfigApi.md#getmapstyle) | **GET** /system-config/map/style.json |
[**getStorageTemplateOptions**](SystemConfigApi.md#getstoragetemplateoptions) | **GET** /system-config/storage-template-options |
[**updateConfig**](SystemConfigApi.md#updateconfig) | **PUT** /system-config |
@@ -117,6 +118,61 @@ 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)
+# **getMapStyle**
+> Object getMapStyle(theme)
+
+
+
+### 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 = SystemConfigApi();
+final theme = ; // MapTheme |
+
+try {
+ final result = api_instance.getMapStyle(theme);
+ print(result);
+} catch (e) {
+ print('Exception when calling SystemConfigApi->getMapStyle: $e\n');
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **theme** | [**MapTheme**](.md)| |
+
+### Return type
+
+[**Object**](Object.md)
+
+### Authorization
+
+[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer)
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **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)
+
# **getStorageTemplateOptions**
> SystemConfigTemplateStorageOptionDto getStorageTemplateOptions()
diff --git a/mobile/openapi/doc/SystemConfigMapDto.md b/mobile/openapi/doc/SystemConfigMapDto.md
index 99fa91fd2..1846563eb 100644
--- a/mobile/openapi/doc/SystemConfigMapDto.md
+++ b/mobile/openapi/doc/SystemConfigMapDto.md
@@ -8,8 +8,9 @@ import 'package:openapi/api.dart';
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
+**darkStyle** | **String** | |
**enabled** | **bool** | |
-**tileUrl** | **String** | |
+**lightStyle** | **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/UpdateAlbumDto.md b/mobile/openapi/doc/UpdateAlbumDto.md
index 283b8bc29..4ded87d1b 100644
--- a/mobile/openapi/doc/UpdateAlbumDto.md
+++ b/mobile/openapi/doc/UpdateAlbumDto.md
@@ -11,6 +11,7 @@ Name | Type | Description | Notes
**albumName** | **String** | | [optional]
**albumThumbnailAssetId** | **String** | | [optional]
**description** | **String** | | [optional]
+**isActivityEnabled** | **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/lib/api.dart b/mobile/openapi/lib/api.dart
index 2bd437010..7e4ed3a7b 100644
--- a/mobile/openapi/lib/api.dart
+++ b/mobile/openapi/lib/api.dart
@@ -54,7 +54,6 @@ part 'model/activity_create_dto.dart';
part 'model/activity_response_dto.dart';
part 'model/activity_statistics_response_dto.dart';
part 'model/add_users_dto.dart';
-part 'model/admin_signup_response_dto.dart';
part 'model/album_count_response_dto.dart';
part 'model/album_response_dto.dart';
part 'model/all_job_status_response_dto.dart';
@@ -117,6 +116,7 @@ part 'model/login_credential_dto.dart';
part 'model/login_response_dto.dart';
part 'model/logout_response_dto.dart';
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/model_type.dart';
@@ -133,6 +133,7 @@ part 'model/person_response_dto.dart';
part 'model/person_statistics_response_dto.dart';
part 'model/person_update_dto.dart';
part 'model/queue_status_dto.dart';
+part 'model/reaction_level.dart';
part 'model/reaction_type.dart';
part 'model/recognition_config.dart';
part 'model/scan_library_dto.dart';
diff --git a/mobile/openapi/lib/api/activity_api.dart b/mobile/openapi/lib/api/activity_api.dart
index 458538a5d..8e2354e20 100644
--- a/mobile/openapi/lib/api/activity_api.dart
+++ b/mobile/openapi/lib/api/activity_api.dart
@@ -112,8 +112,10 @@ class ActivityApi {
///
/// * [ReactionType] type:
///
+ /// * [ReactionLevel] level:
+ ///
/// * [String] userId:
- Future getActivitiesWithHttpInfo(String albumId, { String? assetId, ReactionType? type, String? userId, }) async {
+ Future getActivitiesWithHttpInfo(String albumId, { String? assetId, ReactionType? type, ReactionLevel? level, String? userId, }) async {
// ignore: prefer_const_declarations
final path = r'/activity';
@@ -131,6 +133,9 @@ class ActivityApi {
if (type != null) {
queryParams.addAll(_queryParams('', 'type', type));
}
+ if (level != null) {
+ queryParams.addAll(_queryParams('', 'level', level));
+ }
if (userId != null) {
queryParams.addAll(_queryParams('', 'userId', userId));
}
@@ -157,9 +162,11 @@ class ActivityApi {
///
/// * [ReactionType] type:
///
+ /// * [ReactionLevel] level:
+ ///
/// * [String] userId:
- Future?> getActivities(String albumId, { String? assetId, ReactionType? type, String? userId, }) async {
- final response = await getActivitiesWithHttpInfo(albumId, assetId: assetId, type: type, userId: userId, );
+ Future?> getActivities(String albumId, { String? assetId, ReactionType? type, ReactionLevel? level, String? userId, }) async {
+ final response = await getActivitiesWithHttpInfo(albumId, assetId: assetId, type: type, level: level, userId: userId, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
diff --git a/mobile/openapi/lib/api/asset_api.dart b/mobile/openapi/lib/api/asset_api.dart
index b0e9c822d..0d3c2bfe8 100644
--- a/mobile/openapi/lib/api/asset_api.dart
+++ b/mobile/openapi/lib/api/asset_api.dart
@@ -309,19 +309,23 @@ class AssetApi {
///
/// Parameters:
///
+ /// * [int] skip:
+ ///
+ /// * [int] take:
+ ///
/// * [String] userId:
///
/// * [bool] isFavorite:
///
/// * [bool] isArchived:
///
- /// * [num] skip:
- ///
/// * [DateTime] updatedAfter:
///
+ /// * [DateTime] updatedBefore:
+ ///
/// * [String] ifNoneMatch:
/// ETag of data already cached on the client
- Future getAllAssetsWithHttpInfo({ String? userId, bool? isFavorite, bool? isArchived, num? skip, DateTime? updatedAfter, String? ifNoneMatch, }) async {
+ Future getAllAssetsWithHttpInfo({ int? skip, int? take, String? userId, bool? isFavorite, bool? isArchived, DateTime? updatedAfter, DateTime? updatedBefore, String? ifNoneMatch, }) async {
// ignore: prefer_const_declarations
final path = r'/asset';
@@ -332,6 +336,12 @@ class AssetApi {
final headerParams = {};
final formParams = {};
+ if (skip != null) {
+ queryParams.addAll(_queryParams('', 'skip', skip));
+ }
+ if (take != null) {
+ queryParams.addAll(_queryParams('', 'take', take));
+ }
if (userId != null) {
queryParams.addAll(_queryParams('', 'userId', userId));
}
@@ -341,12 +351,12 @@ class AssetApi {
if (isArchived != null) {
queryParams.addAll(_queryParams('', 'isArchived', isArchived));
}
- if (skip != null) {
- queryParams.addAll(_queryParams('', 'skip', skip));
- }
if (updatedAfter != null) {
queryParams.addAll(_queryParams('', 'updatedAfter', updatedAfter));
}
+ if (updatedBefore != null) {
+ queryParams.addAll(_queryParams('', 'updatedBefore', updatedBefore));
+ }
if (ifNoneMatch != null) {
headerParams[r'if-none-match'] = parameterToString(ifNoneMatch);
@@ -370,20 +380,24 @@ class AssetApi {
///
/// Parameters:
///
+ /// * [int] skip:
+ ///
+ /// * [int] take:
+ ///
/// * [String] userId:
///
/// * [bool] isFavorite:
///
/// * [bool] isArchived:
///
- /// * [num] skip:
- ///
/// * [DateTime] updatedAfter:
///
+ /// * [DateTime] updatedBefore:
+ ///
/// * [String] ifNoneMatch:
/// ETag of data already cached on the client
- Future?> getAllAssets({ String? userId, bool? isFavorite, bool? isArchived, num? skip, DateTime? updatedAfter, String? ifNoneMatch, }) async {
- final response = await getAllAssetsWithHttpInfo( userId: userId, isFavorite: isFavorite, isArchived: isArchived, skip: skip, updatedAfter: updatedAfter, ifNoneMatch: ifNoneMatch, );
+ Future?> getAllAssets({ int? skip, int? take, String? userId, bool? isFavorite, bool? isArchived, DateTime? updatedAfter, DateTime? updatedBefore, String? ifNoneMatch, }) async {
+ final response = await getAllAssetsWithHttpInfo( skip: skip, take: take, userId: userId, isFavorite: isFavorite, isArchived: isArchived, updatedAfter: updatedAfter, updatedBefore: updatedBefore, ifNoneMatch: ifNoneMatch, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
@@ -1660,8 +1674,6 @@ class AssetApi {
///
/// * [DateTime] fileModifiedAt (required):
///
- /// * [bool] isFavorite (required):
- ///
/// * [String] key:
///
/// * [String] duration:
@@ -1670,6 +1682,8 @@ class AssetApi {
///
/// * [bool] isExternal:
///
+ /// * [bool] isFavorite:
+ ///
/// * [bool] isOffline:
///
/// * [bool] isReadOnly:
@@ -1681,7 +1695,7 @@ class AssetApi {
/// * [MultipartFile] livePhotoData:
///
/// * [MultipartFile] sidecarData:
- Future uploadFileWithHttpInfo(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, bool isFavorite, { String? key, String? duration, bool? isArchived, bool? isExternal, 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? isExternal, bool? isFavorite, bool? isOffline, bool? isReadOnly, bool? isVisible, String? libraryId, MultipartFile? livePhotoData, MultipartFile? sidecarData, }) async {
// ignore: prefer_const_declarations
final path = r'/asset/upload';
@@ -1790,8 +1804,6 @@ class AssetApi {
///
/// * [DateTime] fileModifiedAt (required):
///
- /// * [bool] isFavorite (required):
- ///
/// * [String] key:
///
/// * [String] duration:
@@ -1800,6 +1812,8 @@ class AssetApi {
///
/// * [bool] isExternal:
///
+ /// * [bool] isFavorite:
+ ///
/// * [bool] isOffline:
///
/// * [bool] isReadOnly:
@@ -1811,8 +1825,8 @@ class AssetApi {
/// * [MultipartFile] livePhotoData:
///
/// * [MultipartFile] sidecarData:
- Future uploadFile(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, bool isFavorite, { String? key, String? duration, bool? isArchived, bool? isExternal, bool? isOffline, bool? isReadOnly, bool? isVisible, String? libraryId, MultipartFile? livePhotoData, MultipartFile? sidecarData, }) async {
- final response = await uploadFileWithHttpInfo(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, key: key, duration: duration, isArchived: isArchived, isExternal: isExternal, 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? 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, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
diff --git a/mobile/openapi/lib/api/authentication_api.dart b/mobile/openapi/lib/api/authentication_api.dart
index 3b986d34d..7c6dac147 100644
--- a/mobile/openapi/lib/api/authentication_api.dart
+++ b/mobile/openapi/lib/api/authentication_api.dart
@@ -300,7 +300,7 @@ class AuthenticationApi {
/// Parameters:
///
/// * [SignUpDto] signUpDto (required):
- Future signUpAdmin(SignUpDto signUpDto,) async {
+ Future signUpAdmin(SignUpDto signUpDto,) async {
final response = await signUpAdminWithHttpInfo(signUpDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
@@ -309,7 +309,7 @@ class AuthenticationApi {
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
- return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'AdminSignupResponseDto',) as AdminSignupResponseDto;
+ return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserResponseDto',) as UserResponseDto;
}
return null;
diff --git a/mobile/openapi/lib/api/system_config_api.dart b/mobile/openapi/lib/api/system_config_api.dart
index c8b0c58ec..f13f8d52d 100644
--- a/mobile/openapi/lib/api/system_config_api.dart
+++ b/mobile/openapi/lib/api/system_config_api.dart
@@ -98,6 +98,55 @@ class SystemConfigApi {
return null;
}
+ /// Performs an HTTP 'GET /system-config/map/style.json' operation and returns the [Response].
+ /// Parameters:
+ ///
+ /// * [MapTheme] theme (required):
+ Future getMapStyleWithHttpInfo(MapTheme theme,) async {
+ // ignore: prefer_const_declarations
+ final path = r'/system-config/map/style.json';
+
+ // ignore: prefer_final_locals
+ Object? postBody;
+
+ final queryParams = [];
+ final headerParams = {};
+ final formParams = {};
+
+ queryParams.addAll(_queryParams('', 'theme', theme));
+
+ const contentTypes = [];
+
+
+ return apiClient.invokeAPI(
+ path,
+ 'GET',
+ queryParams,
+ postBody,
+ headerParams,
+ formParams,
+ contentTypes.isEmpty ? null : contentTypes.first,
+ );
+ }
+
+ /// Parameters:
+ ///
+ /// * [MapTheme] theme (required):
+ Future