From c8f05f44a688647eec324cfe5ae2bc51bcd9437c Mon Sep 17 00:00:00 2001 From: Matte23 Date: Tue, 22 Dec 2020 15:25:32 +0100 Subject: [PATCH] Add share sheet --- .../circolapp.xcodeproj/project.pbxproj | 8 +++- ios/circolapp/circolapp/URLUtils.swift | 9 ++++ .../circolapp/View/AttachmentView.swift | 33 ++++++-------- .../circolapp/View/CircularView.swift | 34 ++++++-------- ios/circolapp/circolapp/View/ShareSheet.swift | 44 +++++++++++++++++++ 5 files changed, 87 insertions(+), 41 deletions(-) create mode 100644 ios/circolapp/circolapp/View/ShareSheet.swift diff --git a/ios/circolapp/circolapp.xcodeproj/project.pbxproj b/ios/circolapp/circolapp.xcodeproj/project.pbxproj index b1f7ea5..bda50d9 100644 --- a/ios/circolapp/circolapp.xcodeproj/project.pbxproj +++ b/ios/circolapp/circolapp.xcodeproj/project.pbxproj @@ -36,6 +36,7 @@ 95CA31B7255C1EE000AC095B /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 95CA31B6255C1EE000AC095B /* Preview Assets.xcassets */; }; 95CA31C0255C28C300AC095B /* CircularView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95CA31BF255C28C300AC095B /* CircularView.swift */; }; 95DB71AB258A1C1500A78033 /* CarteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95DB71AA258A1C1500A78033 /* CarteView.swift */; }; + 95E58FBB2592195B00689C37 /* ShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95E58FBA2592195B00689C37 /* ShareSheet.swift */; }; 95F6666E2590D712006DE74F /* URLUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95F6666D2590D712006DE74F /* URLUtils.swift */; }; /* End PBXBuildFile section */ @@ -87,6 +88,7 @@ 95CA31B8255C1EE000AC095B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 95CA31BF255C28C300AC095B /* CircularView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircularView.swift; sourceTree = ""; }; 95DB71AA258A1C1500A78033 /* CarteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarteView.swift; sourceTree = ""; }; + 95E58FBA2592195B00689C37 /* ShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareSheet.swift; sourceTree = ""; }; 95F6666D2590D712006DE74F /* URLUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLUtils.swift; sourceTree = ""; }; 976621FBDDCA894FD23FBA8B /* Pods-circolapp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-circolapp.release.xcconfig"; path = "Target Support Files/Pods-circolapp/Pods-circolapp.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -137,8 +139,9 @@ 95CA31B1255C1EDE00AC095B /* ContentView.swift */, 95CA31BF255C28C300AC095B /* CircularView.swift */, 95BC3BF72572BCF900F24400 /* AttachmentView.swift */, - 9512D3C0257AB4F60023C3A1 /* NewReminderView.swift */, + 95E58FBA2592195B00689C37 /* ShareSheet.swift */, 955B7A0D257D098C0091B1F9 /* SearchBar.swift */, + 9512D3C0257AB4F60023C3A1 /* NewReminderView.swift */, 955B7A0F257D10A70091B1F9 /* ViewControllerResolver.swift */, 9554BDB7257E498F00D8925B /* OnboardingView.swift */, 954AF8F52588A5C300666D0C /* CircularList.swift */, @@ -190,12 +193,12 @@ 95CA31AF255C1EDE00AC095B /* AppDelegate.swift */, 952DEDDE2576F8DC001DF85D /* SceneDelegate.swift */, 954E683C2574ED9E0034EBA8 /* UserDefaultsExtensions.swift */, + 95F6666D2590D712006DE74F /* URLUtils.swift */, 953DDE7D2580312500C457CE /* LaunchScreen.storyboard */, 95CA31B8255C1EE000AC095B /* Info.plist */, 95906F4C257510370060F5D0 /* GoogleService-Info.plist */, 95906F47257506360060F5D0 /* Assets.xcassets */, 95CA31B5255C1EE000AC095B /* Preview Content */, - 95F6666D2590D712006DE74F /* URLUtils.swift */, ); path = circolapp; sourceTree = ""; @@ -375,6 +378,7 @@ 954E68352574E3890034EBA8 /* iOSServerApi.swift in Sources */, 95DB71AB258A1C1500A78033 /* CarteView.swift in Sources */, 950C1784258E582E00B2DBFE /* PadView.swift in Sources */, + 95E58FBB2592195B00689C37 /* ShareSheet.swift in Sources */, 954AF8F82588A5CF00666D0C /* FavouritesList.swift in Sources */, 954AF8F62588A5C300666D0C /* CircularList.swift in Sources */, 954AF8FD2588A61000666D0C /* FavouritesViewModel.swift in Sources */, diff --git a/ios/circolapp/circolapp/URLUtils.swift b/ios/circolapp/circolapp/URLUtils.swift index 16d2d59..19c8824 100644 --- a/ios/circolapp/circolapp/URLUtils.swift +++ b/ios/circolapp/circolapp/URLUtils.swift @@ -18,10 +18,19 @@ import Foundation import UIKit +import SwiftUI class URLUtils { static func openUrl(url: String) { guard let safeUrl = URL(string: url.addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed)!) else { return } UIApplication.shared.open(safeUrl) } + + static func shareSheetView(url: String) -> some View { + if let safeUrl = URL(string: url.addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed)!) { + return ShareSheet(activityItems: [safeUrl]) + } else { + return ShareSheet(activityItems: [url]) + } + } } diff --git a/ios/circolapp/circolapp/View/AttachmentView.swift b/ios/circolapp/circolapp/View/AttachmentView.swift index f6f937a..ee41fb2 100644 --- a/ios/circolapp/circolapp/View/AttachmentView.swift +++ b/ios/circolapp/circolapp/View/AttachmentView.swift @@ -20,6 +20,9 @@ import SwiftUI import Shared struct AttachmentView: View { + @State private var sharingPhone: Bool = false + @State private var sharingPad: Bool = false + var attachmentName: String var attachmentUrl: String @@ -43,34 +46,26 @@ struct AttachmentView: View { .buttonStyle(BorderlessButtonStyle()) Button(action: { - guard let url = URL(string: attachmentUrl) else { return } - - let downloadTask = URLSession.shared.downloadTask(with: url) { - urlOrNil, responseOrNil, errorOrNil in - - guard let fileURL = urlOrNil else { return } - do { - let documentsURL = try - FileManager.default.url(for: .documentDirectory, - in: .userDomainMask, - appropriateFor: nil, - create: false) - let savedURL = documentsURL.appendingPathComponent(fileURL.lastPathComponent) - try FileManager.default.moveItem(at: fileURL, to: savedURL) - } catch { - print ("file error: \(error)") - } + if UIDevice.current.userInterfaceIdiom == .phone { + sharingPhone = true + } else { + sharingPad = true } - downloadTask.resume() }) { - Image(systemName: "square.and.arrow.down.fill") + Image(systemName: "square.and.arrow.up.fill") .resizable() .scaledToFit() .frame(width: 20.0, height: 20.0) .padding(8.0) } .buttonStyle(BorderlessButtonStyle()) + .sheet(isPresented: $sharingPhone) { + URLUtils.shareSheetView(url: attachmentUrl) + } + .popover(isPresented: $sharingPad) { + URLUtils.shareSheetView(url: attachmentUrl) + } } } } diff --git a/ios/circolapp/circolapp/View/CircularView.swift b/ios/circolapp/circolapp/View/CircularView.swift index b319aba..b1d2a61 100644 --- a/ios/circolapp/circolapp/View/CircularView.swift +++ b/ios/circolapp/circolapp/View/CircularView.swift @@ -21,7 +21,10 @@ import Shared struct CircularView: View { @State private var creatingReminder: Bool = false + @State private var sharingPhone: Bool = false + @State private var sharingPad: Bool = false @State private var showDetail = false + var circular: Circular var body: some View { @@ -61,33 +64,24 @@ struct CircularView: View { Spacer() Button(action: { - guard let url = URL(string: circular.url) else { return } - - let downloadTask = URLSession.shared.downloadTask(with: url) { - urlOrNil, responseOrNil, errorOrNil in - - guard let fileURL = urlOrNil else { return } - do { - let documentsURL = try - FileManager.default.url(for: .documentDirectory, - in: .userDomainMask, - appropriateFor: nil, - create: false) - let savedURL = documentsURL.appendingPathComponent(fileURL.lastPathComponent) - try FileManager.default.moveItem(at: fileURL, to: savedURL) - } catch { - print ("file error: \(error)") - } + if UIDevice.current.userInterfaceIdiom == .phone { + sharingPhone = true + } else { + sharingPad = true } - - downloadTask.resume() }) { - Image(systemName: "square.and.arrow.down.fill") + Image(systemName: "square.and.arrow.up.fill") .resizable() .scaledToFit() .frame(width: 20.0, height: 20.0) } .buttonStyle(BorderlessButtonStyle()) + .sheet(isPresented: $sharingPhone) { + URLUtils.shareSheetView(url: circular.url) + } + .popover(isPresented: $sharingPad) { + URLUtils.shareSheetView(url: circular.url) + } Spacer() diff --git a/ios/circolapp/circolapp/View/ShareSheet.swift b/ios/circolapp/circolapp/View/ShareSheet.swift new file mode 100644 index 0000000..6f8ccc6 --- /dev/null +++ b/ios/circolapp/circolapp/View/ShareSheet.swift @@ -0,0 +1,44 @@ +/* + * Circolapp + * Copyright (C) 2019-2020 Matteo Schiff + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import Foundation +import UIKit +import SwiftUI + +struct ShareSheet: UIViewControllerRepresentable { + typealias Callback = (_ activityType: UIActivity.ActivityType?, _ completed: Bool, _ returnedItems: [Any]?, _ error: Error?) -> Void + + let activityItems: [Any] + let applicationActivities: [UIActivity]? = nil + let excludedActivityTypes: [UIActivity.ActivityType]? = nil + let callback: Callback? = nil + + func makeUIViewController(context: Context) -> UIActivityViewController { + let controller = UIActivityViewController( + activityItems: activityItems, + applicationActivities: applicationActivities) + controller.excludedActivityTypes = excludedActivityTypes + controller.completionWithItemsHandler = callback + controller.isModalInPresentation = true + return controller + } + + func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) { + // nothing to do here + } +}