merge main
This commit is contained in:
@@ -3,7 +3,6 @@ import 'dart:collection';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/constants/enums.dart';
|
||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||
@@ -24,6 +23,7 @@ import 'package:immich_mobile/services/entity.service.dart';
|
||||
import 'package:immich_mobile/services/sync.service.dart';
|
||||
import 'package:immich_mobile/utils/hash.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:immich_mobile/utils/debug_print.dart';
|
||||
|
||||
final albumServiceProvider = Provider(
|
||||
(ref) => AlbumService(
|
||||
@@ -124,7 +124,7 @@ class AlbumService {
|
||||
} finally {
|
||||
_localCompleter.complete(changes);
|
||||
}
|
||||
debugPrint("refreshDeviceAlbums took ${sw.elapsedMilliseconds}ms");
|
||||
dPrint(() => "refreshDeviceAlbums took ${sw.elapsedMilliseconds}ms");
|
||||
return changes;
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ class AlbumService {
|
||||
} finally {
|
||||
_remoteCompleter.complete(changes);
|
||||
}
|
||||
debugPrint("refreshRemoteAlbums took ${sw.elapsedMilliseconds}ms");
|
||||
dPrint(() => "refreshRemoteAlbums took ${sw.elapsedMilliseconds}ms");
|
||||
return changes;
|
||||
}
|
||||
|
||||
@@ -220,7 +220,7 @@ class AlbumService {
|
||||
|
||||
return AlbumAddAssetsResponse(alreadyInAlbum: result.duplicates, successfullyAdded: addedAssets.length);
|
||||
} catch (e) {
|
||||
debugPrint("Error addAssets ${e.toString()}");
|
||||
dPrint(() => "Error addAssets ${e.toString()}");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -242,7 +242,7 @@ class AlbumService {
|
||||
await _albumRepository.update(album);
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint("Error setActivityEnabled ${e.toString()}");
|
||||
dPrint(() => "Error setActivityEnabled ${e.toString()}");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -271,7 +271,7 @@ class AlbumService {
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint("Error deleteAlbum ${e.toString()}");
|
||||
dPrint(() => "Error deleteAlbum ${e.toString()}");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -281,7 +281,7 @@ class AlbumService {
|
||||
await _albumApiRepository.removeUser(album.remoteId!, userId: "me");
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint("Error leaveAlbum ${e.toString()}");
|
||||
dPrint(() => "Error leaveAlbum ${e.toString()}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -293,7 +293,7 @@ class AlbumService {
|
||||
await _updateAssets(album.id, remove: toRemove.toList());
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint("Error removeAssetFromAlbum ${e.toString()}");
|
||||
dPrint(() => "Error removeAssetFromAlbum ${e.toString()}");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -310,7 +310,7 @@ class AlbumService {
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
debugPrint("Error removeUser ${error.toString()}");
|
||||
dPrint(() => "Error removeUser ${error.toString()}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -327,7 +327,7 @@ class AlbumService {
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
debugPrint("Error addUsers ${error.toString()}");
|
||||
dPrint(() => "Error addUsers ${error.toString()}");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -340,7 +340,7 @@ class AlbumService {
|
||||
await _albumRepository.update(album);
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint("Error changeTitleAlbum ${e.toString()}");
|
||||
dPrint(() => "Error changeTitleAlbum ${e.toString()}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -353,7 +353,7 @@ class AlbumService {
|
||||
await _albumRepository.update(album);
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint("Error changeDescriptionAlbum ${e.toString()}");
|
||||
dPrint(() => "Error changeDescriptionAlbum ${e.toString()}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,14 @@ import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||
import 'package:immich_mobile/entities/store.entity.dart';
|
||||
import 'package:immich_mobile/utils/url_helper.dart';
|
||||
import 'package:immich_mobile/utils/user_agent.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:openapi/api.dart';
|
||||
import 'package:immich_mobile/utils/user_agent.dart';
|
||||
import 'package:immich_mobile/utils/debug_print.dart';
|
||||
|
||||
class ApiService implements Authentication {
|
||||
late ApiClient _apiClient;
|
||||
@@ -86,7 +86,7 @@ class ApiService implements Authentication {
|
||||
setEndpoint(endpoint);
|
||||
|
||||
// Save in local database for next startup
|
||||
await Store.put(StoreKey.serverEndpoint, endpoint);
|
||||
Store.put(StoreKey.serverEndpoint, endpoint);
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ class ApiService implements Authentication {
|
||||
return endpoint;
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint("Could not locate /.well-known/immich at $baseUrl");
|
||||
dPrint(() => "Could not locate /.well-known/immich at $baseUrl");
|
||||
}
|
||||
|
||||
return "";
|
||||
|
||||
@@ -46,7 +46,7 @@ enum AppSettingsEnum<T> {
|
||||
syncAlbums<bool>(StoreKey.syncAlbums, null, false),
|
||||
autoEndpointSwitching<bool>(StoreKey.autoEndpointSwitching, null, false),
|
||||
photoManagerCustomFilter<bool>(StoreKey.photoManagerCustomFilter, null, true),
|
||||
betaTimeline<bool>(StoreKey.betaTimeline, null, false),
|
||||
betaTimeline<bool>(StoreKey.betaTimeline, null, true),
|
||||
enableBackup<bool>(StoreKey.enableBackup, null, false),
|
||||
useCellularForUploadVideos<bool>(StoreKey.useWifiForUploadVideos, null, false),
|
||||
useCellularForUploadPhotos<bool>(StoreKey.useWifiForUploadPhotos, null, false),
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/constants/enums.dart';
|
||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||
@@ -26,6 +25,7 @@ import 'package:immich_mobile/services/sync.service.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
import 'package:openapi/api.dart';
|
||||
import 'package:immich_mobile/utils/debug_print.dart';
|
||||
|
||||
final assetServiceProvider = Provider(
|
||||
(ref) => AssetService(
|
||||
@@ -87,7 +87,7 @@ class AssetService {
|
||||
getChangedAssets: _getRemoteAssetChanges,
|
||||
loadAssets: _getRemoteAssets,
|
||||
);
|
||||
debugPrint("refreshRemoteAssets full took ${sw.elapsedMilliseconds}ms");
|
||||
dPrint(() => "refreshRemoteAssets full took ${sw.elapsedMilliseconds}ms");
|
||||
return changes;
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ class AssetService {
|
||||
if (a.isInDb) {
|
||||
await _assetRepository.transaction(() => _assetRepository.update(a));
|
||||
} else {
|
||||
debugPrint("[loadExif] parameter Asset is not from DB!");
|
||||
dPrint(() => "[loadExif] parameter Asset is not from DB!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import 'dart:ui' show DartPluginRegistrant, IsolateNameServer, PluginUtilities;
|
||||
import 'package:cancellation_token_http/http.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
@@ -29,6 +28,7 @@ import 'package:immich_mobile/services/backup.service.dart';
|
||||
import 'package:immich_mobile/services/localization.service.dart';
|
||||
import 'package:immich_mobile/utils/backup_progress.dart';
|
||||
import 'package:immich_mobile/utils/bootstrap.dart';
|
||||
import 'package:immich_mobile/utils/debug_print.dart';
|
||||
import 'package:immich_mobile/utils/diff.dart';
|
||||
import 'package:immich_mobile/utils/http_ssl_options.dart';
|
||||
import 'package:path_provider_foundation/path_provider_foundation.dart';
|
||||
@@ -165,7 +165,7 @@ class BackgroundService {
|
||||
]);
|
||||
}
|
||||
} catch (error) {
|
||||
debugPrint("[_updateNotification] failed to communicate with plugin");
|
||||
dPrint(() => "[_updateNotification] failed to communicate with plugin");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -177,7 +177,7 @@ class BackgroundService {
|
||||
return await _backgroundChannel.invokeMethod('showError', [title, content, individualTag]);
|
||||
}
|
||||
} catch (error) {
|
||||
debugPrint("[_showErrorNotification] failed to communicate with plugin");
|
||||
dPrint(() => "[_showErrorNotification] failed to communicate with plugin");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -188,7 +188,7 @@ class BackgroundService {
|
||||
return await _backgroundChannel.invokeMethod('clearErrorNotifications');
|
||||
}
|
||||
} catch (error) {
|
||||
debugPrint("[_clearErrorNotifications] failed to communicate with plugin");
|
||||
dPrint(() => "[_clearErrorNotifications] failed to communicate with plugin");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -196,7 +196,7 @@ class BackgroundService {
|
||||
/// await to ensure this thread (foreground or background) has exclusive access
|
||||
Future<bool> acquireLock() async {
|
||||
if (_hasLock) {
|
||||
debugPrint("WARNING: [acquireLock] called more than once");
|
||||
dPrint(() => "WARNING: [acquireLock] called more than once");
|
||||
return true;
|
||||
}
|
||||
final int lockTime = Timeline.now;
|
||||
@@ -302,19 +302,19 @@ class BackgroundService {
|
||||
|
||||
final bool hasAccess = await waitForLock;
|
||||
if (!hasAccess) {
|
||||
debugPrint("[_callHandler] could not acquire lock, exiting");
|
||||
dPrint(() => "[_callHandler] could not acquire lock, exiting");
|
||||
return false;
|
||||
}
|
||||
|
||||
final translationsOk = await loadTranslations();
|
||||
if (!translationsOk) {
|
||||
debugPrint("[_callHandler] could not load translations");
|
||||
dPrint(() => "[_callHandler] could not load translations");
|
||||
}
|
||||
|
||||
final bool ok = await _onAssetsChanged();
|
||||
return ok;
|
||||
} catch (error) {
|
||||
debugPrint(error.toString());
|
||||
dPrint(() => error.toString());
|
||||
return false;
|
||||
} finally {
|
||||
releaseLock();
|
||||
@@ -324,14 +324,14 @@ class BackgroundService {
|
||||
_cancellationToken?.cancel();
|
||||
return true;
|
||||
default:
|
||||
debugPrint("Unknown method ${call.method}");
|
||||
dPrint(() => "Unknown method ${call.method}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> _onAssetsChanged() async {
|
||||
final (isar, drift, logDb) = await Bootstrap.initDB();
|
||||
await Bootstrap.initDomain(isar, drift, logDb);
|
||||
await Bootstrap.initDomain(isar, drift, logDb, shouldBufferLogs: false, listenStoreUpdates: false);
|
||||
|
||||
final ref = ProviderContainer(
|
||||
overrides: [
|
||||
@@ -344,9 +344,7 @@ class BackgroundService {
|
||||
HttpSSLOptions.apply();
|
||||
await ref.read(apiServiceProvider).setAccessToken(Store.get(StoreKey.accessToken));
|
||||
await ref.read(authServiceProvider).setOpenApiServiceEndpoint();
|
||||
if (kDebugMode) {
|
||||
debugPrint("[BG UPLOAD] Using endpoint: ${ref.read(apiServiceProvider).apiClient.basePath}");
|
||||
}
|
||||
dPrint(() => "[BG UPLOAD] Using endpoint: ${ref.read(apiServiceProvider).apiClient.basePath}");
|
||||
|
||||
final selectedAlbums = await ref.read(backupAlbumRepositoryProvider).getAllBySelection(BackupSelection.select);
|
||||
final excludedAlbums = await ref.read(backupAlbumRepositoryProvider).getAllBySelection(BackupSelection.exclude);
|
||||
|
||||
@@ -4,7 +4,6 @@ import 'dart:io';
|
||||
|
||||
import 'package:cancellation_token_http/http.dart' as http;
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||
import 'package:immich_mobile/entities/album.entity.dart';
|
||||
@@ -29,6 +28,7 @@ import 'package:openapi/api.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:permission_handler/permission_handler.dart' as pm;
|
||||
import 'package:photo_manager/photo_manager.dart' show PMProgressHandler;
|
||||
import 'package:immich_mobile/utils/debug_print.dart';
|
||||
|
||||
final backupServiceProvider = Provider(
|
||||
(ref) => BackupService(
|
||||
@@ -69,7 +69,7 @@ class BackupService {
|
||||
try {
|
||||
return await _apiService.assetsApi.getAllUserAssetsByDeviceId(deviceId);
|
||||
} catch (e) {
|
||||
debugPrint('Error [getDeviceBackupAsset] ${e.toString()}');
|
||||
dPrint(() => 'Error [getDeviceBackupAsset] ${e.toString()}');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -356,8 +356,9 @@ class BackupService {
|
||||
final error = responseBody;
|
||||
final errorMessage = error['message'] ?? error['error'];
|
||||
|
||||
debugPrint(
|
||||
"Error(${error['statusCode']}) uploading ${asset.localId} | $originalFileName | Created on ${asset.fileCreatedAt} | ${error['error']}",
|
||||
dPrint(
|
||||
() =>
|
||||
"Error(${error['statusCode']}) uploading ${asset.localId} | $originalFileName | Created on ${asset.fileCreatedAt} | ${error['error']}",
|
||||
);
|
||||
|
||||
onError(
|
||||
@@ -398,11 +399,11 @@ class BackupService {
|
||||
}
|
||||
}
|
||||
} on http.CancelledException {
|
||||
debugPrint("Backup was cancelled by the user");
|
||||
dPrint(() => "Backup was cancelled by the user");
|
||||
anyErrors = true;
|
||||
break;
|
||||
} catch (error, stackTrace) {
|
||||
debugPrint("Error backup asset: ${error.toString()}: $stackTrace");
|
||||
dPrint(() => "Error backup asset: ${error.toString()}: $stackTrace");
|
||||
anyErrors = true;
|
||||
continue;
|
||||
} finally {
|
||||
@@ -411,7 +412,7 @@ class BackupService {
|
||||
await file?.delete();
|
||||
await livePhotoFile?.delete();
|
||||
} catch (e) {
|
||||
debugPrint("ERROR deleting file: ${e.toString()}");
|
||||
dPrint(() => "ERROR deleting file: ${e.toString()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -454,7 +455,9 @@ class BackupService {
|
||||
if (![200, 201].contains(response.statusCode)) {
|
||||
var error = responseBody;
|
||||
|
||||
debugPrint("Error(${error['statusCode']}) uploading livePhoto for assetId | $livePhotoTitle | ${error['error']}");
|
||||
dPrint(
|
||||
() => "Error(${error['statusCode']}) uploading livePhoto for assetId | $livePhotoTitle | ${error['error']}",
|
||||
);
|
||||
}
|
||||
|
||||
return responseBody.containsKey('id') ? responseBody['id'] : null;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/providers/backup/manual_upload.provider.dart';
|
||||
import 'package:immich_mobile/providers/notification_permission.provider.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:immich_mobile/utils/debug_print.dart';
|
||||
|
||||
final localNotificationService = Provider(
|
||||
(ref) => LocalNotificationService(ref.watch(notificationPermissionProvider), ref),
|
||||
@@ -110,7 +110,7 @@ class LocalNotificationService {
|
||||
switch (notificationResponse.actionId) {
|
||||
case cancelUploadActionID:
|
||||
{
|
||||
debugPrint("User cancelled manual upload operation");
|
||||
dPrint(() => "User cancelled manual upload operation");
|
||||
ref.read(manualUploadProvider.notifier).cancelBackup();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
import 'package:easy_localization/src/easy_localization_controller.dart';
|
||||
import 'package:easy_localization/src/localization.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:immich_mobile/constants/locales.dart';
|
||||
import 'package:immich_mobile/generated/codegen_loader.g.dart';
|
||||
import 'package:immich_mobile/utils/debug_print.dart';
|
||||
|
||||
/// Workaround to manually load translations in another Isolate
|
||||
Future<bool> loadTranslations() async {
|
||||
@@ -17,7 +17,7 @@ Future<bool> loadTranslations() async {
|
||||
assetLoader: const CodegenLoader(),
|
||||
path: translationsPath,
|
||||
useOnlyLangCode: false,
|
||||
onLoadError: (e) => debugPrint(e.toString()),
|
||||
onLoadError: (e) => dPrint(() => e.toString()),
|
||||
fallbackLocale: locales.values.first,
|
||||
);
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/extensions/string_extensions.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/search_api.repository.dart';
|
||||
@@ -10,6 +9,7 @@ import 'package:immich_mobile/repositories/asset.repository.dart';
|
||||
import 'package:immich_mobile/services/api.service.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:openapi/api.dart';
|
||||
import 'package:immich_mobile/utils/debug_print.dart';
|
||||
|
||||
final searchServiceProvider = Provider(
|
||||
(ref) => SearchService(
|
||||
@@ -43,7 +43,7 @@ class SearchService {
|
||||
model: model,
|
||||
);
|
||||
} catch (e) {
|
||||
debugPrint("[ERROR] [getSearchSuggestions] ${e.toString()}");
|
||||
dPrint(() => "[ERROR] [getSearchSuggestions] ${e.toString()}");
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/models/server_info/server_config.model.dart';
|
||||
import 'package:immich_mobile/models/server_info/server_disk_info.model.dart';
|
||||
@@ -6,6 +5,7 @@ import 'package:immich_mobile/models/server_info/server_features.model.dart';
|
||||
import 'package:immich_mobile/models/server_info/server_version.model.dart';
|
||||
import 'package:immich_mobile/providers/api.provider.dart';
|
||||
import 'package:immich_mobile/services/api.service.dart';
|
||||
import 'package:immich_mobile/utils/debug_print.dart';
|
||||
|
||||
final serverInfoServiceProvider = Provider((ref) => ServerInfoService(ref.watch(apiServiceProvider)));
|
||||
|
||||
@@ -14,6 +14,15 @@ class ServerInfoService {
|
||||
|
||||
const ServerInfoService(this._apiService);
|
||||
|
||||
Future<bool> ping() async {
|
||||
try {
|
||||
await _apiService.serverInfoApi.pingServer().timeout(const Duration(seconds: 5));
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<ServerDiskInfo?> getDiskInfo() async {
|
||||
try {
|
||||
final dto = await _apiService.serverInfoApi.getStorage();
|
||||
@@ -21,7 +30,7 @@ class ServerInfoService {
|
||||
return ServerDiskInfo.fromDto(dto);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint("Error [getDiskInfo] ${e.toString()}");
|
||||
dPrint(() => "Error [getDiskInfo] ${e.toString()}");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -33,7 +42,7 @@ class ServerInfoService {
|
||||
return ServerVersion.fromDto(dto);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint("Error [getServerVersion] ${e.toString()}");
|
||||
dPrint(() => "Error [getServerVersion] ${e.toString()}");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -45,7 +54,7 @@ class ServerInfoService {
|
||||
return ServerFeatures.fromDto(dto);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint("Error [getServerFeatures] ${e.toString()}");
|
||||
dPrint(() => "Error [getServerFeatures] ${e.toString()}");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -57,7 +66,7 @@ class ServerInfoService {
|
||||
return ServerConfig.fromDto(dto);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint("Error [getServerConfig] ${e.toString()}");
|
||||
dPrint(() => "Error [getServerConfig] ${e.toString()}");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/providers/api.provider.dart';
|
||||
import 'package:immich_mobile/repositories/asset.repository.dart';
|
||||
import 'package:immich_mobile/services/api.service.dart';
|
||||
import 'package:openapi/api.dart';
|
||||
import 'package:immich_mobile/utils/debug_print.dart';
|
||||
|
||||
class StackService {
|
||||
const StackService(this._api, this._assetRepository);
|
||||
@@ -16,7 +16,7 @@ class StackService {
|
||||
try {
|
||||
return _api.stacksApi.getStack(stackId);
|
||||
} catch (error) {
|
||||
debugPrint("Error while fetching stack: $error");
|
||||
dPrint(() => "Error while fetching stack: $error");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -25,7 +25,7 @@ class StackService {
|
||||
try {
|
||||
return _api.stacksApi.createStack(StackCreateDto(assetIds: assetIds));
|
||||
} catch (error) {
|
||||
debugPrint("Error while creating stack: $error");
|
||||
dPrint(() => "Error while creating stack: $error");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -34,7 +34,7 @@ class StackService {
|
||||
try {
|
||||
return await _api.stacksApi.updateStack(stackId, StackUpdateDto(primaryAssetId: primaryAssetId));
|
||||
} catch (error) {
|
||||
debugPrint("Error while updating stack children: $error");
|
||||
dPrint(() => "Error while updating stack children: $error");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -54,7 +54,7 @@ class StackService {
|
||||
}
|
||||
await _assetRepository.transaction(() => _assetRepository.updateAll(removeAssets));
|
||||
} catch (error) {
|
||||
debugPrint("Error while deleting stack: $error");
|
||||
dPrint(() => "Error while deleting stack: $error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,7 +147,9 @@ class SyncService {
|
||||
dbUsers,
|
||||
compare: (UserDto a, UserDto b) => a.id.compareTo(b.id),
|
||||
both: (UserDto a, UserDto b) {
|
||||
if (!a.updatedAt.isAtSameMomentAs(b.updatedAt) ||
|
||||
if ((a.updatedAt == null && b.updatedAt != null) ||
|
||||
(a.updatedAt != null && b.updatedAt == null) ||
|
||||
(a.updatedAt != null && b.updatedAt != null && !a.updatedAt!.isAtSameMomentAs(b.updatedAt!)) ||
|
||||
a.isPartnerSharedBy != b.isPartnerSharedBy ||
|
||||
a.isPartnerSharedWith != b.isPartnerSharedWith ||
|
||||
a.inTimeline != b.inTimeline) {
|
||||
|
||||
@@ -3,7 +3,7 @@ import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:background_downloader/background_downloader.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cancellation_token_http/http.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/constants/constants.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
@@ -19,7 +19,9 @@ import 'package:immich_mobile/providers/infrastructure/storage.provider.dart';
|
||||
import 'package:immich_mobile/repositories/upload.repository.dart';
|
||||
import 'package:immich_mobile/services/api.service.dart';
|
||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:immich_mobile/utils/debug_print.dart';
|
||||
|
||||
final uploadServiceProvider = Provider((ref) {
|
||||
final service = UploadService(
|
||||
@@ -51,6 +53,7 @@ class UploadService {
|
||||
final StorageRepository _storageRepository;
|
||||
final DriftLocalAssetRepository _localAssetRepository;
|
||||
final AppSettingsService _appSettingsService;
|
||||
final Logger _logger = Logger('UploadService');
|
||||
|
||||
final StreamController<TaskStatusUpdate> _taskStatusController = StreamController<TaskStatusUpdate>.broadcast();
|
||||
final StreamController<TaskProgressUpdate> _taskProgressController = StreamController<TaskProgressUpdate>.broadcast();
|
||||
@@ -78,7 +81,7 @@ class UploadService {
|
||||
_taskProgressController.close();
|
||||
}
|
||||
|
||||
Future<void> enqueueTasks(List<UploadTask> tasks) {
|
||||
Future<List<bool>> enqueueTasks(List<UploadTask> tasks) {
|
||||
return _uploadRepository.enqueueBackgroundAll(tasks);
|
||||
}
|
||||
|
||||
@@ -138,7 +141,6 @@ class UploadService {
|
||||
}
|
||||
|
||||
final batch = candidates.skip(i).take(batchSize).toList();
|
||||
|
||||
List<UploadTask> tasks = [];
|
||||
for (final asset in batch) {
|
||||
final task = await _getUploadTask(asset);
|
||||
@@ -156,9 +158,7 @@ class UploadService {
|
||||
}
|
||||
}
|
||||
|
||||
// Enqueue All does not work from the background on Android yet. This method is a temporary workaround
|
||||
// that enqueues tasks one by one.
|
||||
Future<void> startBackupSerial(String userId) async {
|
||||
Future<void> startBackupWithHttpClient(String userId, bool hasWifi, CancellationToken token) async {
|
||||
await _storageRepository.clearCache();
|
||||
|
||||
shouldAbortQueuingTasks = false;
|
||||
@@ -168,14 +168,29 @@ class UploadService {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final asset in candidates) {
|
||||
if (shouldAbortQueuingTasks) {
|
||||
const batchSize = 100;
|
||||
for (int i = 0; i < candidates.length; i += batchSize) {
|
||||
if (shouldAbortQueuingTasks || token.isCancelled) {
|
||||
break;
|
||||
}
|
||||
|
||||
final task = await _getUploadTask(asset);
|
||||
if (task != null) {
|
||||
await _uploadRepository.enqueueBackground(task);
|
||||
final batch = candidates.skip(i).take(batchSize).toList();
|
||||
List<UploadTaskWithFile> tasks = [];
|
||||
for (final asset in batch) {
|
||||
final requireWifi = _shouldRequireWiFi(asset);
|
||||
if (requireWifi && !hasWifi) {
|
||||
_logger.warning('Skipping upload for ${asset.id} because it requires WiFi');
|
||||
continue;
|
||||
}
|
||||
|
||||
final task = await _getUploadTaskWithFile(asset);
|
||||
if (task != null) {
|
||||
tasks.add(task);
|
||||
}
|
||||
}
|
||||
|
||||
if (tasks.isNotEmpty && !shouldAbortQueuingTasks) {
|
||||
await _uploadRepository.backupWithDartClient(tasks, token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,10 +253,46 @@ class UploadService {
|
||||
|
||||
await enqueueTasks([uploadTask]);
|
||||
} catch (error, stackTrace) {
|
||||
debugPrint("Error handling live photo upload task: $error $stackTrace");
|
||||
dPrint(() => "Error handling live photo upload task: $error $stackTrace");
|
||||
}
|
||||
}
|
||||
|
||||
Future<UploadTaskWithFile?> _getUploadTaskWithFile(LocalAsset asset) async {
|
||||
final entity = await _storageRepository.getAssetEntityForAsset(asset);
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final file = await _storageRepository.getFileForAsset(asset.id);
|
||||
if (file == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final originalFileName = entity.isLivePhoto ? p.setExtension(asset.name, p.extension(file.path)) : asset.name;
|
||||
|
||||
String metadata = UploadTaskMetadata(
|
||||
localAssetId: asset.id,
|
||||
isLivePhotos: entity.isLivePhoto,
|
||||
livePhotoVideoId: '',
|
||||
).toJson();
|
||||
|
||||
return UploadTaskWithFile(
|
||||
file: file,
|
||||
task: await buildUploadTask(
|
||||
file,
|
||||
createdAt: asset.createdAt,
|
||||
modifiedAt: asset.updatedAt,
|
||||
originalFileName: originalFileName,
|
||||
deviceAssetId: asset.id,
|
||||
metadata: metadata,
|
||||
group: "group",
|
||||
priority: 0,
|
||||
isFavorite: asset.isFavorite,
|
||||
requiresWiFi: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<UploadTask?> _getUploadTask(LocalAsset asset, {String group = kBackupGroup, int? priority}) async {
|
||||
final entity = await _storageRepository.getAssetEntityForAsset(asset);
|
||||
if (entity == null) {
|
||||
|
||||
Reference in New Issue
Block a user