This commit is contained in:
2026-07-17 16:04:57 +02:00
parent 77872ed1ea
commit b2ff1dc624
+91 -68
View File
@@ -8,7 +8,7 @@ import UIKit
import ZIPFoundation
let preloadCount = 2
// With a whopping 2 cores, and 2 threads because no hyperthreading, it makes sense to only have a queue as an extra thread to do work with to allow the main thread for ui.
/// With a whopping 2 cores, and 2 threads because no hyperthreading, it makes sense to only have a queue as an extra thread to do work with to allow the main thread for ui.
let queue = DispatchQueue(label: "queue", qos: .utility)
enum PageTurn {
@@ -170,7 +170,7 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
}
func loadComics() {
let alert = UIAlertController(title: "Failed to load comics.", message: "This is an alert.", preferredStyle: .alert)
let alert = UIAlertController(title: "Failed to load comics.", message: "This is an alert.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
do {
var directories: [URL] = []
@@ -259,7 +259,8 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
func saveGlobalState() {
do {
try JSONEncoder().encode(globalState).write(
to: documentsURL.appendingPathComponent("state.json"))
to: documentsURL.appendingPathComponent("state.json")
)
} catch {
print("failed to save global state")
}
@@ -298,7 +299,8 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
guard let properties = CGImageSourceCopyPropertiesAtIndex(source, 0, nil) as? [CFString: Any],
let width = properties[kCGImagePropertyPixelWidth] as? CGFloat,
let height = properties[kCGImagePropertyPixelHeight] as? CGFloat else {
let height = properties[kCGImagePropertyPixelHeight] as? CGFloat
else {
return nil
}
@@ -322,8 +324,8 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
var currentChapter: (UInt32, UInt32?)!
if fileManager.fileExists(
atPath: path.appendingPathComponent(metadataFilename).absoluteString)
{
atPath: path.appendingPathComponent(metadataFilename).absoluteString
) {
print("skipped metadata file creation")
return
}
@@ -335,9 +337,9 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
var currentImages: [Offset] = []
var previousVolumeURL = ""
var titleValue: String = ""
var titleValue = ""
let alert = UIAlertController(title: "Failed to get metadata from filename.", message: "This is an alert.", preferredStyle: .alert)
let alert = UIAlertController(title: "Failed to get metadata from filename.", message: "This is an alert.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
let volumeDir = path.appendingPathComponent("volumes")
@@ -352,8 +354,8 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
includingPropertiesForKeys: [.isRegularFileKey],
options: [.skipsHiddenFiles]
).filter { $0.pathExtension == "cbz" }
.sorted { $0.lastPathComponent < $1.lastPathComponent }
if volumeURLs == nil {
.sorted { $0.lastPathComponent < $1.lastPathComponent }
if volumeURLs == nil {
alert.message = String(format: "failed to read dir: \(volumeDir)")
pendingAlert = alert
return
@@ -478,14 +480,12 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
nChapter0, chapterParts.count > 1 ? UInt32(chapterParts[1]) : nil
)
guard let volume: UInt32 = UInt32((filename as NSString).substring(with: match.range(at: volumeRegexPosition))) else {
guard let volume = UInt32((filename as NSString).substring(with: match.range(at: volumeRegexPosition))) else {
alert.message = String(format: "failed to get match for volume in filename: \(filename)")
pendingAlert = alert
return
}
let pageStr = (filename as NSString).substring(with: match.range(at: pageRegexPosition))
let pageParts = pageStr.split(separator: "-", maxSplits: 1)
guard let nPage = UInt32(pageParts[0]) else {
@@ -512,7 +512,8 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
return
}
let m_filename = builder.create(string: filename)
let imageMetadata = ImageMetadata.createImageMetadata(&builder,
let imageMetadata = ImageMetadata.createImageMetadata(
&builder,
doublePage: doublePage,
filenameOffset: m_filename,
firstPage: page,
@@ -525,12 +526,13 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
let chapterName = builder.create(string: "")
let imagesOffset = builder.createVector(ofOffsets: currentImages)
let chapterMetadata = ChapterMetadata.createChapterMetadata(&builder,
let chapterMetadata = ChapterMetadata.createChapterMetadata(
&builder,
chapter: MetaValue(
main: currentChapter.0, bonus: currentChapter.1 ?? 0
),
nameOffset: chapterName,
imagesVectorOffset: imagesOffset,
imagesVectorOffset: imagesOffset
)
currentChapters.append(chapterMetadata)
@@ -543,7 +545,7 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
volume: MetaValue(main: currentVolume, bonus: 0),
titleOffset: volumeTitle,
archiveOffset: volumeURLOffset,
chaptersVectorOffset: chaptersOffset,
chaptersVectorOffset: chaptersOffset
)
volumes.append(volumeMetadata)
@@ -574,12 +576,13 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
let chapterName = builder.create(string: "")
let imagesOffset = builder.createVector(ofOffsets: currentImages)
let chapterMetadata = ChapterMetadata.createChapterMetadata(&builder,
let chapterMetadata = ChapterMetadata.createChapterMetadata(
&builder,
chapter: MetaValue(
main: currentChapter.0, bonus: currentChapter.1 ?? 0
),
nameOffset: chapterName,
imagesVectorOffset: imagesOffset,
imagesVectorOffset: imagesOffset
)
currentChapters.append(chapterMetadata)
@@ -592,15 +595,16 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
} else {
currentImages.append(imageMetadata)
}
if (i == filenames.count - 1) {
if i == filenames.count - 1 {
let chapterName = builder.create(string: "")
let imagesOffset = builder.createVector(ofOffsets: currentImages)
let chapterMetadata = ChapterMetadata.createChapterMetadata(&builder,
let chapterMetadata = ChapterMetadata.createChapterMetadata(
&builder,
chapter: MetaValue(
main: chapter.0, bonus: chapter.1 ?? 0
),
nameOffset: chapterName,
imagesVectorOffset: imagesOffset,
imagesVectorOffset: imagesOffset
)
currentChapters.append(chapterMetadata)
@@ -658,7 +662,7 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
endReleaseDate: Date(year: 2000, month: 1, day: 1),
tagsVectorOffset: tags,
descriptionOffset: description,
volumesVectorOffset: volumeOffsets,
volumesVectorOffset: volumeOffsets
)
builder.finish(offset: metadata)
@@ -702,7 +706,8 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
progress: newProgress, backgroundColor: self.convertColorToString(color: color)
)
).write(
to: self.currentPath.appendingPathComponent("state.json"))
to: self.currentPath.appendingPathComponent("state.json")
)
} catch {
print("failed to save local state")
}
@@ -1037,25 +1042,33 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
equalTo: topBarView.leadingAnchor, constant: 32
),
backgroundColorDropdownButton.centerYAnchor.constraint(
equalTo: topBarView.centerYAnchor),
equalTo: topBarView.centerYAnchor
),
backgroundColorDropdownButton.topAnchor.constraint(
equalTo: topBarView.topAnchor),
equalTo: topBarView.topAnchor
),
backgroundColorDropdownButton.bottomAnchor.constraint(
equalTo: topBarView.bottomAnchor),
equalTo: topBarView.bottomAnchor
),
backgroundColorDropdownView.topAnchor.constraint(
equalTo: backgroundColorDropdownButton.bottomAnchor),
equalTo: backgroundColorDropdownButton.bottomAnchor
),
backgroundColorDropdownView.leadingAnchor.constraint(
equalTo: backgroundColorDropdownButton.leadingAnchor),
equalTo: backgroundColorDropdownButton.leadingAnchor
),
backgroundColorDropdownView.trailingAnchor.constraint(
equalTo: backgroundColorDropdownButton.trailingAnchor),
equalTo: backgroundColorDropdownButton.trailingAnchor
),
stackView.topAnchor.constraint(
equalTo: backgroundColorDropdownView.topAnchor),
equalTo: backgroundColorDropdownView.topAnchor
),
stackView.bottomAnchor.constraint(equalTo: backgroundColorDropdownView.bottomAnchor),
stackView.leadingAnchor.constraint(equalTo: backgroundColorDropdownView.leadingAnchor),
stackView.trailingAnchor.constraint(
equalTo: backgroundColorDropdownView.trailingAnchor),
equalTo: backgroundColorDropdownView.trailingAnchor
),
])
}
@@ -1103,25 +1116,33 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
equalTo: backgroundColorDropdownButton.trailingAnchor, constant: 32
),
pageTurnDropdownButton.centerYAnchor.constraint(
equalTo: topBarView.centerYAnchor),
equalTo: topBarView.centerYAnchor
),
pageTurnDropdownButton.topAnchor.constraint(
equalTo: topBarView.topAnchor),
equalTo: topBarView.topAnchor
),
pageTurnDropdownButton.bottomAnchor.constraint(
equalTo: topBarView.bottomAnchor),
equalTo: topBarView.bottomAnchor
),
pageTurnDropdownView.topAnchor.constraint(
equalTo: pageTurnDropdownButton.bottomAnchor),
equalTo: pageTurnDropdownButton.bottomAnchor
),
pageTurnDropdownView.leadingAnchor.constraint(
equalTo: pageTurnDropdownButton.leadingAnchor),
equalTo: pageTurnDropdownButton.leadingAnchor
),
pageTurnDropdownView.trailingAnchor.constraint(
equalTo: pageTurnDropdownButton.trailingAnchor),
equalTo: pageTurnDropdownButton.trailingAnchor
),
stackView.topAnchor.constraint(
equalTo: pageTurnDropdownView.topAnchor),
equalTo: pageTurnDropdownView.topAnchor
),
stackView.bottomAnchor.constraint(equalTo: pageTurnDropdownView.bottomAnchor),
stackView.leadingAnchor.constraint(equalTo: pageTurnDropdownView.leadingAnchor),
stackView.trailingAnchor.constraint(
equalTo: pageTurnDropdownView.trailingAnchor),
equalTo: pageTurnDropdownView.trailingAnchor
),
])
}
@@ -1378,9 +1399,8 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
func getImagePath(_ progress: ProgressIndices) -> String {
let (v, c, i) = (progress.v, progress.c, progress.i)
let modernPath = metadata.volumes[v].chapters[c].images[i].filename!
return metadata.volumes[v].chapters[c].images[i].filename!
// if fileManager.fileExists(atPath: modernPath.path) {
return modernPath
// }
// return nil
}
@@ -1445,7 +1465,7 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
archiveURL: getArchiveURL(newProgress.v),
filename: getImagePath(newProgress),
scaling: scaling,
screenSize: UIScreen.main.bounds.size,
screenSize: UIScreen.main.bounds.size
)
}
}
@@ -1471,7 +1491,8 @@ func getGlobalState() -> GlobalState {
let json = try Data(
String(
contentsOfFile: path
).utf8)
).utf8
)
return try JSONDecoder().decode(GlobalState.self, from: json)
} catch {
print("Error reading directory contents: \(error)")
@@ -1538,14 +1559,14 @@ extension ViewController: UICollectionViewDataSource, UICollectionViewDelegateFl
}
var newProgress = ProgressIndices(v: 0, c: 0, i: 0)
if indexPath.item != 0 {
for _ in 0 ..< indexPath.item {
newProgress = getProgressIndicesFromTurn(turn: .next, progress: newProgress)
}
for _ in 0 ..< indexPath.item {
newProgress = getProgressIndicesFromTurn(turn: .next, progress: newProgress)
}
}
imageLoader.loadImage(
archiveURL: getArchiveURL(progress.v),
filename: getImagePath(newProgress),
scaling: scaling, screenSize: UIScreen.main.bounds.size
archiveURL: getArchiveURL(progress.v),
filename: getImagePath(newProgress),
scaling: scaling, screenSize: UIScreen.main.bounds.size
) { image in
cell.imageView.image = image
}
@@ -1579,7 +1600,7 @@ extension ViewController: UICollectionViewDataSource, UICollectionViewDelegateFl
}
var newProgress = ProgressIndices(v: 0, c: 0, i: 0)
for _ in 0 ..< indexPath.item {
newProgress = getProgressIndicesFromTurn(turn: .next, progress: newProgress)
newProgress = getProgressIndicesFromTurn(turn: .next, progress: newProgress)
}
let imageMetadata = metadata.volumes[newProgress.v].chapters[newProgress.c].images[newProgress.i]
return CGSize(
@@ -1767,7 +1788,7 @@ class ImageLoader {
orientation: rotation,
screenSize: screenSize,
scaling: scaling,
filename: key,
filename: key
)
if token.isCancelled { finish(); return }
@@ -1781,14 +1802,14 @@ class ImageLoader {
orientation: otherOrientation,
screenSize: screenSize,
scaling: scaling,
filename: key,
filename: key
)
finish()
}
}
func scaleAndCacheImage(image: UIImage, orientation: Rotation, screenSize: CGSize, scaling: UIView.ContentMode, filename: String) -> UIImage {
let resizeTo: CGSize = if orientation == .vertical {
let resizeTo = if orientation == .vertical {
CGSize(
width: min(screenSize.width, screenSize.height),
height: max(screenSize.height, screenSize.width)
@@ -1802,17 +1823,17 @@ class ImageLoader {
let scaledSize = aspectSize(for: image.size, in: resizeTo, scaling: scaling)
let scaledImage = resizeImage(image, to: scaledSize)
let cost = imageByteSize(scaledImage)!
switch ((orientation, scaling)) {
case (.vertical, .scaleAspectFit):
self.portraitFitCache.setObject(scaledImage, forKey: filename as NSString, cost: cost)
case (.vertical, .scaleAspectFill):
self.portraitFillCache.setObject(scaledImage, forKey: filename as NSString, cost: cost)
case (.horizontal, .scaleAspectFit):
self.landscapeFitCache.setObject(scaledImage, forKey: filename as NSString, cost: cost)
case (.horizontal, .scaleAspectFill):
self.landscapeFillCache.setObject(scaledImage, forKey: filename as NSString, cost: cost)
default:
assertionFailure()
switch (orientation, scaling) {
case (.vertical, .scaleAspectFit):
portraitFitCache.setObject(scaledImage, forKey: filename as NSString, cost: cost)
case (.vertical, .scaleAspectFill):
portraitFillCache.setObject(scaledImage, forKey: filename as NSString, cost: cost)
case (.horizontal, .scaleAspectFit):
landscapeFitCache.setObject(scaledImage, forKey: filename as NSString, cost: cost)
case (.horizontal, .scaleAspectFill):
landscapeFillCache.setObject(scaledImage, forKey: filename as NSString, cost: cost)
default:
assertionFailure()
}
return scaledImage
}
@@ -1897,12 +1918,13 @@ func imageDimensions(of entry: Entry, in archive: Archive) throws -> ImageDimens
if let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [String: Any],
let width = properties[kCGImagePropertyPixelWidth as String] as? Int,
let height = properties[kCGImagePropertyPixelHeight as String] as? Int {
let height = properties[kCGImagePropertyPixelHeight as String] as? Int
{
// We have what we need abort the rest of the decompression
throw ImageSizeResult.found(ImageDimensions(width: width, height: height))
}
}
} catch ImageSizeResult.found(let dimensions) {
} catch let ImageSizeResult.found(dimensions) {
return dimensions
}
@@ -1910,7 +1932,8 @@ func imageDimensions(of entry: Entry, in archive: Archive) throws -> ImageDimens
CGImageSourceUpdateData(imageSource, accumulatedData as CFData, true)
if let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [String: Any],
let width = properties[kCGImagePropertyPixelWidth as String] as? Int,
let height = properties[kCGImagePropertyPixelHeight as String] as? Int {
let height = properties[kCGImagePropertyPixelHeight as String] as? Int
{
print("This fell back to loading the complete image for size metadata")
return ImageDimensions(width: width, height: height)
}