Skip to content

Commit

Permalink
Fix #2333. Handle export in Mac App (#2334)
Browse files Browse the repository at this point in the history
  • Loading branch information
chenilim committed Feb 15, 2022
1 parent 57071c0 commit fdcbc45
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 71 deletions.
8 changes: 6 additions & 2 deletions mac/Focalboard.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
8014951C261598D600A51700 /* PortUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8014951B261598D600A51700 /* PortUtils.swift */; };
804E57FC27441B6B008526F0 /* whatsnew.txt in Resources */ = {isa = PBXBuildFile; fileRef = 804E57FB27441B6B008526F0 /* whatsnew.txt */; };
80672A8B27BAFEBA00257B8C /* DownloadHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80672A8A27BAFEBA00257B8C /* DownloadHandler.swift */; };
80D6DEBB252E13CB00AEED9E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80D6DEBA252E13CB00AEED9E /* AppDelegate.swift */; };
80D6DEBD252E13CB00AEED9E /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80D6DEBC252E13CB00AEED9E /* ViewController.swift */; };
80D6DEBF252E13CD00AEED9E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 80D6DEBE252E13CD00AEED9E /* Assets.xcassets */; };
Expand Down Expand Up @@ -42,6 +43,7 @@
/* Begin PBXFileReference section */
8014951B261598D600A51700 /* PortUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PortUtils.swift; sourceTree = "<group>"; };
804E57FB27441B6B008526F0 /* whatsnew.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = whatsnew.txt; sourceTree = "<group>"; };
80672A8A27BAFEBA00257B8C /* DownloadHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadHandler.swift; sourceTree = "<group>"; };
80D6DEB7252E13CB00AEED9E /* Focalboard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Focalboard.app; sourceTree = BUILT_PRODUCTS_DIR; };
80D6DEBA252E13CB00AEED9E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
80D6DEBC252E13CB00AEED9E /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -116,6 +118,7 @@
80F8BF572624EB0C00FF3943 /* Globals.swift */,
8014951B261598D600A51700 /* PortUtils.swift */,
80D6DEBC252E13CB00AEED9E /* ViewController.swift */,
80672A8A27BAFEBA00257B8C /* DownloadHandler.swift */,
80F174B62788C1A2000A9EEA /* CustomWKWebView.swift */,
80F8BF4F2624E1BB00FF3943 /* WhatsNewViewController.swift */,
804E57FB27441B6B008526F0 /* whatsnew.txt */,
Expand Down Expand Up @@ -303,6 +306,7 @@
80F8BF502624E1BB00FF3943 /* WhatsNewViewController.swift in Sources */,
80F174B72788C1A2000A9EEA /* CustomWKWebView.swift in Sources */,
80F8BF582624EB0C00FF3943 /* Globals.swift in Sources */,
80672A8B27BAFEBA00257B8C /* DownloadHandler.swift in Sources */,
80D6DF18252F9BDE00AEED9E /* AutoSaveWindowController.swift in Sources */,
80D6DEBD252E13CB00AEED9E /* ViewController.swift in Sources */,
80D6DEBB252E13CB00AEED9E /* AppDelegate.swift in Sources */,
Expand Down Expand Up @@ -403,7 +407,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MACOSX_DEPLOYMENT_TARGET = 11.3;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
Expand Down Expand Up @@ -458,7 +462,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MACOSX_DEPLOYMENT_TARGET = 11.3;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
Expand Down
40 changes: 40 additions & 0 deletions mac/Focalboard/DownloadHandler.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import Foundation
import WebKit

class DownloadHandler: NSObject, WKDownloadDelegate {
func download(_ download: WKDownload, decideDestinationUsing response: URLResponse, suggestedFilename: String, completionHandler: @escaping (URL?) -> Void) {
DispatchQueue.main.async {
// Let user select location of file
let savePanel = NSSavePanel()
savePanel.canCreateDirectories = true
savePanel.nameFieldStringValue = suggestedFilename
// BUGBUG: Specifying the allowedFileTypes causes Catalina to hang / error out
//savePanel.allowedFileTypes = [".boardsarchive"]
savePanel.begin { (result) in
if result.rawValue == NSApplication.ModalResponse.OK.rawValue,
let fileUrl = savePanel.url {
if (FileManager.default.fileExists(atPath: fileUrl.path)) {
// HACKHACK: WKWebView doesn't appear to overwrite files, so delete exsiting files first
do {
try FileManager.default.removeItem(at: fileUrl)
} catch {
let alert = NSAlert()
alert.messageText = "Unable to replace \(fileUrl.path)"
alert.addButton(withTitle: "OK")
alert.alertStyle = .warning
alert.runModal()
}
}
completionHandler(fileUrl)
}
}
}
}

func downloadDidFinish(_ download: WKDownload) {
NSLog("downloadDidFinish")
}
}
93 changes: 24 additions & 69 deletions mac/Focalboard/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class ViewController:
@IBOutlet var webView: CustomWKWebView!
private var didLoad = false
private var refreshWebViewOnLoad = true
private let downloadHandler = DownloadHandler()

