From 2534292a461da48bd51ab616be333d2aac226dc4 Mon Sep 17 00:00:00 2001 From: Ahmed Hamdy Date: Sun, 24 Dec 2017 23:44:07 +0200 Subject: [PATCH 01/22] swift4 --- .../project.pbxproj | 29 ++++-- .../Base.lproj/Main.storyboard | 48 +++++----- .../DownloadsTableViewCell.swift | 4 +- .../DownloadsViewController.swift | 90 ++++++++++--------- Cheapjack.podspec | 41 +++++++++ Cheapjack.xcodeproj/project.pbxproj | 14 ++- .../xcshareddata/xcschemes/Cheapjack.xcscheme | 4 +- Cheapjack/CheapjackManager.swift | 1 + 8 files changed, 159 insertions(+), 72 deletions(-) create mode 100644 Cheapjack.podspec diff --git a/Cheapjack-Example/Cheapjack-Example.xcodeproj/project.pbxproj b/Cheapjack-Example/Cheapjack-Example.xcodeproj/project.pbxproj index 9e0084c..ad925b8 100644 --- a/Cheapjack-Example/Cheapjack-Example.xcodeproj/project.pbxproj +++ b/Cheapjack-Example/Cheapjack-Example.xcodeproj/project.pbxproj @@ -7,8 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 22CACEDC1B8FC577001F494B /* Cheapjack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22C573981B8E8D100088E47E /* Cheapjack.framework */; }; - 22CACEDD1B8FC577001F494B /* Cheapjack.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 22C573981B8E8D100088E47E /* Cheapjack.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; AEB1F8721A8B58C300D1CFE4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEB1F8711A8B58C300D1CFE4 /* AppDelegate.swift */; }; AEB1F8741A8B58C300D1CFE4 /* DownloadsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEB1F8731A8B58C300D1CFE4 /* DownloadsTableViewCell.swift */; }; AEB1F8771A8B58C300D1CFE4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AEB1F8751A8B58C300D1CFE4 /* Main.storyboard */; }; @@ -24,7 +22,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 22CACEDD1B8FC577001F494B /* Cheapjack.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -32,7 +29,6 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 22C573981B8E8D100088E47E /* Cheapjack.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; name = Cheapjack.framework; path = "/Users/tim/Library/Developer/Xcode/DerivedData/Cheapjack-bthxvoovdrtvkpagdjxxmufkwzaz/Build/Products/Debug-iphoneos/Cheapjack.framework"; sourceTree = ""; }; AEB1F86C1A8B58C300D1CFE4 /* Cheapjack-Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Cheapjack-Example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; AEB1F8701A8B58C300D1CFE4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; AEB1F8711A8B58C300D1CFE4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -48,7 +44,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 22CACEDC1B8FC577001F494B /* Cheapjack.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -58,7 +53,6 @@ AEB1F8631A8B58C300D1CFE4 = { isa = PBXGroup; children = ( - 22C573981B8E8D100088E47E /* Cheapjack.framework */, AEB1F86E1A8B58C300D1CFE4 /* Cheapjack-Example */, AEB1F86D1A8B58C300D1CFE4 /* Products */, ); @@ -122,7 +116,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0700; + LastUpgradeCheck = 0920; ORGANIZATIONNAME = "Gurpartap Singh"; TargetAttributes = { AEB1F86B1A8B58C300D1CFE4 = { @@ -208,13 +202,21 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -223,6 +225,7 @@ ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -240,6 +243,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -251,13 +255,21 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -265,6 +277,7 @@ ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -274,6 +287,8 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.2; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.0; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/Cheapjack-Example/Cheapjack-Example/Base.lproj/Main.storyboard b/Cheapjack-Example/Cheapjack-Example/Base.lproj/Main.storyboard index 8141374..87a5448 100644 --- a/Cheapjack-Example/Cheapjack-Example/Base.lproj/Main.storyboard +++ b/Cheapjack-Example/Cheapjack-Example/Base.lproj/Main.storyboard @@ -1,8 +1,13 @@ - - + + + + + - + + + @@ -14,52 +19,53 @@ - + - - + + - + + - - + @@ -91,7 +97,7 @@ - + @@ -102,7 +108,7 @@ - + @@ -119,7 +125,7 @@ - + diff --git a/Cheapjack-Example/Cheapjack-Example/DownloadsTableViewCell.swift b/Cheapjack-Example/Cheapjack-Example/DownloadsTableViewCell.swift index feabd3e..a22902d 100644 --- a/Cheapjack-Example/Cheapjack-Example/DownloadsTableViewCell.swift +++ b/Cheapjack-Example/Cheapjack-Example/DownloadsTableViewCell.swift @@ -47,7 +47,7 @@ class DownloadsTableViewCell: UITableViewCell { } @IBAction func actionButtonPressed(sender: UIButton) { - delegate?.actionButtonPressed(sender, inCell: self) + delegate?.actionButtonPressed(sender: sender, inCell: self) } override func prepareForReuse() { @@ -62,7 +62,7 @@ class DownloadsTableViewCell: UITableViewCell { // Both are necessary for changing title without undesired animation. actionButton?.titleLabel?.text = downloadItem.action.rawValue - actionButton?.setTitle(downloadItem.action.rawValue, forState: .Normal) + actionButton?.setTitle(downloadItem.action.rawValue, for: .normal) progressView?.progress = Float(downloadItem.progress) } diff --git a/Cheapjack-Example/Cheapjack-Example/DownloadsViewController.swift b/Cheapjack-Example/Cheapjack-Example/DownloadsViewController.swift index 876b504..a3eaa5b 100644 --- a/Cheapjack-Example/Cheapjack-Example/DownloadsViewController.swift +++ b/Cheapjack-Example/Cheapjack-Example/DownloadsViewController.swift @@ -54,8 +54,8 @@ class DownloadsTableViewCellItem { self.progress = 0 } - func url() -> NSURL { - return NSURL(string: urlString)! + func url() -> URL { + return URL(string: urlString)! } } @@ -71,30 +71,32 @@ class DownloadsViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() CheapjackManager.sharedManager.delegate = self + } @IBAction func addDownloadItem(sender: UIBarButtonItem) { - let identifier = NSUUID().UUIDString + let identifier = NSUUID().uuidString let urlString = "https://archive.org/download/testmp3testfile/mpthreetest.mp3" let downloadItem = DownloadsTableViewCellItem(identifier: identifier, urlString: urlString, infoLabelTitle: "mp3 test file from archive.org", stateLabelTitle: identifier, progressLabelTitle: "", action: DownloadsTableViewCellAction.Download) - addDownloadItem(downloadItem, withIdentifier: identifier) + addDownloadItem(downloadItem: downloadItem, withIdentifier: identifier) } func addDownloadItem(downloadItem: DownloadsTableViewCellItem, withIdentifier identifier: CheapjackFile.Identifier) { downloadItems[identifier] = downloadItem identifiers.append(identifier) - let indexPathToInsert = NSIndexPath(forRow: downloadItems.count-1, inSection: 0) - tableView.insertRowsAtIndexPaths([indexPathToInsert], withRowAnimation: UITableViewRowAnimation.Automatic) + + let indexPathToInsert = IndexPath(row: downloadItems.count-1, section: 0) + tableView.insertRows(at: [indexPathToInsert as IndexPath], with: UITableViewRowAnimation.automatic) } func removeDownloadItemWithIdentifier(identifier: CheapjackFile.Identifier) { - if let index = self.identifiers.indexOf(identifier) { - downloadItems.removeValueForKey(identifier) - identifiers.removeAtIndex(index) + if let index = self.identifiers.index(of: identifier) { + downloadItems.removeValue(forKey: identifier) + identifiers.remove(at: index) - let indexPathToDelete = NSIndexPath(forRow: index, inSection: 0) - tableView.deleteRowsAtIndexPaths([indexPathToDelete], withRowAnimation: UITableViewRowAnimation.Automatic) + let indexPathToDelete = IndexPath(row: index, section: 0) + tableView.deleteRows(at: [indexPathToDelete as IndexPath], with: UITableViewRowAnimation.automatic) } } @@ -107,12 +109,12 @@ extension DownloadsViewController: UITableViewDataSource { return 1 } - func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return identifiers.count } - func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCellWithIdentifier("DownloadsTableViewCellIdentifier") as! DownloadsTableViewCell + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "DownloadsTableViewCellIdentifier") as! DownloadsTableViewCell cell.delegate = self cell.downloadItem = downloadItems[identifiers[indexPath.row]] @@ -126,9 +128,13 @@ extension DownloadsViewController: UITableViewDataSource { extension DownloadsViewController: DownloadsTableViewCellDelegate { func actionButtonPressed(sender: UIButton, inCell cell: DownloadsTableViewCell) { + + + switch (sender.titleLabel?.text)! { case "Download": CheapjackManager.sharedManager.download(cell.downloadItem.url(), identifier: cell.downloadItem.identifier) + case "Pause": if CheapjackManager.sharedManager.pause(cell.downloadItem.identifier) { print("pausing") @@ -147,7 +153,7 @@ extension DownloadsViewController: DownloadsTableViewCellDelegate { } else { print("couldn't cancel") } - removeDownloadItemWithIdentifier(cell.downloadItem.identifier) + removeDownloadItemWithIdentifier(identifier: cell.downloadItem.identifier) default: break } @@ -157,34 +163,36 @@ extension DownloadsViewController: DownloadsTableViewCellDelegate { extension DownloadsViewController: CheapjackDelegate { + - func cheapjackManager(manager: CheapjackManager, didChangeState from: CheapjackFile.State, to: CheapjackFile.State, forFile file: CheapjackFile) { - dispatch_async(dispatch_get_main_queue()) { - if let index = self.identifiers.indexOf(file.identifier) { - let indexPath = NSIndexPath(forItem: index, inSection: 0) - if let cell = self.tableView.cellForRowAtIndexPath(indexPath) as? DownloadsTableViewCell { + + func cheapjackManager(_ manager: CheapjackManager, didChangeState from: CheapjackFile.State, to: CheapjackFile.State, forFile file: CheapjackFile) { + DispatchQueue.main.async() { + if let index = self.identifiers.index(of: file.identifier) { + let indexPath = IndexPath(row: index, section: 0) + if let cell = self.tableView.cellForRow(at: indexPath as IndexPath) as? DownloadsTableViewCell { switch to { - case .Waiting: + case .waiting: self.downloadItems[file.identifier]?.stateLabelTitle = "Waiting..." self.downloadItems[file.identifier]?.action = DownloadsTableViewCellAction.Pause break - case .Downloading: + case .downloading: self.downloadItems[file.identifier]?.stateLabelTitle = "Downloading..." self.downloadItems[file.identifier]?.action = DownloadsTableViewCellAction.Pause break - case .Paused: + case .paused: self.downloadItems[file.identifier]?.stateLabelTitle = "Paused" self.downloadItems[file.identifier]?.action = DownloadsTableViewCellAction.Resume break - case .Finished: + case .finished: self.downloadItems[file.identifier]?.stateLabelTitle = "Finished" self.downloadItems[file.identifier]?.action = DownloadsTableViewCellAction.Remove break - case .Cancelled: + case .cancelled: self.downloadItems[file.identifier]?.stateLabelTitle = "Cancelled" self.downloadItems[file.identifier]?.action = DownloadsTableViewCellAction.Download break - case .Unknown: + case .unknown: self.downloadItems[file.identifier]?.stateLabelTitle = "Unknown" self.downloadItems[file.identifier]?.action = DownloadsTableViewCellAction.Download break @@ -197,13 +205,13 @@ extension DownloadsViewController: CheapjackDelegate { } } - func cheapjackManager(manager: CheapjackManager, didUpdateProgress progress: Double, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64, forFile file: CheapjackFile) { - dispatch_async(dispatch_get_main_queue()) { - if let index = self.identifiers.indexOf(file.identifier) { - let indexPath = NSIndexPath(forItem: index, inSection: 0) - if let cell = self.tableView.cellForRowAtIndexPath(indexPath) as? DownloadsTableViewCell { - let formattedWrittenBytes = NSByteCountFormatter.stringFromByteCount(totalBytesWritten, countStyle: .File) - let formattedTotalBytes = NSByteCountFormatter.stringFromByteCount(totalBytesExpectedToWrite, countStyle: .File) + func cheapjackManager(_ manager: CheapjackManager, didUpdateProgress progress: Double, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64, forFile file: CheapjackFile) { + DispatchQueue.main.async() { + if let index = self.identifiers.index(of: file.identifier) { + let indexPath = IndexPath(row: index, section: 0) + if let cell = self.tableView.cellForRow(at: indexPath as IndexPath) as? DownloadsTableViewCell { + let formattedWrittenBytes = ByteCountFormatter.string(fromByteCount: totalBytesWritten, countStyle: .file) + let formattedTotalBytes = ByteCountFormatter.string(fromByteCount: totalBytesExpectedToWrite, countStyle: .file) self.downloadItems[file.identifier]?.progressLabelTitle = "\(Int(progress * 100))% - \(formattedWrittenBytes) of \(formattedTotalBytes)" self.downloadItems[file.identifier]?.progress = progress cell.downloadItem = self.downloadItems[file.identifier] @@ -212,13 +220,15 @@ extension DownloadsViewController: CheapjackDelegate { } } - func cheapjackManager(manager: CheapjackManager, didReceiveError error: NSError?) { - dispatch_async(dispatch_get_main_queue()) { + func cheapjackManager(_ manager: CheapjackManager, didReceiveError error: NSError?) { + DispatchQueue.main.async() { } } - func cheapjackManager(manager: CheapjackManager, didFinishDownloading withSession: NSURLSession, downloadTask: NSURLSessionDownloadTask, url: NSURL, forFile file: CheapjackFile) { + func cheapjackManager(_ manager: CheapjackManager, didFinishDownloading withSession: URLSession, downloadTask: URLSessionDownloadTask, url: URL, forFile file: CheapjackFile) { + + print(file.url) } @@ -227,14 +237,14 @@ extension DownloadsViewController: CheapjackDelegate { extension DownloadsViewController: CheapjackFileDelegate { - func cheapjackFile(file: CheapjackFile, didChangeState from: CheapjackFile.State, to: CheapjackFile.State) { - dispatch_async(dispatch_get_main_queue()) { + func cheapjackFile(_ file: CheapjackFile, didChangeState from: CheapjackFile.State, to: CheapjackFile.State) { + DispatchQueue.main.async() { } } - func cheapjackFile(file: CheapjackFile, didUpdateProgress progress: Double, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { - dispatch_async(dispatch_get_main_queue()) { + func cheapjackFile(_ file: CheapjackFile, didUpdateProgress progress: Double, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { + DispatchQueue.main.async() { } } diff --git a/Cheapjack.podspec b/Cheapjack.podspec new file mode 100644 index 0000000..faa31a2 --- /dev/null +++ b/Cheapjack.podspec @@ -0,0 +1,41 @@ +# +# Be sure to run `pod lib lint Cheapjack.podspec' to ensure this is a +# valid spec before submitting. +# +# Any lines starting with a # are optional, but their use is encouraged +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# + +Pod::Spec.new do |s| + s.name = 'Cheapjack' + s.version = '0.1.0' + s.summary = 'Cheapjack is a download manager providing an interface over NSURLSessionDownloadTask' + +# This description is used to generate tags and improve search results. +# * Think: What does it do? Why did you write it? What is the focus? +# * Try to keep it short, snappy and to the point. +# * Write the description between the DESC delimiters below. +# * Finally, don't worry about the indent, CocoaPods strips it! + + s.description = " Cheapjack is a download manager providing an interface over NSURLSessionDownloadTask for managing multiple, simultaneous downloads with easier control over resuming, etc." + + + s.homepage = 'https://github.com/dimohamdy/Cheapjack' + # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' + s.license = { :type => 'MIT', :file => 'LICENSE' } + s.author = { 'dimohamdy' => 'dimo.hamdy@gmail.com' } + s.source = { :git => 'https://github.com/dimohamdy/Cheapjack.git', :tag => s.version.to_s } + # s.social_media_url = 'https://twitter.com/' + + s.ios.deployment_target = '8.0' + + s.source_files = 'Cheapjack/*' + + # s.resource_bundles = { + # 'Cheapjack' => ['Cheapjack/Assets/*.png'] + # } + + # s.public_header_files = 'Pod/Classes/**/*.h' + # s.frameworks = 'UIKit', 'MapKit' + # s.dependency 'AFNetworking', '~> 2.3' +end diff --git a/Cheapjack.xcodeproj/project.pbxproj b/Cheapjack.xcodeproj/project.pbxproj index fce6d85..4cf9b3d 100644 --- a/Cheapjack.xcodeproj/project.pbxproj +++ b/Cheapjack.xcodeproj/project.pbxproj @@ -165,7 +165,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 0920; ORGANIZATIONNAME = "Gurpartap Singh"; TargetAttributes = { AEB1F8461A8B57FE00D1CFE4 = { @@ -249,14 +249,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -299,14 +305,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; diff --git a/Cheapjack.xcodeproj/xcshareddata/xcschemes/Cheapjack.xcscheme b/Cheapjack.xcodeproj/xcshareddata/xcschemes/Cheapjack.xcscheme index 512b6f7..f9134ab 100644 --- a/Cheapjack.xcodeproj/xcshareddata/xcschemes/Cheapjack.xcscheme +++ b/Cheapjack.xcodeproj/xcshareddata/xcschemes/Cheapjack.xcscheme @@ -1,6 +1,6 @@ @@ -36,6 +37,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/Cheapjack/CheapjackManager.swift b/Cheapjack/CheapjackManager.swift index e13f2c3..523cb5a 100644 --- a/Cheapjack/CheapjackManager.swift +++ b/Cheapjack/CheapjackManager.swift @@ -191,6 +191,7 @@ extension CheapjackManager: URLSessionDownloadDelegate { public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { if let file = files[downloadTask.taskDescription!] { file.setState(.finished) + print(file.url.absoluteString) delegate?.cheapjackManager(self, didFinishDownloading: session, downloadTask: downloadTask, url: location, forFile: file) if let didFinishDownloadingBlock = didFinishDownloadingBlock { didFinishDownloadingBlock(session, downloadTask, location, file) From 2b7517904533e3338c4feeb24786613e7d8d29d8 Mon Sep 17 00:00:00 2001 From: Ahmed Hamdy Date: Sun, 24 Dec 2017 23:52:48 +0200 Subject: [PATCH 02/22] Update Cheapjack.podspec --- Cheapjack.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cheapjack.podspec b/Cheapjack.podspec index faa31a2..f62b6d6 100644 --- a/Cheapjack.podspec +++ b/Cheapjack.podspec @@ -29,7 +29,7 @@ Pod::Spec.new do |s| s.ios.deployment_target = '8.0' - s.source_files = 'Cheapjack/*' + s.source_files = 'Cheapjack/*.*' # s.resource_bundles = { # 'Cheapjack' => ['Cheapjack/Assets/*.png'] From 36ba95fc8ef07f96bc8cc4e5ff58fcd30d6bba21 Mon Sep 17 00:00:00 2001 From: Ahmed Hamdy Date: Tue, 16 Jan 2018 11:59:04 +0200 Subject: [PATCH 03/22] save resume data to nsuserdefault --- Cheapjack/CheapjackFile.swift | 138 +++++++++++++++++++++++++------ Cheapjack/CheapjackManager.swift | 36 ++++++-- 2 files changed, 141 insertions(+), 33 deletions(-) diff --git a/Cheapjack/CheapjackFile.swift b/Cheapjack/CheapjackFile.swift index 9a997a0..0dc0baf 100644 --- a/Cheapjack/CheapjackFile.swift +++ b/Cheapjack/CheapjackFile.swift @@ -10,7 +10,7 @@ import Foundation public protocol CheapjackFileDelegate: class { - func cheapjackFile(_ file: CheapjackFile, didChangeState from: CheapjackFile.State, to: CheapjackFile.State) + func cheapjackFile(_ file: CheapjackFile, didChangeState from: State, to: State) func cheapjackFile(_ file: CheapjackFile, didUpdateProgress progress: Double, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) } @@ -20,10 +20,10 @@ public func ==(lhs: CheapjackFile, rhs: CheapjackFile) -> Bool { } -extension CheapjackFile.State: Equatable { +extension State: Equatable { } -public func ==(lhs: CheapjackFile.State, rhs: CheapjackFile.State) -> Bool { +public func ==(lhs: State, rhs: State) -> Bool { switch (lhs, rhs) { case (let .paused(data1), let .paused(data2)): return data1 == data2 @@ -45,12 +45,13 @@ public func ==(lhs: CheapjackFile.State, rhs: CheapjackFile.State) -> Bool { } -open class CheapjackFile: Equatable { - + +open class CheapjackFile:Equatable,Codable { + // A listener may implement either of delegate and blocks. open class Listener { - public typealias DidChangeStateBlock = (_ from: CheapjackFile.State, _ to: CheapjackFile.State) -> (Void) + public typealias DidChangeStateBlock = (_ from: State, _ to: State) -> (Void) public typealias DidUpdateProgressBlock = (_ progress: Double, _ totalBytesWritten: Int64, _ totalBytesExpectedToWrite: Int64) -> (Void) @@ -65,29 +66,46 @@ open class CheapjackFile: Equatable { } } - - - // File states default to .Unknown - public enum State { - case unknown - case waiting - case downloading - case paused(Data) - case finished - case cancelled - case failed + private enum CodingKeys: String, CodingKey { + case identifier ,url,state,lastState,totalBytesWritten,totalBytesExpectedToWrite + + } + + required public init(from decoder: Decoder) throws + { + let values = try decoder.container(keyedBy: CodingKeys.self) + identifier = try values.decode(String.self, forKey: .identifier) + url = try values.decode(URL.self, forKey: .url) + state = try values.decode(State.self, forKey: .state) + lastState = try values.decode(State.self, forKey: .lastState) + totalBytesWritten = try values.decode(Int64.self, forKey: .totalBytesWritten) + totalBytesExpectedToWrite = try values.decode(Int64.self, forKey: .totalBytesExpectedToWrite) + + } + public func encode(to encoder: Encoder) throws + { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(identifier, forKey: .identifier) + try container.encode(url, forKey: .url) + try container.encode(state, forKey: .state) + try container.encode(lastState, forKey: .lastState) + try container.encode(totalBytesWritten, forKey: .totalBytesWritten) + try container.encode(totalBytesExpectedToWrite, forKey: .totalBytesExpectedToWrite) + + + } public typealias Identifier = String // MARK: - CheapjackFile public properties - internal weak var manager: CheapjackManager? - open var identifier: CheapjackFile.Identifier - open var url: URL - open var request: URLRequest + internal weak var manager: CheapjackManager? = nil + open var identifier: CheapjackFile.Identifier = "" + open var url: URL? = nil + open var request: URLRequest? = nil open var progress: Double { if totalBytesExpectedToWrite > 0 { @@ -101,8 +119,8 @@ open class CheapjackFile: Equatable { // MARK: - CheapjackFile public read-only properties - open fileprivate(set) var lastState: CheapjackFile.State - open fileprivate(set) var state: CheapjackFile.State { + open fileprivate(set) var lastState: State = .unknown + open fileprivate(set) var state: State { willSet { lastState = state } @@ -110,7 +128,7 @@ open class CheapjackFile: Equatable { notifyChangeStateListeners() } } - open fileprivate(set) var totalBytesExpectedToWrite: Int64 + open fileprivate(set) var totalBytesExpectedToWrite: Int64 = 0 open fileprivate(set) var totalBytesWritten: Int64 { didSet { notifyUpdateProgressListeners() @@ -119,8 +137,8 @@ open class CheapjackFile: Equatable { // MARK: - CheapjackFile private properties - internal var listeners: [CheapjackFile.Listener] - internal var downloadTask: URLSessionDownloadTask? + internal var listeners: [CheapjackFile.Listener] = [CheapjackFile.Listener]() + internal var downloadTask: URLSessionDownloadTask? = nil // MARK: - Initializers @@ -148,7 +166,7 @@ open class CheapjackFile: Equatable { listeners.append(listener) } - internal func setState(_ to: CheapjackFile.State) { + internal func setState(_ to: State) { state = to } @@ -199,3 +217,69 @@ open class CheapjackFile: Equatable { } } + +// File states default to .Unknown +public enum State { + case unknown + case waiting + case downloading + case paused(Data) + case finished + case cancelled + case failed +} +extension State: Codable { + private enum CodingKeys: String, CodingKey { + case base, pausedData + } + private enum Base: String, Codable { + case unknown,waiting,failed,cancelled, downloading, finished, paused + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + let base = try container.decode(Base.self, forKey: .base) + + switch base { + case .cancelled: + self = .cancelled + case .downloading: + self = .downloading + case .finished: + self = .finished + case .paused: + let pausedData = try container.decode(Data.self, forKey: .pausedData) + self = .paused(pausedData) + case .unknown: + self = .unknown + case .waiting: + self = .waiting + case .failed: + self = .failed + + } + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + switch self { + case .cancelled: + try container.encode(Base.cancelled, forKey: .base) + case .downloading: + try container.encode(Base.downloading, forKey: .base) + case .finished: + try container.encode(Base.finished, forKey: .base) + case .paused(let data): + try container.encode(Base.paused, forKey: .base) + try container.encode(data, forKey: .pausedData) + case .unknown: + try container.encode(Base.unknown, forKey: .base) + case .waiting: + try container.encode(Base.waiting, forKey: .base) + case .failed: + try container.encode(Base.failed, forKey: .base) + + } + } +} diff --git a/Cheapjack/CheapjackManager.swift b/Cheapjack/CheapjackManager.swift index 523cb5a..a911a8a 100644 --- a/Cheapjack/CheapjackManager.swift +++ b/Cheapjack/CheapjackManager.swift @@ -10,7 +10,7 @@ import Foundation public protocol CheapjackDelegate: class { - func cheapjackManager(_ manager: CheapjackManager, didChangeState from: CheapjackFile.State, to: CheapjackFile.State, forFile file: CheapjackFile) + func cheapjackManager(_ manager: CheapjackManager, didChangeState from: State, to: State, forFile file: CheapjackFile) func cheapjackManager(_ manager: CheapjackManager, didUpdateProgress progress: Double, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64, forFile file: CheapjackFile) func cheapjackManager(_ manager: CheapjackManager, didReceiveError error: NSError?) func cheapjackManager(_ manager: CheapjackManager, didFinishDownloading withSession: URLSession, downloadTask: URLSessionDownloadTask, url: URL, forFile file: CheapjackFile) @@ -110,14 +110,17 @@ extension CheapjackManager { file.manager = self files[file.identifier] = file - + print(file.state) switch file.state { case .paused(let data): file.setState(.waiting) file.downloadTask = backgroundSession.downloadTask(withResumeData: data) default: file.setState(.waiting) - file.downloadTask = backgroundSession.downloadTask(with: file.request) + if file.request == nil { + file.request = URLRequest(url: file.url!) + } + file.downloadTask = backgroundSession.downloadTask(with: file.request!) } file.downloadTask?.taskDescription = file.identifier file.downloadTask?.resume() @@ -149,6 +152,7 @@ extension CheapjackManager { extension CheapjackManager { public func resumeAll() { + restoredDownloadItems() for file in files.values { resume(file) } @@ -158,6 +162,9 @@ extension CheapjackManager { for file in files.values { pause(file) } + + storeDemoDownloadItems() + } public func cancelAll() { @@ -166,6 +173,22 @@ extension CheapjackManager { } } + + func storeDemoDownloadItems() { + print(files.values.first?.state) + + try? UserDefaults.standard.set(PropertyListEncoder().encode(files), forKey: "downloadItems") + + } + + func restoredDownloadItems() { + + let encoded = UserDefaults.standard.object(forKey: "downloadItems") as! Data + files = try! PropertyListDecoder().decode([CheapjackFile.Identifier: CheapjackFile].self, from: encoded) + print(files.values.first?.state) + + } + } @@ -174,7 +197,7 @@ extension CheapjackManager { files.removeValue(forKey: identifier) } - public func remove(_ filesWithState: CheapjackFile.State) { + public func remove(_ filesWithState: State) { var filesCopy = files for (identifier, file) in filesCopy { if file.state != filesWithState { @@ -191,7 +214,7 @@ extension CheapjackManager: URLSessionDownloadDelegate { public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { if let file = files[downloadTask.taskDescription!] { file.setState(.finished) - print(file.url.absoluteString) + print(file.url?.absoluteString) delegate?.cheapjackManager(self, didFinishDownloading: session, downloadTask: downloadTask, url: location, forFile: file) if let didFinishDownloadingBlock = didFinishDownloadingBlock { didFinishDownloadingBlock(session, downloadTask, location, file) @@ -206,7 +229,7 @@ extension CheapjackManager: URLSessionDownloadDelegate { public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { if let file = files[downloadTask.taskDescription!] { - if file.state != CheapjackFile.State.downloading { + if file.state != State.downloading { file.setState(.downloading) } @@ -247,3 +270,4 @@ extension CheapjackManager: URLSessionTaskDelegate { } } + From e664aa75fd892b859eb6c446737387c4304c7e96 Mon Sep 17 00:00:00 2001 From: Ahmed Hamdy Date: Tue, 16 Jan 2018 15:47:02 +0200 Subject: [PATCH 04/22] pause and resume using saved data in user default --- .../project.pbxproj | 18 +++++++- .../Base.lproj/Main.storyboard | 6 +++ .../DownloadsViewController.swift | 27 ++++++++++-- Cheapjack/CheapjackManager.swift | 43 +++++++++++++------ 4 files changed, 75 insertions(+), 19 deletions(-) diff --git a/Cheapjack-Example/Cheapjack-Example.xcodeproj/project.pbxproj b/Cheapjack-Example/Cheapjack-Example.xcodeproj/project.pbxproj index ad925b8..e0b90b8 100644 --- a/Cheapjack-Example/Cheapjack-Example.xcodeproj/project.pbxproj +++ b/Cheapjack-Example/Cheapjack-Example.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 3D96EC05200D16B7008B217C /* Cheapjack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D96EC06200D16B7008B217C /* Cheapjack.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; AEB1F8721A8B58C300D1CFE4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEB1F8711A8B58C300D1CFE4 /* AppDelegate.swift */; }; AEB1F8741A8B58C300D1CFE4 /* DownloadsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEB1F8731A8B58C300D1CFE4 /* DownloadsTableViewCell.swift */; }; AEB1F8771A8B58C300D1CFE4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AEB1F8751A8B58C300D1CFE4 /* Main.storyboard */; }; @@ -29,6 +30,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 3D96EC04200D10A0008B217C /* Cheapjack.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Cheapjack.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 3D96EC06200D16B7008B217C /* Cheapjack.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Cheapjack.framework; sourceTree = BUILT_PRODUCTS_DIR; }; AEB1F86C1A8B58C300D1CFE4 /* Cheapjack-Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Cheapjack-Example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; AEB1F8701A8B58C300D1CFE4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; AEB1F8711A8B58C300D1CFE4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -44,17 +47,28 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 3D96EC05200D16B7008B217C /* Cheapjack.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 3D96EC02200D10A0008B217C /* Frameworks */ = { + isa = PBXGroup; + children = ( + 3D96EC06200D16B7008B217C /* Cheapjack.framework */, + 3D96EC04200D10A0008B217C /* Cheapjack.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; AEB1F8631A8B58C300D1CFE4 = { isa = PBXGroup; children = ( AEB1F86E1A8B58C300D1CFE4 /* Cheapjack-Example */, AEB1F86D1A8B58C300D1CFE4 /* Products */, + 3D96EC02200D10A0008B217C /* Frameworks */, ); sourceTree = ""; }; @@ -121,7 +135,7 @@ TargetAttributes = { AEB1F86B1A8B58C300D1CFE4 = { CreatedOnToolsVersion = 6.2; - DevelopmentTeam = AHKVBQHP6Z; + DevelopmentTeam = 7QH458A3QD; SystemCapabilities = { com.apple.BackgroundModes = { enabled = 1; @@ -299,6 +313,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEVELOPMENT_TEAM = 7QH458A3QD; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/Cheapjack-cbvlnqogbdcjbubhsnbenbjlkvsi/Build/Products/Debug-iphoneos", @@ -318,6 +333,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEVELOPMENT_TEAM = 7QH458A3QD; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/Cheapjack-cbvlnqogbdcjbubhsnbenbjlkvsi/Build/Products/Debug-iphoneos", diff --git a/Cheapjack-Example/Cheapjack-Example/Base.lproj/Main.storyboard b/Cheapjack-Example/Cheapjack-Example/Base.lproj/Main.storyboard index 87a5448..69b8610 100644 --- a/Cheapjack-Example/Cheapjack-Example/Base.lproj/Main.storyboard +++ b/Cheapjack-Example/Cheapjack-Example/Base.lproj/Main.storyboard @@ -106,6 +106,11 @@ + + + + + @@ -113,6 +118,7 @@ + diff --git a/Cheapjack-Example/Cheapjack-Example/DownloadsViewController.swift b/Cheapjack-Example/Cheapjack-Example/DownloadsViewController.swift index a3eaa5b..957f4eb 100644 --- a/Cheapjack-Example/Cheapjack-Example/DownloadsViewController.swift +++ b/Cheapjack-Example/Cheapjack-Example/DownloadsViewController.swift @@ -71,16 +71,35 @@ class DownloadsViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() CheapjackManager.sharedManager.delegate = self - + pause.title = "pasue" } @IBAction func addDownloadItem(sender: UIBarButtonItem) { let identifier = NSUUID().uuidString - let urlString = "https://archive.org/download/testmp3testfile/mpthreetest.mp3" + let urlString = "https://web.whatsapp.com/desktop/mac/files/WhatsApp.dmg" let downloadItem = DownloadsTableViewCellItem(identifier: identifier, urlString: urlString, infoLabelTitle: "mp3 test file from archive.org", stateLabelTitle: identifier, progressLabelTitle: "", action: DownloadsTableViewCellAction.Download) addDownloadItem(downloadItem: downloadItem, withIdentifier: identifier) } + @IBOutlet weak var pause: UIBarButtonItem! + var current = "pasue" + @IBAction func pasueDownlaod(_ sender: UIBarButtonItem) { + if current == "pasue"{ + //pasue all + CheapjackManager.sharedManager.pauseAll() + + current = "resume" + pause.title = "resume" + + }else{ + //resume all + + CheapjackManager.sharedManager.resumeAll() + current = "pasue" + pause.title = "pasue" + + } + } func addDownloadItem(downloadItem: DownloadsTableViewCellItem, withIdentifier identifier: CheapjackFile.Identifier) { downloadItems[identifier] = downloadItem identifiers.append(identifier) @@ -166,7 +185,7 @@ extension DownloadsViewController: CheapjackDelegate { - func cheapjackManager(_ manager: CheapjackManager, didChangeState from: CheapjackFile.State, to: CheapjackFile.State, forFile file: CheapjackFile) { + func cheapjackManager(_ manager: CheapjackManager, didChangeState from: State, to: State, forFile file: CheapjackFile) { DispatchQueue.main.async() { if let index = self.identifiers.index(of: file.identifier) { let indexPath = IndexPath(row: index, section: 0) @@ -237,7 +256,7 @@ extension DownloadsViewController: CheapjackDelegate { extension DownloadsViewController: CheapjackFileDelegate { - func cheapjackFile(_ file: CheapjackFile, didChangeState from: CheapjackFile.State, to: CheapjackFile.State) { + func cheapjackFile(_ file: CheapjackFile, didChangeState from: State, to: State) { DispatchQueue.main.async() { } diff --git a/Cheapjack/CheapjackManager.swift b/Cheapjack/CheapjackManager.swift index a911a8a..8bfb37e 100644 --- a/Cheapjack/CheapjackManager.swift +++ b/Cheapjack/CheapjackManager.swift @@ -130,6 +130,8 @@ extension CheapjackManager { file.downloadTask?.cancel(byProducingResumeData: { resumeDataOrNil in if let data = resumeDataOrNil { file.setState(.paused(data)) + //save download item + self.storeDownloadItem(file: file) print("paused") } else { file.setState(.cancelled) @@ -152,7 +154,7 @@ extension CheapjackManager { extension CheapjackManager { public func resumeAll() { - restoredDownloadItems() + files = restoredDownloadItems() for file in files.values { resume(file) } @@ -162,9 +164,7 @@ extension CheapjackManager { for file in files.values { pause(file) } - - storeDemoDownloadItems() - + storeDownloadItems() } public func cancelAll() { @@ -173,20 +173,35 @@ extension CheapjackManager { } } + func storeDownloadItem(file:CheapjackFile) { + try? UserDefaults.standard.set(PropertyListEncoder().encode(file), forKey: file.identifier) + + } + func restoredDownloadItem(identifier:CheapjackFile.Identifier) -> CheapjackFile { + + let encoded = UserDefaults.standard.object(forKey: identifier) as! Data + let file = try! PropertyListDecoder().decode(CheapjackFile.self, from: encoded) + return file + } - func storeDemoDownloadItems() { - print(files.values.first?.state) - - try? UserDefaults.standard.set(PropertyListEncoder().encode(files), forKey: "downloadItems") - + func storeDownloadItems() { + //save the identifiers of files + try? UserDefaults.standard.set(PropertyListEncoder().encode(Array(files.keys)), forKey: "downloadItemKeys") } - func restoredDownloadItems() { - - let encoded = UserDefaults.standard.object(forKey: "downloadItems") as! Data - files = try! PropertyListDecoder().decode([CheapjackFile.Identifier: CheapjackFile].self, from: encoded) - print(files.values.first?.state) + func restoredDownloadItems() -> [CheapjackFile.Identifier:CheapjackFile] { + let encoded = UserDefaults.standard.object(forKey: "downloadItemKeys") as! Data + let filesKeys:[CheapjackFile.Identifier] = try! PropertyListDecoder().decode([CheapjackFile.Identifier].self, from: encoded) + + var savedFiles:[CheapjackFile.Identifier:CheapjackFile] = [CheapjackFile.Identifier:CheapjackFile]() + + for key in filesKeys { + let encoded = UserDefaults.standard.object(forKey: key) as! Data + let file = try! PropertyListDecoder().decode(CheapjackFile.self, from: encoded) + savedFiles[key] = file + } + return savedFiles } } From 1cc4e271f095b9d341cda79d29f21c699aa73c62 Mon Sep 17 00:00:00 2001 From: Ahmed Hamdy Date: Tue, 16 Jan 2018 15:49:48 +0200 Subject: [PATCH 05/22] change text of button --- .../Cheapjack-Example/DownloadsViewController.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cheapjack-Example/Cheapjack-Example/DownloadsViewController.swift b/Cheapjack-Example/Cheapjack-Example/DownloadsViewController.swift index 957f4eb..8a0850d 100644 --- a/Cheapjack-Example/Cheapjack-Example/DownloadsViewController.swift +++ b/Cheapjack-Example/Cheapjack-Example/DownloadsViewController.swift @@ -82,21 +82,21 @@ class DownloadsViewController: UIViewController { } @IBOutlet weak var pause: UIBarButtonItem! - var current = "pasue" + var current = "pasue all" @IBAction func pasueDownlaod(_ sender: UIBarButtonItem) { - if current == "pasue"{ + if current == "pasue all"{ //pasue all CheapjackManager.sharedManager.pauseAll() - current = "resume" - pause.title = "resume" + current = "resume all" + pause.title = "resume all" }else{ //resume all CheapjackManager.sharedManager.resumeAll() - current = "pasue" - pause.title = "pasue" + current = "pasue all" + pause.title = "pasue all" } } From 3a64604210ab5c6fea08389ad771104c365f693f Mon Sep 17 00:00:00 2001 From: Ahmed Hamdy Date: Tue, 16 Jan 2018 15:58:29 +0200 Subject: [PATCH 06/22] Update README.md --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2650e21..fb4f024 100644 --- a/README.md +++ b/README.md @@ -72,10 +72,19 @@ class ViewController: UIViewController { * iOS 8.1 SDK+ * Xcode 6.1+ + +### Installation + +**CocoaPods:** + +Add the line `pod "Cheapjack"` to your `Podfile` + ##### Manual Installation + + ```sh -git clone https://github.com/Gurpartap/Cheapjack.git +git clone https://github.com/dimohamdy/Cheapjack.git cd Cheapjack ``` From 7b98891f100c9300e72c0e5f274fae26ad0fe11b Mon Sep 17 00:00:00 2001 From: Ahmed Hamdy Date: Sun, 28 Jan 2018 12:46:41 +0200 Subject: [PATCH 07/22] Update Cheapjack.podspec --- Cheapjack.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cheapjack.podspec b/Cheapjack.podspec index f62b6d6..732a992 100644 --- a/Cheapjack.podspec +++ b/Cheapjack.podspec @@ -27,7 +27,7 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/dimohamdy/Cheapjack.git', :tag => s.version.to_s } # s.social_media_url = 'https://twitter.com/' - s.ios.deployment_target = '8.0' + s.ios.deployment_target = '10.0' s.source_files = 'Cheapjack/*.*' From 6cb2df57257ef23f557cc6900430ec079f0eb167 Mon Sep 17 00:00:00 2001 From: Ahmed Hamdy Date: Sun, 28 Jan 2018 19:32:51 +0200 Subject: [PATCH 08/22] change access of listeners change listeners and addListener to open --- Cheapjack/CheapjackFile.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cheapjack/CheapjackFile.swift b/Cheapjack/CheapjackFile.swift index 0dc0baf..e77d51f 100644 --- a/Cheapjack/CheapjackFile.swift +++ b/Cheapjack/CheapjackFile.swift @@ -137,7 +137,7 @@ open class CheapjackFile:Equatable,Codable { // MARK: - CheapjackFile private properties - internal var listeners: [CheapjackFile.Listener] = [CheapjackFile.Listener]() + open var listeners: [CheapjackFile.Listener] = [CheapjackFile.Listener]() internal var downloadTask: URLSessionDownloadTask? = nil @@ -162,7 +162,7 @@ open class CheapjackFile:Equatable,Codable { // MARK: - CheapjackFile private setter methods - fileprivate func addListener(_ listener: CheapjackFile.Listener) { + public func addListener(_ listener: CheapjackFile.Listener) { listeners.append(listener) } From c5de3fdd8d16f241794eb365b8e9c21424129996 Mon Sep 17 00:00:00 2001 From: Ahmed Hamdy Date: Mon, 29 Jan 2018 13:33:11 +0200 Subject: [PATCH 09/22] add file name and directory name when download --- .../project.pbxproj | 8 ++-- .../Base.lproj/Main.storyboard | 9 ++-- .../DownloadsViewController.swift | 5 +- Cheapjack.xcodeproj/project.pbxproj | 4 +- Cheapjack/CheapjackFile.swift | 34 ++++++++------ Cheapjack/CheapjackManager.swift | 47 +++++++++++++++---- 6 files changed, 74 insertions(+), 33 deletions(-) diff --git a/Cheapjack-Example/Cheapjack-Example.xcodeproj/project.pbxproj b/Cheapjack-Example/Cheapjack-Example.xcodeproj/project.pbxproj index e0b90b8..6ab51da 100644 --- a/Cheapjack-Example/Cheapjack-Example.xcodeproj/project.pbxproj +++ b/Cheapjack-Example/Cheapjack-Example.xcodeproj/project.pbxproj @@ -252,7 +252,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.2; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -298,7 +298,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.2; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -319,7 +319,7 @@ "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/Cheapjack-cbvlnqogbdcjbubhsnbenbjlkvsi/Build/Products/Debug-iphoneos", ); INFOPLIST_FILE = "Cheapjack-Example/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.gurpartap.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -339,7 +339,7 @@ "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/Cheapjack-cbvlnqogbdcjbubhsnbenbjlkvsi/Build/Products/Debug-iphoneos", ); INFOPLIST_FILE = "Cheapjack-Example/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.gurpartap.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/Cheapjack-Example/Cheapjack-Example/Base.lproj/Main.storyboard b/Cheapjack-Example/Cheapjack-Example/Base.lproj/Main.storyboard index 69b8610..18acf5f 100644 --- a/Cheapjack-Example/Cheapjack-Example/Base.lproj/Main.storyboard +++ b/Cheapjack-Example/Cheapjack-Example/Base.lproj/Main.storyboard @@ -33,8 +33,8 @@ -