From 8f0e1ecd1666edaadfd7d8ec840b6ae77d0e7126 Mon Sep 17 00:00:00 2001 From: Grigor Hakobyan Date: Fri, 17 Apr 2026 11:38:58 +0400 Subject: [PATCH 01/13] Remove unused `spreadView(_:present:)` delegate method --- Sources/Navigator/EPUB/EPUBNavigatorViewController.swift | 4 ---- Sources/Navigator/EPUB/EPUBSpreadView.swift | 3 --- 2 files changed, 7 deletions(-) diff --git a/Sources/Navigator/EPUB/EPUBNavigatorViewController.swift b/Sources/Navigator/EPUB/EPUBNavigatorViewController.swift index c44609d3f0..322a89d23a 100644 --- a/Sources/Navigator/EPUB/EPUBNavigatorViewController.swift +++ b/Sources/Navigator/EPUB/EPUBNavigatorViewController.swift @@ -1232,10 +1232,6 @@ extension EPUBNavigatorViewController: EPUBSpreadViewDelegate { } } - func spreadView(_ spreadView: EPUBSpreadView, present viewController: UIViewController) { - present(viewController, animated: true) - } - func spreadViewDidTerminate() { reloadSpreads() } diff --git a/Sources/Navigator/EPUB/EPUBSpreadView.swift b/Sources/Navigator/EPUB/EPUBSpreadView.swift index 3853242299..5bd7570feb 100644 --- a/Sources/Navigator/EPUB/EPUBSpreadView.swift +++ b/Sources/Navigator/EPUB/EPUBSpreadView.swift @@ -29,9 +29,6 @@ protocol EPUBSpreadViewDelegate: AnyObject { /// Called when the pages visible in the spread changed. func spreadViewPagesDidChange(_ spreadView: EPUBSpreadView) - /// Called when the spread view needs to present a view controller. - func spreadView(_ spreadView: EPUBSpreadView, present viewController: UIViewController) - /// Called when the user triggered an input pointer event. func spreadView(_ spreadView: EPUBSpreadView, didReceive event: PointerEvent) From 73543ed0451f38e62c2e2743653352d6c5f922fc Mon Sep 17 00:00:00 2001 From: Grigor Hakobyan Date: Fri, 17 Apr 2026 11:41:21 +0400 Subject: [PATCH 02/13] Remove unused `orderedViews` property from `PaginationView` --- Sources/Navigator/Toolkit/PaginationView.swift | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/Sources/Navigator/Toolkit/PaginationView.swift b/Sources/Navigator/Toolkit/PaginationView.swift index b72488c731..dc3afa97ce 100644 --- a/Sources/Navigator/Toolkit/PaginationView.swift +++ b/Sources/Navigator/Toolkit/PaginationView.swift @@ -78,19 +78,6 @@ final class PaginationView: UIView, Loggable { loadedViews[currentIndex] } - /// Loaded page views in reading order. - private var orderedViews: [UIView & PageView] { - var orderedViews = loadedViews - .sorted { $0.key < $1.key } - .map(\.value) - - if readingProgression == .rtl { - orderedViews.reverse() - } - - return orderedViews - } - private let scrollView = UIScrollView() /// Set while a transition animation is in progress to prevent From ff35f102b7367595af37ca8f98159a1589d66a36 Mon Sep 17 00:00:00 2001 From: Grigor Hakobyan Date: Fri, 17 Apr 2026 11:46:51 +0400 Subject: [PATCH 03/13] Refactor PDFParser --- Sources/Streamer/Parser/PDF/PDFParser.swift | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Sources/Streamer/Parser/PDF/PDFParser.swift b/Sources/Streamer/Parser/PDF/PDFParser.swift index 6110db2ee3..0bd05c628d 100644 --- a/Sources/Streamer/Parser/PDF/PDFParser.swift +++ b/Sources/Streamer/Parser/PDF/PDFParser.swift @@ -8,23 +8,7 @@ import CoreGraphics import Foundation import ReadiumShared -/// Errors thrown during the parsing of the PDF. -public enum PDFParserError: Error, Sendable { - /// The file at 'path' is missing from the container. - case missingFile(path: String) - /// Failed to open the PDF - case openFailed - /// The PDF is encrypted with a password. This is not supported right now. - case fileEncryptedWithPassword - /// The LCP for PDF Package is malformed. - case invalidLCPDF -} - public final class PDFParser: PublicationParser, Loggable { - enum Error: Swift.Error { - case fileNotReadable - } - private let pdfFactory: PDFDocumentFactory public init(pdfFactory: PDFDocumentFactory) { From 08c0b25b84df4fb1cbc19532e000b6803c0356f8 Mon Sep 17 00:00:00 2001 From: Grigor Hakobyan Date: Fri, 17 Apr 2026 11:47:09 +0400 Subject: [PATCH 04/13] Delete unused string extension --- .../Streamer/Toolkit/StringExtension.swift | 44 ------------------- 1 file changed, 44 deletions(-) delete mode 100644 Sources/Streamer/Toolkit/StringExtension.swift diff --git a/Sources/Streamer/Toolkit/StringExtension.swift b/Sources/Streamer/Toolkit/StringExtension.swift deleted file mode 100644 index 85395ba131..0000000000 --- a/Sources/Streamer/Toolkit/StringExtension.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright 2026 Readium Foundation. All rights reserved. -// Use of this source code is governed by the BSD-style license -// available in the top-level LICENSE file of the project. -// - -import Foundation - -extension String { - var ns: NSString { - self as NSString - } - - func appending(pathComponent: String) -> String { - (self as NSString).appendingPathComponent(pathComponent) - } - - var deletingLastPathComponent: String { - ns.deletingLastPathComponent - } - - var lastPathComponent: String { - ns.lastPathComponent - } - - var pathExtension: String { - ns.pathExtension - } - - func endIndex(of string: String, options: CompareOptions = .literal) -> Index? { - range(of: string, options: options)?.upperBound - } - - func startIndex(of string: String, options: CompareOptions = .literal) -> Index? { - range(of: string, options: options)?.lowerBound - } - - func insert(string: String, at index: String.Index) -> String { - let prefix = self[.. Date: Fri, 17 Apr 2026 11:53:14 +0400 Subject: [PATCH 05/13] Cleanup Optional extension in Shared target --- Sources/Shared/Toolkit/Extensions/Optional.swift | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Sources/Shared/Toolkit/Extensions/Optional.swift b/Sources/Shared/Toolkit/Extensions/Optional.swift index 20d12083e0..41fd1b947b 100644 --- a/Sources/Shared/Toolkit/Extensions/Optional.swift +++ b/Sources/Shared/Toolkit/Extensions/Optional.swift @@ -27,11 +27,4 @@ public extension Optional { } return value } - - /// Returns the wrapped value and modify the variable to be nil. - internal mutating func pop() -> Wrapped? { - let res = self - self = nil - return res - } } From 68d78b402522f5ae9ccd753a53476382271a6a01 Mon Sep 17 00:00:00 2001 From: Grigor Hakobyan Date: Fri, 17 Apr 2026 12:16:41 +0400 Subject: [PATCH 06/13] Cleanup OPDS parsers --- Sources/OPDS/OPDS2Parser.swift | 4 ---- Sources/OPDS/OPDSParser.swift | 4 ---- 2 files changed, 8 deletions(-) diff --git a/Sources/OPDS/OPDS2Parser.swift b/Sources/OPDS/OPDS2Parser.swift index 6b3925ce6d..07bcfe3e5e 100644 --- a/Sources/OPDS/OPDS2Parser.swift +++ b/Sources/OPDS/OPDS2Parser.swift @@ -271,7 +271,3 @@ public class OPDS2Parser: Loggable { } } } - -private func hrefNormalizer(_ baseURL: URL?) -> (String) -> (String) { - { href in URLHelper.getAbsolute(href: href, base: baseURL) ?? href } -} diff --git a/Sources/OPDS/OPDSParser.swift b/Sources/OPDS/OPDSParser.swift index eb5142e789..904eccc73d 100644 --- a/Sources/OPDS/OPDSParser.swift +++ b/Sources/OPDS/OPDSParser.swift @@ -13,8 +13,6 @@ public enum OPDSParserError: Error, Sendable { } public enum OPDSParser: Sendable { - static var feedURL: URL? - /// Parse an OPDS feed or publication. /// Feed can be v1 (XML) or v2 (JSON). /// - Parameters: @@ -22,8 +20,6 @@ public enum OPDSParser: Sendable { /// - completion: A closure called when the parsing is complete, returning the /// parsed `ParseData` on success, or an `Error` if the operation failed. public static func parseURL(url: URL, completion: @escaping (ParseData?, Error?) -> Void) { - feedURL = url - URLSession.shared.dataTask(with: url) { data, response, error in guard let data = data, let response = response else { completion(nil, error ?? OPDSParserError.documentNotFound) From 7a32d1f14581330e28674760a5cd283e3c171058 Mon Sep 17 00:00:00 2001 From: Grigor Hakobyan Date: Fri, 17 Apr 2026 12:22:48 +0400 Subject: [PATCH 07/13] Cleanup AVTTSEngine --- Sources/Navigator/TTS/AVTTSEngine.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/Sources/Navigator/TTS/AVTTSEngine.swift b/Sources/Navigator/TTS/AVTTSEngine.swift index ce9e34f0a1..03ed03120b 100644 --- a/Sources/Navigator/TTS/AVTTSEngine.swift +++ b/Sources/Navigator/TTS/AVTTSEngine.swift @@ -128,8 +128,6 @@ public final class AVTTSEngine: NSObject, TTSEngine, AVSpeechSynthesizerDelegate private func taskUtterance(with task: Task) -> TaskUtterance { let utter = TaskUtterance(task: task) -// utter.rate = rateMultiplierToAVRate(task.utterance.rateMultiplier) -// utter.pitchMultiplier = Float(task.utterance.pitchMultiplier) utter.preUtteranceDelay = task.utterance.delay utter.voice = voice(for: task.utterance) delegate?.avTTSEngine(self, didCreateUtterance: utter) From c451db6f1af8fc0ac8914c6bc46a4cfdb7235b06 Mon Sep 17 00:00:00 2001 From: Grigor Hakobyan Date: Fri, 17 Apr 2026 12:27:13 +0400 Subject: [PATCH 08/13] Remove unused import --- Sources/LCP/License/License.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/LCP/License/License.swift b/Sources/LCP/License/License.swift index 7557b3727d..cb3a6c4337 100644 --- a/Sources/LCP/License/License.swift +++ b/Sources/LCP/License/License.swift @@ -6,7 +6,6 @@ import Foundation import ReadiumShared -import ReadiumZIPFoundation final class License: Loggable { /// Last Documents which passed the integrity checks. From ffe4b30c7c4c72f5c1cd7eac28ce8f753d7ee95a Mon Sep 17 00:00:00 2001 From: Grigor Hakobyan Date: Fri, 17 Apr 2026 12:39:13 +0400 Subject: [PATCH 09/13] Cleanup Internals --- Sources/Internal/Extensions/Array.swift | 16 ---------------- Sources/Internal/Extensions/Date+ISO8601.swift | 5 +---- 2 files changed, 1 insertion(+), 20 deletions(-) diff --git a/Sources/Internal/Extensions/Array.swift b/Sources/Internal/Extensions/Array.swift index 6c1bf08da8..2cc4257601 100644 --- a/Sources/Internal/Extensions/Array.swift +++ b/Sources/Internal/Extensions/Array.swift @@ -61,20 +61,4 @@ public extension Array where Element: Hashable { } return result } - - @inlinable func removing(_ element: Element) -> Self { - var array = self - array.removeAll { other in other == element } - return array - } - - @inlinable mutating func remove(_ element: Element) { - removeAll { other in other == element } - } -} - -public extension Array where Element: Equatable { - func firstMemberFrom(_ candidates: Element?...) -> Element? { - candidates.compactMap { $0 }.first { contains($0) } - } } diff --git a/Sources/Internal/Extensions/Date+ISO8601.swift b/Sources/Internal/Extensions/Date+ISO8601.swift index 6f3cc79ec9..584a827033 100644 --- a/Sources/Internal/Extensions/Date+ISO8601.swift +++ b/Sources/Internal/Extensions/Date+ISO8601.swift @@ -27,10 +27,7 @@ public extension DateFormatter { // Otherwise it will accept bad format, for exmaple 2018-04-24XXXXXXXXX // Because it will only test the part you asssigned, date, time, timezone. // But we should also cover the optional cases. So there is not too much benefit. -// let formatter = ISO8601DateFormatter() -// formatter.formatOptions = [.withFullDate] -// return formatter - + // https://developer.apple.com/documentation/foundation/dateformatter // Doesn't support millisecond or uncompleted part for date, time, timezone offset. let formats = [ From 1b24f7d9d5a682c000affc2b73d85085e0b8beee Mon Sep 17 00:00:00 2001 From: Grigor Hakobyan Date: Fri, 17 Apr 2026 12:50:29 +0400 Subject: [PATCH 10/13] Cleanup Adapters --- Sources/Adapters/GCDWebServer/GCDHTTPServer.swift | 4 ---- Sources/Adapters/GCDWebServer/ResourceResponse.swift | 9 --------- 2 files changed, 13 deletions(-) diff --git a/Sources/Adapters/GCDWebServer/GCDHTTPServer.swift b/Sources/Adapters/GCDWebServer/GCDHTTPServer.swift index 09caafd2c9..d49899a8c6 100644 --- a/Sources/Adapters/GCDWebServer/GCDHTTPServer.swift +++ b/Sources/Adapters/GCDWebServer/GCDHTTPServer.swift @@ -294,10 +294,6 @@ public final class GCDHTTPServer: HTTPServer, Loggable { private func isPortFree(_ port: UInt) -> Bool { let port = in_port_t(port) - func getErrnoMessage() -> String { - String(cString: UnsafePointer(strerror(errno))) - } - let socketDescriptor = socket(AF_INET, SOCK_STREAM, 0) if socketDescriptor == -1 { // Just in case, returns true to attempt restarting the server. diff --git a/Sources/Adapters/GCDWebServer/ResourceResponse.swift b/Sources/Adapters/GCDWebServer/ResourceResponse.swift index 1624c38efd..9bdac0d14e 100644 --- a/Sources/Adapters/GCDWebServer/ResourceResponse.swift +++ b/Sources/Adapters/GCDWebServer/ResourceResponse.swift @@ -8,15 +8,6 @@ import Foundation import ReadiumGCDWebServer import ReadiumShared -/// Errors thrown by the `WebServerResourceResponse` -/// -/// - streamOpenFailed: The stream is not open, stream.open() failed. -/// - invalidRange: The range queried is invalid. -enum WebServerResponseError: Error { - case streamOpenFailed - case invalidRange -} - /// The object containing the response's ressource data. /// If the ressource to be served is too big, multiple responses will be created. class ResourceResponse: ReadiumGCDWebServerResponse, Loggable { From f87f073197fa7fd36c4bcb3a7416bafb87f082d0 Mon Sep 17 00:00:00 2001 From: Grigor Hakobyan Date: Fri, 17 Apr 2026 13:16:45 +0400 Subject: [PATCH 11/13] Fix linting issue --- Sources/Internal/Extensions/Date+ISO8601.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/Internal/Extensions/Date+ISO8601.swift b/Sources/Internal/Extensions/Date+ISO8601.swift index 584a827033..f1251ec581 100644 --- a/Sources/Internal/Extensions/Date+ISO8601.swift +++ b/Sources/Internal/Extensions/Date+ISO8601.swift @@ -27,7 +27,6 @@ public extension DateFormatter { // Otherwise it will accept bad format, for exmaple 2018-04-24XXXXXXXXX // Because it will only test the part you asssigned, date, time, timezone. // But we should also cover the optional cases. So there is not too much benefit. - // https://developer.apple.com/documentation/foundation/dateformatter // Doesn't support millisecond or uncompleted part for date, time, timezone offset. let formats = [ From 1b93850db7f248aec00e208c4dbbac6ab6dc3bf8 Mon Sep 17 00:00:00 2001 From: Grigor Hakobyan Date: Mon, 1 Jun 2026 19:57:12 +0400 Subject: [PATCH 12/13] Restore commented-out rate/pitch lines in AVTTSEngine (TODOs/FIXMEs) --- Sources/Navigator/TTS/AVTTSEngine.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sources/Navigator/TTS/AVTTSEngine.swift b/Sources/Navigator/TTS/AVTTSEngine.swift index 03ed03120b..ce9e34f0a1 100644 --- a/Sources/Navigator/TTS/AVTTSEngine.swift +++ b/Sources/Navigator/TTS/AVTTSEngine.swift @@ -128,6 +128,8 @@ public final class AVTTSEngine: NSObject, TTSEngine, AVSpeechSynthesizerDelegate private func taskUtterance(with task: Task) -> TaskUtterance { let utter = TaskUtterance(task: task) +// utter.rate = rateMultiplierToAVRate(task.utterance.rateMultiplier) +// utter.pitchMultiplier = Float(task.utterance.pitchMultiplier) utter.preUtteranceDelay = task.utterance.delay utter.voice = voice(for: task.utterance) delegate?.avTTSEngine(self, didCreateUtterance: utter) From 7132d93ecc9174932c3bf0442f7de7a87b68667d Mon Sep 17 00:00:00 2001 From: Grigor Hakobyan Date: Mon, 1 Jun 2026 19:57:12 +0400 Subject: [PATCH 13/13] Remove orphaned comments in Date+ISO8601 referring to removed code --- Sources/Internal/Extensions/Date+ISO8601.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Sources/Internal/Extensions/Date+ISO8601.swift b/Sources/Internal/Extensions/Date+ISO8601.swift index f1251ec581..d115a3d576 100644 --- a/Sources/Internal/Extensions/Date+ISO8601.swift +++ b/Sources/Internal/Extensions/Date+ISO8601.swift @@ -23,10 +23,6 @@ public extension DateFormatter { }() static func iso8601Formatter(for string: String) -> DateFormatter { - // On iOS 10 and later, this API should be treated withFullTime or withTimeZone for different cases. - // Otherwise it will accept bad format, for exmaple 2018-04-24XXXXXXXXX - // Because it will only test the part you asssigned, date, time, timezone. - // But we should also cover the optional cases. So there is not too much benefit. // https://developer.apple.com/documentation/foundation/dateformatter // Doesn't support millisecond or uncompleted part for date, time, timezone offset. let formats = [