diff --git a/ios/FluffyChat Share/Base.lproj/MainInterface.storyboard b/ios/FluffyChat Share/Base.lproj/MainInterface.storyboard
new file mode 100644
index 00000000..286a5089
--- /dev/null
+++ b/ios/FluffyChat Share/Base.lproj/MainInterface.storyboard
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/FluffyChat Share/FluffyChat Share.entitlements b/ios/FluffyChat Share/FluffyChat Share.entitlements
new file mode 100644
index 00000000..b6eb37e5
--- /dev/null
+++ b/ios/FluffyChat Share/FluffyChat Share.entitlements
@@ -0,0 +1,10 @@
+
+
+
+
+ com.apple.security.application-groups
+
+ group.com.famedly.app
+
+
+
diff --git a/ios/FluffyChat Share/Info.plist b/ios/FluffyChat Share/Info.plist
new file mode 100644
index 00000000..d3a136ec
--- /dev/null
+++ b/ios/FluffyChat Share/Info.plist
@@ -0,0 +1,52 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ FluffyChat Share
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ $(PRODUCT_BUNDLE_PACKAGE_TYPE)
+ CFBundleShortVersionString
+ $(MARKETING_VERSION)
+ CFBundleVersion
+ $(CURRENT_PROJECT_VERSION)
+ NSExtension
+
+ NSExtensionAttributes
+
+ NSExtensionActivationRule
+
+ NSExtensionActivationSupportsFileWithMaxCount
+ 1
+ NSExtensionActivationSupportsImageWithMaxCount
+ 1
+ NSExtensionActivationSupportsMovieWithMaxCount
+ 1
+ NSExtensionActivationSupportsText
+
+ NSExtensionActivationSupportsWebURLWithMaxCount
+ 1
+
+ PHSupportedMediaTypes
+
+ Video
+ Image
+
+
+ NSExtensionMainStoryboard
+ MainInterface
+ NSExtensionPointIdentifier
+ com.apple.share-services
+
+
+
diff --git a/ios/FluffyChat Share/ShareViewController.swift b/ios/FluffyChat Share/ShareViewController.swift
new file mode 100644
index 00000000..3cea3a79
--- /dev/null
+++ b/ios/FluffyChat Share/ShareViewController.swift
@@ -0,0 +1,335 @@
+import UIKit
+import Social
+import MobileCoreServices
+import Photos
+
+class ShareViewController: SLComposeServiceViewController {
+ // TODO: IMPORTANT: This should be your host app bundle identifier
+ let hostAppBundleIdentifier = "com.kasem.sharing"
+ 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!
+ }
+}
+
+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/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index a3537381..7134eee4 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -14,9 +14,22 @@
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
AB0F2865DE230DE37373E0E0 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50DEFC207B70632D9C56ED78 /* Pods_Runner.framework */; };
+ C1005C45261071B5002F4F32 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1005C44261071B5002F4F32 /* ShareViewController.swift */; };
+ C1005C48261071B5002F4F32 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C1005C46261071B5002F4F32 /* MainInterface.storyboard */; };
+ C1005C4C261071B5002F4F32 /* FluffyChat Share.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = C1005C42261071B5002F4F32 /* FluffyChat Share.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
C149567C25C7274F00A16396 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = C149567B25C7274F00A16396 /* GoogleService-Info.plist */; };
/* End PBXBuildFile section */
+/* Begin PBXContainerItemProxy section */
+ C1005C4A261071B5002F4F32 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 97C146E61CF9000F007C117D /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C1005C41261071B5002F4F32;
+ remoteInfo = "FluffyChat Share";
+ };
+/* End PBXContainerItemProxy section */
+
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
@@ -28,6 +41,17 @@
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
+ C1005C4D261071B5002F4F32 /* Embed App Extensions */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 13;
+ files = (
+ C1005C4C261071B5002F4F32 /* FluffyChat Share.appex in Embed App Extensions */,
+ );
+ name = "Embed App Extensions";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
@@ -47,6 +71,11 @@
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
9DB2F3524376810E74C799A8 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
+ C1005C42261071B5002F4F32 /* FluffyChat Share.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "FluffyChat Share.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
+ C1005C44261071B5002F4F32 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = ""; };
+ C1005C47261071B5002F4F32 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; };
+ C1005C49261071B5002F4F32 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ C1005C53261072D4002F4F32 /* FluffyChat Share.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "FluffyChat Share.entitlements"; 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 = ""; };
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 = ""; };
@@ -61,6 +90,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C1005C3F261071B5002F4F32 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@@ -88,6 +124,7 @@
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
+ C1005C43261071B5002F4F32 /* FluffyChat Share */,
97C146EF1CF9000F007C117D /* Products */,
E89DCAC000D371640E94E65B /* Pods */,
075EE1BE25359E34308E0B78 /* Frameworks */,
@@ -98,6 +135,7 @@
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
+ C1005C42261071B5002F4F32 /* FluffyChat Share.appex */,
);
name = Products;
sourceTree = "";
@@ -119,6 +157,17 @@
path = Runner;
sourceTree = "";
};
+ C1005C43261071B5002F4F32 /* FluffyChat Share */ = {
+ isa = PBXGroup;
+ children = (
+ C1005C53261072D4002F4F32 /* FluffyChat Share.entitlements */,
+ C1005C44261071B5002F4F32 /* ShareViewController.swift */,
+ C1005C46261071B5002F4F32 /* MainInterface.storyboard */,
+ C1005C49261071B5002F4F32 /* Info.plist */,
+ );
+ path = "FluffyChat Share";
+ sourceTree = "";
+ };
E89DCAC000D371640E94E65B /* Pods */ = {
isa = PBXGroup;
children = (
@@ -144,22 +193,42 @@
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
F9C8EE392B9AB471149C306E /* [CP] Embed Pods Frameworks */,
+ C1005C4D261071B5002F4F32 /* Embed App Extensions */,
);
buildRules = (
);
dependencies = (
+ C1005C4B261071B5002F4F32 /* PBXTargetDependency */,
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
+ C1005C41261071B5002F4F32 /* FluffyChat Share */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C1005C51261071B5002F4F32 /* Build configuration list for PBXNativeTarget "FluffyChat Share" */;
+ buildPhases = (
+ C1005C3E261071B5002F4F32 /* Sources */,
+ C1005C3F261071B5002F4F32 /* Frameworks */,
+ C1005C40261071B5002F4F32 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "FluffyChat Share";
+ productName = "FluffyChat Share";
+ productReference = C1005C42261071B5002F4F32 /* FluffyChat Share.appex */;
+ productType = "com.apple.product-type.app-extension";
+ };
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
+ LastSwiftUpdateCheck = 1240;
LastUpgradeCheck = 1020;
ORGANIZATIONNAME = "";
TargetAttributes = {
@@ -167,6 +236,9 @@
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
};
+ C1005C41261071B5002F4F32 = {
+ CreatedOnToolsVersion = 12.4;
+ };
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
@@ -183,6 +255,7 @@
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
+ C1005C41261071B5002F4F32 /* FluffyChat Share */,
);
};
/* End PBXProject section */
@@ -200,6 +273,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C1005C40261071B5002F4F32 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C1005C48261071B5002F4F32 /* MainInterface.storyboard in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
@@ -282,8 +363,24 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C1005C3E261071B5002F4F32 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C1005C45261071B5002F4F32 /* ShareViewController.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXSourcesBuildPhase section */
+/* Begin PBXTargetDependency section */
+ C1005C4B261071B5002F4F32 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C1005C41261071B5002F4F32 /* FluffyChat Share */;
+ targetProxy = C1005C4A261071B5002F4F32 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
@@ -301,6 +398,14 @@
name = LaunchScreen.storyboard;
sourceTree = "";
};
+ C1005C46261071B5002F4F32 /* MainInterface.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ C1005C47261071B5002F4F32 /* Base */,
+ );
+ name = MainInterface.storyboard;
+ sourceTree = "";
+ };
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
@@ -358,6 +463,7 @@
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;
@@ -496,6 +602,7 @@
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;
@@ -528,6 +635,7 @@
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;
@@ -555,6 +663,102 @@
};
name = Release;
};
+ C1005C4E261071B5002F4F32 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ 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 = "FluffyChat Share/FluffyChat Share.entitlements";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 0;
+ DEVELOPMENT_TEAM = 4NXF6Z997G;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = "FluffyChat Share/Info.plist";
+ IPHONEOS_DEPLOYMENT_TARGET = 14.4;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@executable_path/../../Frameworks",
+ );
+ MARKETING_VERSION = 0.28.0;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = "im.fluffychat.app.FluffyChat-Share";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ C1005C4F261071B5002F4F32 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ 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 = "FluffyChat Share/FluffyChat Share.entitlements";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 0;
+ DEVELOPMENT_TEAM = 4NXF6Z997G;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = "FluffyChat Share/Info.plist";
+ IPHONEOS_DEPLOYMENT_TARGET = 14.4;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@executable_path/../../Frameworks",
+ );
+ MARKETING_VERSION = 0.28.0;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = "im.fluffychat.app.FluffyChat-Share";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Release;
+ };
+ C1005C50261071B5002F4F32 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ 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 = "FluffyChat Share/FluffyChat Share.entitlements";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 0;
+ DEVELOPMENT_TEAM = 4NXF6Z997G;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = "FluffyChat Share/Info.plist";
+ IPHONEOS_DEPLOYMENT_TARGET = 14.4;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@executable_path/../../Frameworks",
+ );
+ MARKETING_VERSION = 0.28.0;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = "im.fluffychat.app.FluffyChat-Share";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Profile;
+ };
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@@ -578,6 +782,16 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ C1005C51261071B5002F4F32 /* Build configuration list for PBXNativeTarget "FluffyChat Share" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C1005C4E261071B5002F4F32 /* Debug */,
+ C1005C4F261071B5002F4F32 /* Release */,
+ C1005C50261071B5002F4F32 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 595592c6..e4ea89e7 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -22,6 +22,20 @@
$(FLUTTER_BUILD_NAME)
CFBundleSignature
????
+ CFBundleURLTypes
+
+
+ CFBundleTypeRole
+ Editor
+ CFBundleURLName
+ im.fluffychat.app.uris
+ CFBundleURLSchemes
+
+ ShareMedia
+ im.fluffychat
+
+
+
CFBundleVersion
$(FLUTTER_BUILD_NUMBER)
LSRequiresIPhoneOS
@@ -59,17 +73,6 @@
LaunchScreen
UIMainStoryboardFile
Main
- CFBundleURLTypes
-
-
- CFBundleTypeRole
- Editor
- CFBundleURLSchemes
-
- im.fluffychat
-
-
-
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
diff --git a/ios/Runner/Runner.entitlements b/ios/Runner/Runner.entitlements
index 903def2a..eb0b314e 100644
--- a/ios/Runner/Runner.entitlements
+++ b/ios/Runner/Runner.entitlements
@@ -4,5 +4,13 @@
aps-environment
development
+ com.apple.developer.associated-domains
+
+ applinks:example.com
+
+ com.apple.security.application-groups
+
+ group.com.famedly.app
+
diff --git a/lib/views/homeserver_picker.dart b/lib/views/homeserver_picker.dart
index 8b478fea..72a257db 100644
--- a/lib/views/homeserver_picker.dart
+++ b/lib/views/homeserver_picker.dart
@@ -104,9 +104,9 @@ class _HomeserverPickerState extends State {
.any((flow) => flow.type == AuthenticationTypes.sso)) {
final redirectUrl = kIsWeb
? html.window.location.href
- : '${Uri.encodeQueryComponent(AppConfig.appOpenUrlScheme.toLowerCase() + '://sso')}';
+ : AppConfig.appOpenUrlScheme.toLowerCase() + '://sso';
await launch(
- '${Matrix.of(context).client.homeserver?.toString()}/_matrix/client/r0/login/sso/redirect?redirectUrl=$redirectUrl');
+ '${Matrix.of(context).client.homeserver?.toString()}/_matrix/client/r0/login/sso/redirect?redirectUrl=${Uri.encodeQueryComponent(redirectUrl)}');
}
} catch (e) {
// ignore: unawaited_futures