Skip to content

Commit

Permalink
Merge pull request #729 from kiwix/180-export-and-share-article-featu…
Browse files Browse the repository at this point in the history
…re-request

180 export and share article feature request
  • Loading branch information
kelson42 authored Apr 19, 2024
2 parents 7b88cb9 + cb2d3aa commit 5eb6868
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 22 deletions.
1 change: 1 addition & 0 deletions App/App_iOS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ struct Kiwix: App {
.environmentObject(navigation)
.modifier(AlertHandler())
.modifier(OpenFileHandler())
.modifier(SharePDFHandler())
.modifier(SaveContentHandler())
.onChange(of: scenePhase) { newValue in
guard newValue == .inactive else { return }
Expand Down
2 changes: 2 additions & 0 deletions App/CompactViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ private struct CompactView: View {
Spacer()
BookmarkButton()
Spacer()
ShareButton()
Spacer()
TabsManagerButton()
if FeatureFlags.hasLibrary {
Spacer()
Expand Down
13 changes: 13 additions & 0 deletions Model/Utilities/URL.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,17 @@ extension URL {
init(appStoreReviewForName appName: String, appStoreID: String) {
self.init(string: "itms-apps://itunes.apple.com/us/app/\(appName)/\(appStoreID)?action=write-review")!
}

init(temporaryFileWithName fileName: String) {
let directory = FileManager.default.temporaryDirectory
if #available(macOS 13.0, iOS 16.0, *) {
self = directory.appending(path: fileName)
} else {
self = directory.appendingPathComponent(fileName)
}
}

func toTemporaryFileURL() -> URL? {
URL(temporaryFileWithName: lastPathComponent)
}
}
5 changes: 5 additions & 0 deletions SwiftUI/Patches.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ extension Notification.Name {
static let alert = Notification.Name("alert")
static let openFiles = Notification.Name("openFiles")
static let openURL = Notification.Name("openURL")
static let sharePDF = Notification.Name("sharePDF")
static let saveContent = Notification.Name("saveContent")
static let toggleSidebar = Notification.Name("toggleSidebar")
}
Expand All @@ -89,6 +90,10 @@ extension NotificationCenter {
NotificationCenter.default.post(name: .openFiles, object: nil, userInfo: ["urls": urls, "context": context])
}

static func sharePDF(_ data: Data, fileName: String) {
NotificationCenter.default.post(name: .sharePDF, object: nil, userInfo: ["data": data, "fileName": fileName])
}

static func saveContent(url: URL) {
NotificationCenter.default.post(name: .saveContent, object: nil, userInfo: ["url": url])
}
Expand Down
38 changes: 38 additions & 0 deletions Views/ActivityViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// This file is part of Kiwix for iOS & macOS.
//
// Kiwix 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
// any later version.
//
// Kiwix 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 Kiwix; If not, see https://www.gnu.org/licenses/.

import SwiftUI

#if os(iOS)
struct ActivityViewController: UIViewControllerRepresentable {

@Environment(\.dismiss) var dismissAction
var activityItems: [Any]

func makeUIViewController(
context: UIViewControllerRepresentableContext<ActivityViewController>
) -> UIActivityViewController {
let controller = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
controller.modalPresentationStyle = .pageSheet
controller.completionWithItemsHandler = { (_, _, _, _) in
self.dismissAction()
}
return controller
}

func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) {
}
}
#endif
1 change: 1 addition & 0 deletions Views/BrowserTab.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ struct BrowserTab: View {
#endif
ToolbarItemGroup(placement: .primaryAction) {
OutlineButton()
ShareButton()
BookmarkButton()
ArticleShortcutButtons(displayMode: .mainAndRandomArticle)
}
Expand Down
56 changes: 56 additions & 0 deletions Views/Buttons/ShareButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// This file is part of Kiwix for iOS & macOS.
//
// Kiwix 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
// any later version.
//
// Kiwix 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 Kiwix; If not, see https://www.gnu.org/licenses/.

import SwiftUI

struct ShareButton: View {

@EnvironmentObject private var browser: BrowserViewModel

private func dataAndName() async -> (Data, String)? {
guard let browserURLName = browser.webView.url?.lastPathComponent else {
return nil
}
guard let pdfData = try? await browser.webView.pdf() else {
return nil
}
return (pdfData, browserURLName)
}

private func tempFileURL() async -> URL? {
guard let (pdfData, browserURLName) = await dataAndName() else { return nil }
return PDFHandler.tempFileFrom(pdfData: pdfData, fileName: browserURLName)
}

var body: some View {
Button {
Task {
#if os(iOS)
guard let (pdfData, browserURLName) = await dataAndName() else { return }
NotificationCenter.sharePDF(pdfData, fileName: browserURLName)
#else
guard let url = await tempFileURL() else { return }
NSSharingServicePicker(items: [url]).show(relativeTo: .null, of: browser.webView, preferredEdge: .minY)
#endif
}
} label: {
Label {
Text("Share".localized)
} icon: {
Image(systemName: "square.and.arrow.up")
}
}.disabled(browser.zimFileName.isEmpty)
}
}
22 changes: 0 additions & 22 deletions Views/ViewModifiers/SaveContentHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,28 +93,6 @@ struct SaveContentHandler: ViewModifier {
#endif
}

#if os(iOS)
struct ActivityViewController: UIViewControllerRepresentable {

var activityItems: [Any]
@Environment(\.dismiss) var dismissAction
func makeUIViewController(
context: UIViewControllerRepresentableContext<ActivityViewController>
) -> UIActivityViewController {
let controller = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
controller.modalPresentationStyle = .pageSheet
controller.completionWithItemsHandler = { (_, _, _, _) in
self.dismissAction()
}
return controller
}

func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) {
}
}

#endif

extension URL {
fileprivate func tempFileURL() -> URL? {
let directory = FileManager.default.temporaryDirectory
Expand Down
63 changes: 63 additions & 0 deletions Views/ViewModifiers/SharePDFHandler.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// This file is part of Kiwix for iOS & macOS.
//
// Kiwix 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
// any later version.
//
// Kiwix 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 Kiwix; If not, see https://www.gnu.org/licenses/.

import SwiftUI

enum PDFHandler {
static func tempFileFrom(pdfData: Data, fileName: String) -> URL? {
guard let tempFileName = fileName.split(separator: ".").first?.appending(".pdf") else {
return nil
}
let tempFileURL = URL(temporaryFileWithName: tempFileName)
guard (try? pdfData.write(to: tempFileURL)) != nil else {
return nil
}
return tempFileURL
}
}

#if os(iOS)
/// On receiving pdf content and a file name, it gives the ability to share it
struct SharePDFHandler: ViewModifier {

private let sharePDF = NotificationCenter.default.publisher(for: .sharePDF)
@State private var temporaryURL: URL?

func body(content: Content) -> some View {
content.onReceive(sharePDF) { notification in

guard let userInfo = notification.userInfo,
let pdfData = userInfo["data"] as? Data,
let fileName = userInfo["fileName"] as? String,
let tempURL = PDFHandler.tempFileFrom(pdfData: pdfData, fileName: fileName) else {
temporaryURL = nil
return
}
temporaryURL = tempURL
}
.sheet(
isPresented: Binding<Bool>.constant($temporaryURL.wrappedValue != nil),
onDismiss: {
if let temporaryURL {
try? FileManager.default.removeItem(at: temporaryURL)
}
temporaryURL = nil
}, content: {
ActivityViewController(activityItems: [temporaryURL].compactMap { $0 })
}
)
}
}
#endif

0 comments on commit 5eb6868

Please sign in to comment.