diff --git a/r2-shared-swift.xcodeproj/project.pbxproj b/r2-shared-swift.xcodeproj/project.pbxproj index f2e769b4..e708525c 100644 --- a/r2-shared-swift.xcodeproj/project.pbxproj +++ b/r2-shared-swift.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + AEF39DF320E3895200A560F3 /* UserProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEF39DF220E3895200A560F3 /* UserProperties.swift */; }; + 57470F7E20ED0D1A000CDCA3 /* DownloadSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57470F7D20ED0D1A000CDCA3 /* DownloadSession.swift */; }; F32314A21F8616C2000FCFB0 /* Drm.swift in Sources */ = {isa = PBXBuildFile; fileRef = F32314A11F8616C2000FCFB0 /* Drm.swift */; }; F34CB2891FC56CAD005E3A37 /* DrmLicense.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34CB2881FC56CAD005E3A37 /* DrmLicense.swift */; }; F39E9E6F1FC2E1B70098F77E /* ObjectMapper.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F3E7D4201F4ECA9800DF166D /* ObjectMapper.framework */; }; @@ -36,6 +38,8 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + AEF39DF220E3895200A560F3 /* UserProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProperties.swift; sourceTree = ""; }; + 57470F7D20ED0D1A000CDCA3 /* DownloadSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloadSession.swift; sourceTree = ""; }; F32314A11F8616C2000FCFB0 /* Drm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Drm.swift; sourceTree = ""; }; F34CB2881FC56CAD005E3A37 /* DrmLicense.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DrmLicense.swift; sourceTree = ""; }; F3B1879F1FA33D4D00BB46BF /* Feed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Feed.swift; sourceTree = ""; }; @@ -78,6 +82,14 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 57470F7F20ED0D25000CDCA3 /* Toolkit */ = { + isa = PBXGroup; + children = ( + 57470F7D20ED0D1A000CDCA3 /* DownloadSession.swift */, + ); + path = Toolkit; + sourceTree = ""; + }; F34CB28A1FC5714D005E3A37 /* Drm */ = { isa = PBXGroup; children = ( @@ -122,6 +134,7 @@ F3E7D3F81F4EBE2100DF166D /* Info.plist */, F3E7D40C1F4EC69100DF166D /* RootFile.swift */, F3E7D4221F4ECB3D00DF166D /* ISO8601DateString.swift */, + 57470F7F20ED0D25000CDCA3 /* Toolkit */, F34CB28A1FC5714D005E3A37 /* Drm */, F3E7D41B1F4EC69C00DF166D /* Publication */, F3B1879E1FA33D3700BB46BF /* OPDS */, @@ -134,6 +147,7 @@ children = ( F3E7D40A1F4EC69100DF166D /* Publication.swift */, F3E7D4061F4EC69100DF166D /* Metadata.swift */, + AEF39DF220E3895200A560F3 /* UserProperties.swift */, F3E7D41C1F4EC6B300DF166D /* Metadata */, F3E7D41D1F4EC6B900DF166D /* Link */, F3E7D41E1F4EC6CC00DF166D /* MediaOverlays */, @@ -275,9 +289,11 @@ F3E7D4161F4EC69100DF166D /* Properties.swift in Sources */, F3E7D4231F4ECB3D00DF166D /* ISO8601DateString.swift in Sources */, F3E7D41A1F4EC69100DF166D /* Subject.swift in Sources */, + 57470F7E20ED0D1A000CDCA3 /* DownloadSession.swift in Sources */, F3B187A61FA33E4900BB46BF /* Group.swift in Sources */, F3E7D4191F4EC69100DF166D /* RootFile.swift in Sources */, F3E7D4141F4EC69100DF166D /* MetadataItem.swift in Sources */, + AEF39DF320E3895200A560F3 /* UserProperties.swift in Sources */, F3F41E181FA3377E00F97737 /* Price.swift in Sources */, F3E7D4101F4EC69100DF166D /* Link.swift in Sources */, F34CB2891FC56CAD005E3A37 /* DrmLicense.swift in Sources */, diff --git a/r2-shared-swift.xcodeproj/xcshareddata/xcschemes/r2-shared-swift.xcscheme b/r2-shared-swift.xcodeproj/xcshareddata/xcschemes/r2-shared-swift.xcscheme index 2261a709..14e9288e 100644 --- a/r2-shared-swift.xcodeproj/xcshareddata/xcschemes/r2-shared-swift.xcscheme +++ b/r2-shared-swift.xcodeproj/xcshareddata/xcschemes/r2-shared-swift.xcscheme @@ -1,6 +1,6 @@ Bool { - // return l1.href?.localizedStandardCompare(l2.href!) == ComparisonResult.orderedAscending - // } - // orderedPublication.links.sort(by: linkOrderedAscending) - // ... + var jsonString = canonicalPublication.toJSONString(prettyPrint: false) ?? "" jsonString = jsonString.replacingOccurrences(of: "\\", with: "") @@ -251,26 +254,41 @@ extension Publication: Mappable { } } -// The keys in ReadiumCss. Also used for storing UserSettings in UserDefaults. -public enum ReadiumCSSKey: String { - case fontSize = "--USER__fontSize" - case font = "--USER__fontFamily" - case appearance = "--USER__appearance" - case scroll = "--USER__scroll" - case publisherSettings = "--USER__advancedSettings" - case wordSpacing = "--USER__wordSpacing" - case letterSpacing = "--USER__letterSpacing" - case columnCount = "--USER__colCount" - case pageMargins = "--USER__pageMargins" - case textAlignement = "--USER__textAlign" - //--USER__darkenImages --USER__invertImages - - case paraIndent = "--USER__paraIndent" - - case hyphens = "--USER__bodyHyphens" - case ligatures = "--USER__ligatures" - - case publisherFont = "--USER__fontOverride" +/// List of strings that can identify a user setting +public enum ReadiumCSSReference: String { + case fontSize = "fontSize" + case fontFamily = "fontFamily" + case fontOverride = "fontOverride" + case appearance = "appearance" + case scroll = "scroll" + case publisherDefault = "advancedSettings" + case textAlignment = "textAlign" + case columnCount = "colCount" + case wordSpacing = "wordSpacing" + case letterSpacing = "letterSpacing" + case pageMargins = "pageMargins" + case paraIndent = "paraIndent" + case hyphens = "bodyHyphens" + case ligatures = "ligatures" +} + +/// List of strings that can identify the name of a CSS custom property +/// Also used for storing UserSettings in UserDefaults +public enum ReadiumCSSName: String { + case fontSize = "--USER__fontSize" + case fontFamily = "--USER__fontFamily" + case fontOverride = "--USER__fontOverride" + case appearance = "--USER__appearance" + case scroll = "--USER__scroll" + case publisherDefault = "--USER__advancedSettings" + case textAlignment = "--USER__textAlign" + case columnCount = "--USER__colCount" + case wordSpacing = "--USER__wordSpacing" + case letterSpacing = "--USER__letterSpacing" + case pageMargins = "--USER__pageMargins" + case paraIndent = "--USER__paraIndent" + case hyphens = "--USER__bodyHyphens" + case ligatures = "--USER__ligatures" } // MARK: - Parsing related errors diff --git a/r2-shared-swift/Rendition.swift b/r2-shared-swift/Rendition.swift index 7b571514..9fbd3ebf 100644 --- a/r2-shared-swift/Rendition.swift +++ b/r2-shared-swift/Rendition.swift @@ -1,9 +1,12 @@ // // Rendition.swift -// R2Streamer +// r2-shared-swift // // Created by Alexandre Camilleri on 2/17/17. -// Copyright © 2017 Readium. All rights reserved. +// +// Copyright 2018 Readium Foundation. All rights reserved. +// Use of this source code is governed by a BSD-style license which is detailed +// in the LICENSE file present in the project repository where this source code is maintained. // import Foundation diff --git a/r2-shared-swift/RootFile.swift b/r2-shared-swift/RootFile.swift index 2a1f2a83..f72a0a0b 100644 --- a/r2-shared-swift/RootFile.swift +++ b/r2-shared-swift/RootFile.swift @@ -1,9 +1,12 @@ // // RootFile.swift -// R2Streamer +// r2-shared-swift // // Created by Alexandre Camilleri on 3/3/17. -// Copyright © 2017 Readium. All rights reserved. +// +// Copyright 2018 Readium Foundation. All rights reserved. +// Use of this source code is governed by a BSD-style license which is detailed +// in the LICENSE file present in the project repository where this source code is maintained. // import Foundation diff --git a/r2-shared-swift/Subject.swift b/r2-shared-swift/Subject.swift index 1eaf9fc0..62b68abd 100644 --- a/r2-shared-swift/Subject.swift +++ b/r2-shared-swift/Subject.swift @@ -1,9 +1,12 @@ // // Subject.swift -// R2Streamer +// r2-shared-swift // // Created by Alexandre Camilleri on 2/17/17. -// Copyright © 2017 Readium. All rights reserved. +// +// Copyright 2018 Readium Foundation. All rights reserved. +// Use of this source code is governed by a BSD-style license which is detailed +// in the LICENSE file present in the project repository where this source code is maintained. // import Foundation diff --git a/r2-shared-swift/Toolkit/DownloadSession.swift b/r2-shared-swift/Toolkit/DownloadSession.swift new file mode 100644 index 00000000..011c77df --- /dev/null +++ b/r2-shared-swift/Toolkit/DownloadSession.swift @@ -0,0 +1,88 @@ +// +// DownloadSession.swift +// r2-shared-swift +// +// Created by Senda Li on 2018/7/4. +// Copyright © 2018 Readium. All rights reserved. +// + +import Foundation + +public protocol DownloadDisplayDelegate { + func didStartDownload(task:URLSessionDownloadTask, description:String); + func didFinishDownload(task:URLSessionDownloadTask); + func didFailWithError(task:URLSessionDownloadTask, error: Error?); + func didUpdateDownloadPercentage(task:URLSessionDownloadTask, percentage: Float); +} + +public typealias completionHandlerType = ((URL?, URLResponse?, Error?, URLSessionDownloadTask) -> Bool?) + +public class DownloadSession: NSObject, URLSessionDelegate, URLSessionDownloadDelegate { + + public static let shared = DownloadSession() + private override init() { super.init() } + + private lazy var session: URLSession = { + let config = URLSessionConfiguration.default + return URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main) + } () + + public var displayDelegate:DownloadDisplayDelegate? + private var taskMap = [URLSessionTask:completionHandlerType]() + + public func launch(request: URLRequest, description:String?, completionHandler:completionHandlerType?) { + let task = self.session.downloadTask(with: request); task.resume() + + DispatchQueue.main.async { + + self.taskMap[task] = completionHandler + let localizedDescription = description ?? "..." + self.displayDelegate?.didStartDownload(task: task, description: localizedDescription) + } + } + + public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { + + let done = self.taskMap[downloadTask]?(location, nil, nil, downloadTask) ?? false + + DispatchQueue.main.async { + self.taskMap.removeValue(forKey: downloadTask) + + if done { + self.displayDelegate?.didFinishDownload(task: downloadTask) + } else { + self.displayDelegate?.didFailWithError(task: downloadTask, error: nil) + } + } + } + + public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { + let progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite) + + DispatchQueue.main.async { + self.displayDelegate?.didUpdateDownloadPercentage(task: downloadTask, percentage: progress) + } + } + + public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64) { + let progress = Float(fileOffset) / Float(expectedTotalBytes) + + DispatchQueue.main.async { + self.displayDelegate?.didUpdateDownloadPercentage(task: downloadTask, percentage: progress) + } + } + + public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { + + DispatchQueue.main.async { + + guard let downloadTask = task as? URLSessionDownloadTask else {return} + + guard let theError = error else {return} + _ = self.taskMap[task]?(nil, nil, error, downloadTask) + self.taskMap.removeValue(forKey: task) + + self.displayDelegate?.didFailWithError(task: downloadTask, error: theError) + } + } +} diff --git a/r2-shared-swift/UserProperties.swift b/r2-shared-swift/UserProperties.swift new file mode 100644 index 00000000..795d1d17 --- /dev/null +++ b/r2-shared-swift/UserProperties.swift @@ -0,0 +1,126 @@ +// +// UserProperties.swift +// r2-shared-swift +// +// Created by Geoffrey Bugniot on 27/06/2018. +// Copyright © 2018 Readium. All rights reserved. +// + +import Foundation + +public protocol UserPropertyStringifier { + func toString() -> String +} + +public class UserProperty: UserPropertyStringifier { + + public var reference: String + public var name: String + + init(_ reference: String, _ name: String) { + self.reference = reference + self.name = name + } + + public func toString() -> String { + return "" + } + +} + +public class Enumerable: UserProperty { + + public var index: Int + public var values: [String] + + init(index: Int, values: [String], reference: String, name: String) { + self.index = index + self.values = values + + super.init(reference, name) + } + + public override func toString() -> String { + return values[index] + } + +} + +public class Incrementable: UserProperty { + + public var value, min, max, step: Float + public var suffix: String + + init(value: Float, min: Float, max: Float, step: Float, suffix: String, reference: String, name: String) { + self.value = value + self.min = min + self.max = max + self.step = step + self.suffix = suffix + + super.init(reference, name) + } + + public func increment() { + value += ( (value + step) <= max ) ? step : 0.0 + } + + public func decrement() { + value -= ( (value - step) >= min ) ? step : 0.0 + } + + public override func toString() -> String { + return "\(value)" + suffix + } + +} + +public class Switchable: UserProperty { + + public var onValue: String + public var offValue: String + public var on: Bool + public var values: [Bool: String] + + init(onValue: String, offValue: String, on: Bool, reference: String, name: String) { + self.onValue = onValue + self.offValue = offValue + self.on = on + + values = [true: onValue, false: offValue] + + super.init(reference, name) + } + + public func switchValue() { + on = !on + } + + public override func toString() -> String { + return values[on]! + } + +} + +public class UserProperties { + + public var properties = [UserProperty]() + + public init() {} + + public func addEnumerable(index: Int, values: [String], reference: String, name: String) { + properties.append(Enumerable(index: index, values: values, reference: reference, name: name)) + } + + public func addIncrementable(nValue: Float, min: Float, max: Float, step: Float, suffix: String, reference: String, name: String) { + properties.append(Incrementable(value: nValue, min: min, max: max, step: step, suffix: suffix, reference: reference, name: name)) + } + + public func addSwitchable(onValue: String, offValue: String, on: Bool, reference: String, name: String) { + properties.append(Switchable(onValue: onValue, offValue: offValue, on: on, reference: reference, name: name)) + } + + public func getProperty(reference: String) -> UserProperty? { + return properties.filter { $0.reference == reference }.first + } +} diff --git a/r2-shared-swift/r2-shared-swift.h b/r2-shared-swift/r2-shared-swift.h index 0a473488..22fe44c2 100644 --- a/r2-shared-swift/r2-shared-swift.h +++ b/r2-shared-swift/r2-shared-swift.h @@ -3,7 +3,10 @@ // r2-shared-swift // // Created by Alexandre Camilleri on 8/24/17. -// Copyright © 2017 Readium. All rights reserved. +// +// Copyright 2018 Readium Foundation. All rights reserved. +// Use of this source code is governed by a BSD-style license which is detailed +// in the LICENSE file present in the project repository where this source code is maintained. // #import