From 35605ba89f8075ce699adba99a7fb56d8f4fdcc3 Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Wed, 10 Apr 2019 15:27:18 +0200 Subject: [PATCH] Download resource with progress HUD --- Passepartout-iOS/Global/Downloader.swift | 101 ++++++++++++++++++ .../Scenes/ServiceViewController.swift | 11 +- Passepartout.xcodeproj/project.pbxproj | 4 + 3 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 Passepartout-iOS/Global/Downloader.swift diff --git a/Passepartout-iOS/Global/Downloader.swift b/Passepartout-iOS/Global/Downloader.swift new file mode 100644 index 00000000..dd879794 --- /dev/null +++ b/Passepartout-iOS/Global/Downloader.swift @@ -0,0 +1,101 @@ +// +// Downloader.swift +// Passepartout-iOS +// +// Created by Davide De Rosa on 4/10/19. +// Copyright (c) 2019 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout 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. +// +// Passepartout 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 Passepartout. If not, see . +// + +import Foundation +import MBProgressHUD +import SwiftyBeaver +import Passepartout_Core + +private let log = SwiftyBeaver.self + +class Downloader: NSObject { + static let shared = Downloader(temporaryURL: GroupConstants.App.cachesURL.appendingPathComponent("downloaded.tmp")) + + private let temporaryURL: URL + + private var hud: MBProgressHUD? + + private var completionHandler: ((URL?, Error?) -> Void)? + + init(temporaryURL: URL) { + self.temporaryURL = temporaryURL + } + + func download(url: URL, in view: UIView, completionHandler: @escaping (URL?, Error?) -> Void) -> Bool { + guard hud == nil else { + log.info("Download in progress, skipping") + return false + } + + log.info("Downloading from: \(url)") + let session = URLSession(configuration: .default, delegate: self, delegateQueue: .main) + let request = URLRequest(url: url, cachePolicy: .reloadIgnoringCacheData, timeoutInterval: AppConstants.Web.timeout) + let task = session.downloadTask(with: request) + + hud = MBProgressHUD.showAdded(to: view, animated: true) + hud?.mode = .annularDeterminate + hud?.progressObject = task.progress + + self.completionHandler = completionHandler + task.resume() + return true + } +} + +extension Downloader: URLSessionDelegate, URLSessionDownloadDelegate { + func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { + if let error = error { + log.error("Download failed: \(error)") + hud?.hide(animated: true) + hud = nil + completionHandler?(nil, error) + completionHandler = nil + return + } + completionHandler = nil + } + + func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { + log.info("Download complete!") + if let url = downloadTask.originalRequest?.url { + log.info("\tFrom: \(url)") + } + log.debug("\tTo: \(location)") + + let fm = FileManager.default + do { + try? fm.removeItem(at: temporaryURL) + try fm.copyItem(at: location, to: temporaryURL) + } catch let e { + log.error("Failed to copy downloaded file: \(e)") + return + } + + hud?.hide(animated: true) + hud = nil + completionHandler?(temporaryURL, nil) + completionHandler = nil + } +} diff --git a/Passepartout-iOS/Scenes/ServiceViewController.swift b/Passepartout-iOS/Scenes/ServiceViewController.swift index 369622c6..d190d897 100644 --- a/Passepartout-iOS/Scenes/ServiceViewController.swift +++ b/Passepartout-iOS/Scenes/ServiceViewController.swift @@ -26,6 +26,7 @@ import UIKit import NetworkExtension import CoreTelephony +import MBProgressHUD import TunnelKit import Passepartout_Core @@ -460,13 +461,17 @@ class ServiceViewController: UIViewController, TableModelHost { ) alert.addCancelAction(L10n.Global.cancel) alert.addDefaultAction(L10n.Global.ok) { - - // FIXME: start external download - print(downloadURL) + self.confirmDownload(URL(string: downloadURL)!) } present(alert, animated: true, completion: nil) } + private func confirmDownload(_ url: URL) { + _ = Downloader.shared.download(url: url, in: view) { (url, error) in + // FIXME: handle downloaded resource into current infrastructure + } + } + // MARK: Notifications @objc private func vpnDidUpdate() { diff --git a/Passepartout.xcodeproj/project.pbxproj b/Passepartout.xcodeproj/project.pbxproj index 81b8d6ab..4d76924d 100644 --- a/Passepartout.xcodeproj/project.pbxproj +++ b/Passepartout.xcodeproj/project.pbxproj @@ -106,6 +106,7 @@ 0EDE8DC420C86910004C739C /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDE8DC320C86910004C739C /* PacketTunnelProvider.swift */; }; 0EDE8DC820C86910004C739C /* Passepartout-Tunnel.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 0EDE8DBF20C86910004C739C /* Passepartout-Tunnel.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 0EE3BBB2215ED3A900F30952 /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE3BBB1215ED3A900F30952 /* AboutViewController.swift */; }; + 0EEB53B2225D525B00746300 /* Downloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB53B1225D525B00746300 /* Downloader.swift */; }; 0EF56BBB2185AC8500B0C8AB /* SwiftGen+Segues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF56BBA2185AC8500B0C8AB /* SwiftGen+Segues.swift */; }; 0EF5CF252141CE58004FF1BD /* HUD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF5CF242141CE58004FF1BD /* HUD.swift */; }; 0EF5CF292141F31F004FF1BD /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E4FD7ED20D539A0002221FF /* Utils.swift */; }; @@ -276,6 +277,7 @@ 0EDE8DE620C93945004C739C /* Credentials.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Credentials.swift; sourceTree = ""; }; 0EDE8DED20C93E4C004C739C /* GroupConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupConstants.swift; sourceTree = ""; }; 0EE3BBB1215ED3A900F30952 /* AboutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = ""; }; + 0EEB53B1225D525B00746300 /* Downloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Downloader.swift; sourceTree = ""; }; 0EF56BBA2185AC8500B0C8AB /* SwiftGen+Segues.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SwiftGen+Segues.swift"; sourceTree = ""; }; 0EF5CF242141CE58004FF1BD /* HUD.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HUD.swift; sourceTree = ""; }; 0EFBFAC021AC464800887A8C /* CreditsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreditsViewController.swift; sourceTree = ""; }; @@ -547,6 +549,7 @@ 0EDE8DEC20C93E3B004C739C /* Global */ = { isa = PBXGroup; children = ( + 0EEB53B1225D525B00746300 /* Downloader.swift */, 0EF5CF242141CE58004FF1BD /* HUD.swift */, 0E24273F225951B00064A1A3 /* InApp.swift */, 0EFD943D215BE10800529B64 /* IssueReporter.swift */, @@ -1065,6 +1068,7 @@ 0ECC60DE2256B68A0020BEAC /* SwiftGen+Assets.swift in Sources */, 0E242742225956AC0064A1A3 /* DonationViewController.swift in Sources */, 0ED38AEC2141260D0004D387 /* ConfigurationModificationDelegate.swift in Sources */, + 0EEB53B2225D525B00746300 /* Downloader.swift in Sources */, 0ECEE45020E1182E00A6BB43 /* Theme+Cells.swift in Sources */, 0E242740225951B00064A1A3 /* InApp.swift in Sources */, 0E1066C920E0F84A004F98B7 /* Cells.swift in Sources */,