diff --git a/Cheapjack-Example/Cheapjack-Example.xcodeproj/project.pbxproj b/Cheapjack-Example/Cheapjack-Example.xcodeproj/project.pbxproj index 9e0084c..6ab51da 100644 --- a/Cheapjack-Example/Cheapjack-Example.xcodeproj/project.pbxproj +++ b/Cheapjack-Example/Cheapjack-Example.xcodeproj/project.pbxproj @@ -7,8 +7,7 @@ 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, ); }; }; + 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 */; }; @@ -24,7 +23,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 22CACEDD1B8FC577001F494B /* Cheapjack.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -32,7 +30,8 @@ /* 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 = ""; }; + 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 = ""; }; @@ -48,19 +47,28 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 22CACEDC1B8FC577001F494B /* Cheapjack.framework in Frameworks */, + 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 = ( - 22C573981B8E8D100088E47E /* Cheapjack.framework */, AEB1F86E1A8B58C300D1CFE4 /* Cheapjack-Example */, AEB1F86D1A8B58C300D1CFE4 /* Products */, + 3D96EC02200D10A0008B217C /* Frameworks */, ); sourceTree = ""; }; @@ -122,12 +130,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0700; + LastUpgradeCheck = 0920; ORGANIZATIONNAME = "Gurpartap Singh"; TargetAttributes = { AEB1F86B1A8B58C300D1CFE4 = { CreatedOnToolsVersion = 6.2; - DevelopmentTeam = AHKVBQHP6Z; + DevelopmentTeam = 7QH458A3QD; SystemCapabilities = { com.apple.BackgroundModes = { enabled = 1; @@ -208,13 +216,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 +239,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", @@ -235,11 +252,12 @@ 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; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -251,13 +269,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,15 +291,18 @@ 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; 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"; + SWIFT_VERSION = 4.0; VALIDATE_PRODUCT = YES; }; name = Release; @@ -284,12 +313,13 @@ 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", ); 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)"; @@ -303,12 +333,13 @@ 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", ); 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 8141374..18acf5f 100644 --- a/Cheapjack-Example/Cheapjack-Example/Base.lproj/Main.storyboard +++ b/Cheapjack-Example/Cheapjack-Example/Base.lproj/Main.storyboard @@ -1,8 +1,13 @@ - - + + + + + - + + + @@ -14,61 +19,65 @@ - + - - + + - + + - + + - + + + @@ -91,7 +100,7 @@ - + @@ -100,13 +109,19 @@ + + + + + - + + @@ -119,7 +134,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..889454f 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)! } } @@ -70,31 +70,55 @@ class DownloadsViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() + + } + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) 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 identifier = NSUUID().uuidString + 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, withIdentifier: identifier) + addDownloadItem(downloadItem: downloadItem, withIdentifier: identifier) } + @IBOutlet weak var pause: UIBarButtonItem! + var current = "pasue all" + @IBAction func pasueDownlaod(_ sender: UIBarButtonItem) { + if current == "pasue all"{ + //pasue all + CheapjackManager.sharedManager.pauseAll() + + current = "resume all" + pause.title = "resume all" + + }else{ + //resume all + + CheapjackManager.sharedManager.resumeAll() + current = "pasue all" + pause.title = "pasue all" + + } + } 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 +131,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 +150,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 +175,7 @@ extension DownloadsViewController: DownloadsTableViewCellDelegate { } else { print("couldn't cancel") } - removeDownloadItemWithIdentifier(cell.downloadItem.identifier) + removeDownloadItemWithIdentifier(identifier: cell.downloadItem.identifier) default: break } @@ -157,34 +185,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: 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) + 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 +227,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 +242,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 +259,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: State, to: 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..732a992 --- /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 = '10.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..cb73a7f 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; @@ -346,7 +358,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Cheapjack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.gurpartap.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -368,7 +380,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Cheapjack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.gurpartap.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; 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/CheapjackFile.swift b/Cheapjack/CheapjackFile.swift index 9a997a0..36097d2 100644 --- a/Cheapjack/CheapjackFile.swift +++ b/Cheapjack/CheapjackFile.swift @@ -10,7 +10,8 @@ import Foundation public protocol CheapjackFileDelegate: class { - func cheapjackFile(_ file: CheapjackFile, didChangeState from: CheapjackFile.State, to: CheapjackFile.State) + var identifier: Int { get} + func cheapjackFile(_ file: CheapjackFile, didChangeState from: State, to: State) func cheapjackFile(_ file: CheapjackFile, didUpdateProgress progress: Double, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) } @@ -20,10 +21,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 +46,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) @@ -64,30 +66,50 @@ open class CheapjackFile: Equatable { self.didUpdateProgressBlock = didUpdateProgressBlock } + } + private enum CodingKeys: String, CodingKey { + case identifier ,url,state,lastState,totalBytesWritten,totalBytesExpectedToWrite,fileName,directoryName + } - - // File states default to .Unknown - public enum State { - case unknown - case waiting - case downloading - case paused(Data) - case finished - case cancelled - case failed + 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) + fileName = try values.decode(String.self, forKey: .fileName) + directoryName = try values.decode(String.self, forKey: .directoryName) + } + 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) + try container.encode(fileName, forKey: .fileName) + try container.encode(directoryName, forKey: .directoryName) + } 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 fileName : String? = nil + open var directoryName : String? = nil open var progress: Double { if totalBytesExpectedToWrite > 0 { @@ -101,8 +123,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 +132,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,13 +141,14 @@ open class CheapjackFile: Equatable { // MARK: - CheapjackFile private properties - internal var listeners: [CheapjackFile.Listener] - internal var downloadTask: URLSessionDownloadTask? + open var listeners: [CheapjackFile.Listener] = [CheapjackFile.Listener]() + internal var downloadTask: URLSessionDownloadTask? = nil // MARK: - Initializers - public init(identifier: CheapjackFile.Identifier, request: URLRequest, listeners: [CheapjackFile.Listener]? = nil) { + public init(identifier: CheapjackFile.Identifier, request: URLRequest, listeners: [CheapjackFile.Listener]? = nil,fileName: String? = nil , + directoryName: String? = nil ) { self.identifier = identifier self.url = request.url! self.request = request @@ -134,6 +157,8 @@ open class CheapjackFile: Equatable { self.totalBytesWritten = 0 self.totalBytesExpectedToWrite = 0 self.listeners = listeners ?? Array() + self.fileName = fileName ?? url?.lastPathComponent + self.directoryName = directoryName ?? "Doc" } public convenience init(identifer: CheapjackFile.Identifier, url: URL, listeners: [CheapjackFile.Listener]? = nil) { @@ -144,11 +169,16 @@ open class CheapjackFile: Equatable { // MARK: - CheapjackFile private setter methods - fileprivate func addListener(_ listener: CheapjackFile.Listener) { + public func addListener(_ listener: CheapjackFile.Listener) { listeners.append(listener) } - internal func setState(_ to: CheapjackFile.State) { + public func removeListener(_ listener: CheapjackFile.Listener) { + let listeners = self.listeners.filter { $0.delegate?.identifier != listener.delegate?.identifier} + self.listeners = listeners + } + + internal func setState(_ to: State) { state = to } @@ -185,7 +215,6 @@ open class CheapjackFile: Equatable { // CheapjackDelegate manager.delegate?.cheapjackManager(manager, didUpdateProgress: progress, totalBytesWritten: totalBytesWritten, totalBytesExpectedToWrite: totalBytesExpectedToWrite, forFile: self) } - // CheapjackFile.Listener for listener in listeners { // CheapjackFileDelegate @@ -199,3 +228,70 @@ 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 e13f2c3..275142f 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) @@ -37,6 +37,7 @@ open class CheapjackManager: NSObject { open static let sharedManager = CheapjackManager() + @objc dynamic open var numberOfPendingDownloads:Int = 0 override init() { files = Dictionary() @@ -48,18 +49,20 @@ open class CheapjackManager: NSObject { } // Helper method for starting a download for a new CheapjackFile instance. - open func download(_ url: URL, identifier: CheapjackFile.Identifier, userInfo: Dictionary? = nil, delegate: CheapjackFileDelegate? = nil, didChangeStateBlock: CheapjackFile.Listener.DidChangeStateBlock? = nil, didUpdateProgressBlock: CheapjackFile.Listener.DidUpdateProgressBlock? = nil) { + open func download(_ url: URL,fileName: String? = nil,directoryName: String? = nil, identifier: CheapjackFile.Identifier, userInfo: Dictionary? = nil, delegate: CheapjackFileDelegate? = nil, didChangeStateBlock: CheapjackFile.Listener.DidChangeStateBlock? = nil, didUpdateProgressBlock: CheapjackFile.Listener.DidUpdateProgressBlock? = nil) { let request = URLRequest(url: url) - download(request, identifier: identifier, userInfo: userInfo, delegate: delegate, didChangeStateBlock: didChangeStateBlock, didUpdateProgressBlock: didUpdateProgressBlock) + download(request,fileName: fileName,directoryName:directoryName, identifier: identifier, userInfo: userInfo, delegate: delegate, didChangeStateBlock: didChangeStateBlock, didUpdateProgressBlock: didUpdateProgressBlock) } - open func download(_ request: URLRequest, identifier: CheapjackFile.Identifier, userInfo: Dictionary? = nil, delegate: CheapjackFileDelegate? = nil, didChangeStateBlock: CheapjackFile.Listener.DidChangeStateBlock? = nil, didUpdateProgressBlock: CheapjackFile.Listener.DidUpdateProgressBlock? = nil) { + open func download(_ request: URLRequest,fileName: String? = nil,directoryName: String? = nil,identifier: CheapjackFile.Identifier, userInfo: Dictionary? = nil, delegate: CheapjackFileDelegate? = nil, didChangeStateBlock: CheapjackFile.Listener.DidChangeStateBlock? = nil, didUpdateProgressBlock: CheapjackFile.Listener.DidUpdateProgressBlock? = nil) { let listener = CheapjackFile.Listener(delegate: delegate, didChangeStateBlock: didChangeStateBlock, didUpdateProgressBlock: didUpdateProgressBlock) - let file = CheapjackFile(identifier: identifier, request: request, listeners: [listener]) + let file = CheapjackFile(identifier: identifier, request: request, listeners: [listener],fileName: fileName , + directoryName: directoryName) if let ui = userInfo { file.userInfo = ui } resume(file) + } open func pendingDownloads() -> Int { @@ -67,7 +70,6 @@ open class CheapjackManager: NSObject { return file.state != .finished && file.state != .cancelled }).count } - } @@ -110,23 +112,28 @@ extension CheapjackManager { file.manager = self files[file.identifier] = file - 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() + numberOfPendingDownloads = pendingDownloads() } public func pause(_ file: CheapjackFile) { 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) @@ -149,6 +156,9 @@ extension CheapjackManager { extension CheapjackManager { public func resumeAll() { + guard let files = restoredDownloadItems() else { + return + } for file in files.values { resume(file) } @@ -158,6 +168,7 @@ extension CheapjackManager { for file in files.values { pause(file) } + storeDownloadItems() } public func cancelAll() { @@ -166,15 +177,54 @@ extension CheapjackManager { } } + func storeDownloadItem(file:CheapjackFile) { + try? UserDefaults.standard.set(PropertyListEncoder().encode(file), forKey: file.identifier) + + } + func restoredDownloadItem(identifier:CheapjackFile.Identifier) -> CheapjackFile? { + + guard let encoded = UserDefaults.standard.object(forKey: identifier) as? Data else{ + return nil + } + let file = try! PropertyListDecoder().decode(CheapjackFile.self, from: encoded) + return file + } + + func storeDownloadItems() { + //save the identifiers of files + try? UserDefaults.standard.set(PropertyListEncoder().encode(Array(files.keys)), forKey: "downloadItemKeys") + } + + public func restoredDownloadItems() -> [CheapjackFile.Identifier:CheapjackFile]? { + + guard let encoded = UserDefaults.standard.object(forKey: "downloadItemKeys") as? Data else{ + return nil + } + + let filesKeys:[CheapjackFile.Identifier] = try! PropertyListDecoder().decode([CheapjackFile.Identifier].self, from: encoded) + + var savedFiles:[CheapjackFile.Identifier:CheapjackFile] = [CheapjackFile.Identifier:CheapjackFile]() + + for key in filesKeys { + if let encoded = UserDefaults.standard.object(forKey: key) as? Data,let file = try? PropertyListDecoder().decode(CheapjackFile.self, from: encoded){ + savedFiles[key] = file + } + } + return savedFiles + } + } extension CheapjackManager { public func remove(_ identifier: CheapjackFile.Identifier) { + cancel(identifier) + UserDefaults.standard.removeObject(forKey: identifier) files.removeValue(forKey: identifier) + numberOfPendingDownloads = pendingDownloads() } - public func remove(_ filesWithState: CheapjackFile.State) { + public func remove(_ filesWithState: State) { var filesCopy = files for (identifier, file) in filesCopy { if file.state != filesWithState { @@ -183,14 +233,17 @@ extension CheapjackManager { } files = filesCopy } + } extension CheapjackManager: URLSessionDownloadDelegate { + public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { - if let file = files[downloadTask.taskDescription!] { + if let taskDescription = downloadTask.taskDescription,let file = files[taskDescription] { file.setState(.finished) + move(cheapjackFile: file, location: location) delegate?.cheapjackManager(self, didFinishDownloading: session, downloadTask: downloadTask, url: location, forFile: file) if let didFinishDownloadingBlock = didFinishDownloadingBlock { didFinishDownloadingBlock(session, downloadTask, location, file) @@ -198,6 +251,7 @@ extension CheapjackManager: URLSessionDownloadDelegate { if deleteFileAfterComplete { files.removeValue(forKey: downloadTask.taskDescription!) + numberOfPendingDownloads = pendingDownloads() } } @@ -205,7 +259,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) } @@ -246,3 +300,32 @@ extension CheapjackManager: URLSessionTaskDelegate { } } + +extension CheapjackManager { + static func docmentDirectoryPath () -> URL { + return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] + } + + func move(cheapjackFile:CheapjackFile,location:URL) { + let directory = CheapjackManager.docmentDirectoryPath() + let path = directory.appendingPathComponent(cheapjackFile.directoryName!) + do { + if (!FileManager.default.fileExists(atPath: path.absoluteString)) { + try FileManager.default.createDirectory(at: path, withIntermediateDirectories: true, attributes: nil) + } + + let destinationLocation = path.appendingPathComponent(cheapjackFile.fileName!) + + if FileManager.default.fileExists(atPath: destinationLocation.path) { + try! FileManager.default.removeItem(at: destinationLocation) + } + + try FileManager.default.moveItem(at: location, to: destinationLocation) + + } catch { + print("Error while moving file! \( print(error.localizedDescription))") + } + } + +} + diff --git a/Cheapjack/Info.plist b/Cheapjack/Info.plist deleted file mode 100644 index d3de8ee..0000000 --- a/Cheapjack/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - 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 ```