mirror of
https://github.com/immich-app/immich.git
synced 2026-06-22 06:42:27 -07:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e4cf79263b | |||
| b24a617142 | |||
| 62b00a1f26 | |||
| 95fc5e9682 |
@@ -15,14 +15,14 @@ When using "Deduplicate All" or viewing suggestions, Immich automatically presel
|
||||
|
||||
### Synchronizing metadata
|
||||
|
||||
When resolving duplicates, metadata from trashed assets is automatically synchronized to the kept assets. The following metadata is synchronized:
|
||||
When resolving duplicates, metadata from trashed assets is automatically synchronized to the kept asset. This synchronization only happens when **exactly one** asset is kept and at least one asset is trashed. When more than one asset is kept, metadata is not merged — the assets keep their own metadata and are simply removed from the duplicate group. The following metadata is synchronized:
|
||||
|
||||
| Name | Description |
|
||||
| ----------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Album | The kept assets will be added to _every_ album that the other assets in the group belong to. |
|
||||
| Favorite | If any of the assets in the group have been added to favorites, every kept asset will also be added to favorites. |
|
||||
| Rating | If one or more assets in the duplicate group have a rating, the highest rating is selected and synchronized to the kept assets. |
|
||||
| Description | Descriptions from each asset are combined together and synchronized to all the kept assets. |
|
||||
| Visibility | The most restrictive visibility is applied to the kept assets. |
|
||||
| Location | Latitude and longitude are copied if all assets with geolocation data in the group share the same coordinates. |
|
||||
| Tag | Tags from all assets in the group are merged and applied to every kept asset. |
|
||||
| Name | Description |
|
||||
| ----------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| Album | The kept asset will be added to _every_ album that the other assets in the group belong to. |
|
||||
| Favorite | If any of the assets in the group have been added to favorites, the kept asset will also be added to favorites. |
|
||||
| Rating | If one or more assets in the duplicate group have a rating, the highest rating is selected and synchronized to the kept asset. |
|
||||
| Description | Descriptions from each asset are combined together and synchronized to the kept asset. |
|
||||
| Visibility | The most restrictive visibility is applied to the kept asset. |
|
||||
| Location | Latitude and longitude are copied if all assets with geolocation data in the group share the same coordinates. |
|
||||
| Tag | Tags from all assets in the group are merged and applied to the kept asset. |
|
||||
|
||||
@@ -22,7 +22,7 @@ platform :android do
|
||||
task: 'bundle',
|
||||
build_type: 'Release',
|
||||
properties: {
|
||||
"android.injected.version.code" => 3049,
|
||||
"android.injected.version.code" => 3050,
|
||||
"android.injected.version.name" => "3.0.0-rc.2",
|
||||
}
|
||||
)
|
||||
@@ -35,7 +35,7 @@ platform :android do
|
||||
task: 'bundle',
|
||||
build_type: 'Release',
|
||||
properties: {
|
||||
"android.injected.version.code" => 3049,
|
||||
"android.injected.version.code" => 3050,
|
||||
"android.injected.version.name" => "3.0.0-rc.2",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 54;
|
||||
objectVersion = 77;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@@ -11,6 +11,7 @@
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
467DA6EAF83F3481F8BD94AB /* Pods_ShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AB817AA297EDEC88B23F3F6 /* Pods_ShareExtension.framework */; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
@@ -19,9 +20,9 @@
|
||||
B21E34AC2E5B09190031FDB9 /* BackgroundWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B21E34AB2E5B09100031FDB9 /* BackgroundWorker.swift */; };
|
||||
B25D377A2E72CA15008B6CA7 /* Connectivity.g.swift in Sources */ = {isa = PBXBuildFile; fileRef = B25D37782E72CA15008B6CA7 /* Connectivity.g.swift */; };
|
||||
B25D377C2E72CA26008B6CA7 /* ConnectivityApiImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = B25D377B2E72CA20008B6CA7 /* ConnectivityApiImpl.swift */; };
|
||||
B2BE315F2E5E5229006EEF88 /* BackgroundWorker.g.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2BE315E2E5E5229006EEF88 /* BackgroundWorker.g.swift */; };
|
||||
B2EE00022E72CA15008B6CA7 /* PermissionApi.g.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2EE00012E72CA15008B6CA7 /* PermissionApi.g.swift */; };
|
||||
B2EE00042E72CA15008B6CA7 /* PermissionApiImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2EE00032E72CA15008B6CA7 /* PermissionApiImpl.swift */; };
|
||||
B2BE315F2E5E5229006EEF88 /* BackgroundWorker.g.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2BE315E2E5E5229006EEF88 /* BackgroundWorker.g.swift */; };
|
||||
D3BED739C0BC29BB32E18EB2 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CC499FBCE6B29B2DAFED7130 /* Pods_Runner.framework */; };
|
||||
F02538E92DFBCBDD008C3FA3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
F0B57D3A2DF764BD00DC5BCC /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F0B57D392DF764BD00DC5BCC /* WidgetKit.framework */; };
|
||||
@@ -39,7 +40,6 @@
|
||||
FEE084F82EC172460045228E /* SQLiteData in Frameworks */ = {isa = PBXBuildFile; productRef = FEE084F72EC172460045228E /* SQLiteData */; };
|
||||
FEE084FB2EC1725A0045228E /* RawStructuredFieldValues in Frameworks */ = {isa = PBXBuildFile; productRef = FEE084FA2EC1725A0045228E /* RawStructuredFieldValues */; };
|
||||
FEE084FD2EC1725A0045228E /* StructuredFieldValues in Frameworks */ = {isa = PBXBuildFile; productRef = FEE084FC2EC1725A0045228E /* StructuredFieldValues */; };
|
||||
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -94,6 +94,7 @@
|
||||
6D160F04A389B9FFBC557803 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
8AB817AA297EDEC88B23F3F6 /* Pods_ShareExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ShareExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
937632897A02DE9C249F20A6 /* Pods-ShareExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShareExtension.debug.xcconfig"; path = "Target Support Files/Pods-ShareExtension/Pods-ShareExtension.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
@@ -109,9 +110,9 @@
|
||||
B21E34AB2E5B09100031FDB9 /* BackgroundWorker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundWorker.swift; sourceTree = "<group>"; };
|
||||
B25D37782E72CA15008B6CA7 /* Connectivity.g.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Connectivity.g.swift; sourceTree = "<group>"; };
|
||||
B25D377B2E72CA20008B6CA7 /* ConnectivityApiImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectivityApiImpl.swift; sourceTree = "<group>"; };
|
||||
B2BE315E2E5E5229006EEF88 /* BackgroundWorker.g.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundWorker.g.swift; sourceTree = "<group>"; };
|
||||
B2EE00012E72CA15008B6CA7 /* PermissionApi.g.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermissionApi.g.swift; sourceTree = "<group>"; };
|
||||
B2EE00032E72CA15008B6CA7 /* PermissionApiImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermissionApiImpl.swift; sourceTree = "<group>"; };
|
||||
B2BE315E2E5E5229006EEF88 /* BackgroundWorker.g.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundWorker.g.swift; sourceTree = "<group>"; };
|
||||
C4A6A71F33CE37B3C913115C /* Pods-ShareExtension.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShareExtension.profile.xcconfig"; path = "Target Support Files/Pods-ShareExtension/Pods-ShareExtension.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
CC499FBCE6B29B2DAFED7130 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F0B57D382DF764BD00DC5BCC /* WidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = WidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -130,7 +131,6 @@
|
||||
FE5499F72F1198DE006016CB /* RemoteImagesImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteImagesImpl.swift; sourceTree = "<group>"; };
|
||||
FE5FE4AD2F30FBC000A71243 /* ImageProcessing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageProcessing.swift; sourceTree = "<group>"; };
|
||||
FEAFA8722E4D42F4001E47FE /* Thumbhash.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Thumbhash.swift; sourceTree = "<group>"; };
|
||||
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||
@@ -153,15 +153,11 @@
|
||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||
B231F52D2E93A44A00BC45D1 /* Core */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
);
|
||||
path = Core;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B2CF7F8C2DDE4EBB00744BF6 /* Sync */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
);
|
||||
path = Sync;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -183,8 +179,6 @@
|
||||
};
|
||||
FEE084F22EC172080045228E /* Schemas */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
);
|
||||
path = Schemas;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -364,9 +358,6 @@
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
97C146ED1CF9000F007C117D /* Runner */ = {
|
||||
packageProductDependencies = (
|
||||
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
|
||||
);
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
buildPhases = (
|
||||
@@ -473,7 +464,7 @@
|
||||
);
|
||||
mainGroup = 97C146E51CF9000F007C117D;
|
||||
packageReferences = (
|
||||
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */,
|
||||
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
|
||||
FEE084F62EC172460045228E /* XCRemoteSwiftPackageReference "sqlite-data" */,
|
||||
FEE084F92EC1725A0045228E /* XCRemoteSwiftPackageReference "swift-http-structured-headers" */,
|
||||
);
|
||||
@@ -528,10 +519,14 @@
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||
@@ -561,10 +556,14 @@
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||
@@ -758,7 +757,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
NEW_SETTING = "";
|
||||
SDKROOT = iphoneos;
|
||||
@@ -777,7 +776,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 240;
|
||||
CURRENT_PROJECT_VERSION = 4;
|
||||
DEVELOPMENT_TEAM = 2W7AC6T8T5;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
@@ -786,7 +785,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.121.0;
|
||||
MARKETING_VERSION = 3.0.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = app.futo.immich.profile;
|
||||
PRODUCT_NAME = "Immich-Profile";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@@ -847,7 +846,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
NEW_SETTING = "";
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
@@ -901,7 +900,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
NEW_SETTING = "";
|
||||
SDKROOT = iphoneos;
|
||||
@@ -922,7 +921,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 240;
|
||||
CURRENT_PROJECT_VERSION = 4;
|
||||
DEVELOPMENT_TEAM = 2W7AC6T8T5;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
@@ -931,7 +930,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.121.0;
|
||||
MARKETING_VERSION = 3.0.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = app.futo.immich.debug;
|
||||
PRODUCT_NAME = "Immich-Debug";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@@ -951,7 +950,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 240;
|
||||
CURRENT_PROJECT_VERSION = 4;
|
||||
DEVELOPMENT_TEAM = 2W7AC6T8T5;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
@@ -960,7 +959,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.121.0;
|
||||
MARKETING_VERSION = 3.0.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = app.alextran.immich;
|
||||
PRODUCT_NAME = Immich;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@@ -1262,7 +1261,7 @@
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCLocalSwiftPackageReference section */
|
||||
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = {
|
||||
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
|
||||
isa = XCLocalSwiftPackageReference;
|
||||
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
|
||||
};
|
||||
@@ -1307,17 +1306,7 @@
|
||||
package = FEE084F92EC1725A0045228E /* XCRemoteSwiftPackageReference "swift-http-structured-headers" */;
|
||||
productName = StructuredFieldValues;
|
||||
};
|
||||
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = FlutterGeneratedPluginSwiftPackage;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
/* Begin XCLocalSwiftPackageReference section */
|
||||
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
|
||||
isa = XCLocalSwiftPackageReference;
|
||||
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
|
||||
};
|
||||
/* End XCLocalSwiftPackageReference section */
|
||||
};
|
||||
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||
}
|
||||
|
||||
+203
-202
@@ -1,205 +1,206 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>AppGroupId</key>
|
||||
<string>$(CUSTOM_GROUP_ID)</string>
|
||||
<key>BGTaskSchedulerPermittedIdentifiers</key>
|
||||
<array>
|
||||
<string>app.alextran.immich.background.refreshUpload</string>
|
||||
<string>app.alextran.immich.background.processingUpload</string>
|
||||
</array>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>ShareHandler</string>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Alternate</string>
|
||||
<key>LSItemContentTypes</key>
|
||||
<array>
|
||||
<string>public.file-url</string>
|
||||
<string>public.image</string>
|
||||
<string>public.text</string>
|
||||
<string>public.movie</string>
|
||||
<string>public.url</string>
|
||||
<string>public.data</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleLocalizations</key>
|
||||
<array>
|
||||
<string>en</string>
|
||||
<string>ar</string>
|
||||
<string>ca</string>
|
||||
<string>cs</string>
|
||||
<string>da</string>
|
||||
<string>de</string>
|
||||
<string>es</string>
|
||||
<string>fi</string>
|
||||
<string>fr</string>
|
||||
<string>he</string>
|
||||
<string>hi</string>
|
||||
<string>hu</string>
|
||||
<string>it</string>
|
||||
<string>ja</string>
|
||||
<string>ko</string>
|
||||
<string>lv</string>
|
||||
<string>mn</string>
|
||||
<string>nb</string>
|
||||
<string>nl</string>
|
||||
<string>pl</string>
|
||||
<string>pt</string>
|
||||
<string>ro</string>
|
||||
<string>ru</string>
|
||||
<string>sk</string>
|
||||
<string>sl</string>
|
||||
<string>sr</string>
|
||||
<string>sv</string>
|
||||
<string>th</string>
|
||||
<string>uk</string>
|
||||
<string>vi</string>
|
||||
<string>zh</string>
|
||||
</array>
|
||||
<key>CFBundleName</key>
|
||||
<string>immich_mobile</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.0.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>Share Extension</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>ShareMedia-$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>Deep Link</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>immich</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>240</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>https</string>
|
||||
</array>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||
<string>No</string>
|
||||
<key>MGLMapboxMetricsEnabledSettingShownInApp</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>NSBonjourServices</key>
|
||||
<array>
|
||||
<string>_googlecast._tcp</string>
|
||||
<string>_CC1AD845._googlecast._tcp</string>
|
||||
</array>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>We need to access the camera to let you take beautiful video using this app</string>
|
||||
<key>NSFaceIDUsageDescription</key>
|
||||
<string>We need to use FaceID to allow access to your locked folder</string>
|
||||
<key>NSLocalNetworkUsageDescription</key>
|
||||
<string>We need local network permission to connect to the local server using IP address and allow the casting feature to work</string>
|
||||
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
||||
<string>We require this permission to access the local WiFi name for background upload mechanism</string>
|
||||
<key>NSLocationUsageDescription</key>
|
||||
<string>We require this permission to access the local WiFi name</string>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>We require this permission to access the local WiFi name</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>We need to access the microphone to let you take beautiful video using this app</string>
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
<string>We need to manage backup your photos album</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>We need to manage backup your photos album</string>
|
||||
<key>NSUserActivityTypes</key>
|
||||
<array>
|
||||
<string>INSendMessageIntent</string>
|
||||
</array>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
<false/>
|
||||
<key>UISceneConfigurations</key>
|
||||
<dict>
|
||||
<key>UIWindowSceneSessionRoleApplication</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UISceneClassName</key>
|
||||
<string>UIWindowScene</string>
|
||||
<key>UISceneConfigurationName</key>
|
||||
<string>flutter</string>
|
||||
<key>UISceneDelegateClassName</key>
|
||||
<string>FlutterSceneDelegate</string>
|
||||
<key>UISceneStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>fetch</string>
|
||||
<string>processing</string>
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<false/>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<true/>
|
||||
<key>io.flutter.embedded_views_preview</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
<dict>
|
||||
<key>AppGroupId</key>
|
||||
<string>$(CUSTOM_GROUP_ID)</string>
|
||||
<key>BGTaskSchedulerPermittedIdentifiers</key>
|
||||
<array>
|
||||
<string>app.alextran.immich.background.refreshUpload</string>
|
||||
<string>app.alextran.immich.background.processingUpload</string>
|
||||
</array>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true />
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>ShareHandler</string>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Alternate</string>
|
||||
<key>LSItemContentTypes</key>
|
||||
<array>
|
||||
<string>public.file-url</string>
|
||||
<string>public.image</string>
|
||||
<string>public.text</string>
|
||||
<string>public.movie</string>
|
||||
<string>public.url</string>
|
||||
<string>public.data</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleLocalizations</key>
|
||||
<array>
|
||||
<string>en</string>
|
||||
<string>ar</string>
|
||||
<string>ca</string>
|
||||
<string>cs</string>
|
||||
<string>da</string>
|
||||
<string>de</string>
|
||||
<string>es</string>
|
||||
<string>fi</string>
|
||||
<string>fr</string>
|
||||
<string>he</string>
|
||||
<string>hi</string>
|
||||
<string>hu</string>
|
||||
<string>it</string>
|
||||
<string>ja</string>
|
||||
<string>ko</string>
|
||||
<string>lv</string>
|
||||
<string>mn</string>
|
||||
<string>nb</string>
|
||||
<string>nl</string>
|
||||
<string>pl</string>
|
||||
<string>pt</string>
|
||||
<string>ro</string>
|
||||
<string>ru</string>
|
||||
<string>sk</string>
|
||||
<string>sl</string>
|
||||
<string>sr</string>
|
||||
<string>sv</string>
|
||||
<string>th</string>
|
||||
<string>uk</string>
|
||||
<string>vi</string>
|
||||
<string>zh</string>
|
||||
</array>
|
||||
<key>CFBundleName</key>
|
||||
<string>immich_mobile</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.0.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>Share Extension</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>ShareMedia-$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>Deep Link</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>immich</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>4</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false />
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>https</string>
|
||||
</array>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true />
|
||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||
<string>No</string>
|
||||
<key>MGLMapboxMetricsEnabledSettingShownInApp</key>
|
||||
<true />
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true />
|
||||
</dict>
|
||||
<key>NSBonjourServices</key>
|
||||
<array>
|
||||
<string>_googlecast._tcp</string>
|
||||
<string>_CC1AD845._googlecast._tcp</string>
|
||||
</array>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>We need to access the camera to let you take beautiful video using this app</string>
|
||||
<key>NSFaceIDUsageDescription</key>
|
||||
<string>We need to use FaceID to allow access to your locked folder</string>
|
||||
<key>NSLocalNetworkUsageDescription</key>
|
||||
<string>We need local network permission to connect to the local server using IP address and
|
||||
allow the casting feature to work</string>
|
||||
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
||||
<string>We require this permission to access the local WiFi name for background upload mechanism</string>
|
||||
<key>NSLocationUsageDescription</key>
|
||||
<string>We require this permission to access the local WiFi name</string>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>We require this permission to access the local WiFi name</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>We need to access the microphone to let you take beautiful video using this app</string>
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
<string>We need to manage backup your photos album</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>We need to manage backup your photos album</string>
|
||||
<key>NSUserActivityTypes</key>
|
||||
<array>
|
||||
<string>INSendMessageIntent</string>
|
||||
</array>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
<false />
|
||||
<key>UISceneConfigurations</key>
|
||||
<dict>
|
||||
<key>UIWindowSceneSessionRoleApplication</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UISceneClassName</key>
|
||||
<string>UIWindowScene</string>
|
||||
<key>UISceneConfigurationName</key>
|
||||
<string>flutter</string>
|
||||
<key>UISceneDelegateClassName</key>
|
||||
<string>FlutterSceneDelegate</string>
|
||||
<key>UISceneStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true />
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>fetch</string>
|
||||
<string>processing</string>
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<false />
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<true />
|
||||
<key>io.flutter.embedded_views_preview</key>
|
||||
<true />
|
||||
</dict>
|
||||
</plist>
|
||||
+1
-1
@@ -2,7 +2,7 @@ name: immich_mobile
|
||||
description: Immich - selfhosted backup media file on mobile phone
|
||||
|
||||
publish_to: 'none'
|
||||
version: 3.0.0-rc.2+3049
|
||||
version: 3.0.0-rc.2+3050
|
||||
|
||||
environment:
|
||||
sdk: '>=3.12.0 <4.0.0'
|
||||
|
||||
@@ -289,6 +289,34 @@
|
||||
"required": ["albumIds"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "assetDataWebhook",
|
||||
"title": "Trigger Webhook",
|
||||
"description": "POST asset data to any URL",
|
||||
"types": ["AssetV1"],
|
||||
"hostFunctions": true,
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string",
|
||||
"title": "URL",
|
||||
"description": "Asset data will be POSTed to this URL as a JSON object"
|
||||
},
|
||||
"headerName": {
|
||||
"type": "string",
|
||||
"title": "Header name",
|
||||
"description": "The name of an additional header to include with the request (e.g. authentication)"
|
||||
},
|
||||
"headerValue": {
|
||||
"type": "string",
|
||||
"title": "Header value",
|
||||
"description": "The value of the additional header"
|
||||
}
|
||||
},
|
||||
"required": ["url"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "noop1",
|
||||
"title": "DEV: Nested properties",
|
||||
|
||||
Vendored
+2
@@ -5,6 +5,7 @@ declare module 'extism:host' {
|
||||
createAlbum(ptr: PTR): I64;
|
||||
addAssetsToAlbum(ptr: PTR): I64;
|
||||
addAssetsToAlbums(ptr: PTR): I64;
|
||||
httpRequest(ptr: PTR): I64;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,4 +25,5 @@ declare module 'main' {
|
||||
export function assetTimeline(): I32;
|
||||
export function assetTrash(): I32;
|
||||
export function assetAddToAlbums(): I32;
|
||||
export function assetDataWebhook(): I32;
|
||||
}
|
||||
|
||||
@@ -181,3 +181,25 @@ export const assetAddToAlbums = () => {
|
||||
return {};
|
||||
});
|
||||
};
|
||||
|
||||
export const assetDataWebhook = () => {
|
||||
return wrapper<WorkflowType.AssetV1, { url: string; headerName?: string; headerValue?: string }>(
|
||||
({ config, data, functions }) => {
|
||||
let headers: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
if (config.headerName && config.headerValue) {
|
||||
headers[config.headerName] = config.headerValue;
|
||||
}
|
||||
|
||||
functions.httpRequest(config.url, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data.asset),
|
||||
headers,
|
||||
});
|
||||
|
||||
return {};
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -13,6 +13,7 @@ declare module 'extism:host' {
|
||||
createAlbum(ptr: PTR): I64;
|
||||
addAssetsToAlbum(ptr: PTR): I64;
|
||||
addAssetsToAlbums(ptr: PTR): I64;
|
||||
httpRequest(ptr: PTR): I64;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +34,11 @@ type HostFunctionResult<T> =
|
||||
|
||||
type QueryParams<T extends (...args: any) => any> = Parameters<T>[0];
|
||||
type AlbumSearchDto = QueryParams<typeof getAllAlbums>;
|
||||
type HttpRequestOptions = {
|
||||
method?: string;
|
||||
headers?: Record<string, string>;
|
||||
body?: string;
|
||||
};
|
||||
|
||||
export const hostFunctions = (authToken: string) => {
|
||||
const host = Host.getFunctions();
|
||||
@@ -75,5 +81,11 @@ export const hostFunctions = (authToken: string) => {
|
||||
),
|
||||
addAssetsToAlbums: ({ assetIds, albumIds }: AlbumsToAssets) =>
|
||||
call('addAssetsToAlbums', authToken, [{ albumIds, assetIds }]),
|
||||
httpRequest: (url: string, options?: HttpRequestOptions) =>
|
||||
call<[string, HttpRequestOptions | undefined], string>(
|
||||
'httpRequest',
|
||||
authToken,
|
||||
[url, options],
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -74,12 +74,26 @@ export class WorkflowExecutionService extends BaseService {
|
||||
const addAssetsToAlbums = this.wrap<[dto: AlbumsAddAssetsDto]>((authDto, args) =>
|
||||
albumService.addAssetsToAlbums(authDto, ...args),
|
||||
);
|
||||
const httpRequest = this.wrap<
|
||||
[
|
||||
url: string,
|
||||
options?: {
|
||||
method?: string;
|
||||
headers?: Record<string, string>;
|
||||
body?: string;
|
||||
},
|
||||
]
|
||||
>(async (_, args) => {
|
||||
const res = await fetch(...args);
|
||||
return res.text();
|
||||
});
|
||||
|
||||
const functions = {
|
||||
searchAlbums,
|
||||
createAlbum,
|
||||
addAssetsToAlbum,
|
||||
addAssetsToAlbums,
|
||||
httpRequest,
|
||||
};
|
||||
|
||||
const stubs: typeof functions = {
|
||||
@@ -87,6 +101,7 @@ export class WorkflowExecutionService extends BaseService {
|
||||
createAlbum: dummy,
|
||||
addAssetsToAlbum: dummy,
|
||||
addAssetsToAlbums: dummy,
|
||||
httpRequest: dummy,
|
||||
};
|
||||
|
||||
const plugins = await this.pluginRepository.getForLoad();
|
||||
|
||||
@@ -499,11 +499,9 @@
|
||||
{album}
|
||||
{person}
|
||||
{stack}
|
||||
showSlideshow={true}
|
||||
preAction={handlePreAction}
|
||||
onAction={handleAction}
|
||||
{onUndoDelete}
|
||||
onPlaySlideshow={() => ($slideshowState = SlideshowState.PlaySlideshow)}
|
||||
onClose={onClose ? () => onClose(stack?.primaryAssetId ?? asset.id) : undefined}
|
||||
{onRemoveFromAlbum}
|
||||
{playOriginalVideo}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
import RatingAction from '$lib/components/asset-viewer/actions/RatingAction.svelte';
|
||||
import RemoveAssetFromStack from '$lib/components/asset-viewer/actions/RemoveAssetFromStack.svelte';
|
||||
import RestoreAction from '$lib/components/asset-viewer/actions/RestoreAction.svelte';
|
||||
import SetAlbumCoverAction from '$lib/components/asset-viewer/actions/SetAlbumCoverAction.svelte';
|
||||
import SetFeaturedPhotoAction from '$lib/components/asset-viewer/actions/SetPersonFeaturedAction.svelte';
|
||||
import SetProfilePictureAction from '$lib/components/asset-viewer/actions/SetProfilePictureAction.svelte';
|
||||
import SetStackPrimaryAsset from '$lib/components/asset-viewer/actions/SetStackPrimaryAsset.svelte';
|
||||
@@ -24,6 +23,7 @@
|
||||
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
|
||||
import { languageManager } from '$lib/managers/language-manager.svelte';
|
||||
import { Route } from '$lib/route';
|
||||
import { getAlbumAssetActions } from '$lib/services/album.service';
|
||||
import { getGlobalActions } from '$lib/services/app.service';
|
||||
import { getAssetActions } from '$lib/services/asset.service';
|
||||
import { getSharedLink, withoutIcons } from '$lib/utils';
|
||||
@@ -38,15 +38,7 @@
|
||||
type StackResponseDto,
|
||||
} from '@immich/sdk';
|
||||
import { ActionButton, CommandPaletteDefaultProvider, Tooltip, type ActionItem } from '@immich/ui';
|
||||
import {
|
||||
mdiArrowLeft,
|
||||
mdiArrowRight,
|
||||
mdiCompare,
|
||||
mdiDotsVertical,
|
||||
mdiImageSearch,
|
||||
mdiPresentationPlay,
|
||||
mdiVideoOutline,
|
||||
} from '@mdi/js';
|
||||
import { mdiArrowLeft, mdiArrowRight, mdiCompare, mdiDotsVertical, mdiImageSearch, mdiVideoOutline } from '@mdi/js';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
interface Props {
|
||||
@@ -54,11 +46,9 @@
|
||||
album?: AlbumResponseDto | null;
|
||||
person?: PersonResponseDto | null;
|
||||
stack?: StackResponseDto | null;
|
||||
showSlideshow?: boolean;
|
||||
preAction: PreAction;
|
||||
onAction: OnAction;
|
||||
onUndoDelete?: OnUndoDelete;
|
||||
onPlaySlideshow: () => void;
|
||||
onClose?: () => void;
|
||||
onRemoveFromAlbum?: (assetIds: string[]) => void;
|
||||
playOriginalVideo: boolean;
|
||||
@@ -70,11 +60,9 @@
|
||||
album = null,
|
||||
person = null,
|
||||
stack = null,
|
||||
showSlideshow = false,
|
||||
preAction,
|
||||
onAction,
|
||||
onUndoDelete = undefined,
|
||||
onPlaySlideshow,
|
||||
onClose,
|
||||
onRemoveFromAlbum,
|
||||
playOriginalVideo = false,
|
||||
@@ -147,9 +135,7 @@
|
||||
|
||||
{#if !sharedLink}
|
||||
<ButtonContextMenu direction="left" align="top-right" color="secondary" title={$t('more')} icon={mdiDotsVertical}>
|
||||
{#if showSlideshow && !isLocked}
|
||||
<MenuOption icon={mdiPresentationPlay} text={$t('slideshow')} onClick={onPlaySlideshow} />
|
||||
{/if}
|
||||
<ActionMenuItem action={Actions.PlaySlideshow} />
|
||||
|
||||
<ActionMenuItem action={Actions.Download} />
|
||||
<ActionMenuItem action={Actions.DownloadOriginal} />
|
||||
@@ -177,7 +163,8 @@
|
||||
{/if}
|
||||
{/if}
|
||||
{#if album}
|
||||
<SetAlbumCoverAction {asset} {album} />
|
||||
{@const { SetCover } = getAlbumAssetActions($t, album, asset)}
|
||||
<ActionMenuItem action={SetCover} />
|
||||
{/if}
|
||||
{#if person}
|
||||
<SetFeaturedPhotoAction {asset} {person} {onAction} />
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
<script lang="ts">
|
||||
import MenuOption from '$lib/components/shared-components/context-menu/MenuOption.svelte';
|
||||
import { eventManager } from '$lib/managers/event-manager.svelte';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { updateAlbumInfo, type AlbumResponseDto, type AssetResponseDto } from '@immich/sdk';
|
||||
import { toastManager } from '@immich/ui';
|
||||
import { mdiImageOutline } from '@mdi/js';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
interface Props {
|
||||
asset: AssetResponseDto;
|
||||
album: AlbumResponseDto;
|
||||
}
|
||||
|
||||
let { asset, album }: Props = $props();
|
||||
|
||||
const handleUpdateThumbnail = async () => {
|
||||
try {
|
||||
const response = await updateAlbumInfo({
|
||||
id: album.id,
|
||||
updateAlbumDto: {
|
||||
albumThumbnailAssetId: asset.id,
|
||||
},
|
||||
});
|
||||
eventManager.emit('AlbumUpdate', response);
|
||||
toastManager.primary($t('album_cover_updated'));
|
||||
} catch (error) {
|
||||
handleError(error, $t('errors.unable_to_update_album_cover'));
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<MenuOption text={$t('set_as_album_cover')} icon={mdiImageOutline} onClick={handleUpdateThumbnail} />
|
||||
@@ -10,12 +10,13 @@ import {
|
||||
updateAlbumUser,
|
||||
type AlbumResponseDto,
|
||||
type AlbumsAddAssetsResponseDto,
|
||||
type AssetResponseDto,
|
||||
type BulkIdResponseDto,
|
||||
type UpdateAlbumDto,
|
||||
type UserResponseDto,
|
||||
} from '@immich/sdk';
|
||||
import { modalManager, toastManager, type ActionItem } from '@immich/ui';
|
||||
import { mdiLink, mdiPlus, mdiPlusBoxOutline, mdiShareVariantOutline, mdiUpload } from '@mdi/js';
|
||||
import { mdiImageOutline, mdiLink, mdiPlus, mdiPlusBoxOutline, mdiShareVariantOutline, mdiUpload } from '@mdi/js';
|
||||
import { type MessageFormatter } from 'svelte-i18n';
|
||||
import { goto } from '$app/navigation';
|
||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||
@@ -68,6 +69,16 @@ export const getAlbumActions = ($t: MessageFormatter, album: AlbumResponseDto) =
|
||||
return { Share, AddUsers, CreateSharedLink };
|
||||
};
|
||||
|
||||
export const getAlbumAssetActions = ($t: MessageFormatter, album: AlbumResponseDto, asset: AssetResponseDto) => {
|
||||
const SetCover: ActionItem = {
|
||||
title: $t('set_as_album_cover'),
|
||||
icon: mdiImageOutline,
|
||||
onAction: () => handleUpdateThumbnail(album, asset.id),
|
||||
};
|
||||
|
||||
return { SetCover };
|
||||
};
|
||||
|
||||
export const getAlbumAssetsActions = ($t: MessageFormatter, album: AlbumResponseDto, assets: TimelineAsset[]) => {
|
||||
const AddAssets: ActionItem = {
|
||||
title: $t('add_assets'),
|
||||
@@ -206,6 +217,23 @@ export const handleRemoveUserFromAlbum = async (album: AlbumResponseDto, albumUs
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpdateThumbnail = async (album: AlbumResponseDto, assetId: string) => {
|
||||
const $t = await getFormatter();
|
||||
|
||||
try {
|
||||
const response = await updateAlbumInfo({
|
||||
id: album.id,
|
||||
updateAlbumDto: {
|
||||
albumThumbnailAssetId: assetId,
|
||||
},
|
||||
});
|
||||
eventManager.emit('AlbumUpdate', response);
|
||||
toastManager.primary($t('album_cover_updated'));
|
||||
} catch (error) {
|
||||
handleError(error, $t('errors.unable_to_update_album_cover'));
|
||||
}
|
||||
};
|
||||
|
||||
export const handleUpdateAlbum = async ({ id }: { id: string }, dto: UpdateAlbumDto) => {
|
||||
const $t = await getFormatter();
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
mdiMotionPauseOutline,
|
||||
mdiMotionPlayOutline,
|
||||
mdiPlus,
|
||||
mdiPresentationPlay,
|
||||
mdiShareVariantOutline,
|
||||
mdiTagPlusOutline,
|
||||
mdiTune,
|
||||
@@ -41,6 +42,7 @@ import { eventManager } from '$lib/managers/event-manager.svelte';
|
||||
import AssetAddToAlbumModal from '$lib/modals/AssetAddToAlbumModal.svelte';
|
||||
import AssetTagModal from '$lib/modals/AssetTagModal.svelte';
|
||||
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
|
||||
import { SlideshowState, slideshowStore } from '$lib/stores/slideshow.store';
|
||||
import { getAssetMediaUrl, getSharedLink, sleep } from '$lib/utils';
|
||||
import { downloadUrl } from '$lib/utils';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
@@ -140,6 +142,13 @@ export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) =
|
||||
},
|
||||
};
|
||||
|
||||
const PlaySlideshow: ActionItem = {
|
||||
title: $t('slideshow'),
|
||||
icon: mdiPresentationPlay,
|
||||
$if: () => asset.visibility !== AssetVisibility.Locked,
|
||||
onAction: () => slideshowStore.slideshowState.set(SlideshowState.PlaySlideshow),
|
||||
};
|
||||
|
||||
const Favorite: ActionItem = {
|
||||
title: $t('to_favorite'),
|
||||
icon: mdiHeartOutline,
|
||||
@@ -269,6 +278,7 @@ export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) =
|
||||
Unfavorite,
|
||||
PlayMotionPhoto,
|
||||
StopMotionPhoto,
|
||||
PlaySlideshow,
|
||||
AddToAlbum,
|
||||
ZoomIn,
|
||||
ZoomOut,
|
||||
|
||||
Reference in New Issue
Block a user