diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 149424e6ab..d5dfef41a4 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -49,10 +49,14 @@
+
+
+
+
@@ -61,38 +65,61 @@
android:scheme="https"
android:host="matrix.to"/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/FluffyChat Share/ShareViewController.swift b/ios/FluffyChat Share/ShareViewController.swift
index 96d921432f..4d10e6bd8d 100644
--- a/ios/FluffyChat Share/ShareViewController.swift
+++ b/ios/FluffyChat Share/ShareViewController.swift
@@ -1,335 +1,14 @@
-import UIKit
-import Social
-import MobileCoreServices
-import Photos
-
-class ShareViewController: SLComposeServiceViewController {
- // TODO: IMPORTANT: This should be your host app bundle identifier
- let hostAppBundleIdentifier = "im.fluffychat.app"
- 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() {
- print("didSelectPost");
- }
-
- 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!
- }
+// If you get no such module 'receive_sharing_intent' error.
+// Go to Build Phases of your Runner target and
+// move `Embed Foundation Extension` to the top of `Thin Binary`.
+import receive_sharing_intent
+
+class ShareViewController: RSIShareViewController {
+
+ // Use this method to return false if you don't want to redirect to host app automatically.
+ // Default is true
+ override func shouldAutoRedirect() -> Bool {
+ return false
+ }
+
}
-
-extension Array {
- subscript (safe index: UInt) -> Element? {
- return Int(index) < count ? self[Int(index)] : nil
- }
-}
\ No newline at end of file
diff --git a/ios/Podfile b/ios/Podfile
index fac4d8176f..4c88a11417 100644
--- a/ios/Podfile
+++ b/ios/Podfile
@@ -32,6 +32,11 @@ target 'Runner' do
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
+
+ # From package https://pub.dev/packages/receive_sharing_intent
+ target 'FluffyChat Share' do
+ inherit! :search_paths
+ end
end
post_install do |installer|
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 9d57b73aad..27e9bef000 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -9,6 +9,7 @@
/* 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 */; };
+ 609046320A2D7D2B0D36583B /* Pods_FluffyChat_Share.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9EB6E6475A19949A37A2634 /* Pods_FluffyChat_Share.framework */; };
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 */; };
@@ -56,10 +57,12 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 09545B0C8C397F94966EA956 /* Pods-FluffyChat Share.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FluffyChat Share.debug.xcconfig"; path = "Target Support Files/Pods-FluffyChat Share/Pods-FluffyChat Share.debug.xcconfig"; sourceTree = ""; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
50DEFC207B70632D9C56ED78 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 58F7B95D036AD8E67B27588D /* Pods-FluffyChat Share.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FluffyChat Share.profile.xcconfig"; path = "Target Support Files/Pods-FluffyChat Share/Pods-FluffyChat Share.profile.xcconfig"; sourceTree = ""; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
76737C9A857D5FD6D2634A3F /* 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 = ""; };
@@ -80,7 +83,9 @@
C137635D2AD1446100A8F905 /* notification.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = notification.caf; sourceTree = ""; };
C149567B25C7274F00A16396 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; };
C149567D25C7276200A16396 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; };
+ C9EB6E6475A19949A37A2634 /* Pods_FluffyChat_Share.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_FluffyChat_Share.framework; sourceTree = BUILT_PRODUCTS_DIR; };
EA246783222E02DD03959891 /* 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 = ""; };
+ F3778959E67CDA0CDB0D97BC /* Pods-FluffyChat Share.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FluffyChat Share.release.xcconfig"; path = "Target Support Files/Pods-FluffyChat Share/Pods-FluffyChat Share.release.xcconfig"; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -96,6 +101,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 609046320A2D7D2B0D36583B /* Pods_FluffyChat_Share.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -106,6 +112,7 @@
isa = PBXGroup;
children = (
50DEFC207B70632D9C56ED78 /* Pods_Runner.framework */,
+ C9EB6E6475A19949A37A2634 /* Pods_FluffyChat_Share.framework */,
);
name = Frameworks;
sourceTree = "";
@@ -177,6 +184,9 @@
76737C9A857D5FD6D2634A3F /* Pods-Runner.debug.xcconfig */,
EA246783222E02DD03959891 /* Pods-Runner.release.xcconfig */,
9DB2F3524376810E74C799A8 /* Pods-Runner.profile.xcconfig */,
+ 09545B0C8C397F94966EA956 /* Pods-FluffyChat Share.debug.xcconfig */,
+ F3778959E67CDA0CDB0D97BC /* Pods-FluffyChat Share.release.xcconfig */,
+ 58F7B95D036AD8E67B27588D /* Pods-FluffyChat Share.profile.xcconfig */,
);
path = Pods;
sourceTree = "";
@@ -195,9 +205,9 @@
97C146EC1CF9000F007C117D /* Resources */,
C1005C4D261071B5002F4F32 /* Embed App Extensions */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
- 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
F9C8EE392B9AB471149C306E /* [CP] Embed Pods Frameworks */,
064CBD7CE0D4CD6850C6880A /* [CP] Copy Pods Resources */,
+ 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
);
buildRules = (
);
@@ -213,6 +223,7 @@
isa = PBXNativeTarget;
buildConfigurationList = C1005C51261071B5002F4F32 /* Build configuration list for PBXNativeTarget "FluffyChat Share" */;
buildPhases = (
+ 67579C1EA0B5C7B918473158 /* [CP] Check Pods Manifest.lock */,
C1005C3E261071B5002F4F32 /* Sources */,
C1005C3F261071B5002F4F32 /* Frameworks */,
C1005C40261071B5002F4F32 /* Resources */,
@@ -320,7 +331,29 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n";
+ };
+ 67579C1EA0B5C7B918473158 /* [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-FluffyChat Share-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;
};
8C9CCA7C5C45651F90C7BFDD /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
@@ -357,7 +390,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
};
F9C8EE392B9AB471149C306E /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
@@ -693,6 +726,7 @@
};
C1005C4E261071B5002F4F32 /* Debug */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = 09545B0C8C397F94966EA956 /* Pods-FluffyChat Share.debug.xcconfig */;
buildSettings = {
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
@@ -727,6 +761,7 @@
};
C1005C4F261071B5002F4F32 /* Release */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = F3778959E67CDA0CDB0D97BC /* Pods-FluffyChat Share.release.xcconfig */;
buildSettings = {
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
@@ -758,6 +793,7 @@
};
C1005C50261071B5002F4F32 /* Profile */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = 58F7B95D036AD8E67B27588D /* Pods-FluffyChat Share.profile.xcconfig */;
buildSettings = {
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index f53992f999..c94401f483 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -33,7 +33,7 @@
im.fluffychat.app.uris
CFBundleURLSchemes
- ShareMedia
+ ShareMedia-$(PRODUCT_BUNDLE_IDENTIFIER)
im.fluffychat
matrix
diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart
index 553c979df5..22f1982f7f 100644
--- a/lib/pages/chat_list/chat_list.dart
+++ b/lib/pages/chat_list/chat_list.dart
@@ -1,5 +1,4 @@
import 'dart:async';
-import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@@ -26,7 +25,6 @@ import 'package:fluffychat/widgets/avatar.dart';
import 'package:fluffychat/widgets/future_loading_dialog.dart';
import '../../../utils/account_bundles.dart';
import '../../config/setting_keys.dart';
-import '../../utils/matrix_sdk_extensions/matrix_file_extension.dart';
import '../../utils/url_launcher.dart';
import '../../utils/voip/callkeep_manager.dart';
import '../../widgets/fluffy_chat_app.dart';
@@ -196,20 +194,14 @@ class ChatListController extends State
// Share content into this room
final shareContent = Matrix.of(context).shareContent;
if (shareContent != null) {
- final shareFile = shareContent.tryGet('file');
+ final shareFile = shareContent.tryGet('file');
if (shareContent.tryGet('msgtype') == 'chat.fluffy.shared_file' &&
shareFile != null) {
await showDialog(
context: context,
useRootNavigator: false,
builder: (c) => SendFileDialog(
- files: [
- XFile.fromData(
- shareFile.bytes,
- name: shareFile.name,
- mimeType: shareFile.mimeType,
- ),
- ],
+ files: [shareFile],
room: room,
outerContext: context,
),
@@ -432,16 +424,32 @@ class ChatListController extends State
? SelectMode.share
: SelectMode.normal;
- void _processIncomingSharedFiles(List files) {
+ void _processIncomingSharedMedia(List files) {
if (files.isEmpty) return;
- final file = File(files.first.path.replaceFirst('file://', ''));
+
+ if (files.length > 1) {
+ Logs().w(
+ 'Received ${files.length} incoming shared media but app can only handle the first one',
+ );
+ }
+
+ // We only handle the first file currently
+ final sharedMedia = files.first;
+
+ // Handle URIs and Texts, which are also passed in path
+ if (sharedMedia.type case SharedMediaType.text || SharedMediaType.url) {
+ return _processIncomingSharedText(sharedMedia.path);
+ }
+
+ final file = XFile(
+ sharedMedia.path.replaceFirst('file://', ''),
+ mimeType: sharedMedia.mimeType,
+ );
Matrix.of(context).shareContent = {
'msgtype': 'chat.fluffy.shared_file',
- 'file': MatrixFile(
- bytes: file.readAsBytesSync(),
- name: file.path,
- ).detectFileType,
+ 'file': file,
+ if (sharedMedia.message != null) 'body': sharedMedia.message,
};
context.go('/rooms');
}
@@ -473,18 +481,14 @@ class ChatListController extends State
if (!PlatformInfos.isMobile) return;
// For sharing images coming from outside the app while the app is in the memory
- _intentFileStreamSubscription = ReceiveSharingIntent.getMediaStream()
- .listen(_processIncomingSharedFiles, onError: print);
+ _intentFileStreamSubscription = ReceiveSharingIntent.instance
+ .getMediaStream()
+ .listen(_processIncomingSharedMedia, onError: print);
// For sharing images coming from outside the app while the app is closed
- ReceiveSharingIntent.getInitialMedia().then(_processIncomingSharedFiles);
-
- // For sharing or opening urls/text coming from outside the app while the app is in the memory
- _intentDataStreamSubscription = ReceiveSharingIntent.getTextStream()
- .listen(_processIncomingSharedText, onError: print);
-
- // For sharing or opening urls/text coming from outside the app while the app is closed
- ReceiveSharingIntent.getInitialText().then(_processIncomingSharedText);
+ ReceiveSharingIntent.instance
+ .getInitialMedia()
+ .then(_processIncomingSharedMedia);
// For receiving shared Uris
_intentUriStreamSubscription = linkStream.listen(_processIncomingUris);
diff --git a/lib/utils/matrix_sdk_extensions/matrix_file_extension.dart b/lib/utils/matrix_sdk_extensions/matrix_file_extension.dart
index 648a0ca69e..9327632cb2 100644
--- a/lib/utils/matrix_sdk_extensions/matrix_file_extension.dart
+++ b/lib/utils/matrix_sdk_extensions/matrix_file_extension.dart
@@ -1,9 +1,9 @@
import 'dart:io';
-import 'package:file_selector/file_selector.dart';
import 'package:flutter/material.dart';
import 'package:file_picker/file_picker.dart';
+import 'package:file_selector/file_selector.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'package:share_plus/share_plus.dart';
diff --git a/pubspec.lock b/pubspec.lock
index 7725343a78..6e60615bf8 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -1630,10 +1630,10 @@ packages:
dependency: "direct main"
description:
name: receive_sharing_intent
- sha256: "912bebb551bce75a14098891fd750305b30d53eba0d61cc70cd9973be9866e8d"
+ sha256: ec76056e4d258ad708e76d85591d933678625318e411564dcb9059048ca3a593
url: "https://pub.dev"
source: hosted
- version: "1.4.5"
+ version: "1.8.1"
record:
dependency: "direct main"
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 9667542a41..8a4f4ba521 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -77,7 +77,7 @@ dependencies:
provider: ^6.0.2
punycode: ^1.0.0
qr_code_scanner: ^1.0.1
- receive_sharing_intent: 1.4.5 # Update needs more work
+ receive_sharing_intent: ^1.8.1
record: ^5.1.2
scroll_to_index: ^3.0.1
share_plus: ^10.0.2