mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 06:28:41 +00:00
fixes #340 and continue with #333
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
This commit is contained in:
parent
0984eaf347
commit
230809290a
18 changed files with 1219 additions and 167 deletions
|
|
@ -33,6 +33,16 @@
|
|||
<data android:scheme="http" android:host="me.twonly.eu" />
|
||||
<data android:scheme="https" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="image/*" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="video/*" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
|
|
@ -46,19 +56,11 @@
|
|||
android:name="com.google.android.datatransport.runtime.scheduling.jobscheduling.JobInfoSchedulerService"
|
||||
tools:node="remove">
|
||||
</service>
|
||||
|
||||
<!-- <service
|
||||
android:name="com.pravera.flutter_foreground_task.service.ForegroundService"
|
||||
android:foregroundServiceType="dataSync|remoteMessaging"
|
||||
android:exported="false" /> -->
|
||||
|
||||
<meta-data
|
||||
android:name="eu.twonly.service.TWONLY_LOGO"
|
||||
android:resource="@drawable/ic_launcher_foreground" />
|
||||
</application>
|
||||
|
||||
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 83475a912851acb6a718ea32a6f0f754d64a50d8
|
||||
Subproject commit 7930d9727019344238297d810661bc3e8f724c37
|
||||
|
|
@ -43,6 +43,13 @@ target 'Runner' do
|
|||
target 'RunnerTests' do
|
||||
inherit! :search_paths
|
||||
end
|
||||
|
||||
# Share Extension is name of Extension which you created which is in this case 'Share Extension'
|
||||
target 'ShareExtension' do
|
||||
inherit! :search_paths
|
||||
# flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
|
|
|
|||
|
|
@ -122,6 +122,8 @@ PODS:
|
|||
- flutter_secure_storage_darwin (10.0.0):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- flutter_sharing_intent (1.0.1):
|
||||
- Flutter
|
||||
- flutter_volume_controller (0.0.1):
|
||||
- Flutter
|
||||
- gal (1.0.0):
|
||||
|
|
@ -260,7 +262,7 @@ PODS:
|
|||
- nanopb/encode (= 3.30910.0)
|
||||
- nanopb/decode (3.30910.0)
|
||||
- nanopb/encode (3.30910.0)
|
||||
- "no_screenshot (0.0.1+4)":
|
||||
- no_screenshot (0.3.2-beta.3):
|
||||
- Flutter
|
||||
- ScreenProtectorKit (~> 1.3.1)
|
||||
- objective_c (0.0.1):
|
||||
|
|
@ -350,6 +352,7 @@ DEPENDENCIES:
|
|||
- flutter_keyboard_visibility_temp_fork (from `.symlinks/plugins/flutter_keyboard_visibility_temp_fork/ios`)
|
||||
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
||||
- flutter_secure_storage_darwin (from `.symlinks/plugins/flutter_secure_storage_darwin/darwin`)
|
||||
- flutter_sharing_intent (from `.symlinks/plugins/flutter_sharing_intent/ios`)
|
||||
- flutter_volume_controller (from `.symlinks/plugins/flutter_volume_controller/ios`)
|
||||
- gal (from `.symlinks/plugins/gal/darwin`)
|
||||
- google_mlkit_barcode_scanning (from `.symlinks/plugins/google_mlkit_barcode_scanning/ios`)
|
||||
|
|
@ -441,6 +444,8 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/flutter_local_notifications/ios"
|
||||
flutter_secure_storage_darwin:
|
||||
:path: ".symlinks/plugins/flutter_secure_storage_darwin/darwin"
|
||||
flutter_sharing_intent:
|
||||
:path: ".symlinks/plugins/flutter_sharing_intent/ios"
|
||||
flutter_volume_controller:
|
||||
:path: ".symlinks/plugins/flutter_volume_controller/ios"
|
||||
gal:
|
||||
|
|
@ -507,7 +512,8 @@ SPEC CHECKSUMS:
|
|||
flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1
|
||||
flutter_keyboard_visibility_temp_fork: 95b2d534bacf6ac62e7fcbe5c2a9e2c2a17ce06f
|
||||
flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb
|
||||
flutter_secure_storage_darwin: ce237a8775b39723566dc72571190a3769d70468
|
||||
flutter_secure_storage_darwin: acdb3f316ed05a3e68f856e0353b133eec373a23
|
||||
flutter_sharing_intent: 0c1e53949f09fa8df8ac2268505687bde8ff264c
|
||||
flutter_volume_controller: c2be490cb0487e8b88d0d9fc2b7e1c139a4ebccb
|
||||
gal: baecd024ebfd13c441269ca7404792a7152fde89
|
||||
google_mlkit_barcode_scanning: 8f5987f244a43fe1167689c548342a5174108159
|
||||
|
|
@ -529,7 +535,7 @@ SPEC CHECKSUMS:
|
|||
MLKitCommon: 07c2c33ae5640e5380beaaa6e4b9c249a205542d
|
||||
MLKitVision: 45e79d68845a2de77e2dd4d7f07947f0ed157b0e
|
||||
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
|
||||
no_screenshot: 6d183496405a3ab709a67a54e5cd0f639e94729e
|
||||
no_screenshot: 89e778ede9f1e39cc3fb9404d782a42712f2a0b2
|
||||
objective_c: 89e720c30d716b036faf9c9684022048eee1eee2
|
||||
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
||||
path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
|
||||
|
|
@ -551,6 +557,6 @@ SPEC CHECKSUMS:
|
|||
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
|
||||
video_player_avfoundation: dd410b52df6d2466a42d28550e33e4146928280a
|
||||
|
||||
PODFILE CHECKSUM: c0c524475498435108850efecde62ba98e081c25
|
||||
PODFILE CHECKSUM: ae041999f13ba7b2285ff9ad9bc688ed647bbcb7
|
||||
|
||||
COCOAPODS: 1.16.2
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
05CF222065FC24670B05B6D0 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1EE71614E1B4F84D6FDC2D /* Pods_RunnerTests.framework */; };
|
||||
06AA21445BEAF2C45DC9DCDF /* Pods_NotificationService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A198C9B5D90584C4F96206B2 /* Pods_NotificationService.framework */; };
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||
30EBDD0F93DC44E774F3B785 /* Pods_ShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E190E82D9973B318A389650B /* Pods_ShareExtension.framework */; };
|
||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
|
|
@ -19,6 +20,7 @@
|
|||
CA4FDF5DD8F229C30DE512AF /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EE2CCFEE4ABECF33852F7735 /* Pods_Runner.framework */; };
|
||||
D21FCEAB2D9F2B750088701D /* NotificationService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D21FCEA42D9F2B750088701D /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
D25D4D1E2EF626E30029F805 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D25D4D1D2EF626E30029F805 /* StoreKit.framework */; };
|
||||
D25D4D7A2EFF41DB0029F805 /* ShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D25D4D702EFF41DB0029F805 /* ShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
F3C66D726A2EB28484DF0B10 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 16FBC6F5B58E1C6646F5D447 /* GoogleService-Info.plist */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
|
|
@ -37,6 +39,13 @@
|
|||
remoteGlobalIDString = D21FCEA32D9F2B750088701D;
|
||||
remoteInfo = NotificationService;
|
||||
};
|
||||
D25D4D782EFF41DB0029F805 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = D25D4D6F2EFF41DB0029F805;
|
||||
remoteInfo = ShareExtension;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
|
|
@ -56,6 +65,7 @@
|
|||
dstPath = "";
|
||||
dstSubfolderSpec = 13;
|
||||
files = (
|
||||
D25D4D7A2EFF41DB0029F805 /* ShareExtension.appex in Embed Foundation Extensions */,
|
||||
D21FCEAB2D9F2B750088701D /* NotificationService.appex in Embed Foundation Extensions */,
|
||||
);
|
||||
name = "Embed Foundation Extensions";
|
||||
|
|
@ -67,10 +77,12 @@
|
|||
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>"; };
|
||||
1581CC44342D555EFB889768 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
15CEF849B61A620CFB2DC5F1 /* 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>"; };
|
||||
16FBC6F5B58E1C6646F5D447 /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = "<group>"; };
|
||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
35366FD433E0EFC6EF19A452 /* Pods-NotificationService.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.release.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.release.xcconfig"; sourceTree = "<group>"; };
|
||||
39FB86A38393489D58A01B0B /* 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>"; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
4D78471482626812FE2468E9 /* Pods-NotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.debug.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
6EB462F87F0A23758713308F /* 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>"; };
|
||||
|
|
@ -87,11 +99,15 @@
|
|||
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>"; };
|
||||
A198C9B5D90584C4F96206B2 /* Pods_NotificationService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_NotificationService.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
A22BD564F16069E5FCB60767 /* 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>"; };
|
||||
B3B27B7FBEEA31DB7793A0C2 /* 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>"; };
|
||||
D21FCEA42D9F2B750088701D /* NotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D2265DD42D920142000D99BB /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||
D25D4D1D2EF626E30029F805 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
|
||||
D25D4D702EFF41DB0029F805 /* ShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D25D4D802EFF437F0029F805 /* RunnerDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerDebug.entitlements; sourceTree = "<group>"; };
|
||||
DC1EE71614E1B4F84D6FDC2D /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
E190E82D9973B318A389650B /* Pods_ShareExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ShareExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
E96A5ACA32A7118204F050A5 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
EE2CCFEE4ABECF33852F7735 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F02F7A1D63544AA9F23A1085 /* Pods-NotificationService.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.profile.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
|
|
@ -105,6 +121,13 @@
|
|||
);
|
||||
target = D21FCEA32D9F2B750088701D /* NotificationService */;
|
||||
};
|
||||
D25D4D7E2EFF41DB0029F805 /* Exceptions for "ShareExtension" folder in "ShareExtension" target */ = {
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
Info.plist,
|
||||
);
|
||||
target = D25D4D6F2EFF41DB0029F805 /* ShareExtension */;
|
||||
};
|
||||
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||
|
|
@ -116,6 +139,14 @@
|
|||
path = NotificationService;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D25D4D712EFF41DB0029F805 /* ShareExtension */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
D25D4D7E2EFF41DB0029F805 /* Exceptions for "ShareExtension" folder in "ShareExtension" target */,
|
||||
);
|
||||
path = ShareExtension;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXFileSystemSynchronizedRootGroup section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
|
@ -144,6 +175,14 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D25D4D6D2EFF41DB0029F805 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
30EBDD0F93DC44E774F3B785 /* Pods_ShareExtension.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
|
|
@ -172,6 +211,7 @@
|
|||
9740EEB11CF90186004384FC /* Flutter */,
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
D21FCEA52D9F2B750088701D /* NotificationService */,
|
||||
D25D4D712EFF41DB0029F805 /* ShareExtension */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||
16FBC6F5B58E1C6646F5D447 /* GoogleService-Info.plist */,
|
||||
|
|
@ -186,6 +226,7 @@
|
|||
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
|
||||
D21FCEA42D9F2B750088701D /* NotificationService.appex */,
|
||||
D25D4D702EFF41DB0029F805 /* ShareExtension.appex */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -193,6 +234,7 @@
|
|||
97C146F01CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D25D4D802EFF437F0029F805 /* RunnerDebug.entitlements */,
|
||||
D2265DD42D920142000D99BB /* Runner.entitlements */,
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||
|
|
@ -213,6 +255,7 @@
|
|||
A198C9B5D90584C4F96206B2 /* Pods_NotificationService.framework */,
|
||||
EE2CCFEE4ABECF33852F7735 /* Pods_Runner.framework */,
|
||||
DC1EE71614E1B4F84D6FDC2D /* Pods_RunnerTests.framework */,
|
||||
E190E82D9973B318A389650B /* Pods_ShareExtension.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -229,6 +272,9 @@
|
|||
4D78471482626812FE2468E9 /* Pods-NotificationService.debug.xcconfig */,
|
||||
35366FD433E0EFC6EF19A452 /* Pods-NotificationService.release.xcconfig */,
|
||||
F02F7A1D63544AA9F23A1085 /* Pods-NotificationService.profile.xcconfig */,
|
||||
15CEF849B61A620CFB2DC5F1 /* Pods-ShareExtension.debug.xcconfig */,
|
||||
A22BD564F16069E5FCB60767 /* Pods-ShareExtension.release.xcconfig */,
|
||||
39FB86A38393489D58A01B0B /* Pods-ShareExtension.profile.xcconfig */,
|
||||
);
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -274,6 +320,7 @@
|
|||
);
|
||||
dependencies = (
|
||||
D21FCEAA2D9F2B750088701D /* PBXTargetDependency */,
|
||||
D25D4D792EFF41DB0029F805 /* PBXTargetDependency */,
|
||||
);
|
||||
name = Runner;
|
||||
productName = Runner;
|
||||
|
|
@ -301,6 +348,27 @@
|
|||
productReference = D21FCEA42D9F2B750088701D /* NotificationService.appex */;
|
||||
productType = "com.apple.product-type.app-extension";
|
||||
};
|
||||
D25D4D6F2EFF41DB0029F805 /* ShareExtension */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = D25D4D7F2EFF41DB0029F805 /* Build configuration list for PBXNativeTarget "ShareExtension" */;
|
||||
buildPhases = (
|
||||
627F39EA1643E08048D23996 /* [CP] Check Pods Manifest.lock */,
|
||||
D25D4D6C2EFF41DB0029F805 /* Sources */,
|
||||
D25D4D6D2EFF41DB0029F805 /* Frameworks */,
|
||||
D25D4D6E2EFF41DB0029F805 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
fileSystemSynchronizedGroups = (
|
||||
D25D4D712EFF41DB0029F805 /* ShareExtension */,
|
||||
);
|
||||
name = ShareExtension;
|
||||
productName = ShareExtension;
|
||||
productReference = D25D4D702EFF41DB0029F805 /* ShareExtension.appex */;
|
||||
productType = "com.apple.product-type.app-extension";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
|
|
@ -308,7 +376,7 @@
|
|||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastSwiftUpdateCheck = 1620;
|
||||
LastSwiftUpdateCheck = 2610;
|
||||
LastUpgradeCheck = 1510;
|
||||
ORGANIZATIONNAME = "";
|
||||
TargetAttributes = {
|
||||
|
|
@ -323,6 +391,9 @@
|
|||
D21FCEA32D9F2B750088701D = {
|
||||
CreatedOnToolsVersion = 16.2;
|
||||
};
|
||||
D25D4D6F2EFF41DB0029F805 = {
|
||||
CreatedOnToolsVersion = 26.1.1;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
||||
|
|
@ -341,6 +412,7 @@
|
|||
97C146ED1CF9000F007C117D /* Runner */,
|
||||
331C8080294A63A400263BE5 /* RunnerTests */,
|
||||
D21FCEA32D9F2B750088701D /* NotificationService */,
|
||||
D25D4D6F2EFF41DB0029F805 /* ShareExtension */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
|
@ -372,6 +444,13 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D25D4D6E2EFF41DB0029F805 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
|
|
@ -452,6 +531,28 @@
|
|||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n";
|
||||
};
|
||||
627F39EA1643E08048D23996 /* [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;
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
|
|
@ -533,6 +634,13 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D25D4D6C2EFF41DB0029F805 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
|
|
@ -546,6 +654,11 @@
|
|||
target = D21FCEA32D9F2B750088701D /* NotificationService */;
|
||||
targetProxy = D21FCEA92D9F2B750088701D /* PBXContainerItemProxy */;
|
||||
};
|
||||
D25D4D792EFF41DB0029F805 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = D25D4D6F2EFF41DB0029F805 /* ShareExtension */;
|
||||
targetProxy = D25D4D782EFF41DB0029F805 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
|
|
@ -631,6 +744,7 @@
|
|||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
CUSTOM_GROUP_ID = group.eu.twonly.shareIntent;
|
||||
DEVELOPMENT_TEAM = CN332ZUGRP;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
|
|
@ -827,8 +941,9 @@
|
|||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/RunnerDebug.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
CUSTOM_GROUP_ID = group.eu.twonly.shareIntent;
|
||||
DEVELOPMENT_TEAM = CN332ZUGRP;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
|
|
@ -863,6 +978,7 @@
|
|||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
CUSTOM_GROUP_ID = group.eu.twonly.shareIntent;
|
||||
DEVELOPMENT_TEAM = CN332ZUGRP;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
|
|
@ -1004,6 +1120,133 @@
|
|||
};
|
||||
name = Profile;
|
||||
};
|
||||
D25D4D7B2EFF41DB0029F805 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 15CEF849B61A620CFB2DC5F1 /* 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/ShareExtensionDebug.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
CUSTOM_GROUP_ID = group.eu.twonly.shareIntent;
|
||||
DEVELOPMENT_TEAM = CN332ZUGRP;
|
||||
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 = 26.1;
|
||||
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 = eu.twonly.ShareExtension;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
D25D4D7C2EFF41DB0029F805 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = A22BD564F16069E5FCB60767 /* 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_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
CUSTOM_GROUP_ID = group.eu.twonly.shareIntent;
|
||||
DEVELOPMENT_TEAM = CN332ZUGRP;
|
||||
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 = 26.1;
|
||||
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 = eu.twonly.ShareExtension;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
D25D4D7D2EFF41DB0029F805 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 39FB86A38393489D58A01B0B /* 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_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
CUSTOM_GROUP_ID = group.eu.twonly.shareIntent;
|
||||
DEVELOPMENT_TEAM = CN332ZUGRP;
|
||||
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 = 26.1;
|
||||
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 = eu.twonly.ShareExtension;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
|
|
@ -1047,6 +1290,16 @@
|
|||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
D25D4D7F2EFF41DB0029F805 /* Build configuration list for PBXNativeTarget "ShareExtension" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
D25D4D7B2EFF41DB0029F805 /* Debug */,
|
||||
D25D4D7C2EFF41DB0029F805 /* Release */,
|
||||
D25D4D7D2EFF41DB0029F805 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import Flutter
|
|||
import Foundation
|
||||
import UIKit
|
||||
import UserNotifications
|
||||
import flutter_sharing_intent
|
||||
|
||||
@main
|
||||
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
|
||||
|
|
@ -14,6 +15,17 @@ import UserNotifications
|
|||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
|
||||
override func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
|
||||
|
||||
let sharingIntent = SwiftFlutterSharingIntentPlugin.instance
|
||||
if sharingIntent.hasSameSchemePrefix(url: url) {
|
||||
return sharingIntent.application(app, open: url, options: options)
|
||||
}
|
||||
|
||||
// Proceed url handling for other Flutter libraries like app_links
|
||||
return super.application(app, open: url, options:options)
|
||||
}
|
||||
|
||||
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
|
||||
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,9 +87,21 @@
|
|||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<!--Disable Firebase Telemetry-->
|
||||
<key>firebase_performance_collection_deactivated</key>
|
||||
<true/>
|
||||
<!--...-->
|
||||
|
||||
<key>AppGroupId</key>
|
||||
<string>$(CUSTOM_GROUP_ID)</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>SharingMedia-$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
20
ios/Runner/RunnerDebug.entitlements
Normal file
20
ios/Runner/RunnerDebug.entitlements
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?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>aps-environment</key>
|
||||
<string>development</string>
|
||||
<key>com.apple.developer.associated-domains</key>
|
||||
<array>
|
||||
<string>applinks:me.twonly.eu</string>
|
||||
</array>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.eu.twonly.shareIntent</string>
|
||||
</array>
|
||||
<key>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>$(AppIdentifierPrefix)eu.twonly.shared</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
24
ios/ShareExtension/Base.lproj/MainInterface.storyboard
Normal file
24
ios/ShareExtension/Base.lproj/MainInterface.storyboard
Normal file
|
|
@ -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>
|
||||
553
ios/ShareExtension/FSIShareViewController.swift
Normal file
553
ios/ShareExtension/FSIShareViewController.swift
Normal file
|
|
@ -0,0 +1,553 @@
|
|||
// SOURCE: https://github.com/bhagat-techind/flutter_sharing_intent/blob/main/example/ios/Share%20Extension/FSIShareViewController.swift
|
||||
|
||||
// FSIShareViewController.swift
|
||||
// Merged, optimized controller: uses RSI architecture with all FSI features preserved
|
||||
// Uses model name `SharingFile` (same fields as SharedMediaFile) where `value` = path
|
||||
|
||||
import AVFoundation
|
||||
import MobileCoreServices
|
||||
import Social
|
||||
import UIKit
|
||||
import UniformTypeIdentifiers
|
||||
|
||||
public let kSchemePrefix = "SharingMedia"
|
||||
public let kUserDefaultsKey = "SharingKey"
|
||||
public let kUserDefaultsMessageKey = "SharingMessageKey"
|
||||
public let kAppGroupIdKey = "AppGroupId"
|
||||
public let kAppChannel = "flutter_sharing_intent"
|
||||
|
||||
@available(swift, introduced: 5.0)
|
||||
open class FSIShareViewController: SLComposeServiceViewController {
|
||||
// MARK: - Config
|
||||
private(set) var hostAppBundleIdentifier: String = ""
|
||||
private(set) var appGroupId: String = ""
|
||||
|
||||
// Results
|
||||
private var sharedMedia: [SharingFile] = []
|
||||
|
||||
// Debug
|
||||
private let debugLogs = false
|
||||
|
||||
// MARK: - Lifecycle
|
||||
open override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
loadIds()
|
||||
}
|
||||
|
||||
open override func isContentValid() -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
open override func didSelectPost() {
|
||||
if self.sharedMedia.isEmpty {
|
||||
if let text = self.contentText, !text.isEmpty {
|
||||
self.sharedMedia.append(
|
||||
SharingFile(value: text, thumbnail: nil, duration: nil, type: .text)
|
||||
)
|
||||
self.saveAndRedirect(message: text)
|
||||
return
|
||||
}
|
||||
self.completeAndExit()
|
||||
} else {
|
||||
self.saveAndRedirect()
|
||||
}
|
||||
}
|
||||
|
||||
open override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
// Process attachments automatically on appear like original FSI
|
||||
processAttachments()
|
||||
}
|
||||
|
||||
// MARK: - Load Ids
|
||||
private func loadIds() {
|
||||
let shareExtId = Bundle.main.bundleIdentifier ?? ""
|
||||
if let idx = shareExtId.lastIndex(of: ".") {
|
||||
hostAppBundleIdentifier = String(shareExtId[..<idx])
|
||||
} else {
|
||||
hostAppBundleIdentifier = shareExtId
|
||||
}
|
||||
let custom = Bundle.main.object(forInfoDictionaryKey: kAppGroupIdKey) as? String
|
||||
appGroupId = custom ?? "group.\(hostAppBundleIdentifier)"
|
||||
log("loaded host=\(hostAppBundleIdentifier) group=\(appGroupId)")
|
||||
}
|
||||
|
||||
// MARK: - Attachment processing (clean RSI style, preserve FSI features)
|
||||
private func processAttachments() {
|
||||
guard let content = extensionContext?.inputItems.first as? NSExtensionItem else {
|
||||
completeAndExit()
|
||||
return
|
||||
}
|
||||
|
||||
guard let attachments = content.attachments, !attachments.isEmpty else {
|
||||
completeAndExit()
|
||||
return
|
||||
}
|
||||
|
||||
// Use DispatchGroup to wait for async loads
|
||||
let group = DispatchGroup()
|
||||
for (index, provider) in attachments.enumerated() {
|
||||
group.enter()
|
||||
// Try all SharedMediaType options similar to RSI but preserve explicit FSI order
|
||||
if provider.isImage {
|
||||
provider.loadItem(forTypeIdentifier: UType.image, options: nil) { [weak self] data, error in
|
||||
defer { group.leave() }
|
||||
guard let self = self, error == nil else { self?.dismissWithError(); return }
|
||||
self.handleImageItem(data: data, index: index, total: attachments.count)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if provider.isMovie {
|
||||
provider.loadItem(forTypeIdentifier: UType.movie, options: nil) { [weak self] data, error in
|
||||
defer { group.leave() }
|
||||
guard let self = self, error == nil else { self?.dismissWithError(); return }
|
||||
self.handleVideoItem(data: data, index: index, total: attachments.count)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if provider.isFile {
|
||||
provider.loadItem(forTypeIdentifier: UType.fileURL, options: nil) { [weak self] data, error in
|
||||
defer { group.leave() }
|
||||
guard let self = self, error == nil else { self?.dismissWithError(); return }
|
||||
self.handleFileItem(data: data, index: index, total: attachments.count)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if provider.isURL {
|
||||
provider.loadItem(forTypeIdentifier: UType.url, options: nil) { [weak self] data, error in
|
||||
defer { group.leave() }
|
||||
guard let self = self, error == nil else { self?.dismissWithError(); return }
|
||||
self.handleUrlItem(data: data, index: index, total: attachments.count)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if provider.isText {
|
||||
let id = provider.hasItemConformingToTypeIdentifier(UType.plainText)
|
||||
? UType.plainText
|
||||
: UType.text
|
||||
provider.loadItem(forTypeIdentifier: id, options: nil) { [weak self] data, error in
|
||||
defer { group.leave() }
|
||||
guard let self = self, error == nil else { self?.dismissWithError(); return }
|
||||
self.handleTextItem(data: data, index: index, total: attachments.count)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if provider.isData {
|
||||
provider.loadItem(forTypeIdentifier: UType.data, options: nil) { [weak self] data, error in
|
||||
defer { group.leave() }
|
||||
guard let self = self, error == nil else { self?.dismissWithError(); return }
|
||||
self.handleFileItem(data: data, index: index, total: attachments.count)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if provider.isItem {
|
||||
provider.loadItem(forTypeIdentifier: UType.item, options: nil) { [weak self] data, error in
|
||||
defer { group.leave() }
|
||||
guard let self = self, error == nil else { self?.dismissWithError(); return }
|
||||
self.handleFileItem(data: data, index: index, total: attachments.count)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
log("Unknown provider type: \(provider.registeredTypeIdentifiers)")
|
||||
|
||||
// Unknown type: just leave
|
||||
group.leave()
|
||||
}
|
||||
|
||||
group.notify(queue: .main) { [weak self] in
|
||||
guard let self = self else { return }
|
||||
// if we have media -> media, else fallback to complete
|
||||
if !self.sharedMedia.isEmpty {
|
||||
self.saveAndRedirect()
|
||||
} else {
|
||||
print("FSIShare: No shared media → stopping.")
|
||||
self.completeAndExit()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Individual handlers (preserve FSI behavior)
|
||||
private func handleTextItem(data: NSSecureCoding?, index: Int, total: Int) {
|
||||
if let s = data as? String {
|
||||
sharedMedia.append(SharingFile(value: s, thumbnail: nil, duration: nil, type: .text))
|
||||
} else if let url = data as? URL {
|
||||
sharedMedia.append(SharingFile(value: url.absoluteString, thumbnail: nil, duration: nil, type: .url))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private func handleUrlItem(data: NSSecureCoding?, index: Int, total: Int) {
|
||||
if let url = data as? URL {
|
||||
sharedMedia.append(SharingFile(value: url.absoluteString, thumbnail: nil, duration: nil, type: .url))
|
||||
} else if let s = data as? String {
|
||||
sharedMedia.append(SharingFile(value: s, thumbnail: nil, duration: nil, type: .text))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private func handleImageItem(data: NSSecureCoding?, index: Int, total: Int) {
|
||||
// data can be URL, UIImage, or Data
|
||||
if let url = data as? URL {
|
||||
let filename = getFileName(from: url, type: .image)
|
||||
if let dst = containerURL()?.appendingPathComponent(filename) {
|
||||
if copyFile(at: url, to: dst) {
|
||||
sharedMedia.append(SharingFile(value: dst.absoluteString, mimeType: url.mimeType(), thumbnail: nil, duration: nil, type: .image))
|
||||
}
|
||||
}
|
||||
} else if let img = data as? UIImage {
|
||||
if let saved = writeTempImage(img) {
|
||||
sharedMedia.append(saved)
|
||||
}
|
||||
} else if let raw = data as? Data, let img = UIImage(data: raw) {
|
||||
if let saved = writeTempImage(img) {
|
||||
sharedMedia.append(saved)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private func handleVideoItem(data: NSSecureCoding?, index: Int, total: Int) {
|
||||
if let url = data as? URL {
|
||||
let filename = getFileName(from: url, type: .video)
|
||||
if let dst = containerURL()?.appendingPathComponent(filename) {
|
||||
if copyFile(at: url, to: dst) {
|
||||
if let m = getSharedMediaFile(forVideo: dst) {
|
||||
sharedMedia.append(m)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private func handleFileItem(data: NSSecureCoding?, index: Int, total: Int) {
|
||||
if let url = data as? URL {
|
||||
let filename = getFileName(from: url, type: .file)
|
||||
if let dst = containerURL()?.appendingPathComponent(filename) {
|
||||
if copyFile(at: url, to: dst) {
|
||||
sharedMedia.append(SharingFile(value: dst.absoluteString, mimeType: url.mimeType(), thumbnail: nil, duration: nil, type: .file))
|
||||
}
|
||||
}
|
||||
}
|
||||
else if let raw = data as? Data {
|
||||
let filename = "File_\(UUID().uuidString)"
|
||||
if let dst = containerURL()?.appendingPathComponent(filename) {
|
||||
do {
|
||||
try raw.write(to: dst)
|
||||
sharedMedia.append(SharingFile(value: dst.absoluteString, mimeType: "application/octet-stream", thumbnail: nil, duration: nil, type: .file))
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Helpers: write temp image
|
||||
private func writeTempImage(_ image: UIImage) -> SharingFile? {
|
||||
guard let container = containerURL() else { return nil }
|
||||
let tempName = "TempImage_\(UUID().uuidString).png"
|
||||
let dst = container.appendingPathComponent(tempName)
|
||||
do {
|
||||
if let d = image.pngData() {
|
||||
try d.write(to: dst)
|
||||
let decoded = dst.absoluteString.removingPercentEncoding ?? dst.absoluteString
|
||||
return SharingFile(value: decoded, mimeType: "image/png", thumbnail: nil, duration: nil, type: .image)
|
||||
}
|
||||
} catch {
|
||||
log("writeTempImage error: \(error)")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
private func saveAndRedirect(message: String? = nil) {
|
||||
let ud = UserDefaults(suiteName: appGroupId)
|
||||
if !sharedMedia.isEmpty {
|
||||
if let data = try? JSONEncoder().encode(sharedMedia) {
|
||||
ud?.set(data, forKey: kUserDefaultsKey)
|
||||
}
|
||||
}
|
||||
ud?.set(message, forKey: kUserDefaultsMessageKey)
|
||||
ud?.synchronize()
|
||||
redirectToHostApp()
|
||||
}
|
||||
|
||||
|
||||
private func redirectToHostApp() {
|
||||
// kept for compatibility (RSI style)
|
||||
loadIds()
|
||||
// let raw = "\(kSchemePrefix)-\(hostAppBundleIdentifier):share"
|
||||
let raw = "\(kSchemePrefix)-\(hostAppBundleIdentifier)://dataUrl=\(kUserDefaultsKey)"
|
||||
guard let url = URL(string: raw.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? raw) else { completeAndExit(); return }
|
||||
|
||||
var responder: UIResponder? = self
|
||||
if #available(iOS 18.0, *) {
|
||||
while responder != nil {
|
||||
if let app = responder as? UIApplication { app.open(url, options: [:], completionHandler: nil) }
|
||||
responder = responder?.next
|
||||
}
|
||||
} else {
|
||||
let sel = sel_registerName("openURL:")
|
||||
while responder != nil {
|
||||
if responder?.responds(to: sel) ?? false { _ = responder?.perform(sel, with: url) }
|
||||
responder = responder?.next
|
||||
}
|
||||
}
|
||||
extensionContext?.completeRequest(returningItems: [], completionHandler: nil)
|
||||
}
|
||||
|
||||
// MARK: - File / thumbnail / metadata helpers
|
||||
func getExtension(from url: URL, type: SharingFileType) -> String {
|
||||
let parts = url.lastPathComponent.components(separatedBy: ".")
|
||||
var ex: String? = nil
|
||||
if parts.count > 1 { ex = parts.last }
|
||||
if ex == nil {
|
||||
switch type {
|
||||
case .image: ex = "png"
|
||||
case .video: ex = "mp4"
|
||||
case .file: ex = "txt"
|
||||
case .text: ex = "txt"
|
||||
case .url: ex = "txt"
|
||||
}
|
||||
}
|
||||
return ex ?? "bin"
|
||||
}
|
||||
|
||||
func getFileName(from url: URL, type: SharingFileType) -> String {
|
||||
var name = url.lastPathComponent
|
||||
if name.isEmpty { name = UUID().uuidString + "." + getExtension(from: url, type: type) }
|
||||
return name
|
||||
}
|
||||
|
||||
func copyFile(at srcURL: URL, to dstURL: URL) -> Bool {
|
||||
do {
|
||||
if FileManager.default.fileExists(atPath: dstURL.path) { try FileManager.default.removeItem(at: dstURL) }
|
||||
try FileManager.default.copyItem(at: srcURL, to: dstURL)
|
||||
return true
|
||||
} catch {
|
||||
log("copyFile error: \(error)")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private func getSharedMediaFile(forVideo: URL) -> SharingFile? {
|
||||
let asset = AVAsset(url: forVideo)
|
||||
let duration = (CMTimeGetSeconds(asset.duration) * 1000).rounded()
|
||||
let thumbnailPath = getThumbnailPath(for: forVideo)
|
||||
|
||||
if FileManager.default.fileExists(atPath: thumbnailPath.path) {
|
||||
return SharingFile(value: forVideo.absoluteString, mimeType: forVideo.mimeType(), thumbnail: thumbnailPath.absoluteString, duration: Int(duration), type: .video)
|
||||
}
|
||||
|
||||
let gen = AVAssetImageGenerator(asset: asset)
|
||||
gen.appliesPreferredTrackTransform = true
|
||||
gen.maximumSize = CGSize(width: 360, height: 360)
|
||||
|
||||
// Use first second or zero
|
||||
let time = CMTime(seconds: min(1.0, CMTimeGetSeconds(asset.duration)), preferredTimescale: 600)
|
||||
do {
|
||||
let cg = try gen.copyCGImage(at: time, actualTime: nil)
|
||||
if let data = UIImage(cgImage: cg).jpegData(compressionQuality: 0.8) {
|
||||
try data.write(to: thumbnailPath)
|
||||
return SharingFile(value: forVideo.absoluteString, mimeType: forVideo.mimeType(), thumbnail: thumbnailPath.absoluteString, duration: Int(duration), type: .video)
|
||||
}
|
||||
} catch {
|
||||
log("getSharedMediaFile thumbnail error: \(error)")
|
||||
}
|
||||
|
||||
// fallback
|
||||
return SharingFile(value: forVideo.absoluteString, mimeType: forVideo.mimeType(), thumbnail: nil, duration: Int(duration), type: .video)
|
||||
}
|
||||
|
||||
private func getThumbnailPath(for url: URL) -> URL {
|
||||
guard let container = containerURL() else { fatalError("App group not configured or missing") }
|
||||
let fileName = Data(url.lastPathComponent.utf8).base64EncodedString().replacingOccurrences(of: "=", with: "")
|
||||
return container.appendingPathComponent("\(fileName).jpg")
|
||||
}
|
||||
|
||||
private func containerURL() -> URL? {
|
||||
FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupId)
|
||||
}
|
||||
|
||||
private func completeAndExit() {
|
||||
extensionContext?.completeRequest(returningItems: [], completionHandler: nil)
|
||||
}
|
||||
|
||||
private func dismissWithError() {
|
||||
log("[ERROR] Error loading data!")
|
||||
let alert = UIAlertController(title: "Error", message: "Error loading data", preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .cancel) { _ in self.dismiss(animated: true, completion: nil) })
|
||||
present(alert, animated: true, completion: nil)
|
||||
extensionContext?.completeRequest(returningItems: [], completionHandler: nil)
|
||||
}
|
||||
|
||||
private func writeTempFile(_ image: UIImage, to dstURL: URL) -> Bool {
|
||||
do {
|
||||
if FileManager.default.fileExists(atPath: dstURL.path) { try FileManager.default.removeItem(at: dstURL) }
|
||||
let pngData = image.pngData()
|
||||
try pngData?.write(to: dstURL)
|
||||
return true
|
||||
} catch (let error) {
|
||||
log("writeTempFile error: \(error)")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private func saveToUserDefaults(data: [SharingFile]) {
|
||||
let ud = UserDefaults(suiteName: appGroupId)
|
||||
if let enc = try? JSONEncoder().encode(data) { ud?.set(enc, forKey: kUserDefaultsKey); ud?.synchronize() }
|
||||
}
|
||||
|
||||
// MARK: - Logging
|
||||
private func log(_ s: String) { if debugLogs { print("[FSIShareVC] \(s)") } }
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Extensions
|
||||
extension URL {
|
||||
func mimeType() -> String {
|
||||
if #available(iOS 14.0, *) {
|
||||
if let ut = UTType(filenameExtension: self.pathExtension), let m = ut.preferredMIMEType { return m }
|
||||
} else {
|
||||
if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, self.pathExtension as NSString, nil)?.takeRetainedValue() {
|
||||
if let mimetype = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() { return mimetype as String }
|
||||
}
|
||||
}
|
||||
return "application/octet-stream"
|
||||
}
|
||||
}
|
||||
|
||||
extension NSItemProvider {
|
||||
var isImage: Bool { return hasItemConformingToTypeIdentifier(UType.image) }
|
||||
var isMovie: Bool { return hasItemConformingToTypeIdentifier(UType.movie) }
|
||||
var isText: Bool {
|
||||
hasItemConformingToTypeIdentifier(UType.plainText) || hasItemConformingToTypeIdentifier(UType.text)
|
||||
}
|
||||
var isURL: Bool { return hasItemConformingToTypeIdentifier(UType.url) }
|
||||
var isFile: Bool { return hasItemConformingToTypeIdentifier(UType.fileURL) }
|
||||
var isData:Bool { return hasItemConformingToTypeIdentifier(UType.data) }
|
||||
var isItem: Bool { hasItemConformingToTypeIdentifier(UType.item) }
|
||||
|
||||
}
|
||||
|
||||
extension Array {
|
||||
subscript(safe index: UInt) -> Element? { return Int(index) < count ? self[Int(index)] : nil }
|
||||
}
|
||||
|
||||
|
||||
class SharingFile: Codable {
|
||||
var value: String
|
||||
var mimeType: String?
|
||||
var thumbnail: String?; // video thumbnail
|
||||
var duration: Int?; // video duration in milliseconds
|
||||
var type: SharingFileType;
|
||||
var message: String? // post message
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case value
|
||||
case mimeType
|
||||
case thumbnail
|
||||
case duration
|
||||
case type
|
||||
case message
|
||||
}
|
||||
|
||||
init(value: String, mimeType: String? = nil, thumbnail: String?, duration: Int?,
|
||||
type: SharingFileType, message: String?=nil) {
|
||||
self.value = value
|
||||
self.mimeType = mimeType
|
||||
self.thumbnail = thumbnail
|
||||
self.duration = duration
|
||||
self.type = type
|
||||
self.message = message
|
||||
}
|
||||
|
||||
// Debug method to print out SharedMediaFile details in the console
|
||||
func toString() {
|
||||
print("[SharingFile] \n\tvalue: \(self.value)\n\tthumbnail: \(self.thumbnail ?? "--" )\n\tduration: \(self.duration ?? 0)\n\ttype: \(self.type)\n\tmimeType: \(String(describing: self.mimeType))\n\tmessage: \(String(describing: self.message))")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum SharingFileType: Int, Codable {
|
||||
case text
|
||||
case url
|
||||
case image
|
||||
case video
|
||||
case file
|
||||
}
|
||||
|
||||
// Unified UTType → works on iOS 11–18
|
||||
enum UType {
|
||||
static var image: String {
|
||||
if #available(iOS 14.0, *) {
|
||||
return UTType.image.identifier
|
||||
} else {
|
||||
return kUTTypeImage as String // old API
|
||||
}
|
||||
}
|
||||
|
||||
static var movie: String {
|
||||
if #available(iOS 14.0, *) {
|
||||
return UTType.movie.identifier
|
||||
} else {
|
||||
return kUTTypeMovie as String
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static var url: String {
|
||||
if #available(iOS 14.0, *) {
|
||||
return UTType.url.identifier
|
||||
} else {
|
||||
return kUTTypeURL as String
|
||||
}
|
||||
}
|
||||
|
||||
static var fileURL: String {
|
||||
if #available(iOS 14.0, *) {
|
||||
return UTType.fileURL.identifier
|
||||
} else {
|
||||
return kUTTypeFileURL as String
|
||||
}
|
||||
}
|
||||
|
||||
static var text: String {
|
||||
if #available(iOS 14.0, *) {
|
||||
return UTType.text.identifier
|
||||
} else {
|
||||
return kUTTypeText as String
|
||||
}
|
||||
}
|
||||
|
||||
static var plainText: String {
|
||||
if #available(iOS 14.0, *) {
|
||||
return UTType.plainText.identifier
|
||||
} else {
|
||||
return kUTTypePlainText as String
|
||||
}
|
||||
}
|
||||
|
||||
static var data: String {
|
||||
if #available(iOS 14.0, *) {
|
||||
return UTType.data.identifier
|
||||
} else {
|
||||
return kUTTypeData as String
|
||||
}
|
||||
}
|
||||
|
||||
static var item: String {
|
||||
if #available(iOS 14.0, *) {
|
||||
return UTType.item.identifier
|
||||
} else {
|
||||
return kUTTypeItem as String
|
||||
}
|
||||
}
|
||||
}
|
||||
35
ios/ShareExtension/Info.plist
Normal file
35
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>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionMainStoryboard</key>
|
||||
<string>MainInterface</string>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.share-services</string>
|
||||
<key>NSExtensionAttributes</key>
|
||||
<dict>
|
||||
<key>PHSupportedMediaTypes</key>
|
||||
<array>
|
||||
<string>Video</string>
|
||||
<string>Image</string>
|
||||
</array>
|
||||
|
||||
<key>NSExtensionActivationRule</key>
|
||||
<dict>
|
||||
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
|
||||
<integer>1</integer>
|
||||
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
|
||||
<integer>1</integer>
|
||||
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
10
ios/ShareExtension/ShareExtensionDebug.entitlements
Normal file
10
ios/ShareExtension/ShareExtensionDebug.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.eu.twonly.shareIntent</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
3
ios/ShareExtension/ShareViewController.swift
Normal file
3
ios/ShareExtension/ShareViewController.swift
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
class ShareViewController: FSIShareViewController {
|
||||
|
||||
}
|
||||
180
lib/src/services/intent/links.intent.dart
Normal file
180
lib/src/services/intent/links.intent.dart
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:drift/drift.dart' show Value;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_sharing_intent/model/sharing_file.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
||||
import 'package:twonly/src/database/twonly.db.dart';
|
||||
import 'package:twonly/src/services/api/mediafiles/upload.service.dart';
|
||||
import 'package:twonly/src/services/signal/session.signal.dart';
|
||||
import 'package:twonly/src/utils/log.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/views/camera/share_image_editor_view.dart';
|
||||
import 'package:twonly/src/views/chats/add_new_user.view.dart';
|
||||
import 'package:twonly/src/views/components/alert_dialog.dart';
|
||||
import 'package:twonly/src/views/contact/contact.view.dart';
|
||||
import 'package:twonly/src/views/public_profile.view.dart';
|
||||
|
||||
Future<void> handleIntentUrl(BuildContext context, Uri uri) async {
|
||||
if (!uri.scheme.startsWith('http')) return;
|
||||
if (uri.host != 'me.twonly.eu') return;
|
||||
if (uri.hasEmptyPath) return;
|
||||
|
||||
final publicKey = uri.hasFragment ? uri.fragment : null;
|
||||
final userPaths = uri.path.split('/');
|
||||
if (userPaths.length != 2) return;
|
||||
final username = userPaths[1];
|
||||
|
||||
if (!context.mounted) return;
|
||||
|
||||
if (username == gUser.username) {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return const PublicProfileView();
|
||||
},
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.info(
|
||||
'Opened via deep link!: username = $username public_key = ${uri.fragment}',
|
||||
);
|
||||
final contacts = await twonlyDB.contactsDao.getContactsByUsername(username);
|
||||
if (contacts.isEmpty) {
|
||||
if (!context.mounted) return;
|
||||
Uint8List? publicKeyBytes;
|
||||
if (publicKey != null) {
|
||||
publicKeyBytes = base64Url.decode(publicKey);
|
||||
}
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return AddNewUserView(
|
||||
username: username,
|
||||
publicKey: publicKeyBytes,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
} else if (publicKey != null) {
|
||||
try {
|
||||
final contact = contacts.first;
|
||||
final storedPublicKey = await getPublicKeyFromContact(contact.userId);
|
||||
final receivedPublicKey = base64Url.decode(publicKey);
|
||||
if (storedPublicKey == null ||
|
||||
receivedPublicKey.isEmpty ||
|
||||
!context.mounted) {
|
||||
return;
|
||||
}
|
||||
if (storedPublicKey.equals(receivedPublicKey)) {
|
||||
if (!contact.verified) {
|
||||
final markAsVerified = await showAlertDialog(
|
||||
context,
|
||||
context.lang.linkFromUsername(contact.username),
|
||||
context.lang.linkFromUsernameLong,
|
||||
customOk: context.lang.gotLinkFromFriend,
|
||||
);
|
||||
if (markAsVerified) {
|
||||
await twonlyDB.contactsDao.updateContact(
|
||||
contact.userId,
|
||||
const ContactsCompanion(
|
||||
verified: Value(true),
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return ContactView(contact.userId);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
await showAlertDialog(
|
||||
context,
|
||||
context.lang.couldNotVerifyUsername(contact.username),
|
||||
context.lang.linkPubkeyDoesNotMatch,
|
||||
customCancel: '',
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
Log.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> handleIntentMediaFile(
|
||||
BuildContext context,
|
||||
String filePath,
|
||||
MediaType type,
|
||||
) async {
|
||||
final file = File(filePath);
|
||||
if (!file.existsSync()) {
|
||||
Log.error('The shared intent file does not exits.');
|
||||
return;
|
||||
}
|
||||
|
||||
final newMediaService = await initializeMediaUpload(
|
||||
type,
|
||||
gUser.defaultShowTime,
|
||||
);
|
||||
if (newMediaService == null) {
|
||||
Log.error('Could not create new media file for intent shared file');
|
||||
return;
|
||||
}
|
||||
|
||||
file.copySync(newMediaService.originalPath.path);
|
||||
if (!context.mounted) return;
|
||||
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ShareImageEditorView(
|
||||
mediaFileService: newMediaService,
|
||||
sharedFromGallery: true,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> handleIntentSharedFile(
|
||||
BuildContext context,
|
||||
List<SharedFile> files,
|
||||
) async {
|
||||
for (final file in files) {
|
||||
if (file.value == null) {
|
||||
Log.error(
|
||||
'Got shared media, but value is empty: getMediaStream ${file.mimeType}',
|
||||
);
|
||||
continue;
|
||||
}
|
||||
Log.info('got file via intent ${file.type} ${file.value}');
|
||||
|
||||
switch (file.type) {
|
||||
case SharedMediaType.URL:
|
||||
await handleIntentUrl(context, Uri.parse(file.value!));
|
||||
case SharedMediaType.IMAGE:
|
||||
var type = MediaType.image;
|
||||
if (file.value!.endsWith('.gif')) {
|
||||
type = MediaType.gif;
|
||||
}
|
||||
await handleIntentMediaFile(context, file.value!, type);
|
||||
case SharedMediaType.VIDEO:
|
||||
await handleIntentMediaFile(context, file.value!, MediaType.video);
|
||||
// ignore: no_default_cases
|
||||
default:
|
||||
}
|
||||
break; // only handle one file...
|
||||
}
|
||||
}
|
||||
|
|
@ -227,7 +227,8 @@ class MainCameraController {
|
|||
content: Text(
|
||||
globalRootScaffoldMessengerKey.currentContext?.lang
|
||||
.verifiedPublicKey(
|
||||
getContactDisplayName(contact)) ??
|
||||
getContactDisplayName(contact),
|
||||
) ??
|
||||
'',
|
||||
),
|
||||
duration: const Duration(seconds: 6),
|
||||
|
|
|
|||
|
|
@ -1,29 +1,22 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
import 'package:app_links/app_links.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:drift/drift.dart' show Value;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:flutter_sharing_intent/flutter_sharing_intent.dart';
|
||||
import 'package:flutter_sharing_intent/model/sharing_file.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/src/database/twonly.db.dart';
|
||||
import 'package:twonly/src/services/intent/links.intent.dart';
|
||||
import 'package:twonly/src/services/mediafiles/mediafile.service.dart';
|
||||
import 'package:twonly/src/services/notifications/setup.notifications.dart';
|
||||
import 'package:twonly/src/services/signal/session.signal.dart';
|
||||
import 'package:twonly/src/utils/log.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/views/camera/camera_preview_components/camera_preview.dart';
|
||||
import 'package:twonly/src/views/camera/camera_preview_components/camera_preview_controller_view.dart';
|
||||
import 'package:twonly/src/views/camera/camera_preview_components/main_camera_controller.dart';
|
||||
import 'package:twonly/src/views/camera/share_image_editor_view.dart';
|
||||
import 'package:twonly/src/views/chats/add_new_user.view.dart';
|
||||
import 'package:twonly/src/views/chats/chat_list.view.dart';
|
||||
import 'package:twonly/src/views/components/alert_dialog.dart';
|
||||
import 'package:twonly/src/views/contact/contact.view.dart';
|
||||
import 'package:twonly/src/views/memories/memories.view.dart';
|
||||
import 'package:twonly/src/views/public_profile.view.dart';
|
||||
|
||||
void Function(int) globalUpdateOfHomeViewPageIndex = (a) {};
|
||||
|
||||
|
|
@ -61,6 +54,7 @@ class HomeViewState extends State<HomeView> {
|
|||
final MainCameraController _mainCameraController = MainCameraController();
|
||||
|
||||
final PageController homeViewPageController = PageController(initialPage: 1);
|
||||
late StreamSubscription<List<SharedFile>> _intentStreamSub;
|
||||
late StreamSubscription<Uri> _deepLinkSub;
|
||||
|
||||
double buttonDiameter = 100;
|
||||
|
|
@ -121,99 +115,21 @@ class HomeViewState extends State<HomeView> {
|
|||
|
||||
// Subscribe to all events (initial link and further)
|
||||
_deepLinkSub = AppLinks().uriLinkStream.listen((uri) async {
|
||||
if (!uri.scheme.startsWith('http')) return;
|
||||
if (uri.host != 'me.twonly.eu') return;
|
||||
if (uri.hasEmptyPath) return;
|
||||
if (mounted) await handleIntentUrl(context, uri);
|
||||
});
|
||||
|
||||
final publicKey = uri.hasFragment ? uri.fragment : null;
|
||||
final userPaths = uri.path.split('/');
|
||||
if (userPaths.length != 2) return;
|
||||
final username = userPaths[1];
|
||||
_intentStreamSub = FlutterSharingIntent.instance.getMediaStream().listen(
|
||||
(f) {
|
||||
if (mounted) handleIntentSharedFile(context, f);
|
||||
},
|
||||
// ignore: inference_failure_on_untyped_parameter
|
||||
onError: (err) {
|
||||
Log.error('getIntentDataStream error: $err');
|
||||
},
|
||||
);
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
if (username == gUser.username) {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return const PublicProfileView();
|
||||
},
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.info(
|
||||
'Opened via deep link!: username = $username public_key = ${uri.fragment}',
|
||||
);
|
||||
final contacts =
|
||||
await twonlyDB.contactsDao.getContactsByUsername(username);
|
||||
if (contacts.isEmpty) {
|
||||
if (!mounted) return;
|
||||
Uint8List? publicKeyBytes;
|
||||
if (publicKey != null) {
|
||||
publicKeyBytes = base64Url.decode(publicKey);
|
||||
}
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return AddNewUserView(
|
||||
username: username,
|
||||
publicKey: publicKeyBytes,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
} else if (publicKey != null) {
|
||||
try {
|
||||
final contact = contacts.first;
|
||||
final storedPublicKey = await getPublicKeyFromContact(contact.userId);
|
||||
final receivedPublicKey = base64Url.decode(publicKey);
|
||||
if (storedPublicKey == null ||
|
||||
receivedPublicKey.isEmpty ||
|
||||
!mounted) {
|
||||
return;
|
||||
}
|
||||
if (storedPublicKey.equals(receivedPublicKey)) {
|
||||
if (!contact.verified) {
|
||||
final markAsVerified = await showAlertDialog(
|
||||
context,
|
||||
context.lang.linkFromUsername(contact.username),
|
||||
context.lang.linkFromUsernameLong,
|
||||
customOk: context.lang.gotLinkFromFriend,
|
||||
);
|
||||
if (markAsVerified) {
|
||||
await twonlyDB.contactsDao.updateContact(
|
||||
contact.userId,
|
||||
const ContactsCompanion(
|
||||
verified: Value(true),
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return ContactView(contact.userId);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
await showAlertDialog(
|
||||
context,
|
||||
context.lang.couldNotVerifyUsername(contact.username),
|
||||
context.lang.linkPubkeyDoesNotMatch,
|
||||
customCancel: '',
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
Log.warn(e);
|
||||
}
|
||||
}
|
||||
FlutterSharingIntent.instance.getInitialSharing().then((f) {
|
||||
if (mounted) handleIntentSharedFile(context, f);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -222,6 +138,7 @@ class HomeViewState extends State<HomeView> {
|
|||
unawaited(selectNotificationStream.close());
|
||||
disableCameraTimer?.cancel();
|
||||
_mainCameraController.closeCamera();
|
||||
_intentStreamSub.cancel();
|
||||
_deepLinkSub.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
|
|
|||
52
pubspec.lock
52
pubspec.lock
|
|
@ -742,29 +742,27 @@ packages:
|
|||
flutter_secure_storage:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: flutter_secure_storage
|
||||
ref: a06ead81809c900e7fc421a30db0adf3b5919139
|
||||
resolved-ref: a06ead81809c900e7fc421a30db0adf3b5919139
|
||||
url: "https://github.com/juliansteenbakker/flutter_secure_storage.git"
|
||||
source: git
|
||||
version: "10.0.0-beta.4"
|
||||
name: flutter_secure_storage
|
||||
sha256: da922f2aab2d733db7e011a6bcc4a825b844892d4edd6df83ff156b09a9b2e40
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.0"
|
||||
flutter_secure_storage_darwin:
|
||||
dependency: "direct overridden"
|
||||
dependency: transitive
|
||||
description:
|
||||
path: flutter_secure_storage_darwin
|
||||
ref: a06ead81809c900e7fc421a30db0adf3b5919139
|
||||
resolved-ref: a06ead81809c900e7fc421a30db0adf3b5919139
|
||||
url: "https://github.com/juliansteenbakker/flutter_secure_storage.git"
|
||||
source: git
|
||||
version: "0.1.0"
|
||||
name: flutter_secure_storage_darwin
|
||||
sha256: "8878c25136a79def1668c75985e8e193d9d7d095453ec28730da0315dc69aee3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.0"
|
||||
flutter_secure_storage_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_linux
|
||||
sha256: "9b4b73127e857cd3117d43a70fa3dddadb6e0b253be62e6a6ab85caa0742182c"
|
||||
sha256: "2b5c76dce569ab752d55a1cee6a2242bcc11fdba927078fb88c503f150767cda"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "3.0.0"
|
||||
flutter_secure_storage_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -777,18 +775,25 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_web
|
||||
sha256: "4c3f233e739545c6cb09286eeec1cc4744138372b985113acc904f7263bef517"
|
||||
sha256: "6a1137df62b84b54261dca582c1c09ea72f4f9a4b2fcee21b025964132d5d0c3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
version: "2.1.0"
|
||||
flutter_secure_storage_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_windows
|
||||
sha256: ff32af20f70a8d0e59b2938fc92de35b54a74671041c814275afd80e27df9f21
|
||||
sha256: "3b7c8e068875dfd46719ff57c90d8c459c87f2302ed6b00ff006b3c9fcad1613"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
version: "4.1.0"
|
||||
flutter_sharing_intent:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "dependencies/flutter_sharing_intent"
|
||||
relative: true
|
||||
source: path
|
||||
version: "2.0.4"
|
||||
flutter_svg:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -1243,11 +1248,10 @@ packages:
|
|||
no_screenshot:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: no_screenshot
|
||||
sha256: ec3d86d7ee89a09c3a3939c1003012536ba4b3fcb4f8cbd23d87ada595c99258
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.1"
|
||||
path: "dependencies/no_screenshot"
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.3.2-beta.3"
|
||||
objective_c:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
|||
61
pubspec.yaml
61
pubspec.yaml
|
|
@ -36,6 +36,7 @@ dependencies:
|
|||
url_launcher: ^6.3.2
|
||||
vector_graphics: ^1.1.19
|
||||
video_player: ^2.10.1
|
||||
in_app_purchase: ^3.2.3
|
||||
|
||||
|
||||
# Trusted publisher fluttercommunity.dev
|
||||
|
|
@ -54,44 +55,50 @@ dependencies:
|
|||
scrollable_positioned_list: ^0.3.8 # google.dev
|
||||
|
||||
|
||||
# Flutter Favorite
|
||||
provider: ^6.1.2
|
||||
drift: ^2.25.1
|
||||
drift_flutter: ^0.2.4
|
||||
flutter_local_notifications: ^19.1.0
|
||||
sentry_flutter: ^9.8.0
|
||||
|
||||
|
||||
# With high download
|
||||
app_links: ^7.0.0 # 1.6 mio
|
||||
image: ^4.3.0 # 3.3 mio
|
||||
archive: ^4.0.7 # 6.5 mio
|
||||
file_picker: ^10.3.6 # 2 mio
|
||||
get: ^4.7.2 # 740 k
|
||||
flutter_secure_storage: ^10.0.0 # 1.85 mio
|
||||
permission_handler: ^12.0.0+1 # 2 mio
|
||||
|
||||
|
||||
# Not yet checked
|
||||
archive: ^4.0.7
|
||||
audio_waveforms: ^2.0.0
|
||||
avatar_maker: ^0.4.0
|
||||
background_downloader: ^9.4.0
|
||||
cached_network_image: ^3.4.1
|
||||
cryptography_flutter_plus: ^2.3.4
|
||||
cryptography_plus: ^2.7.0
|
||||
drift: ^2.25.1
|
||||
drift_flutter: ^0.2.4
|
||||
ffmpeg_kit_flutter_new: ^4.1.0
|
||||
file_picker: ^10.3.6
|
||||
flutter_android_volume_keydown: ^1.0.1
|
||||
flutter_image_compress: ^2.4.0
|
||||
flutter_local_notifications: ^19.1.0
|
||||
flutter_secure_storage:
|
||||
git:
|
||||
url: https://github.com/juliansteenbakker/flutter_secure_storage.git
|
||||
ref: a06ead81809c900e7fc421a30db0adf3b5919139 # from develop
|
||||
path: flutter_secure_storage/
|
||||
flutter_volume_controller: ^1.3.4
|
||||
gal: ^2.3.1
|
||||
get: ^4.7.2
|
||||
google_mlkit_barcode_scanning: ^0.14.1
|
||||
image: ^4.3.0
|
||||
no_screenshot: ^0.3.1
|
||||
permission_handler: ^12.0.0+1
|
||||
provider: ^6.1.2
|
||||
restart_app: ^1.3.2
|
||||
sentry_flutter: ^9.8.0
|
||||
app_links: ^7.0.0
|
||||
in_app_purchase: ^3.2.3
|
||||
|
||||
# flutter_secure_storage:
|
||||
# git:
|
||||
# url: https://github.com/juliansteenbakker/flutter_secure_storage.git
|
||||
# ref: a06ead81809c900e7fc421a30db0adf3b5919139 # from develop
|
||||
# path: flutter_secure_storage/
|
||||
|
||||
|
||||
# Overwritten by self-controlled repository
|
||||
emoji_picker_flutter: ^4.3.0
|
||||
|
||||
# Packages which got overwritten using the twonly-app-dependencies repository
|
||||
restart_app: ^1.3.2
|
||||
photo_view: ^0.15.0
|
||||
hashlib: ^2.0.0
|
||||
libsignal_protocol_dart: ^0.7.4
|
||||
|
|
@ -100,6 +107,8 @@ dependencies:
|
|||
introduction_screen: ^4.0.0
|
||||
qr_flutter: ^4.1.0
|
||||
hand_signature: ^3.0.3
|
||||
flutter_sharing_intent: ^2.0.4
|
||||
no_screenshot: ^0.3.1
|
||||
|
||||
dependency_overrides:
|
||||
dots_indicator:
|
||||
|
|
@ -110,6 +119,8 @@ dependency_overrides:
|
|||
path: ./dependencies/introduction_screen
|
||||
libsignal_protocol_dart:
|
||||
path: ./dependencies/libsignal_protocol_dart
|
||||
flutter_sharing_intent:
|
||||
path: ./dependencies/flutter_sharing_intent
|
||||
lottie:
|
||||
path: ./dependencies/lottie
|
||||
mutex:
|
||||
|
|
@ -134,6 +145,8 @@ dependency_overrides:
|
|||
path: ./dependencies/x25519
|
||||
qr_flutter:
|
||||
path: ./dependencies/qr_flutter
|
||||
no_screenshot:
|
||||
path: ./dependencies/no_screenshot
|
||||
camera_android_camerax:
|
||||
# path: ../flutter-packages/packages/camera/camera_android_camerax
|
||||
git:
|
||||
|
|
@ -149,11 +162,11 @@ dependency_overrides:
|
|||
git:
|
||||
url: https://github.com/yenchieh/flutter_android_volume_keydown.git
|
||||
branch: fix/lStar-not-found-error
|
||||
flutter_secure_storage_darwin:
|
||||
git:
|
||||
url: https://github.com/juliansteenbakker/flutter_secure_storage.git
|
||||
ref: a06ead81809c900e7fc421a30db0adf3b5919139 # from develop
|
||||
path: flutter_secure_storage_darwin/
|
||||
# flutter_secure_storage_darwin:
|
||||
# git:
|
||||
# url: https://github.com/juliansteenbakker/flutter_secure_storage.git
|
||||
# ref: a06ead81809c900e7fc421a30db0adf3b5919139 # from develop
|
||||
# path: flutter_secure_storage_darwin/
|
||||
# hardcoding the mirror mode of the VideCapture to MIRROR_MODE_ON_FRONT_ONLY
|
||||
|
||||
dev_dependencies:
|
||||
|
|
|
|||
Loading…
Reference in a new issue