override func viewDidLoad() {
super.viewDidLoad()
Expand Down Expand Up @@ -100,60 +101,6 @@ class ViewController:
webView.load(request)
}

private func downloadJsonUrl(_ url: URL) {
NSLog("downloadJsonUrl")
let prefix = "data:text/json,"
let urlString = url.absoluteString
let encodedJson = String(urlString[urlString.index(urlString.startIndex, offsetBy: prefix.lengthOfBytes(using: .utf8))...])
guard let json = encodedJson.removingPercentEncoding else {
return
}

// Form file name
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-M-d"
let dateString = dateFormatter.string(from: Date())
let filename = "archive-\(dateString).focalboard"

// Save file
let savePanel = NSSavePanel()
savePanel.canCreateDirectories = true
savePanel.nameFieldStringValue = filename
// BUGBUG: Specifying the allowedFileTypes causes Catalina to hang / error out
//savePanel.allowedFileTypes = [".focalboard"]
savePanel.begin { (result) in
if result.rawValue == NSApplication.ModalResponse.OK.rawValue,
let fileUrl = savePanel.url {
try? json.write(to: fileUrl, atomically: true, encoding: .utf8)
}
}
}

private func downloadCsvUrl(_ url: URL) {
NSLog("downloadCsvUrl")
let prefix = "data:text/csv;charset=utf-8,"
let urlString = url.absoluteString
let encodedContents = String(urlString[urlString.index(urlString.startIndex, offsetBy: prefix.lengthOfBytes(using: .utf8))...])
guard let contents = encodedContents.removingPercentEncoding else {
return
}

let filename = "data.csv"

// Save file
let savePanel = NSSavePanel()
savePanel.canCreateDirectories = true
savePanel.nameFieldStringValue = filename
// BUGBUG: Specifying the allowedFileTypes causes Catalina to hang / error out
//savePanel.allowedFileTypes = [".focalboard"]
savePanel.begin { (result) in
if result.rawValue == NSApplication.ModalResponse.OK.rawValue,
let fileUrl = savePanel.url {
try? contents.write(to: fileUrl, atomically: true, encoding: .utf8)
}
}
}

func webView(_ webView: WKWebView, runOpenPanelWith parameters: WKOpenPanelParameters, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping ([URL]?) -> Void) {
NSLog("webView runOpenPanel")
let openPanel = NSOpenPanel()
Expand All @@ -169,22 +116,30 @@ class ViewController:
}
}

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if let url = navigationAction.request.url {
// Intercept archive downloads, and present native UI
if (url.absoluteString.hasPrefix("data:text/json,")) {
decisionHandler(.cancel)
downloadJsonUrl(url)
return
}
if (url.absoluteString.hasPrefix("data:text/csv;charset=utf-8,")) {
decisionHandler(.cancel)
downloadCsvUrl(url)
return
}
NSLog("decidePolicyFor navigationAction: \(url.absoluteString)")
// Handle downloads

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, preferences: WKWebpagePreferences, decisionHandler: @escaping (WKNavigationActionPolicy, WKWebpagePreferences) -> Void) {
if navigationAction.shouldPerformDownload {
decisionHandler(.download, preferences)
} else {
decisionHandler(.allow, preferences)
}
decisionHandler(.allow)
}

func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
if navigationResponse.canShowMIMEType {
decisionHandler(.allow)
} else {
decisionHandler(.download)
}
}

func webView(_ webView: WKWebView, navigationAction: WKNavigationAction, didBecome download: WKDownload) {
download.delegate = downloadHandler
}

func webView(_ webView: WKWebView, navigationResponse: WKNavigationResponse, didBecome download: WKDownload) {
download.delegate = downloadHandler
}

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
Expand Down

0 comments on commit fdcbc45

Please sign in to comment.