mirror of
https://github.com/immich-app/immich.git
synced 2025-05-24 01:12:58 -04:00
feat(mobile): share to mechanism (#15229)
* setup ios * chore: succesfully sent media to the app * share from Android * wip: navigate to share screen * wip: UI for displaying upload candidate * wip: logic * wip: upload logic * wip: up up up we got it up * wip * wip * wip * upload state * feat: i18n * fix: release build ios' * feat: clear file cache * pr feedback * using const for checking download status --------- Co-authored-by: Alex <alex@pop-os.localdomain>
This commit is contained in:
parent
3a2bf91889
commit
fd99bd05cf
@ -43,7 +43,7 @@
|
|||||||
android:name="com.google.firebase.messaging.default_notification_icon"
|
android:name="com.google.firebase.messaging.default_notification_icon"
|
||||||
android:resource="@drawable/notification_icon" />
|
android:resource="@drawable/notification_icon" />
|
||||||
|
|
||||||
<activity android:name=".MainActivity" android:exported="true" android:launchMode="singleTop"
|
<activity android:name=".MainActivity" android:exported="true" android:launchMode="singleTask"
|
||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize">
|
android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize">
|
||||||
@ -61,6 +61,34 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
|
|
||||||
|
<!--TODO:
|
||||||
|
Add this filter if you want to handle shared images-->
|
||||||
|
<intent-filter android:label="Upload to Immich">
|
||||||
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="image/*" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<intent-filter android:label="Upload to Immich">
|
||||||
|
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="image/*" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<!--TODO:
|
||||||
|
Add this filter if you want to handle shared videos-->
|
||||||
|
<intent-filter android:label="Upload to Immich">
|
||||||
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="video/*" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:label="Upload to Immich">
|
||||||
|
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="video/*" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
|
||||||
|
@ -657,5 +657,15 @@
|
|||||||
"viewer_stack_use_as_main_asset": "Use as Main Asset",
|
"viewer_stack_use_as_main_asset": "Use as Main Asset",
|
||||||
"viewer_unstack": "Un-Stack",
|
"viewer_unstack": "Un-Stack",
|
||||||
"wifi_name": "WiFi Name",
|
"wifi_name": "WiFi Name",
|
||||||
"your_wifi_name": "Your WiFi name"
|
"your_wifi_name": "Your WiFi name",
|
||||||
|
"upload": "Upload",
|
||||||
|
"uploading": "Uploading",
|
||||||
|
"shared_intent_upload_button_progress_text": "{} / {} Uploaded",
|
||||||
|
"enqueued": "Enqueued",
|
||||||
|
"not_selected": "Not selected",
|
||||||
|
"completed": "Completed",
|
||||||
|
"failed": "Failed",
|
||||||
|
"paused": "Paused",
|
||||||
|
"canceled": "Canceled",
|
||||||
|
"upload_to_immich": "Upload to Immich ({})"
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,13 @@ target 'Runner' do
|
|||||||
use_modular_headers!
|
use_modular_headers!
|
||||||
|
|
||||||
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
||||||
|
|
||||||
|
# share_handler addition start
|
||||||
|
target 'ShareExtension' do
|
||||||
|
inherit! :search_paths
|
||||||
|
pod "share_handler_ios_models", :path => ".symlinks/plugins/share_handler_ios/ios/Models"
|
||||||
|
end
|
||||||
|
# share_handler addition end
|
||||||
end
|
end
|
||||||
|
|
||||||
post_install do |installer|
|
post_install do |installer|
|
||||||
|
@ -82,9 +82,17 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- SAMKeychain (1.5.3)
|
- SAMKeychain (1.5.3)
|
||||||
- SDWebImage (5.19.4):
|
- SDWebImage (5.20.0):
|
||||||
- SDWebImage/Core (= 5.19.4)
|
- SDWebImage/Core (= 5.20.0)
|
||||||
- SDWebImage/Core (5.19.4)
|
- SDWebImage/Core (5.20.0)
|
||||||
|
- share_handler_ios (0.0.14):
|
||||||
|
- Flutter
|
||||||
|
- share_handler_ios/share_handler_ios_models (= 0.0.14)
|
||||||
|
- share_handler_ios_models
|
||||||
|
- share_handler_ios/share_handler_ios_models (0.0.14):
|
||||||
|
- Flutter
|
||||||
|
- share_handler_ios_models
|
||||||
|
- share_handler_ios_models (0.0.9)
|
||||||
- share_plus (0.0.1):
|
- share_plus (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- shared_preferences_foundation (0.0.1):
|
- shared_preferences_foundation (0.0.1):
|
||||||
@ -94,7 +102,7 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- SwiftyGif (5.4.5)
|
- SwiftyGif (5.4.5)
|
||||||
- Toast (4.0.0)
|
- Toast (4.1.1)
|
||||||
- url_launcher_ios (0.0.1):
|
- url_launcher_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- wakelock_plus (0.0.1):
|
- wakelock_plus (0.0.1):
|
||||||
@ -123,6 +131,8 @@ DEPENDENCIES:
|
|||||||
- path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
|
- path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
|
||||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||||
- photo_manager (from `.symlinks/plugins/photo_manager/ios`)
|
- photo_manager (from `.symlinks/plugins/photo_manager/ios`)
|
||||||
|
- share_handler_ios (from `.symlinks/plugins/share_handler_ios/ios`)
|
||||||
|
- share_handler_ios_models (from `.symlinks/plugins/share_handler_ios/ios/Models`)
|
||||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||||
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
|
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
|
||||||
@ -184,6 +194,10 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||||
photo_manager:
|
photo_manager:
|
||||||
:path: ".symlinks/plugins/photo_manager/ios"
|
:path: ".symlinks/plugins/photo_manager/ios"
|
||||||
|
share_handler_ios:
|
||||||
|
:path: ".symlinks/plugins/share_handler_ios/ios"
|
||||||
|
share_handler_ios_models:
|
||||||
|
:path: ".symlinks/plugins/share_handler_ios/ios/Models"
|
||||||
share_plus:
|
share_plus:
|
||||||
:path: ".symlinks/plugins/share_plus/ios"
|
:path: ".symlinks/plugins/share_plus/ios"
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
@ -222,15 +236,17 @@ SPEC CHECKSUMS:
|
|||||||
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
||||||
photo_manager: ff695c7a1dd5bc379974953a2b5c0a293f7c4c8a
|
photo_manager: ff695c7a1dd5bc379974953a2b5c0a293f7c4c8a
|
||||||
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
|
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
|
||||||
SDWebImage: 066c47b573f408f18caa467d71deace7c0f8280d
|
SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8
|
||||||
|
share_handler_ios: 6dd3a4ac5ca0d955274aec712ba0ecdcaf583e7c
|
||||||
|
share_handler_ios_models: fc638c9b4330dc7f082586c92aee9dfa0b87b871
|
||||||
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
|
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
|
||||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||||
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
||||||
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||||
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
|
Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e
|
||||||
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
||||||
wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1
|
wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1
|
||||||
|
|
||||||
PODFILE CHECKSUM: 2282844f7aed70427ae663932332dad1225156c8
|
PODFILE CHECKSUM: 03b7eead4ee77b9e778179eeb0f3b5513617451c
|
||||||
|
|
||||||
COCOAPODS: 1.15.2
|
COCOAPODS: 1.15.2
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||||
|
3B6A31FED0FC846D6BD69BBC /* Pods_ShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 357FC57E54FD0F51795CF28A /* Pods_ShareExtension.framework */; };
|
||||||
65F32F31299BD2F800CE9261 /* BackgroundServicePlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F32F30299BD2F800CE9261 /* BackgroundServicePlugin.swift */; };
|
65F32F31299BD2F800CE9261 /* BackgroundServicePlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F32F30299BD2F800CE9261 /* BackgroundServicePlugin.swift */; };
|
||||||
65F32F33299D349D00CE9261 /* BackgroundSyncWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F32F32299D349D00CE9261 /* BackgroundSyncWorker.swift */; };
|
65F32F33299D349D00CE9261 /* BackgroundSyncWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F32F32299D349D00CE9261 /* BackgroundSyncWorker.swift */; };
|
||||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||||
@ -16,8 +17,21 @@
|
|||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||||
D218389C4A4C4693F141F7D1 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 886774DBDDE6B35BF2B4F2CD /* Pods_Runner.framework */; };
|
D218389C4A4C4693F141F7D1 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 886774DBDDE6B35BF2B4F2CD /* Pods_Runner.framework */; };
|
||||||
|
FAC6F89B2D287C890078CB2F /* ShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = FAC6F8902D287C890078CB2F /* ShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
|
FAC6F8B72D287F120078CB2F /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAC6F8B52D287F120078CB2F /* ShareViewController.swift */; };
|
||||||
|
FAC6F8B92D287F120078CB2F /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FAC6F8B32D287F120078CB2F /* MainInterface.storyboard */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
FAC6F8982D287C890078CB2F /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = FAC6F88F2D287C890078CB2F;
|
||||||
|
remoteInfo = ShareExtension;
|
||||||
|
};
|
||||||
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
||||||
isa = PBXCopyFilesBuildPhase;
|
isa = PBXCopyFilesBuildPhase;
|
||||||
@ -29,13 +43,26 @@
|
|||||||
name = "Embed Frameworks";
|
name = "Embed Frameworks";
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
FAC6F89A2D287C890078CB2F /* Embed Foundation Extensions */ = {
|
||||||
|
isa = PBXCopyFilesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
dstPath = "";
|
||||||
|
dstSubfolderSpec = 13;
|
||||||
|
files = (
|
||||||
|
FAC6F89B2D287C890078CB2F /* ShareExtension.appex in Embed Foundation Extensions */,
|
||||||
|
);
|
||||||
|
name = "Embed Foundation Extensions";
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||||
2E3441B73560D0F6FD25E04F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
2E3441B73560D0F6FD25E04F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
357FC57E54FD0F51795CF28A /* Pods_ShareExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ShareExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||||
|
571EAA93D77181C7C98C2EA6 /* Pods-ShareExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShareExtension.release.xcconfig"; path = "Target Support Files/Pods-ShareExtension/Pods-ShareExtension.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
65F32F30299BD2F800CE9261 /* BackgroundServicePlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundServicePlugin.swift; sourceTree = "<group>"; };
|
65F32F30299BD2F800CE9261 /* BackgroundServicePlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundServicePlugin.swift; sourceTree = "<group>"; };
|
||||||
65F32F32299D349D00CE9261 /* BackgroundSyncWorker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackgroundSyncWorker.swift; sourceTree = "<group>"; };
|
65F32F32299D349D00CE9261 /* BackgroundSyncWorker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackgroundSyncWorker.swift; sourceTree = "<group>"; };
|
||||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
@ -49,9 +76,16 @@
|
|||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
B1FBA9EE014DE20271B0FE77 /* 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>"; };
|
||||||
E0E99CDC17B3EB7FA8BA2332 /* 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>"; };
|
E0E99CDC17B3EB7FA8BA2332 /* 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>"; };
|
||||||
F7101BB0391A314774615E89 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
F7101BB0391A314774615E89 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
F8A35EA3C3E01BD66AFDE0E5 /* 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>"; };
|
||||||
FA9973382CF6DF4B000EF859 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
FA9973382CF6DF4B000EF859 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||||
|
FAC6F8902D287C890078CB2F /* ShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
FAC6F8B12D287F120078CB2F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
FAC6F8B22D287F120078CB2F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = "<group>"; };
|
||||||
|
FAC6F8B42D287F120078CB2F /* ShareExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ShareExtension.entitlements; sourceTree = "<group>"; };
|
||||||
|
FAC6F8B52D287F120078CB2F /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; };
|
||||||
FAC7416727DB9F5500C668D8 /* RunnerProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerProfile.entitlements; sourceTree = "<group>"; };
|
FAC7416727DB9F5500C668D8 /* RunnerProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerProfile.entitlements; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
@ -64,6 +98,14 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
FAC6F88D2D287C890078CB2F /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
3B6A31FED0FC846D6BD69BBC /* Pods_ShareExtension.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
@ -73,6 +115,9 @@
|
|||||||
2E3441B73560D0F6FD25E04F /* Pods-Runner.debug.xcconfig */,
|
2E3441B73560D0F6FD25E04F /* Pods-Runner.debug.xcconfig */,
|
||||||
E0E99CDC17B3EB7FA8BA2332 /* Pods-Runner.release.xcconfig */,
|
E0E99CDC17B3EB7FA8BA2332 /* Pods-Runner.release.xcconfig */,
|
||||||
F7101BB0391A314774615E89 /* Pods-Runner.profile.xcconfig */,
|
F7101BB0391A314774615E89 /* Pods-Runner.profile.xcconfig */,
|
||||||
|
F8A35EA3C3E01BD66AFDE0E5 /* Pods-ShareExtension.debug.xcconfig */,
|
||||||
|
571EAA93D77181C7C98C2EA6 /* Pods-ShareExtension.release.xcconfig */,
|
||||||
|
B1FBA9EE014DE20271B0FE77 /* Pods-ShareExtension.profile.xcconfig */,
|
||||||
);
|
);
|
||||||
path = Pods;
|
path = Pods;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -81,6 +126,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
886774DBDDE6B35BF2B4F2CD /* Pods_Runner.framework */,
|
886774DBDDE6B35BF2B4F2CD /* Pods_Runner.framework */,
|
||||||
|
357FC57E54FD0F51795CF28A /* Pods_ShareExtension.framework */,
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -110,6 +156,7 @@
|
|||||||
children = (
|
children = (
|
||||||
9740EEB11CF90186004384FC /* Flutter */,
|
9740EEB11CF90186004384FC /* Flutter */,
|
||||||
97C146F01CF9000F007C117D /* Runner */,
|
97C146F01CF9000F007C117D /* Runner */,
|
||||||
|
FAC6F8B62D287F120078CB2F /* ShareExtension */,
|
||||||
97C146EF1CF9000F007C117D /* Products */,
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
0FB772A5B9601143383626CA /* Pods */,
|
0FB772A5B9601143383626CA /* Pods */,
|
||||||
1754452DD81DA6620E279E51 /* Frameworks */,
|
1754452DD81DA6620E279E51 /* Frameworks */,
|
||||||
@ -120,6 +167,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
97C146EE1CF9000F007C117D /* Immich-Debug.app */,
|
97C146EE1CF9000F007C117D /* Immich-Debug.app */,
|
||||||
|
FAC6F8902D287C890078CB2F /* ShareExtension.appex */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -142,6 +190,17 @@
|
|||||||
path = Runner;
|
path = Runner;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
FAC6F8B62D287F120078CB2F /* ShareExtension */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
FAC6F8B12D287F120078CB2F /* Info.plist */,
|
||||||
|
FAC6F8B32D287F120078CB2F /* MainInterface.storyboard */,
|
||||||
|
FAC6F8B42D287F120078CB2F /* ShareExtension.entitlements */,
|
||||||
|
FAC6F8B52D287F120078CB2F /* ShareViewController.swift */,
|
||||||
|
);
|
||||||
|
path = ShareExtension;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
@ -155,6 +214,7 @@
|
|||||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||||
97C146EC1CF9000F007C117D /* Resources */,
|
97C146EC1CF9000F007C117D /* Resources */,
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
|
FAC6F89A2D287C890078CB2F /* Embed Foundation Extensions */,
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
D218A34AEE62BC1EF119F5B0 /* [CP] Embed Pods Frameworks */,
|
D218A34AEE62BC1EF119F5B0 /* [CP] Embed Pods Frameworks */,
|
||||||
6724EEB7D74949FA08581154 /* [CP] Copy Pods Resources */,
|
6724EEB7D74949FA08581154 /* [CP] Copy Pods Resources */,
|
||||||
@ -162,12 +222,31 @@
|
|||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
|
FAC6F8992D287C890078CB2F /* PBXTargetDependency */,
|
||||||
);
|
);
|
||||||
name = Runner;
|
name = Runner;
|
||||||
productName = Runner;
|
productName = Runner;
|
||||||
productReference = 97C146EE1CF9000F007C117D /* Immich-Debug.app */;
|
productReference = 97C146EE1CF9000F007C117D /* Immich-Debug.app */;
|
||||||
productType = "com.apple.product-type.application";
|
productType = "com.apple.product-type.application";
|
||||||
};
|
};
|
||||||
|
FAC6F88F2D287C890078CB2F /* ShareExtension */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = FAC6F8A02D287C890078CB2F /* Build configuration list for PBXNativeTarget "ShareExtension" */;
|
||||||
|
buildPhases = (
|
||||||
|
3BEF3D71D97E337D921C0EB5 /* [CP] Check Pods Manifest.lock */,
|
||||||
|
FAC6F88C2D287C890078CB2F /* Sources */,
|
||||||
|
FAC6F88D2D287C890078CB2F /* Frameworks */,
|
||||||
|
FAC6F88E2D287C890078CB2F /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = ShareExtension;
|
||||||
|
productName = ShareExtension;
|
||||||
|
productReference = FAC6F8902D287C890078CB2F /* ShareExtension.appex */;
|
||||||
|
productType = "com.apple.product-type.app-extension";
|
||||||
|
};
|
||||||
/* End PBXNativeTarget section */
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
/* Begin PBXProject section */
|
/* Begin PBXProject section */
|
||||||
@ -175,6 +254,7 @@
|
|||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
BuildIndependentTargetsInParallel = YES;
|
BuildIndependentTargetsInParallel = YES;
|
||||||
|
LastSwiftUpdateCheck = 1600;
|
||||||
LastUpgradeCheck = 1510;
|
LastUpgradeCheck = 1510;
|
||||||
ORGANIZATIONNAME = "";
|
ORGANIZATIONNAME = "";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
@ -182,6 +262,9 @@
|
|||||||
CreatedOnToolsVersion = 7.3.1;
|
CreatedOnToolsVersion = 7.3.1;
|
||||||
LastSwiftMigration = 1100;
|
LastSwiftMigration = 1100;
|
||||||
};
|
};
|
||||||
|
FAC6F88F2D287C890078CB2F = {
|
||||||
|
CreatedOnToolsVersion = 16.0;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
||||||
@ -198,6 +281,7 @@
|
|||||||
projectRoot = "";
|
projectRoot = "";
|
||||||
targets = (
|
targets = (
|
||||||
97C146ED1CF9000F007C117D /* Runner */,
|
97C146ED1CF9000F007C117D /* Runner */,
|
||||||
|
FAC6F88F2D287C890078CB2F /* ShareExtension */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
@ -214,6 +298,14 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
FAC6F88E2D287C890078CB2F /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
FAC6F8B92D287F120078CB2F /* MainInterface.storyboard in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXShellScriptBuildPhase section */
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
@ -233,6 +325,28 @@
|
|||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||||
};
|
};
|
||||||
|
3BEF3D71D97E337D921C0EB5 /* [CP] Check Pods Manifest.lock */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||||
|
"${PODS_ROOT}/Manifest.lock",
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
"$(DERIVED_FILE_DIR)/Pods-ShareExtension-checkManifestLockResult.txt",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
4044AF030EF7D8721844FFBA /* [CP] Check Pods Manifest.lock */ = {
|
4044AF030EF7D8721844FFBA /* [CP] Check Pods Manifest.lock */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@ -318,8 +432,24 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
FAC6F88C2D287C890078CB2F /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
FAC6F8B72D287F120078CB2F /* ShareViewController.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
/* End PBXSourcesBuildPhase section */
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXTargetDependency section */
|
||||||
|
FAC6F8992D287C890078CB2F /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = FAC6F88F2D287C890078CB2F /* ShareExtension */;
|
||||||
|
targetProxy = FAC6F8982D287C890078CB2F /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
/* Begin PBXVariantGroup section */
|
/* Begin PBXVariantGroup section */
|
||||||
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
|
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
|
||||||
isa = PBXVariantGroup;
|
isa = PBXVariantGroup;
|
||||||
@ -337,6 +467,14 @@
|
|||||||
name = LaunchScreen.storyboard;
|
name = LaunchScreen.storyboard;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
FAC6F8B32D287F120078CB2F /* MainInterface.storyboard */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
FAC6F8B22D287F120078CB2F /* Base */,
|
||||||
|
);
|
||||||
|
name = MainInterface.storyboard;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXVariantGroup section */
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
/* Begin XCBuildConfiguration section */
|
||||||
@ -404,6 +542,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 187;
|
CURRENT_PROJECT_VERSION = 187;
|
||||||
|
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
@ -547,6 +686,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 187;
|
CURRENT_PROJECT_VERSION = 187;
|
||||||
|
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
@ -576,6 +716,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 187;
|
CURRENT_PROJECT_VERSION = 187;
|
||||||
|
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
@ -594,6 +735,129 @@
|
|||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
FAC6F89C2D287C890078CB2F /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = F8A35EA3C3E01BD66AFDE0E5 /* Pods-ShareExtension.debug.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||||
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = ShareExtension/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = app.alextran.immich.vdebug.ShareExtension;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
FAC6F89D2D287C890078CB2F /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 571EAA93D77181C7C98C2EA6 /* Pods-ShareExtension.release.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||||
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = ShareExtension/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = app.alextran.immich.ShareExtension;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
FAC6F89E2D287C890078CB2F /* Profile */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = B1FBA9EE014DE20271B0FE77 /* Pods-ShareExtension.profile.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||||
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = ShareExtension/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = app.alextran.immich.profile.ShareExtension;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Profile;
|
||||||
|
};
|
||||||
/* End XCBuildConfiguration section */
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
/* Begin XCConfigurationList section */
|
||||||
@ -617,6 +881,16 @@
|
|||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
|
FAC6F8A02D287C890078CB2F /* Build configuration list for PBXNativeTarget "ShareExtension" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
FAC6F89C2D287C890078CB2F /* Debug */,
|
||||||
|
FAC6F89D2D287C890078CB2F /* Release */,
|
||||||
|
FAC6F89E2D287C890078CB2F /* Profile */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
};
|
};
|
||||||
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>AppGroupId</key>
|
||||||
|
<string>$(CUSTOM_GROUP_ID)</string>
|
||||||
<key>BGTaskSchedulerPermittedIdentifiers</key>
|
<key>BGTaskSchedulerPermittedIdentifiers</key>
|
||||||
<array>
|
<array>
|
||||||
<string>app.alextran.immich.backgroundFetch</string>
|
<string>app.alextran.immich.backgroundFetch</string>
|
||||||
@ -13,6 +15,24 @@
|
|||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>${PRODUCT_NAME}</string>
|
<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>
|
<key>CFBundleExecutable</key>
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
@ -61,6 +81,17 @@
|
|||||||
<string>1.124.0</string>
|
<string>1.124.0</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
|
<key>CFBundleURLTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Editor</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>ShareMedia-$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>187</string>
|
<string>187</string>
|
||||||
<key>FLTEnableImpeller</key>
|
<key>FLTEnableImpeller</key>
|
||||||
@ -73,6 +104,8 @@
|
|||||||
</array>
|
</array>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||||
|
<string>No</string>
|
||||||
<key>MGLMapboxMetricsEnabledSettingShownInApp</key>
|
<key>MGLMapboxMetricsEnabledSettingShownInApp</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSAppTransportSecurity</key>
|
<key>NSAppTransportSecurity</key>
|
||||||
@ -94,6 +127,10 @@
|
|||||||
<string>We need to manage backup your photos album</string>
|
<string>We need to manage backup your photos album</string>
|
||||||
<key>NSPhotoLibraryUsageDescription</key>
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
<string>We need to manage backup your photos album</string>
|
<string>We need to manage backup your photos album</string>
|
||||||
|
<key>NSUserActivityTypes</key>
|
||||||
|
<array>
|
||||||
|
<string>INSendMessageIntent</string>
|
||||||
|
</array>
|
||||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>UIBackgroundModes</key>
|
<key>UIBackgroundModes</key>
|
||||||
|
@ -4,5 +4,9 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>com.apple.developer.networking.wifi-info</key>
|
<key>com.apple.developer.networking.wifi-info</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>com.apple.security.application-groups</key>
|
||||||
|
<array>
|
||||||
|
<string>group.app.immich.share</string>
|
||||||
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
@ -6,5 +6,9 @@
|
|||||||
<string>development</string>
|
<string>development</string>
|
||||||
<key>com.apple.developer.networking.wifi-info</key>
|
<key>com.apple.developer.networking.wifi-info</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>com.apple.security.application-groups</key>
|
||||||
|
<array>
|
||||||
|
<string>group.app.immich.share</string>
|
||||||
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="j1y-V4-xli">
|
||||||
|
<dependencies>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
||||||
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--Share View Controller-->
|
||||||
|
<scene sceneID="ceB-am-kn3">
|
||||||
|
<objects>
|
||||||
|
<viewController id="j1y-V4-xli" customClass="ShareViewController" customModuleProvider="target" sceneMemberID="viewController">
|
||||||
|
<view key="view" opaque="NO" contentMode="scaleToFill" id="wbc-yd-nQP">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<viewLayoutGuide key="safeArea" id="1Xd-am-t49"/>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="CEy-Cv-SGf" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
</document>
|
35
mobile/ios/ShareExtension/Info.plist
Normal file
35
mobile/ios/ShareExtension/Info.plist
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?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>NSExtension</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSExtensionAttributes</key>
|
||||||
|
<dict>
|
||||||
|
<key>IntentsSupported</key>
|
||||||
|
<array>
|
||||||
|
<string>INSendMessageIntent</string>
|
||||||
|
</array>
|
||||||
|
<key>NSExtensionActivationRule</key>
|
||||||
|
<string>SUBQUERY ( extensionItems, $extensionItem, SUBQUERY ( $extensionItem.attachments,
|
||||||
|
$attachment, ( ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.file-url"
|
||||||
|
|| ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.image" || ANY
|
||||||
|
$attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.text" || ANY
|
||||||
|
$attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.movie" || ANY
|
||||||
|
$attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url" ) ).@count > 0
|
||||||
|
).@count > 0 </string>
|
||||||
|
<key>PHSupportedMediaTypes</key>
|
||||||
|
<array>
|
||||||
|
<string>Video</string>
|
||||||
|
<string>Image</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
<key>NSExtensionMainStoryboard</key>
|
||||||
|
<string>MainInterface</string>
|
||||||
|
<key>NSExtensionPointIdentifier</key>
|
||||||
|
<string>com.apple.share-services</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
10
mobile/ios/ShareExtension/ShareExtension.entitlements
Normal file
10
mobile/ios/ShareExtension/ShareExtension.entitlements
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?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>com.apple.security.application-groups</key>
|
||||||
|
<array>
|
||||||
|
<string>group.app.immich.share</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
3
mobile/ios/ShareExtension/ShareViewController.swift
Normal file
3
mobile/ios/ShareExtension/ShareViewController.swift
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import share_handler_ios_models
|
||||||
|
|
||||||
|
class ShareViewController: ShareHandlerIosViewController {}
|
@ -1 +1,3 @@
|
|||||||
const int noDbId = -9223372036854775808; // from Isar
|
const int noDbId = -9223372036854775808; // from Isar
|
||||||
|
const double downloadCompleted = -1;
|
||||||
|
const double downloadFailed = -2;
|
||||||
|
7
mobile/lib/interfaces/share_handler.interface.dart
Normal file
7
mobile/lib/interfaces/share_handler.interface.dart
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import 'package:immich_mobile/models/upload/share_intent_attachment.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IShareHandlerRepository {
|
||||||
|
void Function(List<ShareIntentAttachment>)? onSharedMedia;
|
||||||
|
|
||||||
|
Future<void> init();
|
||||||
|
}
|
11
mobile/lib/interfaces/upload.interface.dart
Normal file
11
mobile/lib/interfaces/upload.interface.dart
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import 'package:background_downloader/background_downloader.dart';
|
||||||
|
|
||||||
|
abstract interface class IUploadRepository {
|
||||||
|
void Function(TaskStatusUpdate)? onUploadStatus;
|
||||||
|
void Function(TaskProgressUpdate)? onTaskProgress;
|
||||||
|
|
||||||
|
Future<bool> upload(UploadTask task);
|
||||||
|
Future<bool> cancel(String id);
|
||||||
|
Future<void> deleteAllTrackingRecords();
|
||||||
|
Future<void> deleteRecordsWithIds(List<String> id);
|
||||||
|
}
|
@ -4,6 +4,7 @@ import 'dart:io';
|
|||||||
import 'package:background_downloader/background_downloader.dart';
|
import 'package:background_downloader/background_downloader.dart';
|
||||||
import 'package:device_info_plus/device_info_plus.dart';
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:immich_mobile/providers/asset_viewer/share_intent_upload.provider.dart';
|
||||||
import 'package:intl/date_symbol_data_local.dart';
|
import 'package:intl/date_symbol_data_local.dart';
|
||||||
import 'package:timezone/data/latest.dart';
|
import 'package:timezone/data/latest.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
@ -107,10 +108,12 @@ Future<void> initApp() async {
|
|||||||
progressBar: true,
|
progressBar: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
FileDownloader().trackTasksInGroup(
|
await FileDownloader().trackTasksInGroup(
|
||||||
downloadGroupLivePhoto,
|
downloadGroupLivePhoto,
|
||||||
markDownloadedComplete: false,
|
markDownloadedComplete: false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await FileDownloader().trackTasks();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Isar> loadDb() async {
|
Future<Isar> loadDb() async {
|
||||||
@ -208,6 +211,8 @@ class ImmichAppState extends ConsumerState<ImmichApp>
|
|||||||
// needs to be delayed so that EasyLocalization is working
|
// needs to be delayed so that EasyLocalization is working
|
||||||
ref.read(backgroundServiceProvider).resumeServiceIfEnabled();
|
ref.read(backgroundServiceProvider).resumeServiceIfEnabled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ref.read(shareIntentUploadProvider.notifier).init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
114
mobile/lib/models/upload/share_intent_attachment.model.dart
Normal file
114
mobile/lib/models/upload/share_intent_attachment.model.dart
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/utils/bytes_units.dart';
|
||||||
|
import 'package:path/path.dart';
|
||||||
|
|
||||||
|
enum ShareIntentAttachmentType {
|
||||||
|
image,
|
||||||
|
video,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum UploadStatus {
|
||||||
|
enqueued,
|
||||||
|
running,
|
||||||
|
complete,
|
||||||
|
notFound,
|
||||||
|
failed,
|
||||||
|
canceled,
|
||||||
|
waitingtoRetry,
|
||||||
|
paused,
|
||||||
|
}
|
||||||
|
|
||||||
|
class ShareIntentAttachment {
|
||||||
|
final String path;
|
||||||
|
|
||||||
|
// enum
|
||||||
|
final ShareIntentAttachmentType type;
|
||||||
|
|
||||||
|
// enum
|
||||||
|
final UploadStatus status;
|
||||||
|
|
||||||
|
final double uploadProgress;
|
||||||
|
|
||||||
|
final int fileLength;
|
||||||
|
|
||||||
|
ShareIntentAttachment({
|
||||||
|
required this.path,
|
||||||
|
required this.type,
|
||||||
|
required this.status,
|
||||||
|
this.uploadProgress = 0,
|
||||||
|
this.fileLength = 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
int get id => hash(path);
|
||||||
|
|
||||||
|
File get file => File(path);
|
||||||
|
|
||||||
|
String get fileName => basename(file.path);
|
||||||
|
|
||||||
|
bool get isImage => type == ShareIntentAttachmentType.image;
|
||||||
|
|
||||||
|
bool get isVideo => type == ShareIntentAttachmentType.video;
|
||||||
|
|
||||||
|
String? _fileSize;
|
||||||
|
|
||||||
|
String get fileSize => _fileSize ??= formatHumanReadableBytes(fileLength, 2);
|
||||||
|
|
||||||
|
ShareIntentAttachment copyWith({
|
||||||
|
String? path,
|
||||||
|
ShareIntentAttachmentType? type,
|
||||||
|
UploadStatus? status,
|
||||||
|
double? uploadProgress,
|
||||||
|
}) {
|
||||||
|
return ShareIntentAttachment(
|
||||||
|
path: path ?? this.path,
|
||||||
|
type: type ?? this.type,
|
||||||
|
status: status ?? this.status,
|
||||||
|
uploadProgress: uploadProgress ?? this.uploadProgress,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toMap() {
|
||||||
|
return <String, dynamic>{
|
||||||
|
'path': path,
|
||||||
|
'type': type.index,
|
||||||
|
'status': status.index,
|
||||||
|
'uploadProgress': uploadProgress,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
factory ShareIntentAttachment.fromMap(Map<String, dynamic> map) {
|
||||||
|
return ShareIntentAttachment(
|
||||||
|
path: map['path'] as String,
|
||||||
|
type: ShareIntentAttachmentType.values[map['type'] as int],
|
||||||
|
status: UploadStatus.values[map['status'] as int],
|
||||||
|
uploadProgress: map['uploadProgress'] as double,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String toJson() => json.encode(toMap());
|
||||||
|
|
||||||
|
factory ShareIntentAttachment.fromJson(String source) =>
|
||||||
|
ShareIntentAttachment.fromMap(
|
||||||
|
json.decode(source) as Map<String, dynamic>,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'ShareIntentAttachment(path: $path, type: $type, status: $status, uploadProgress: $uploadProgress)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(covariant ShareIntentAttachment other) {
|
||||||
|
if (identical(this, other)) return true;
|
||||||
|
|
||||||
|
return other.path == path && other.type == type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
return path.hashCode ^ type.hashCode;
|
||||||
|
}
|
||||||
|
}
|
@ -32,7 +32,7 @@ class AlbumSharedUserIcons extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () => context.pushRoute(AlbumOptionsRoute()),
|
onTap: () => context.pushRoute(const AlbumOptionsRoute()),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 50,
|
height: 50,
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
|
@ -13,6 +13,9 @@ class LargeLeadingTile extends StatelessWidget {
|
|||||||
horizontal: 16.0,
|
horizontal: 16.0,
|
||||||
),
|
),
|
||||||
this.borderRadius = 20.0,
|
this.borderRadius = 20.0,
|
||||||
|
this.trailing,
|
||||||
|
this.selected = false,
|
||||||
|
this.disabled = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
final Widget leading;
|
final Widget leading;
|
||||||
@ -21,12 +24,21 @@ class LargeLeadingTile extends StatelessWidget {
|
|||||||
final Widget? subtitle;
|
final Widget? subtitle;
|
||||||
final EdgeInsetsGeometry leadingPadding;
|
final EdgeInsetsGeometry leadingPadding;
|
||||||
final double borderRadius;
|
final double borderRadius;
|
||||||
|
final Widget? trailing;
|
||||||
|
final bool selected;
|
||||||
|
final bool disabled;
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return InkWell(
|
return InkWell(
|
||||||
borderRadius: BorderRadius.circular(borderRadius),
|
borderRadius: BorderRadius.circular(borderRadius),
|
||||||
onTap: onTap,
|
onTap: disabled ? null : onTap,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: selected
|
||||||
|
? Theme.of(context).primaryColor.withAlpha(30)
|
||||||
|
: Colors.transparent,
|
||||||
|
borderRadius: BorderRadius.circular(borderRadius),
|
||||||
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
@ -34,7 +46,8 @@ class LargeLeadingTile extends StatelessWidget {
|
|||||||
padding: leadingPadding,
|
padding: leadingPadding,
|
||||||
child: leading,
|
child: leading,
|
||||||
),
|
),
|
||||||
Column(
|
Expanded(
|
||||||
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
@ -44,8 +57,11 @@ class LargeLeadingTile extends StatelessWidget {
|
|||||||
subtitle ?? const SizedBox.shrink(),
|
subtitle ?? const SizedBox.shrink(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
if (trailing != null) trailing!,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,10 +34,12 @@ class PhotosPage extends HookConsumerWidget {
|
|||||||
Future(() => ref.read(assetProvider.notifier).getAllAsset());
|
Future(() => ref.read(assetProvider.notifier).getAllAsset());
|
||||||
Future(() => ref.read(albumProvider.notifier).refreshRemoteAlbums());
|
Future(() => ref.read(albumProvider.notifier).refreshRemoteAlbums());
|
||||||
ref.read(serverInfoProvider.notifier).getServerInfo();
|
ref.read(serverInfoProvider.notifier).getServerInfo();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget buildLoadingIndicator() {
|
Widget buildLoadingIndicator() {
|
||||||
Timer(const Duration(seconds: 2), () => tipOneOpacity.value = 1);
|
Timer(const Duration(seconds: 2), () => tipOneOpacity.value = 1);
|
||||||
|
|
||||||
|
263
mobile/lib/pages/share_intent/share_intent.page.dart
Normal file
263
mobile/lib/pages/share_intent/share_intent.page.dart
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
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/models/upload/share_intent_attachment.model.dart';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/pages/common/large_leading_tile.dart';
|
||||||
|
import 'package:immich_mobile/providers/asset_viewer/share_intent_upload.provider.dart';
|
||||||
|
import 'package:immich_mobile/entities/store.entity.dart' as db_store;
|
||||||
|
|
||||||
|
@RoutePage()
|
||||||
|
class ShareIntentPage extends HookConsumerWidget {
|
||||||
|
const ShareIntentPage({super.key, required this.attachments});
|
||||||
|
|
||||||
|
final List<ShareIntentAttachment> attachments;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final currentEndpoint =
|
||||||
|
db_store.Store.get(db_store.StoreKey.serverEndpoint);
|
||||||
|
final candidates = ref.watch(shareIntentUploadProvider);
|
||||||
|
final isUploaded = useState(false);
|
||||||
|
|
||||||
|
void removeAttachment(ShareIntentAttachment attachment) {
|
||||||
|
ref.read(shareIntentUploadProvider.notifier).removeAttachment(attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addAttachments(List<ShareIntentAttachment> attachments) {
|
||||||
|
ref.read(shareIntentUploadProvider.notifier).addAttachments(attachments);
|
||||||
|
}
|
||||||
|
|
||||||
|
void upload() async {
|
||||||
|
for (final attachment in candidates) {
|
||||||
|
await ref
|
||||||
|
.read(shareIntentUploadProvider.notifier)
|
||||||
|
.upload(attachment.file);
|
||||||
|
}
|
||||||
|
|
||||||
|
isUploaded.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSelected(ShareIntentAttachment attachment) {
|
||||||
|
return candidates.contains(attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
void toggleSelection(ShareIntentAttachment attachment) {
|
||||||
|
if (isSelected(attachment)) {
|
||||||
|
removeAttachment(attachment);
|
||||||
|
} else {
|
||||||
|
addAttachments([attachment]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Column(
|
||||||
|
children: [
|
||||||
|
const Text('upload_to_immich').tr(
|
||||||
|
args: [
|
||||||
|
candidates.length.toString(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
currentEndpoint,
|
||||||
|
style: context.textTheme.labelMedium?.copyWith(
|
||||||
|
color: context.colorScheme.onSurface.withAlpha(200),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: ListView.builder(
|
||||||
|
itemCount: attachments.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final attachment = attachments[index];
|
||||||
|
final target = candidates.firstWhere(
|
||||||
|
(element) => element.id == attachment.id,
|
||||||
|
orElse: () => attachment,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 4.0,
|
||||||
|
horizontal: 16,
|
||||||
|
),
|
||||||
|
child: LargeLeadingTile(
|
||||||
|
onTap: () => toggleSelection(attachment),
|
||||||
|
disabled: isUploaded.value,
|
||||||
|
selected: isSelected(attachment),
|
||||||
|
leading: Stack(
|
||||||
|
children: [
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(16)),
|
||||||
|
child: attachment.isImage
|
||||||
|
? Image.file(
|
||||||
|
attachment.file,
|
||||||
|
width: 64,
|
||||||
|
height: 64,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
)
|
||||||
|
: const SizedBox(
|
||||||
|
width: 64,
|
||||||
|
height: 64,
|
||||||
|
child: Center(
|
||||||
|
child: Icon(
|
||||||
|
Icons.videocam,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (attachment.isImage)
|
||||||
|
const Positioned(
|
||||||
|
top: 8,
|
||||||
|
right: 8,
|
||||||
|
child: Icon(
|
||||||
|
Icons.image,
|
||||||
|
color: Colors.white,
|
||||||
|
size: 20,
|
||||||
|
shadows: [
|
||||||
|
Shadow(
|
||||||
|
offset: Offset(0, 0),
|
||||||
|
blurRadius: 8.0,
|
||||||
|
color: Colors.black45,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
attachment.fileName,
|
||||||
|
style: context.textTheme.titleSmall,
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
attachment.fileSize,
|
||||||
|
style: context.textTheme.labelLarge,
|
||||||
|
),
|
||||||
|
trailing: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||||
|
child: UploadStatusIcon(
|
||||||
|
selected: isSelected(attachment),
|
||||||
|
status: target.status,
|
||||||
|
progress: target.uploadProgress,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
bottomNavigationBar: SafeArea(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: SizedBox(
|
||||||
|
height: 48,
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: isUploaded.value ? null : upload,
|
||||||
|
child: isUploaded.value
|
||||||
|
? UploadingText(candidates: candidates)
|
||||||
|
: const Text('upload').tr(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UploadingText extends StatelessWidget {
|
||||||
|
const UploadingText({super.key, required this.candidates});
|
||||||
|
final List<ShareIntentAttachment> candidates;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final uploadedCount = candidates.where((element) {
|
||||||
|
return element.status == UploadStatus.complete;
|
||||||
|
}).length;
|
||||||
|
|
||||||
|
return const Text("shared_intent_upload_button_progress_text")
|
||||||
|
.tr(args: [uploadedCount.toString(), candidates.length.toString()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UploadStatusIcon extends StatelessWidget {
|
||||||
|
const UploadStatusIcon({
|
||||||
|
super.key,
|
||||||
|
required this.status,
|
||||||
|
required this.selected,
|
||||||
|
this.progress = 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
final UploadStatus status;
|
||||||
|
final double progress;
|
||||||
|
final bool selected;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (!selected) {
|
||||||
|
return Icon(
|
||||||
|
Icons.check_circle_outline_rounded,
|
||||||
|
color: context.colorScheme.onSurface.withAlpha(100),
|
||||||
|
semanticLabel: 'not_selected'.tr(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final statusIcon = switch (status) {
|
||||||
|
UploadStatus.enqueued => Icon(
|
||||||
|
Icons.check_circle_rounded,
|
||||||
|
color: context.primaryColor,
|
||||||
|
semanticLabel: 'enqueued'.tr(),
|
||||||
|
),
|
||||||
|
UploadStatus.running => Stack(
|
||||||
|
alignment: AlignmentDirectional.center,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
child: TweenAnimationBuilder(
|
||||||
|
tween: Tween<double>(begin: 0.0, end: progress),
|
||||||
|
duration: const Duration(milliseconds: 500),
|
||||||
|
builder: (context, value, _) => CircularProgressIndicator(
|
||||||
|
backgroundColor: context.colorScheme.surfaceContainerLow,
|
||||||
|
strokeWidth: 3,
|
||||||
|
value: value,
|
||||||
|
semanticsLabel: 'uploading'.tr(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
(progress * 100).toStringAsFixed(0),
|
||||||
|
style: context.textTheme.labelSmall?.copyWith(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
UploadStatus.complete => Icon(
|
||||||
|
Icons.check_circle_rounded,
|
||||||
|
color: Colors.green,
|
||||||
|
semanticLabel: 'completed'.tr(),
|
||||||
|
),
|
||||||
|
UploadStatus.notFound || UploadStatus.failed => Icon(
|
||||||
|
Icons.error_rounded,
|
||||||
|
color: Colors.red,
|
||||||
|
semanticLabel: 'failed'.tr(),
|
||||||
|
),
|
||||||
|
UploadStatus.canceled => Icon(
|
||||||
|
Icons.cancel_rounded,
|
||||||
|
color: Colors.red,
|
||||||
|
semanticLabel: 'canceled'.tr(),
|
||||||
|
),
|
||||||
|
UploadStatus.waitingtoRetry || UploadStatus.paused => Icon(
|
||||||
|
Icons.pause_circle_rounded,
|
||||||
|
color: context.primaryColor,
|
||||||
|
semanticLabel: 'paused'.tr(),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
return statusIcon;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,143 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:background_downloader/background_downloader.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/constants/constants.dart';
|
||||||
|
import 'package:immich_mobile/extensions/string_extensions.dart';
|
||||||
|
import 'package:immich_mobile/models/upload/share_intent_attachment.model.dart';
|
||||||
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
|
import 'package:immich_mobile/services/share_intent_service.dart';
|
||||||
|
import 'package:immich_mobile/services/upload.service.dart';
|
||||||
|
|
||||||
|
final shareIntentUploadProvider = StateNotifierProvider<
|
||||||
|
ShareIntentUploadStateNotifier, List<ShareIntentAttachment>>(
|
||||||
|
((ref) => ShareIntentUploadStateNotifier(
|
||||||
|
ref.watch(appRouterProvider),
|
||||||
|
ref.watch(uploadServiceProvider),
|
||||||
|
ref.watch(shareIntentServiceProvider),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
|
class ShareIntentUploadStateNotifier
|
||||||
|
extends StateNotifier<List<ShareIntentAttachment>> {
|
||||||
|
final AppRouter router;
|
||||||
|
final UploadService _uploadService;
|
||||||
|
final ShareIntentService _shareIntentService;
|
||||||
|
|
||||||
|
ShareIntentUploadStateNotifier(
|
||||||
|
this.router,
|
||||||
|
this._uploadService,
|
||||||
|
this._shareIntentService,
|
||||||
|
) : super([]) {
|
||||||
|
_uploadService.onUploadStatus = _uploadStatusCallback;
|
||||||
|
_uploadService.onTaskProgress = _taskProgressCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
_shareIntentService.onSharedMedia = onSharedMedia;
|
||||||
|
_shareIntentService.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onSharedMedia(List<ShareIntentAttachment> attachments) {
|
||||||
|
router.removeWhere((route) => route.name == "ShareIntentRoute");
|
||||||
|
clearAttachments();
|
||||||
|
addAttachments(attachments);
|
||||||
|
router.push(ShareIntentRoute(attachments: attachments));
|
||||||
|
}
|
||||||
|
|
||||||
|
void addAttachments(List<ShareIntentAttachment> attachments) {
|
||||||
|
if (attachments.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state = [...state, ...attachments];
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeAttachment(ShareIntentAttachment attachment) {
|
||||||
|
final updatedState =
|
||||||
|
state.where((element) => element != attachment).toList();
|
||||||
|
if (updatedState.length != state.length) {
|
||||||
|
state = updatedState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearAttachments() {
|
||||||
|
if (state.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateUploadStatus(TaskStatusUpdate task, TaskStatus status) async {
|
||||||
|
if (status == TaskStatus.canceled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final taskId = task.task.taskId;
|
||||||
|
final uploadStatus = switch (task.status) {
|
||||||
|
TaskStatus.complete => UploadStatus.complete,
|
||||||
|
TaskStatus.failed => UploadStatus.failed,
|
||||||
|
TaskStatus.canceled => UploadStatus.canceled,
|
||||||
|
TaskStatus.enqueued => UploadStatus.enqueued,
|
||||||
|
TaskStatus.running => UploadStatus.running,
|
||||||
|
TaskStatus.paused => UploadStatus.paused,
|
||||||
|
TaskStatus.notFound => UploadStatus.notFound,
|
||||||
|
TaskStatus.waitingToRetry => UploadStatus.waitingtoRetry
|
||||||
|
};
|
||||||
|
|
||||||
|
state = [
|
||||||
|
for (final attachment in state)
|
||||||
|
if (attachment.id == taskId.toInt())
|
||||||
|
attachment.copyWith(status: uploadStatus)
|
||||||
|
else
|
||||||
|
attachment,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
void _uploadStatusCallback(TaskStatusUpdate update) {
|
||||||
|
_updateUploadStatus(update, update.status);
|
||||||
|
|
||||||
|
switch (update.status) {
|
||||||
|
case TaskStatus.complete:
|
||||||
|
if (update.responseStatusCode == 200) {
|
||||||
|
if (kDebugMode) {
|
||||||
|
debugPrint("[COMPLETE] ${update.task.taskId} - DUPLICATE");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (kDebugMode) {
|
||||||
|
debugPrint("[COMPLETE] ${update.task.taskId}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _taskProgressCallback(TaskProgressUpdate update) {
|
||||||
|
// Ignore if the task is cancled or completed
|
||||||
|
if (update.progress == downloadFailed ||
|
||||||
|
update.progress == downloadCompleted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final taskId = update.task.taskId;
|
||||||
|
state = [
|
||||||
|
for (final attachment in state)
|
||||||
|
if (attachment.id == taskId.toInt())
|
||||||
|
attachment.copyWith(uploadProgress: update.progress)
|
||||||
|
else
|
||||||
|
attachment,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> upload(File file) {
|
||||||
|
return _uploadService.upload(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> cancelUpload(String id) {
|
||||||
|
return _uploadService.cancelUpload(id);
|
||||||
|
}
|
||||||
|
}
|
63
mobile/lib/repositories/share_handler.repository.dart
Normal file
63
mobile/lib/repositories/share_handler.repository.dart
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/interfaces/share_handler.interface.dart';
|
||||||
|
import 'package:immich_mobile/models/upload/share_intent_attachment.model.dart';
|
||||||
|
import 'package:share_handler/share_handler.dart';
|
||||||
|
|
||||||
|
final shareHandlerRepositoryProvider = Provider(
|
||||||
|
(ref) => ShareHandlerRepository(),
|
||||||
|
);
|
||||||
|
|
||||||
|
class ShareHandlerRepository implements IShareHandlerRepository {
|
||||||
|
ShareHandlerRepository();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void Function(List<ShareIntentAttachment> attachments)? onSharedMedia;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> init() async {
|
||||||
|
final handler = ShareHandlerPlatform.instance;
|
||||||
|
final media = await handler.getInitialSharedMedia();
|
||||||
|
|
||||||
|
if (media != null && media.attachments != null) {
|
||||||
|
onSharedMedia?.call(_buildPayload(media.attachments!));
|
||||||
|
}
|
||||||
|
|
||||||
|
handler.sharedMediaStream.listen((SharedMedia media) {
|
||||||
|
if (media.attachments != null) {
|
||||||
|
onSharedMedia?.call(_buildPayload(media.attachments!));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ShareIntentAttachment> _buildPayload(
|
||||||
|
List<SharedAttachment?> attachments,
|
||||||
|
) {
|
||||||
|
final payload = <ShareIntentAttachment>[];
|
||||||
|
|
||||||
|
for (final attachment in attachments) {
|
||||||
|
if (attachment == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final type = attachment.type == SharedAttachmentType.image
|
||||||
|
? ShareIntentAttachmentType.image
|
||||||
|
: ShareIntentAttachmentType.video;
|
||||||
|
|
||||||
|
final fileLength = File(attachment.path).lengthSync();
|
||||||
|
|
||||||
|
payload.add(
|
||||||
|
ShareIntentAttachment(
|
||||||
|
path: attachment.path,
|
||||||
|
type: type,
|
||||||
|
status: UploadStatus.enqueued,
|
||||||
|
uploadProgress: 0.0,
|
||||||
|
fileLength: fileLength,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
}
|
42
mobile/lib/repositories/upload.repository.dart
Normal file
42
mobile/lib/repositories/upload.repository.dart
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import 'package:background_downloader/background_downloader.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/interfaces/upload.interface.dart';
|
||||||
|
import 'package:immich_mobile/utils/upload.dart';
|
||||||
|
|
||||||
|
final uploadRepositoryProvider = Provider((ref) => UploadRepository());
|
||||||
|
|
||||||
|
class UploadRepository implements IUploadRepository {
|
||||||
|
@override
|
||||||
|
void Function(TaskStatusUpdate)? onUploadStatus;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void Function(TaskProgressUpdate)? onTaskProgress;
|
||||||
|
|
||||||
|
UploadRepository() {
|
||||||
|
FileDownloader().registerCallbacks(
|
||||||
|
group: uploadGroup,
|
||||||
|
taskStatusCallback: (update) => onUploadStatus?.call(update),
|
||||||
|
taskProgressCallback: (update) => onTaskProgress?.call(update),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> upload(UploadTask task) {
|
||||||
|
return FileDownloader().enqueue(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> deleteAllTrackingRecords() {
|
||||||
|
return FileDownloader().database.deleteAllRecords();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> cancel(String id) {
|
||||||
|
return FileDownloader().cancelTaskWithId(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> deleteRecordsWithIds(List<String> ids) {
|
||||||
|
return FileDownloader().database.deleteRecordsWithIds(ids);
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@ import 'package:immich_mobile/entities/user.entity.dart';
|
|||||||
import 'package:immich_mobile/models/memories/memory.model.dart';
|
import 'package:immich_mobile/models/memories/memory.model.dart';
|
||||||
import 'package:immich_mobile/models/search/search_filter.model.dart';
|
import 'package:immich_mobile/models/search/search_filter.model.dart';
|
||||||
import 'package:immich_mobile/models/shared_link/shared_link.model.dart';
|
import 'package:immich_mobile/models/shared_link/shared_link.model.dart';
|
||||||
|
import 'package:immich_mobile/models/upload/share_intent_attachment.model.dart';
|
||||||
import 'package:immich_mobile/pages/backup/album_preview.page.dart';
|
import 'package:immich_mobile/pages/backup/album_preview.page.dart';
|
||||||
import 'package:immich_mobile/pages/backup/backup_album_selection.page.dart';
|
import 'package:immich_mobile/pages/backup/backup_album_selection.page.dart';
|
||||||
import 'package:immich_mobile/pages/backup/backup_controller.page.dart';
|
import 'package:immich_mobile/pages/backup/backup_controller.page.dart';
|
||||||
@ -57,6 +58,7 @@ import 'package:immich_mobile/pages/library/partner/partner.page.dart';
|
|||||||
import 'package:immich_mobile/pages/library/partner/partner_detail.page.dart';
|
import 'package:immich_mobile/pages/library/partner/partner_detail.page.dart';
|
||||||
import 'package:immich_mobile/pages/library/shared_link/shared_link.page.dart';
|
import 'package:immich_mobile/pages/library/shared_link/shared_link.page.dart';
|
||||||
import 'package:immich_mobile/pages/library/shared_link/shared_link_edit.page.dart';
|
import 'package:immich_mobile/pages/library/shared_link/shared_link_edit.page.dart';
|
||||||
|
import 'package:immich_mobile/pages/share_intent/share_intent.page.dart';
|
||||||
import 'package:immich_mobile/providers/api.provider.dart';
|
import 'package:immich_mobile/providers/api.provider.dart';
|
||||||
import 'package:immich_mobile/providers/gallery_permission.provider.dart';
|
import 'package:immich_mobile/providers/gallery_permission.provider.dart';
|
||||||
import 'package:immich_mobile/routing/auth_guard.dart';
|
import 'package:immich_mobile/routing/auth_guard.dart';
|
||||||
@ -277,6 +279,10 @@ class AppRouter extends RootStackRouter {
|
|||||||
page: NativeVideoViewerRoute.page,
|
page: NativeVideoViewerRoute.page,
|
||||||
guards: [_authGuard, _duplicateGuard],
|
guards: [_authGuard, _duplicateGuard],
|
||||||
),
|
),
|
||||||
|
AutoRoute(
|
||||||
|
page: ShareIntentRoute.page,
|
||||||
|
guards: [_authGuard, _duplicateGuard],
|
||||||
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,15 +136,10 @@ class AlbumAssetSelectionRouteArgs {
|
|||||||
|
|
||||||
/// generated route for
|
/// generated route for
|
||||||
/// [AlbumOptionsPage]
|
/// [AlbumOptionsPage]
|
||||||
class AlbumOptionsRoute extends PageRouteInfo<AlbumOptionsRouteArgs> {
|
class AlbumOptionsRoute extends PageRouteInfo<void> {
|
||||||
AlbumOptionsRoute({
|
const AlbumOptionsRoute({List<PageRouteInfo>? children})
|
||||||
Key? key,
|
: super(
|
||||||
List<PageRouteInfo>? children,
|
|
||||||
}) : super(
|
|
||||||
AlbumOptionsRoute.name,
|
AlbumOptionsRoute.name,
|
||||||
args: AlbumOptionsRouteArgs(
|
|
||||||
key: key,
|
|
||||||
),
|
|
||||||
initialChildren: children,
|
initialChildren: children,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -153,25 +148,11 @@ class AlbumOptionsRoute extends PageRouteInfo<AlbumOptionsRouteArgs> {
|
|||||||
static PageInfo page = PageInfo(
|
static PageInfo page = PageInfo(
|
||||||
name,
|
name,
|
||||||
builder: (data) {
|
builder: (data) {
|
||||||
final args = data.argsAs<AlbumOptionsRouteArgs>();
|
return const AlbumOptionsPage();
|
||||||
return AlbumOptionsPage(
|
|
||||||
key: args.key,
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class AlbumOptionsRouteArgs {
|
|
||||||
const AlbumOptionsRouteArgs({this.key});
|
|
||||||
|
|
||||||
final Key? key;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'AlbumOptionsRouteArgs{key: $key}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// generated route for
|
/// generated route for
|
||||||
/// [AlbumPreviewPage]
|
/// [AlbumPreviewPage]
|
||||||
class AlbumPreviewRoute extends PageRouteInfo<AlbumPreviewRouteArgs> {
|
class AlbumPreviewRoute extends PageRouteInfo<AlbumPreviewRouteArgs> {
|
||||||
@ -1453,6 +1434,52 @@ class SettingsSubRouteArgs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// generated route for
|
||||||
|
/// [ShareIntentPage]
|
||||||
|
class ShareIntentRoute extends PageRouteInfo<ShareIntentRouteArgs> {
|
||||||
|
ShareIntentRoute({
|
||||||
|
Key? key,
|
||||||
|
required List<ShareIntentAttachment> attachments,
|
||||||
|
List<PageRouteInfo>? children,
|
||||||
|
}) : super(
|
||||||
|
ShareIntentRoute.name,
|
||||||
|
args: ShareIntentRouteArgs(
|
||||||
|
key: key,
|
||||||
|
attachments: attachments,
|
||||||
|
),
|
||||||
|
initialChildren: children,
|
||||||
|
);
|
||||||
|
|
||||||
|
static const String name = 'ShareIntentRoute';
|
||||||
|
|
||||||
|
static PageInfo page = PageInfo(
|
||||||
|
name,
|
||||||
|
builder: (data) {
|
||||||
|
final args = data.argsAs<ShareIntentRouteArgs>();
|
||||||
|
return ShareIntentPage(
|
||||||
|
key: args.key,
|
||||||
|
attachments: args.attachments,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ShareIntentRouteArgs {
|
||||||
|
const ShareIntentRouteArgs({
|
||||||
|
this.key,
|
||||||
|
required this.attachments,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Key? key;
|
||||||
|
|
||||||
|
final List<ShareIntentAttachment> attachments;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'ShareIntentRouteArgs{key: $key, attachments: $attachments}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// generated route for
|
/// generated route for
|
||||||
/// [SharedLinkEditPage]
|
/// [SharedLinkEditPage]
|
||||||
class SharedLinkEditRoute extends PageRouteInfo<SharedLinkEditRouteArgs> {
|
class SharedLinkEditRoute extends PageRouteInfo<SharedLinkEditRouteArgs> {
|
||||||
|
23
mobile/lib/services/share_intent_service.dart
Normal file
23
mobile/lib/services/share_intent_service.dart
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/models/upload/share_intent_attachment.model.dart';
|
||||||
|
import 'package:immich_mobile/repositories/share_handler.repository.dart';
|
||||||
|
|
||||||
|
final shareIntentServiceProvider = Provider(
|
||||||
|
(ref) => ShareIntentService(
|
||||||
|
ref.watch(shareHandlerRepositoryProvider),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
class ShareIntentService {
|
||||||
|
final ShareHandlerRepository shareHandlerRepository;
|
||||||
|
void Function(List<ShareIntentAttachment> attachments)? onSharedMedia;
|
||||||
|
|
||||||
|
ShareIntentService(
|
||||||
|
this.shareHandlerRepository,
|
||||||
|
);
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
shareHandlerRepository.onSharedMedia = onSharedMedia;
|
||||||
|
shareHandlerRepository.init();
|
||||||
|
}
|
||||||
|
}
|
94
mobile/lib/services/upload.service.dart
Normal file
94
mobile/lib/services/upload.service.dart
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:background_downloader/background_downloader.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/entities/store.entity.dart';
|
||||||
|
import 'package:immich_mobile/interfaces/upload.interface.dart';
|
||||||
|
import 'package:immich_mobile/repositories/upload.repository.dart';
|
||||||
|
import 'package:immich_mobile/services/api.service.dart';
|
||||||
|
import 'package:immich_mobile/utils/upload.dart';
|
||||||
|
import 'package:path/path.dart';
|
||||||
|
// import 'package:logging/logging.dart';
|
||||||
|
|
||||||
|
final uploadServiceProvider = Provider(
|
||||||
|
(ref) => UploadService(
|
||||||
|
ref.watch(uploadRepositoryProvider),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
class UploadService {
|
||||||
|
final IUploadRepository _uploadRepository;
|
||||||
|
// final Logger _log = Logger("UploadService");
|
||||||
|
void Function(TaskStatusUpdate)? onUploadStatus;
|
||||||
|
void Function(TaskProgressUpdate)? onTaskProgress;
|
||||||
|
|
||||||
|
UploadService(
|
||||||
|
this._uploadRepository,
|
||||||
|
) {
|
||||||
|
_uploadRepository.onUploadStatus = _onUploadCallback;
|
||||||
|
_uploadRepository.onTaskProgress = _onTaskProgressCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onTaskProgressCallback(TaskProgressUpdate update) {
|
||||||
|
onTaskProgress?.call(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onUploadCallback(TaskStatusUpdate update) {
|
||||||
|
onUploadStatus?.call(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> cancelUpload(String id) {
|
||||||
|
return FileDownloader().cancelTaskWithId(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> upload(File file) async {
|
||||||
|
final task = await _buildUploadTask(
|
||||||
|
hash(file.path).toString(),
|
||||||
|
file,
|
||||||
|
);
|
||||||
|
|
||||||
|
await _uploadRepository.upload(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<UploadTask> _buildUploadTask(
|
||||||
|
String id,
|
||||||
|
File file, {
|
||||||
|
Map<String, String>? fields,
|
||||||
|
}) async {
|
||||||
|
final serverEndpoint = Store.get(StoreKey.serverEndpoint);
|
||||||
|
final url = Uri.parse('$serverEndpoint/assets').toString();
|
||||||
|
final headers = ApiService.getRequestHeaders();
|
||||||
|
final deviceId = Store.get(StoreKey.deviceId);
|
||||||
|
|
||||||
|
final (baseDirectory, directory, filename) =
|
||||||
|
await Task.split(filePath: file.path);
|
||||||
|
final stats = await file.stat();
|
||||||
|
final fileCreatedAt = stats.changed;
|
||||||
|
final fileModifiedAt = stats.modified;
|
||||||
|
|
||||||
|
final fieldsMap = {
|
||||||
|
'filename': filename,
|
||||||
|
'deviceAssetId': id,
|
||||||
|
'deviceId': deviceId,
|
||||||
|
'fileCreatedAt': fileCreatedAt.toUtc().toIso8601String(),
|
||||||
|
'fileModifiedAt': fileModifiedAt.toUtc().toIso8601String(),
|
||||||
|
'isFavorite': 'false',
|
||||||
|
'duration': '0',
|
||||||
|
if (fields != null) ...fields,
|
||||||
|
};
|
||||||
|
|
||||||
|
return UploadTask(
|
||||||
|
taskId: id,
|
||||||
|
httpRequestMethod: 'POST',
|
||||||
|
url: url,
|
||||||
|
headers: headers,
|
||||||
|
filename: filename,
|
||||||
|
fields: fieldsMap,
|
||||||
|
baseDirectory: baseDirectory,
|
||||||
|
directory: directory,
|
||||||
|
fileField: 'assetData',
|
||||||
|
group: uploadGroup,
|
||||||
|
updates: Updates.statusAndProgress,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
String formatBytes(int bytes) {
|
String formatBytes(int bytes) {
|
||||||
const units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB'];
|
const units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB'];
|
||||||
|
|
||||||
@ -14,3 +16,10 @@ String formatBytes(int bytes) {
|
|||||||
|
|
||||||
return "${remainder.toStringAsFixed(magnitude == 0 ? 0 : 1)} ${units[magnitude]}";
|
return "${remainder.toStringAsFixed(magnitude == 0 ? 0 : 1)} ${units[magnitude]}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String formatHumanReadableBytes(int bytes, int decimals) {
|
||||||
|
if (bytes <= 0) return "0 B";
|
||||||
|
const suffixes = ["B", "KB", "MB", "GB", "TB"];
|
||||||
|
var i = (log(bytes) / log(1024)).floor();
|
||||||
|
return '${(bytes / pow(1024, i)).toStringAsFixed(decimals)} ${suffixes[i]}';
|
||||||
|
}
|
||||||
|
1
mobile/lib/utils/upload.dart
Normal file
1
mobile/lib/utils/upload.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
const uploadGroup = 'upload_group';
|
@ -206,7 +206,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
|||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.settings_rounded),
|
leading: const Icon(Icons.settings_rounded),
|
||||||
onTap: () => context.navigateTo(AlbumOptionsRoute()),
|
onTap: () => context.navigateTo(const AlbumOptionsRoute()),
|
||||||
title: const Text(
|
title: const Text(
|
||||||
"translated_text_options",
|
"translated_text_options",
|
||||||
style: TextStyle(fontWeight: FontWeight.w500),
|
style: TextStyle(fontWeight: FontWeight.w500),
|
||||||
|
@ -1328,6 +1328,38 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.8"
|
version: "0.3.8"
|
||||||
|
share_handler:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: share_handler
|
||||||
|
sha256: "76575533be04df3fecbebd3c5b5325a8271b5973131f8b8b0ab8490c395a5d37"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.22"
|
||||||
|
share_handler_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: share_handler_android
|
||||||
|
sha256: "124dcc914fb7ecd89076d3dc28435b98fe2129a988bf7742f7a01dcb66a95667"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.9"
|
||||||
|
share_handler_ios:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: share_handler_ios
|
||||||
|
sha256: cdc21f88f336a944157a8e9ceb191525cee3b082d6eb6c2082488e4f09dc3ece
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.15"
|
||||||
|
share_handler_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: share_handler_platform_interface
|
||||||
|
sha256: "7a4df95a87b326b2f07458d937f2281874567c364b7b7ebe4e7d50efaae5f106"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.6"
|
||||||
share_plus:
|
share_plus:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -77,6 +77,7 @@ dependencies:
|
|||||||
image_picker: ^1.0.7 # only used to select user profile image from system gallery -> we can simply select an image from within immich?
|
image_picker: ^1.0.7 # only used to select user profile image from system gallery -> we can simply select an image from within immich?
|
||||||
logging: ^1.2.0
|
logging: ^1.2.0
|
||||||
file_picker: ^8.0.0+1
|
file_picker: ^8.0.0+1
|
||||||
|
share_handler: ^0.0.22
|
||||||
|
|
||||||
# This is uncommented in F-Droid build script
|
# This is uncommented in F-Droid build script
|
||||||
# Taken from https://github.com/Myzel394/locus/blob/445013d22ec1d759027d4303bd65b30c5c8588c8/pubspec.yaml#L105
|
# Taken from https://github.com/Myzel394/locus/blob/445013d22ec1d759027d4303bd65b30c5c8588c8/pubspec.yaml#L105
|
||||||
|
Loading…
x
Reference in New Issue
Block a user