mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-09 04:07:57 -06:00
Added ios support for receive_sharing_intent, some consistency fixes and bug fixes
This commit is contained in:
@@ -46,6 +46,9 @@ PODS:
|
||||
- Flutter
|
||||
- flutter_native_splash (0.0.1):
|
||||
- Flutter
|
||||
- fluttertoast (0.0.2):
|
||||
- Flutter
|
||||
- Toast
|
||||
- FMDB (2.7.5):
|
||||
- FMDB/standard (= 2.7.5)
|
||||
- FMDB/standard (2.7.5)
|
||||
@@ -62,15 +65,20 @@ PODS:
|
||||
- permission_handler_apple (9.0.4):
|
||||
- Flutter
|
||||
- ReachabilitySwift (5.0.0)
|
||||
- receive_sharing_intent (0.0.1):
|
||||
- Flutter
|
||||
- SDWebImage (5.13.5):
|
||||
- SDWebImage/Core (= 5.13.5)
|
||||
- SDWebImage/Core (5.13.5)
|
||||
- share_plus (0.0.1):
|
||||
- Flutter
|
||||
- shared_preferences_ios (0.0.1):
|
||||
- Flutter
|
||||
- sqflite (0.0.2):
|
||||
- Flutter
|
||||
- FMDB (>= 2.7.5)
|
||||
- SwiftyGif (5.4.3)
|
||||
- Toast (4.0.0)
|
||||
- url_launcher_ios (0.0.1):
|
||||
- Flutter
|
||||
- WeScan (1.7.0)
|
||||
@@ -83,12 +91,15 @@ DEPENDENCIES:
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
|
||||
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
|
||||
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
|
||||
- integration_test (from `.symlinks/plugins/integration_test/ios`)
|
||||
- local_auth_ios (from `.symlinks/plugins/local_auth_ios/ios`)
|
||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||
- path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
|
||||
- pdfx (from `.symlinks/plugins/pdfx/ios`)
|
||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||
- receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`)
|
||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||
- shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
|
||||
- sqflite (from `.symlinks/plugins/sqflite/ios`)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
@@ -101,6 +112,7 @@ SPEC REPOS:
|
||||
- ReachabilitySwift
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- Toast
|
||||
- WeScan
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
@@ -118,6 +130,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/flutter_keyboard_visibility/ios"
|
||||
flutter_native_splash:
|
||||
:path: ".symlinks/plugins/flutter_native_splash/ios"
|
||||
fluttertoast:
|
||||
:path: ".symlinks/plugins/fluttertoast/ios"
|
||||
integration_test:
|
||||
:path: ".symlinks/plugins/integration_test/ios"
|
||||
local_auth_ios:
|
||||
@@ -130,6 +144,10 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/pdfx/ios"
|
||||
permission_handler_apple:
|
||||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||
receive_sharing_intent:
|
||||
:path: ".symlinks/plugins/receive_sharing_intent/ios"
|
||||
share_plus:
|
||||
:path: ".symlinks/plugins/share_plus/ios"
|
||||
shared_preferences_ios:
|
||||
:path: ".symlinks/plugins/shared_preferences_ios/ios"
|
||||
sqflite:
|
||||
@@ -147,6 +165,7 @@ SPEC CHECKSUMS:
|
||||
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
||||
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
|
||||
flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
|
||||
fluttertoast: 74526702fea2c060ea55dde75895b7e1bde1c86b
|
||||
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
||||
integration_test: a1e7d09bd98eca2fc37aefd79d4f41ad37bdbbe5
|
||||
local_auth_ios: 0d333dde7780f669e66f19d2ff6005f3ea84008d
|
||||
@@ -155,10 +174,13 @@ SPEC CHECKSUMS:
|
||||
pdfx: 7b876b09de8b7a0bf444a4f82b439ffcff4ee1ec
|
||||
permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce
|
||||
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
|
||||
receive_sharing_intent: c0d87310754e74c0f9542947e7cbdf3a0335a3b1
|
||||
SDWebImage: 23d714cd599354ee7906dbae26dff89b421c4370
|
||||
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
|
||||
shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
|
||||
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
|
||||
SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780
|
||||
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
|
||||
url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de
|
||||
WeScan: fed582f6c38014d529afb5aa9ffd1bad38fc72b7
|
||||
|
||||
|
||||
@@ -3,12 +3,15 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objectVersion = 51;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
4D0C7954292C15240064EE78 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D0C7953292C15240064EE78 /* ShareViewController.swift */; };
|
||||
4D0C7957292C15240064EE78 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4D0C7955292C15240064EE78 /* MainInterface.storyboard */; };
|
||||
4D0C795B292C15240064EE78 /* receive_sharing_intent.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 4D0C7951292C15240064EE78 /* receive_sharing_intent.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
@@ -16,7 +19,28 @@
|
||||
B8F579F7EE511C92B2614EE2 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 40BF6B81A87C86D22CDB775A /* Pods_Runner.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
4D0C7959292C15240064EE78 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 4D0C7950292C15240064EE78;
|
||||
remoteInfo = receive_sharing_intent;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
4D0C795C292C15250064EE78 /* Embed Foundation Extensions */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 13;
|
||||
files = (
|
||||
4D0C795B292C15240064EE78 /* receive_sharing_intent.appex in Embed Foundation Extensions */,
|
||||
);
|
||||
name = "Embed Foundation Extensions";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -34,6 +58,12 @@
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
40BF6B81A87C86D22CDB775A /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
4D0C7951292C15240064EE78 /* receive_sharing_intent.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = receive_sharing_intent.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
4D0C7953292C15240064EE78 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; };
|
||||
4D0C7956292C15240064EE78 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = "<group>"; };
|
||||
4D0C7958292C15240064EE78 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
4D0C7961292C196E0064EE78 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||
4D0C7962292C19960064EE78 /* receive_sharing_intent.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = receive_sharing_intent.entitlements; sourceTree = "<group>"; };
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
@@ -50,6 +80,13 @@
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
4D0C794E292C15240064EE78 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -61,6 +98,17 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
4D0C7952292C15240064EE78 /* receive_sharing_intent */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4D0C7962292C19960064EE78 /* receive_sharing_intent.entitlements */,
|
||||
4D0C7953292C15240064EE78 /* ShareViewController.swift */,
|
||||
4D0C7955292C15240064EE78 /* MainInterface.storyboard */,
|
||||
4D0C7958292C15240064EE78 /* Info.plist */,
|
||||
);
|
||||
path = receive_sharing_intent;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -77,6 +125,7 @@
|
||||
children = (
|
||||
9740EEB11CF90186004384FC /* Flutter */,
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
4D0C7952292C15240064EE78 /* receive_sharing_intent */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
E525DE4999AE527627D97DCA /* Pods */,
|
||||
FB6F7F4A953DAAA3FFE794E6 /* Frameworks */,
|
||||
@@ -87,6 +136,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||
4D0C7951292C15240064EE78 /* receive_sharing_intent.appex */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -94,6 +144,7 @@
|
||||
97C146F01CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4D0C7961292C196E0064EE78 /* Runner.entitlements */,
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||
@@ -113,7 +164,6 @@
|
||||
9F0882A26646B3A4713EAA3B /* Pods-Runner.release.xcconfig */,
|
||||
895AB075C3F1E3E87F6C3D1A /* Pods-Runner.profile.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -128,6 +178,23 @@
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
4D0C7950292C15240064EE78 /* receive_sharing_intent */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 4D0C7960292C15250064EE78 /* Build configuration list for PBXNativeTarget "receive_sharing_intent" */;
|
||||
buildPhases = (
|
||||
4D0C794D292C15240064EE78 /* Sources */,
|
||||
4D0C794E292C15240064EE78 /* Frameworks */,
|
||||
4D0C794F292C15240064EE78 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = receive_sharing_intent;
|
||||
productName = receive_sharing_intent;
|
||||
productReference = 4D0C7951292C15240064EE78 /* receive_sharing_intent.appex */;
|
||||
productType = "com.apple.product-type.app-extension";
|
||||
};
|
||||
97C146ED1CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
@@ -140,10 +207,12 @@
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
13B6B31A3992BA65B73408A6 /* [CP] Embed Pods Frameworks */,
|
||||
4D0C795C292C15250064EE78 /* Embed Foundation Extensions */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
4D0C795A292C15240064EE78 /* PBXTargetDependency */,
|
||||
);
|
||||
name = Runner;
|
||||
productName = Runner;
|
||||
@@ -156,9 +225,13 @@
|
||||
97C146E61CF9000F007C117D /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1400;
|
||||
LastUpgradeCheck = 1300;
|
||||
ORGANIZATIONNAME = "";
|
||||
TargetAttributes = {
|
||||
4D0C7950292C15240064EE78 = {
|
||||
CreatedOnToolsVersion = 14.0.1;
|
||||
};
|
||||
97C146ED1CF9000F007C117D = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
LastSwiftMigration = 1100;
|
||||
@@ -179,11 +252,20 @@
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
97C146ED1CF9000F007C117D /* Runner */,
|
||||
4D0C7950292C15240064EE78 /* receive_sharing_intent */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
4D0C794F292C15240064EE78 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4D0C7957292C15240064EE78 /* MainInterface.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EC1CF9000F007C117D /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -268,6 +350,14 @@
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
4D0C794D292C15240064EE78 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4D0C7954292C15240064EE78 /* ShareViewController.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EA1CF9000F007C117D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -279,7 +369,23 @@
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
4D0C795A292C15240064EE78 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 4D0C7950292C15240064EE78 /* receive_sharing_intent */;
|
||||
targetProxy = 4D0C7959292C15240064EE78 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
4D0C7955292C15240064EE78 /* MainInterface.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
4D0C7956292C15240064EE78 /* Base */,
|
||||
);
|
||||
name = MainInterface.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
@@ -353,16 +459,19 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterPaperlessNgScanAndShare;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "de.astubenbord.paperless-mobile";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -370,6 +479,114 @@
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
4D0C795D292C15250064EE78 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = receive_sharing_intent/receive_sharing_intent.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = receive_sharing_intent/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = receive_sharing_intent;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "de.astubenbord.paperless-mobile.receive-sharing-intent";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
4D0C795E292C15250064EE78 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = receive_sharing_intent/receive_sharing_intent.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = receive_sharing_intent/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = receive_sharing_intent;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "de.astubenbord.paperless-mobile.receive-sharing-intent";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
4D0C795F292C15250064EE78 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = receive_sharing_intent/receive_sharing_intent.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = receive_sharing_intent/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = receive_sharing_intent;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "de.astubenbord.paperless-mobile.receive-sharing-intent";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
97C147031CF9000F007C117D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
@@ -481,16 +698,19 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterPaperlessNgScanAndShare;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "de.astubenbord.paperless-mobile";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
@@ -503,16 +723,19 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterPaperlessNgScanAndShare;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "de.astubenbord.paperless-mobile";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -523,6 +746,16 @@
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
4D0C7960292C15250064EE78 /* Build configuration list for PBXNativeTarget "receive_sharing_intent" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
4D0C795D292C15250064EE78 /* Debug */,
|
||||
4D0C795E292C15250064EE78 /* Release */,
|
||||
4D0C795F292C15250064EE78 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
||||
@@ -2,6 +2,22 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>ShareMedia</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict/>
|
||||
</array>
|
||||
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>To upload photos, please allow permission to access your photo library.</string>
|
||||
|
||||
<key>NSFaceIDUsageDescription</key>
|
||||
<string>Why is my app authenticating using face id?</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
@@ -48,6 +64,6 @@
|
||||
<key>UIStatusBarHidden</key>
|
||||
<false/>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
10
ios/Runner/Runner.entitlements
Normal file
10
ios/Runner/Runner.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.de.astubenbord.paperless-mobile</string>
|
||||
</array>
|
||||
</dict>
|
||||
</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>
|
||||
28
ios/receive_sharing_intent/Info.plist
Normal file
28
ios/receive_sharing_intent/Info.plist
Normal file
@@ -0,0 +1,28 @@
|
||||
<?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>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionAttributes</key>
|
||||
<dict>
|
||||
<key>PHSupportedMediaTypes</key>
|
||||
<array>
|
||||
<string>Image</string>
|
||||
</array>
|
||||
<key>NSExtensionActivationRule</key>
|
||||
<dict>
|
||||
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
|
||||
<integer>1</integer>
|
||||
<key>NSExtensionActivationSupportsFileWithMaxCount</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>NSExtensionMainStoryboard</key>
|
||||
<string>MainInterface</string>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.share-services</string>
|
||||
</dict>
|
||||
|
||||
</dict>
|
||||
</plist>
|
||||
337
ios/receive_sharing_intent/ShareViewController.swift
Normal file
337
ios/receive_sharing_intent/ShareViewController.swift
Normal file
@@ -0,0 +1,337 @@
|
||||
import UIKit
|
||||
import Social
|
||||
import MobileCoreServices
|
||||
import Photos
|
||||
|
||||
class ShareViewController: SLComposeServiceViewController {
|
||||
let hostAppBundleIdentifier = "de.astubenbord.paperless-mobile"
|
||||
let sharedKey = "ShareKey"
|
||||
var sharedMedia: [SharedMediaFile] = []
|
||||
var sharedText: [String] = []
|
||||
let imageContentType = kUTTypeImage as String
|
||||
let videoContentType = kUTTypeMovie as String
|
||||
let textContentType = kUTTypeText as String
|
||||
let urlContentType = kUTTypeURL as String
|
||||
let fileURLType = kUTTypeFileURL as String;
|
||||
|
||||
override func isContentValid() -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad();
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
// This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.
|
||||
if let content = extensionContext!.inputItems[0] as? NSExtensionItem {
|
||||
if let contents = content.attachments {
|
||||
for (index, attachment) in (contents).enumerated() {
|
||||
if attachment.hasItemConformingToTypeIdentifier(imageContentType) {
|
||||
handleImages(content: content, attachment: attachment, index: index)
|
||||
} else if attachment.hasItemConformingToTypeIdentifier(textContentType) {
|
||||
handleText(content: content, attachment: attachment, index: index)
|
||||
} else if attachment.hasItemConformingToTypeIdentifier(fileURLType) {
|
||||
handleFiles(content: content, attachment: attachment, index: index)
|
||||
} else if attachment.hasItemConformingToTypeIdentifier(urlContentType) {
|
||||
handleUrl(content: content, attachment: attachment, index: index)
|
||||
} else if attachment.hasItemConformingToTypeIdentifier(videoContentType) {
|
||||
handleVideos(content: content, attachment: attachment, index: index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func didSelectPost() {
|
||||
// This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.
|
||||
|
||||
// Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context.
|
||||
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
|
||||
}
|
||||
|
||||
override func configurationItems() -> [Any]! {
|
||||
// To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here.
|
||||
return []
|
||||
}
|
||||
|
||||
private func handleText (content: NSExtensionItem, attachment: NSItemProvider, index: Int) {
|
||||
attachment.loadItem(forTypeIdentifier: textContentType, options: nil) { [weak self] data, error in
|
||||
|
||||
if error == nil, let item = data as? String, let this = self {
|
||||
|
||||
this.sharedText.append(item)
|
||||
|
||||
// If this is the last item, save imagesData in userDefaults and redirect to host app
|
||||
if index == (content.attachments?.count)! - 1 {
|
||||
let userDefaults = UserDefaults(suiteName: "group.\(this.hostAppBundleIdentifier)")
|
||||
userDefaults?.set(this.sharedText, forKey: this.sharedKey)
|
||||
userDefaults?.synchronize()
|
||||
this.redirectToHostApp(type: .text)
|
||||
}
|
||||
|
||||
} else {
|
||||
self?.dismissWithError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func handleUrl (content: NSExtensionItem, attachment: NSItemProvider, index: Int) {
|
||||
attachment.loadItem(forTypeIdentifier: urlContentType, options: nil) { [weak self] data, error in
|
||||
|
||||
if error == nil, let item = data as? URL, let this = self {
|
||||
|
||||
this.sharedText.append(item.absoluteString)
|
||||
|
||||
// If this is the last item, save imagesData in userDefaults and redirect to host app
|
||||
if index == (content.attachments?.count)! - 1 {
|
||||
let userDefaults = UserDefaults(suiteName: "group.\(this.hostAppBundleIdentifier)")
|
||||
userDefaults?.set(this.sharedText, forKey: this.sharedKey)
|
||||
userDefaults?.synchronize()
|
||||
this.redirectToHostApp(type: .text)
|
||||
}
|
||||
|
||||
} else {
|
||||
self?.dismissWithError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func handleImages (content: NSExtensionItem, attachment: NSItemProvider, index: Int) {
|
||||
attachment.loadItem(forTypeIdentifier: imageContentType, options: nil) { [weak self] data, error in
|
||||
|
||||
if error == nil, let url = data as? URL, let this = self {
|
||||
|
||||
// Always copy
|
||||
let fileName = this.getFileName(from: url, type: .image)
|
||||
let newPath = FileManager.default
|
||||
.containerURL(forSecurityApplicationGroupIdentifier: "group.\(this.hostAppBundleIdentifier)")!
|
||||
.appendingPathComponent(fileName)
|
||||
let copied = this.copyFile(at: url, to: newPath)
|
||||
if(copied) {
|
||||
this.sharedMedia.append(SharedMediaFile(path: newPath.absoluteString, thumbnail: nil, duration: nil, type: .image))
|
||||
}
|
||||
|
||||
// If this is the last item, save imagesData in userDefaults and redirect to host app
|
||||
if index == (content.attachments?.count)! - 1 {
|
||||
let userDefaults = UserDefaults(suiteName: "group.\(this.hostAppBundleIdentifier)")
|
||||
userDefaults?.set(this.toData(data: this.sharedMedia), forKey: this.sharedKey)
|
||||
userDefaults?.synchronize()
|
||||
this.redirectToHostApp(type: .media)
|
||||
}
|
||||
|
||||
} else {
|
||||
self?.dismissWithError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func handleVideos (content: NSExtensionItem, attachment: NSItemProvider, index: Int) {
|
||||
attachment.loadItem(forTypeIdentifier: videoContentType, options: nil) { [weak self] data, error in
|
||||
|
||||
if error == nil, let url = data as? URL, let this = self {
|
||||
|
||||
// Always copy
|
||||
let fileName = this.getFileName(from: url, type: .video)
|
||||
let newPath = FileManager.default
|
||||
.containerURL(forSecurityApplicationGroupIdentifier: "group.\(this.hostAppBundleIdentifier)")!
|
||||
.appendingPathComponent(fileName)
|
||||
let copied = this.copyFile(at: url, to: newPath)
|
||||
if(copied) {
|
||||
guard let sharedFile = this.getSharedMediaFile(forVideo: newPath) else {
|
||||
return
|
||||
}
|
||||
this.sharedMedia.append(sharedFile)
|
||||
}
|
||||
|
||||
// If this is the last item, save imagesData in userDefaults and redirect to host app
|
||||
if index == (content.attachments?.count)! - 1 {
|
||||
let userDefaults = UserDefaults(suiteName: "group.\(this.hostAppBundleIdentifier)")
|
||||
userDefaults?.set(this.toData(data: this.sharedMedia), forKey: this.sharedKey)
|
||||
userDefaults?.synchronize()
|
||||
this.redirectToHostApp(type: .media)
|
||||
}
|
||||
|
||||
} else {
|
||||
self?.dismissWithError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func handleFiles (content: NSExtensionItem, attachment: NSItemProvider, index: Int) {
|
||||
attachment.loadItem(forTypeIdentifier: fileURLType, options: nil) { [weak self] data, error in
|
||||
|
||||
if error == nil, let url = data as? URL, let this = self {
|
||||
|
||||
// Always copy
|
||||
let fileName = this.getFileName(from :url, type: .file)
|
||||
let newPath = FileManager.default
|
||||
.containerURL(forSecurityApplicationGroupIdentifier: "group.\(this.hostAppBundleIdentifier)")!
|
||||
.appendingPathComponent(fileName)
|
||||
let copied = this.copyFile(at: url, to: newPath)
|
||||
if (copied) {
|
||||
this.sharedMedia.append(SharedMediaFile(path: newPath.absoluteString, thumbnail: nil, duration: nil, type: .file))
|
||||
}
|
||||
|
||||
if index == (content.attachments?.count)! - 1 {
|
||||
let userDefaults = UserDefaults(suiteName: "group.\(this.hostAppBundleIdentifier)")
|
||||
userDefaults?.set(this.toData(data: this.sharedMedia), forKey: this.sharedKey)
|
||||
userDefaults?.synchronize()
|
||||
this.redirectToHostApp(type: .file)
|
||||
}
|
||||
|
||||
} else {
|
||||
self?.dismissWithError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func dismissWithError() {
|
||||
print("[ERROR] Error loading data!")
|
||||
let alert = UIAlertController(title: "Error", message: "Error loading data", preferredStyle: .alert)
|
||||
|
||||
let action = UIAlertAction(title: "Error", style: .cancel) { _ in
|
||||
self.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
alert.addAction(action)
|
||||
present(alert, animated: true, completion: nil)
|
||||
extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
|
||||
}
|
||||
|
||||
private func redirectToHostApp(type: RedirectType) {
|
||||
let url = URL(string: "ShareMedia://dataUrl=\(sharedKey)#\(type)")
|
||||
var responder = self as UIResponder?
|
||||
let selectorOpenURL = sel_registerName("openURL:")
|
||||
|
||||
while (responder != nil) {
|
||||
if (responder?.responds(to: selectorOpenURL))! {
|
||||
let _ = responder?.perform(selectorOpenURL, with: url)
|
||||
}
|
||||
responder = responder!.next
|
||||
}
|
||||
extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
|
||||
}
|
||||
|
||||
enum RedirectType {
|
||||
case media
|
||||
case text
|
||||
case file
|
||||
}
|
||||
|
||||
func getExtension(from url: URL, type: SharedMediaType) -> 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"
|
||||
}
|
||||
}
|
||||
return ex ?? "Unknown"
|
||||
}
|
||||
|
||||
func getFileName(from url: URL, type: SharedMediaType) -> 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)
|
||||
} catch (let error) {
|
||||
print("Cannot copy item at \(srcURL) to \(dstURL): \(error)")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private func getSharedMediaFile(forVideo: URL) -> SharedMediaFile? {
|
||||
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 SharedMediaFile(path: forVideo.absoluteString, thumbnail: thumbnailPath.absoluteString, duration: duration, type: .video)
|
||||
}
|
||||
|
||||
var saved = false
|
||||
let assetImgGenerate = AVAssetImageGenerator(asset: asset)
|
||||
assetImgGenerate.appliesPreferredTrackTransform = true
|
||||
// let scale = UIScreen.main.scale
|
||||
assetImgGenerate.maximumSize = CGSize(width: 360, height: 360)
|
||||
do {
|
||||
let img = try assetImgGenerate.copyCGImage(at: CMTimeMakeWithSeconds(600, preferredTimescale: Int32(1.0)), actualTime: nil)
|
||||
try UIImage.pngData(UIImage(cgImage: img))()?.write(to: thumbnailPath)
|
||||
saved = true
|
||||
} catch {
|
||||
saved = false
|
||||
}
|
||||
|
||||
return saved ? SharedMediaFile(path: forVideo.absoluteString, thumbnail: thumbnailPath.absoluteString, duration: duration, type: .video) : nil
|
||||
|
||||
}
|
||||
|
||||
private func getThumbnailPath(for url: URL) -> URL {
|
||||
let fileName = Data(url.lastPathComponent.utf8).base64EncodedString().replacingOccurrences(of: "==", with: "")
|
||||
let path = FileManager.default
|
||||
.containerURL(forSecurityApplicationGroupIdentifier: "group.\(hostAppBundleIdentifier)")!
|
||||
.appendingPathComponent("\(fileName).jpg")
|
||||
return path
|
||||
}
|
||||
|
||||
class SharedMediaFile: Codable {
|
||||
var path: String; // can be image, video or url path. It can also be text content
|
||||
var thumbnail: String?; // video thumbnail
|
||||
var duration: Double?; // video duration in milliseconds
|
||||
var type: SharedMediaType;
|
||||
|
||||
|
||||
init(path: String, thumbnail: String?, duration: Double?, type: SharedMediaType) {
|
||||
self.path = path
|
||||
self.thumbnail = thumbnail
|
||||
self.duration = duration
|
||||
self.type = type
|
||||
}
|
||||
|
||||
// Debug method to print out SharedMediaFile details in the console
|
||||
func toString() {
|
||||
print("[SharedMediaFile] \n\tpath: \(self.path)\n\tthumbnail: \(self.thumbnail)\n\tduration: \(self.duration)\n\ttype: \(self.type)")
|
||||
}
|
||||
}
|
||||
|
||||
enum SharedMediaType: Int, Codable {
|
||||
case image
|
||||
case video
|
||||
case file
|
||||
}
|
||||
|
||||
func toData(data: [SharedMediaFile]) -> Data {
|
||||
let encodedData = try? JSONEncoder().encode(data)
|
||||
return encodedData!
|
||||
}
|
||||
}
|
||||
|
||||
extension Array {
|
||||
subscript (safe index: UInt) -> Element? {
|
||||
return Int(index) < count ? self[Int(index)] : nil
|
||||
}
|
||||
}
|
||||
@@ -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.de.astubenbord.paperless-mobile</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -235,7 +235,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
||||
try {
|
||||
await BlocProvider.of<DocumentsCubit>(context).assignAsn(document);
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,7 +410,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
||||
await BlocProvider.of<DocumentsCubit>(context).removeDocument(document);
|
||||
showSnackBar(context, S.of(context).documentDeleteSuccessMessage);
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
} finally {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
||||
await getIt<DocumentsCubit>().updateDocument(updatedDocument);
|
||||
showSnackBar(context, S.of(context).documentUpdateErrorMessage);
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
} finally {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
||||
try {
|
||||
BlocProvider.of<DocumentsCubit>(context).loadDocuments();
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
||||
try {
|
||||
await documentsCubit.loadMore();
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
||||
(filter) => filter.copyWith(page: 1),
|
||||
);
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -476,7 +476,7 @@ class _DocumentFilterPanelState extends State<DocumentFilterPanel> {
|
||||
FocusScope.of(context).unfocus();
|
||||
widget.panelController.close();
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ class _DocumentsPageAppBarState extends State<DocumentsPageAppBar> {
|
||||
S.of(context).documentsPageBulkDeleteSuccessfulText,
|
||||
);
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ class SavedViewSelectionWidget extends StatelessWidget {
|
||||
try {
|
||||
await BlocProvider.of<SavedViewCubit>(context).add(newView);
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,7 +105,7 @@ class SavedViewSelectionWidget extends StatelessWidget {
|
||||
BlocProvider.of<SavedViewCubit>(context).selectView(null);
|
||||
}
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ class SavedViewSelectionWidget extends StatelessWidget {
|
||||
try {
|
||||
BlocProvider.of<SavedViewCubit>(context).remove(view);
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ class _HomePageState extends State<HomePage> {
|
||||
BlocProvider.of<StoragePathCubit>(context).initialize();
|
||||
BlocProvider.of<SavedViewCubit>(context).initialize();
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class BottomNavBar extends StatelessWidget {
|
||||
selectedIndex: selectedIndex,
|
||||
destinations: [
|
||||
NavigationDestination(
|
||||
icon: const Icon(Icons.description),
|
||||
icon: const Icon(Icons.description_outlined),
|
||||
selectedIcon: Icon(
|
||||
Icons.description,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
@@ -27,7 +27,7 @@ class BottomNavBar extends StatelessWidget {
|
||||
label: S.of(context).bottomNavDocumentsPageLabel,
|
||||
),
|
||||
NavigationDestination(
|
||||
icon: const Icon(Icons.document_scanner),
|
||||
icon: const Icon(Icons.document_scanner_outlined),
|
||||
selectedIcon: Icon(
|
||||
Icons.document_scanner,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
@@ -35,9 +35,7 @@ class BottomNavBar extends StatelessWidget {
|
||||
label: S.of(context).bottomNavScannerPageLabel,
|
||||
),
|
||||
NavigationDestination(
|
||||
icon: const Icon(
|
||||
Icons.sell,
|
||||
),
|
||||
icon: const Icon(Icons.sell_outlined),
|
||||
selectedIcon: Icon(
|
||||
Icons.sell,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
|
||||
@@ -191,7 +191,7 @@ class InfoDrawer extends StatelessWidget {
|
||||
getIt<TagCubit>().reset();
|
||||
getIt<DocumentScannerCubit>().reset();
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
},
|
||||
),
|
||||
|
||||
@@ -39,7 +39,7 @@ class EditCorrespondentPage extends StatelessWidget {
|
||||
}
|
||||
Navigator.pop(context);
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ class CorrespondentWidget extends StatelessWidget {
|
||||
}
|
||||
afterSelected?.call();
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ class DocumentTypeWidget extends StatelessWidget {
|
||||
}
|
||||
afterSelected?.call();
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ class EditStoragePathPage extends StatelessWidget {
|
||||
}
|
||||
Navigator.pop(context);
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ class StoragePathWidget extends StatelessWidget {
|
||||
}
|
||||
afterSelected?.call();
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ class EditTagPage extends StatelessWidget {
|
||||
cubit.updateFilter(filter: updatedFilter);
|
||||
Navigator.pop(context);
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ class TagWidget extends StatelessWidget {
|
||||
afterTagTapped!();
|
||||
}
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ class _EditLabelPageState<T extends Label> extends State<EditLabelPage<T>> {
|
||||
} on PaperlessValidationErrors catch (errorMessages) {
|
||||
setState(() => _errors = errorMessages);
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,9 +98,11 @@ class _LoginPageState extends State<LoginPage> {
|
||||
form[ClientCertificateFormField.fkClientCertificate],
|
||||
);
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
} on Map<String, dynamic> catch (error, stackTrace) {
|
||||
showGenericError(context, error.values.first, stackTrace);
|
||||
} catch (unknownError, stackTrace) {
|
||||
showError(context, ErrorMessage.unknown(), stackTrace);
|
||||
showErrorMessage(context, ErrorMessage.unknown(), stackTrace);
|
||||
} finally {
|
||||
setState(() => _isLoginLoading = false);
|
||||
}
|
||||
|
||||
@@ -30,11 +30,16 @@ import 'package:intl/intl.dart';
|
||||
|
||||
class DocumentUploadPage extends StatefulWidget {
|
||||
final Uint8List fileBytes;
|
||||
final String? title;
|
||||
final String? filename;
|
||||
final void Function()? afterUpload;
|
||||
|
||||
const DocumentUploadPage({
|
||||
Key? key,
|
||||
required this.fileBytes,
|
||||
this.afterUpload,
|
||||
this.title,
|
||||
this.filename,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@@ -42,18 +47,21 @@ class DocumentUploadPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _DocumentUploadPageState extends State<DocumentUploadPage> {
|
||||
static const fkFileName = "fileName";
|
||||
|
||||
static const fkFileName = "filename";
|
||||
static final fileNameDateFormat = DateFormat("yyyy_MM_ddTHH_mm_ss");
|
||||
|
||||
final GlobalKey<FormBuilderState> _formKey = GlobalKey();
|
||||
|
||||
PaperlessValidationErrors _errors = {};
|
||||
bool _isUploadLoading = false;
|
||||
late bool _syncTitleAndFilename;
|
||||
final _now = DateTime.now();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
initializeDateFormatting(); //TODO: INTL (has to do with intl below)
|
||||
_syncTitleAndFilename = widget.filename == null && widget.title == null;
|
||||
initializeDateFormatting();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -83,7 +91,8 @@ class _DocumentUploadPageState extends State<DocumentUploadPage> {
|
||||
FormBuilderTextField(
|
||||
autovalidateMode: AutovalidateMode.always,
|
||||
name: DocumentModel.titleKey,
|
||||
initialValue: "scan_${fileNameDateFormat.format(DateTime.now())}",
|
||||
initialValue:
|
||||
widget.title ?? "scan_${fileNameDateFormat.format(_now)}",
|
||||
validator: FormBuilderValidators.required(),
|
||||
decoration: InputDecoration(
|
||||
labelText: S.of(context).documentTitlePropertyLabel,
|
||||
@@ -92,29 +101,58 @@ class _DocumentUploadPageState extends State<DocumentUploadPage> {
|
||||
onPressed: () {
|
||||
_formKey.currentState?.fields[DocumentModel.titleKey]
|
||||
?.didChange("");
|
||||
_formKey.currentState?.fields[fkFileName]
|
||||
?.didChange(".pdf");
|
||||
if (_syncTitleAndFilename) {
|
||||
_formKey.currentState?.fields[fkFileName]?.didChange("");
|
||||
}
|
||||
},
|
||||
),
|
||||
errorText: _errors[DocumentModel.titleKey],
|
||||
),
|
||||
onChanged: (value) {
|
||||
final String? transformedValue =
|
||||
value?.replaceAll(RegExp(r"[\W_]"), "_");
|
||||
_formKey.currentState?.fields[fkFileName]
|
||||
?.didChange("${transformedValue ?? ''}.pdf");
|
||||
final String transformedValue = _formatFilename(value ?? '');
|
||||
if (_syncTitleAndFilename) {
|
||||
_formKey.currentState?.fields[fkFileName]
|
||||
?.didChange(transformedValue);
|
||||
}
|
||||
},
|
||||
),
|
||||
FormBuilderTextField(
|
||||
autovalidateMode: AutovalidateMode.always,
|
||||
readOnly: true,
|
||||
enabled: false,
|
||||
readOnly: _syncTitleAndFilename,
|
||||
enabled: !_syncTitleAndFilename,
|
||||
name: fkFileName,
|
||||
decoration: InputDecoration(
|
||||
labelText: S.of(context).documentUploadFileNameLabel,
|
||||
suffixText: ".pdf",
|
||||
suffixIcon: IconButton(
|
||||
icon: const Icon(Icons.clear),
|
||||
onPressed: () =>
|
||||
_formKey.currentState?.fields[fkFileName]?.didChange(''),
|
||||
),
|
||||
),
|
||||
initialValue:
|
||||
"scan_${fileNameDateFormat.format(DateTime.now())}.pdf",
|
||||
widget.filename ?? "scan_${fileNameDateFormat.format(_now)}",
|
||||
),
|
||||
SwitchListTile(
|
||||
value: _syncTitleAndFilename,
|
||||
onChanged: (value) {
|
||||
setState(
|
||||
() => _syncTitleAndFilename = value,
|
||||
);
|
||||
if (_syncTitleAndFilename) {
|
||||
final String transformedValue = _formatFilename(_formKey
|
||||
.currentState
|
||||
?.fields[DocumentModel.titleKey]
|
||||
?.value as String);
|
||||
if (_syncTitleAndFilename) {
|
||||
_formKey.currentState?.fields[fkFileName]
|
||||
?.didChange(transformedValue);
|
||||
}
|
||||
}
|
||||
},
|
||||
title: Text(S
|
||||
.of(context)
|
||||
.documentUploadPageSynchronizeTitleAndFilenameLabel), //TODO: INTL
|
||||
),
|
||||
FormBuilderDateTimePicker(
|
||||
autovalidateMode: AutovalidateMode.always,
|
||||
@@ -202,7 +240,7 @@ class _DocumentUploadPageState extends State<DocumentUploadPage> {
|
||||
fv[DocumentModel.correspondentKey] as IdQueryParameter;
|
||||
await BlocProvider.of<DocumentsCubit>(context).addDocument(
|
||||
widget.fileBytes,
|
||||
_formKey.currentState?.value[fkFileName],
|
||||
_padWithPdfExtension(_formKey.currentState?.value[fkFileName]),
|
||||
onConsumptionFinished: _onConsumptionFinished,
|
||||
title: title,
|
||||
documentType: docType.id,
|
||||
@@ -215,11 +253,11 @@ class _DocumentUploadPageState extends State<DocumentUploadPage> {
|
||||
Navigator.pop(context);
|
||||
widget.afterUpload?.call();
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
} on PaperlessValidationErrors catch (errorMessages) {
|
||||
setState(() => _errors = errorMessages);
|
||||
} catch (unknownError, stackTrace) {
|
||||
showError(context, ErrorMessage.unknown(), stackTrace);
|
||||
showErrorMessage(context, ErrorMessage.unknown(), stackTrace);
|
||||
} finally {
|
||||
setState(() {
|
||||
_isUploadLoading = false;
|
||||
@@ -228,6 +266,14 @@ class _DocumentUploadPageState extends State<DocumentUploadPage> {
|
||||
}
|
||||
}
|
||||
|
||||
String _padWithPdfExtension(String source) {
|
||||
return source.endsWith(".pdf") ? source : '$source.pdf';
|
||||
}
|
||||
|
||||
String _formatFilename(String source) {
|
||||
return source.replaceAll(RegExp(r"[\W_]"), "_");
|
||||
}
|
||||
|
||||
void _onConsumptionFinished(document) {
|
||||
ScaffoldMessenger.of(rootScaffoldKey.currentContext!).showSnackBar(
|
||||
SnackBar(
|
||||
@@ -236,7 +282,7 @@ class _DocumentUploadPageState extends State<DocumentUploadPage> {
|
||||
try {
|
||||
getIt<DocumentsCubit>().reloadDocuments();
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
},
|
||||
label:
|
||||
|
||||
@@ -192,7 +192,7 @@ class _ScannerPageState extends State<ScannerPage>
|
||||
BlocProvider.of<DocumentScannerCubit>(context)
|
||||
.removeScan(index);
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
},
|
||||
index: index,
|
||||
@@ -205,7 +205,7 @@ class _ScannerPageState extends State<ScannerPage>
|
||||
try {
|
||||
BlocProvider.of<DocumentScannerCubit>(context).reset();
|
||||
} on ErrorMessage catch (error, stackTrace) {
|
||||
showError(context, error, stackTrace);
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,10 +224,16 @@ class _ScannerPageState extends State<ScannerPage>
|
||||
);
|
||||
if (result?.files.single.path != null) {
|
||||
File file = File(result!.files.single.path!);
|
||||
if (!supportedFileExtensions.contains(file.path.split('.').last)) {
|
||||
//TODO: Show error message;
|
||||
if (!supportedFileExtensions.contains(
|
||||
file.path.split('.').last.toLowerCase(),
|
||||
)) {
|
||||
showErrorMessage(
|
||||
context,
|
||||
const ErrorMessage(ErrorCode.unsupportedFileFormat),
|
||||
);
|
||||
return;
|
||||
}
|
||||
final filename = extractFilenameFromPath(file.path);
|
||||
final mimeType = lookupMimeType(file.path) ?? '';
|
||||
late Uint8List fileBytes;
|
||||
if (mimeType.startsWith('image')) {
|
||||
@@ -244,6 +250,7 @@ class _ScannerPageState extends State<ScannerPage>
|
||||
value: getIt<DocumentsCubit>(),
|
||||
child: LabelBlocProvider(
|
||||
child: DocumentUploadPage(
|
||||
filename: filename,
|
||||
fileBytes: fileBytes,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"@@locale": "de",
|
||||
"documentTitlePropertyLabel": "Titel",
|
||||
"documentCreatedPropertyLabel": "Erstellt Am",
|
||||
"documentAddedPropertyLabel": "Hinzugefügt Am",
|
||||
"documentModifiedPropertyLabel": "Geändert Am",
|
||||
"documentCreatedPropertyLabel": "Ausgestellt am",
|
||||
"documentAddedPropertyLabel": "Hinzugefügt am",
|
||||
"documentModifiedPropertyLabel": "Geändert am",
|
||||
"documentDocumentTypePropertyLabel": "Dokumenttyp",
|
||||
"documentCorrespondentPropertyLabel": "Korrespondent",
|
||||
"documentStoragePathPropertyLabel": "Speicherpfad",
|
||||
@@ -107,7 +107,7 @@
|
||||
"documentScannerPageUploadFromThisDeviceButtonLabel": "Lade ein Dokument von diesem Gerät hoch",
|
||||
"addTagPageTitle": "Neuer Tag",
|
||||
"addCorrespondentPageTitle": "Neuer Korrespondent",
|
||||
"addDocumentTypePageTitle": "Neuer Dokumententyp",
|
||||
"addDocumentTypePageTitle": "Neuer Dokumenttyp",
|
||||
"labelNamePropertyLabel": "Name",
|
||||
"labelMatchPropertyLabel": "Zuweisungsmuster",
|
||||
"labelMatchingAlgorithmPropertyLabel": "Zuweisungsalgorithmus",
|
||||
@@ -195,5 +195,6 @@
|
||||
"appDrawerHeaderLoggedInAsText": "Eingeloggt als ",
|
||||
"labelAnyAssignedText": "Beliebig zugewiesen",
|
||||
"deleteViewDialogContentText": "Möchtest Du diese Ansicht wirklich löschen?",
|
||||
"deleteViewDialogTitleText": "Lösche Ansicht "
|
||||
"deleteViewDialogTitleText": "Lösche Ansicht ",
|
||||
"documentUploadPageSynchronizeTitleAndFilenameLabel": "Synchronisiere Titel und Dateiname"
|
||||
}
|
||||
@@ -196,5 +196,6 @@
|
||||
"appDrawerHeaderLoggedInAsText": "Logged in as ",
|
||||
"labelAnyAssignedText": "Any assigned",
|
||||
"deleteViewDialogContentText": "Do you really want to delete this view?",
|
||||
"deleteViewDialogTitleText": "Delete view "
|
||||
"deleteViewDialogTitleText": "Delete view ",
|
||||
"documentUploadPageSynchronizeTitleAndFilenameLabel": "Synchronize title and filename"
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_native_splash/flutter_native_splash.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:form_builder_validators/form_builder_validators.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:intl/intl_standalone.dart';
|
||||
@@ -15,6 +16,7 @@ import 'package:paperless_mobile/core/bloc/paperless_server_information_cubit.da
|
||||
import 'package:paperless_mobile/core/global/asset_images.dart';
|
||||
import 'package:paperless_mobile/core/global/constants.dart';
|
||||
import 'package:paperless_mobile/core/global/http_self_signed_certificate_override.dart';
|
||||
import 'package:paperless_mobile/core/logic/error_code_localization_mapper.dart';
|
||||
import 'package:paperless_mobile/core/model/error_message.dart';
|
||||
import 'package:paperless_mobile/core/service/file_service.dart';
|
||||
import 'package:paperless_mobile/di_initializer.dart';
|
||||
@@ -132,21 +134,40 @@ class AuthenticationWrapper extends StatefulWidget {
|
||||
|
||||
class _AuthenticationWrapperState extends State<AuthenticationWrapper> {
|
||||
bool isFileTypeSupported(SharedMediaFile file) {
|
||||
return supportedFileExtensions.contains(file.path.split('.').last);
|
||||
return supportedFileExtensions.contains(
|
||||
file.path.split('.').last.toLowerCase(),
|
||||
);
|
||||
}
|
||||
|
||||
void handleReceivedFiles(List<SharedMediaFile> files) async {
|
||||
if (files.isEmpty) {
|
||||
return;
|
||||
}
|
||||
if (!isFileTypeSupported(files.first)) {
|
||||
showError(context, const ErrorMessage(ErrorCode.unsupportedFileFormat));
|
||||
await Future.delayed(
|
||||
const Duration(seconds: 2),
|
||||
() => SystemNavigator.pop(),
|
||||
late final SharedMediaFile file;
|
||||
if (Platform.isIOS) {
|
||||
// Workaround: https://stackoverflow.com/a/72813212
|
||||
file = SharedMediaFile(
|
||||
files.first.path.replaceAll('file://', ''),
|
||||
files.first.thumbnail,
|
||||
files.first.duration,
|
||||
files.first.type,
|
||||
);
|
||||
} else {
|
||||
file = files.first;
|
||||
}
|
||||
final bytes = File(files.first.path).readAsBytesSync();
|
||||
|
||||
if (!isFileTypeSupported(file)) {
|
||||
Fluttertoast.showToast(
|
||||
msg: translateError(context, ErrorCode.unsupportedFileFormat),
|
||||
);
|
||||
if (Platform.isAndroid) {
|
||||
// As stated in the docs, SystemNavigator.pop() is ignored on IOS to comply with HCI guidelines.
|
||||
await SystemNavigator.pop();
|
||||
}
|
||||
return;
|
||||
}
|
||||
final filename = extractFilenameFromPath(file.path);
|
||||
final bytes = File(file.path).readAsBytesSync();
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
@@ -156,6 +177,7 @@ class _AuthenticationWrapperState extends State<AuthenticationWrapper> {
|
||||
child: DocumentUploadPage(
|
||||
fileBytes: bytes,
|
||||
afterUpload: () => SystemNavigator.pop(),
|
||||
filename: filename,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -184,7 +206,7 @@ class _AuthenticationWrapperState extends State<AuthenticationWrapper> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SafeArea(
|
||||
top: true,
|
||||
top: false,
|
||||
left: false,
|
||||
right: false,
|
||||
bottom: false,
|
||||
|
||||
@@ -34,7 +34,32 @@ void showSnackBar(
|
||||
);
|
||||
}
|
||||
|
||||
void showError(
|
||||
void showGenericError(
|
||||
BuildContext context,
|
||||
dynamic error, [
|
||||
StackTrace? stackTrace,
|
||||
]) {
|
||||
showSnackBar(
|
||||
context,
|
||||
error.toString(),
|
||||
action: SnackBarAction(
|
||||
label: S.of(context).errorReportLabel,
|
||||
textColor: Colors.amber,
|
||||
onPressed: () => GithubIssueService.createIssueFromError(
|
||||
context,
|
||||
stackTrace: stackTrace,
|
||||
),
|
||||
),
|
||||
);
|
||||
log(
|
||||
"An error has occurred.",
|
||||
error: error,
|
||||
stackTrace: stackTrace,
|
||||
time: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
void showErrorMessage(
|
||||
BuildContext context,
|
||||
ErrorMessage error, [
|
||||
StackTrace? stackTrace,
|
||||
@@ -91,3 +116,7 @@ String formatLocalDate(BuildContext context, DateTime dateTime) {
|
||||
final tag = Localizations.maybeLocaleOf(context)?.toLanguageTag();
|
||||
return DateFormat.yMMMd(tag).format(dateTime);
|
||||
}
|
||||
|
||||
String extractFilenameFromPath(String path) {
|
||||
return path.split(RegExp('[./]')).reversed.skip(1).first;
|
||||
}
|
||||
|
||||
@@ -588,6 +588,13 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
fluttertoast:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: fluttertoast
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "8.1.1"
|
||||
font_awesome_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
||||
@@ -80,6 +80,7 @@ dependencies:
|
||||
receive_sharing_intent: ^1.4.5
|
||||
uuid: ^3.0.6
|
||||
flutter_typeahead: ^4.1.1
|
||||
fluttertoast: ^8.1.1
|
||||
|
||||
dev_dependencies:
|
||||
integration_test:
|
||||
|
||||
Reference in New Issue
Block a user