From 06c6539e264ef7905f11c525cf542d42f851503f Mon Sep 17 00:00:00 2001 From: Vegard Matthey Date: Mon, 29 Dec 2025 15:40:58 +0100 Subject: [PATCH] bonus chapters? --- ImageViewer/ViewController.swift | 137 +++++++++++++++++++------------ 1 file changed, 83 insertions(+), 54 deletions(-) diff --git a/ImageViewer/ViewController.swift b/ImageViewer/ViewController.swift index cd58b33..29093b2 100644 --- a/ImageViewer/ViewController.swift +++ b/ImageViewer/ViewController.swift @@ -3,6 +3,9 @@ //TODO: Properly avoid swallowing of input from UICollectionView used for scrolling //TODO: Convert between state for normal and scrolling page turn //TODO: Support reading with scrolling and landscape mode +//TODO: Support Cover being zeroth page. +//TODO: Support double pages. +//TODO: Do file name parsing. //FIXME: Update comicCollectionView when switching between landscape and portrait mode import UIKit @@ -81,7 +84,7 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { var mode = PageTurnMode.leftToRight var metadata: Metadata! var currentPage: Int! = nil - var currentChapter: Int! = nil + var currentChapterIndex: Int! = nil var currentPath: URL! var changedOrientation = false @@ -220,7 +223,7 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { func saveGlobalState() { do { - try JSONEncoder().encode(self.globalState).write( + try JSONEncoder().encode(globalState).write( to: documentsURL.appendingPathComponent("state.json")) } catch { print("failed to save global state") @@ -257,11 +260,11 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { scrollOffset.y *= (screenSize.height / screenSize.width) } let progress: ReadProgress = - switch self.mode { + switch mode { case .leftToRight: - ReadProgress.leftToRight(chapter: currentChapter, page: currentPage) + ReadProgress.leftToRight(chapter: currentChapterIndex, page: currentPage) case .rightToLeft: - ReadProgress.rightToLeft(chapter: currentChapter, page: currentPage) + ReadProgress.rightToLeft(chapter: currentChapterIndex, page: currentPage) case .scroll: ReadProgress.scroll(scrollOffset) } queue.async { @@ -287,11 +290,11 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { let local = try JSONDecoder().decode(LocalState.self, from: json) switch local.progress { case .leftToRight(let chapter, let page): - currentChapter = chapter + currentChapterIndex = chapter currentPage = page mode = .leftToRight case .rightToLeft(let chapter, let page): - currentChapter = chapter + currentChapterIndex = chapter currentPage = page mode = .rightToLeft case .scroll(let point): @@ -304,12 +307,12 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { } if let indexPath = scrollingCollectionView.indexPathForItem(at: scrollOffset) { let (chapter, page) = chapterAndPages[indexPath.item] - currentChapter = chapter + currentChapterIndex = chapter currentPage = page } } - self.mode = .scroll + mode = .scroll } readerView.backgroundColor = convertStringToColor(str: local.backgroundColor) } catch { @@ -337,7 +340,7 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { if let indexPath = scrollingCollectionView.indexPathForItem(at: centerPoint) { let (chapter, page) = chapterAndPages[indexPath.item] - currentChapter = chapter + currentChapterIndex = chapter currentPage = page } if scrollingCollectionView.isHidden == false { @@ -750,8 +753,8 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { } else { imageLoader.loadImage( at: getImagePath( - chapter: currentChapter, - volume: Int(metadata.chapters[currentChapter - 1].volume), + chapter: metadata.chapters[currentChapterIndex].chapter, + volume: metadata.chapters[currentChapterIndex].volume, page: currentPage, path: currentPath), scaling: .scaleAspectFit @@ -885,12 +888,14 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { func changeImage(turn: PageTurn) { let scaling = UIView.ContentMode.scaleAspectFit var (chapter, page) = getChapterAndPageFromTurn( - chapter: currentChapter, page: currentPage, turn: turn) - if (chapter, page) == (currentChapter, currentPage) { return } - var vol = Int(metadata.chapters[chapter - 1].volume) + chapter: currentChapterIndex, page: currentPage, turn: turn) + if (chapter, page) == (currentChapterIndex, currentPage) { return } + var vol = metadata.chapters[chapter].volume currentPage = page - currentChapter = chapter - if let path = getImagePath(chapter: chapter, volume: vol, page: page, path: currentPath) { + currentChapterIndex = chapter + if let path = getImagePath( + chapter: metadata.chapters[chapter].chapter, volume: vol, page: page, path: currentPath) + { imageLoader.loadImage(at: path, scaling: scaling) { [weak self] image in self?.imageView.image = image self?.updateInfo() @@ -902,9 +907,10 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { for _ in 0...preloadCount { (chapter, page) = getChapterAndPageFromTurn( chapter: chapter, page: page, turn: .next) - vol = Int(metadata.chapters[chapter - 1].volume) + vol = metadata.chapters[chapter].volume if let path = getImagePath( - chapter: chapter, volume: vol, page: page, path: currentPath) + chapter: metadata.chapters[chapter].chapter, volume: vol, page: page, + path: currentPath) { imageLoader.preloadImage(at: path, scaling: scaling) } else { @@ -917,23 +923,29 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { func updateInfo() { if metadata == nil { return } - if currentChapter == nil || currentPage == nil { return } + if currentChapterIndex == nil || currentPage == nil { return } var text = "\(metadata.title)\n" - if let chapterTitle = metadata.chapters[currentChapter - 1].title { + if let chapterTitle = metadata.chapters[currentChapterIndex].title { text += "\(chapterTitle)\n" } + let chapterValue = metadata.chapters[currentChapterIndex].chapter + let chapterString = + chapterValue.truncatingRemainder(dividingBy: 1) == 0 + ? String(Int(chapterValue)) + : String(chapterValue) text += """ - Volume \(Int(metadata.chapters[currentChapter - 1].volume)) of \(Int(metadata.last_volume)) - Chapter \(currentChapter!) of \(Int(metadata.last_chapter)) - Page \(currentPage!) of \(metadata.chapters[currentChapter - 1].pages) + Volume \(Int(metadata.chapters[currentChapterIndex].volume)) of \(Int(metadata.last_volume)) + Chapter \(chapterString) of \(Int(metadata.last_chapter)) + Page \(currentPage!) of \(metadata.chapters[currentChapterIndex].pages) """ if let size = imageLoader.size[ getImagePath( - chapter: currentChapter, volume: Int(metadata.chapters[currentChapter - 1].volume), + chapter: metadata.chapters[currentChapterIndex].chapter, + volume: metadata.chapters[currentChapterIndex].volume, page: currentPage, path: currentPath ).path] @@ -943,9 +955,24 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { info.text = text } - func getImagePath(chapter: Int, volume: Int, page: Int, path: URL) -> URL! { - let modernPath = path.appendingPathComponent(String(format: "volume_%04d", volume)) - .appendingPathComponent(String(format: "chapter_%04d_page_%04d.png", chapter, page)) + func formatNumber(_ value: Float) -> String { + let integerPart = Int(value) + let fractionalPart = value - Float(integerPart) + + if fractionalPart == 0 { + return String(format: "%04d", integerPart) + } else { + // Convert fractional part to string without leading "0" + let fractionalString = String(String(value).split(separator: ".")[1]) + return String(format: "%04d.%@", integerPart, fractionalString) + } + } + + func getImagePath(chapter: Float, volume: Float, page: Int, path: URL) -> URL! { + let modernPath = path.appendingPathComponent(String(format: "volume_%04d", Int(volume))) + .appendingPathComponent( + String(format: "chapter_\(formatNumber(chapter))_page_%04d.png", page)) + print("trying to get path \(modernPath)") // if fileManager.fileExists(atPath: modernPath.path) { return modernPath // } @@ -956,20 +983,20 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { switch turn { case .next: if metadata.chapters.count >= chapter + 1 { - if page + 1 > metadata.chapters[chapter - 1].pages { + if page + 1 > metadata.chapters[chapter].pages { return (chapter + 1, 1) } else { return (chapter, page + 1) } } else { - return (chapter, min(metadata.chapters[chapter - 1].pages, page + 1)) + return (chapter, min(metadata.chapters[chapter].pages, page + 1)) } case .previous: if page < 2 { - if chapter > 1 { + if chapter > 0 { return ( chapter - 1, - metadata.chapters[chapter - 2].pages + metadata.chapters[chapter - 1].pages ) } else { return (chapter, page) @@ -1000,11 +1027,12 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { .scaleAspectFill } else { .scaleAspectFit } var directories: [URL] = [] - if currentPage != nil && currentChapter != nil { - var vol = Int(metadata.chapters[currentChapter - 1].volume) + if currentPage != nil && currentChapterIndex != nil { + var vol = metadata.chapters[currentChapterIndex].volume imageLoader.loadImage( at: getImagePath( - chapter: currentChapter, volume: vol, page: currentPage, path: currentPath + chapter: metadata.chapters[currentChapterIndex].chapter, volume: vol, + page: currentPage, path: currentPath ), scaling: scaling ) { [weak self] image in @@ -1013,11 +1041,12 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { } var (chapter, page) = getChapterAndPageFromTurn( - chapter: currentChapter, page: currentPage, turn: .next) + chapter: currentChapterIndex, page: currentPage, turn: .next) for _ in 0...preloadCount { - vol = Int(metadata.chapters[chapter - 1].volume) + vol = metadata.chapters[chapter].volume if let path = getImagePath( - chapter: chapter, volume: vol, page: page, path: currentPath) + chapter: metadata.chapters[chapter].chapter, volume: vol, page: page, + path: currentPath) { imageLoader.preloadImage(at: path, scaling: scaling) } else { @@ -1049,7 +1078,7 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { let path_meta = current.lastPathComponent.components(separatedBy: "_") assert(path_meta[0] == "chapter") - currentChapter = Int(path_meta[1])! + currentChapterIndex = Int(path_meta[1])! - 1 if path_meta[2] == "page" { currentPage = Int(path_meta[3].components(separatedBy: ".")[0]) if currentPage == nil { @@ -1078,12 +1107,12 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { ) { super.viewWillTransition(to: size, with: coordinator) if mode != .scroll { - self.imageLoader.loadImage( - at: self.getImagePath( - chapter: self.currentChapter, - volume: Int(self.metadata.chapters[self.currentChapter - 1].volume), - page: self.currentPage, - path: self.currentPath), + imageLoader.loadImage( + at: getImagePath( + chapter: metadata.chapters[currentChapterIndex].chapter, + volume: metadata.chapters[currentChapterIndex].volume, + page: currentPage, + path: currentPath), scaling: .scaleAspectFit ) { image in self.imageView.image = image @@ -1154,21 +1183,21 @@ extension ViewController: UICollectionViewDataSource, UICollectionViewDelegateFl if metadata == nil { return cell } - var (chapter, page) = chapterAndPages[indexPath.item] + var (chapterIndex, page) = chapterAndPages[indexPath.item] if let url = getImagePath( - chapter: chapter, - volume: Int(metadata.chapters[chapter - 1].volume), + chapter: metadata.chapters[chapterIndex].chapter, + volume: metadata.chapters[chapterIndex].volume, page: page, path: currentPath) { imageLoader.loadImage(at: url, scaling: scaling) { image in cell.imageView.image = image } for _ in 0...preloadCount { - (chapter, page) = getChapterAndPageFromTurn( - chapter: chapter, page: page, turn: .next) + (chapterIndex, page) = getChapterAndPageFromTurn( + chapter: chapterIndex, page: page, turn: .next) if let url = getImagePath( - chapter: chapter, - volume: Int(metadata.chapters[chapter - 1].volume), + chapter: metadata.chapters[chapterIndex].chapter, + volume: metadata.chapters[chapterIndex].volume, page: page, path: currentPath) { imageLoader.preloadImage(at: url, scaling: scaling) @@ -1212,8 +1241,8 @@ extension ViewController: UICollectionViewDataSource, UICollectionViewDelegateFl } let (chapter, page) = chapterAndPages[indexPath.item] if let imagePath = getImagePath( - chapter: chapter, - volume: Int(metadata.chapters[chapter - 1].volume), + chapter: metadata.chapters[chapter].chapter, + volume: metadata.chapters[chapter].volume, page: page, path: currentPath), let imageSource = CGImageSourceCreateWithURL(imagePath as CFURL, nil), let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil)