feat: alerts #21

Merged
vegardbm merged 1 commits from alerts into master 2026-07-17 21:08:28 +02:00
+144 -24
View File
@@ -59,6 +59,8 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
var scrollPos: CGPoint! var scrollPos: CGPoint!
var hasSetContentOffset = false var hasSetContentOffset = false
var pendingAlert: UIAlertController?
var imageView = UIImageView() var imageView = UIImageView()
var mode = PageTurnMode.leftToRight var mode = PageTurnMode.leftToRight
var metadataList: [URL: Metadata] = [:] var metadataList: [URL: Metadata] = [:]
@@ -105,6 +107,13 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
setup() setup()
} }
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if let alert = pendingAlert {
present(alert, animated: false, completion: nil)
}
}
func setup() { func setup() {
do { do {
if try fileManager.contentsOfDirectory(atPath: documentsURL.path).isEmpty { if try fileManager.contentsOfDirectory(atPath: documentsURL.path).isEmpty {
@@ -140,8 +149,6 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
setupHomeView() setupHomeView()
if let name = globalState.comicName { if let name = globalState.comicName {
readComic(name: name) readComic(name: name)
} else {
print("no comic?")
} }
} }
@@ -163,14 +170,21 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
} }
func loadComics() { func loadComics() {
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 { do {
var directories: [URL] = [] var directories: [URL] = []
let contents = try fileManager.contentsOfDirectory( guard let contents = try? fileManager.contentsOfDirectory(
at: documentsURL, at: documentsURL,
includingPropertiesForKeys: [.isDirectoryKey], includingPropertiesForKeys: [.isDirectoryKey],
options: [.skipsHiddenFiles] options: [.skipsHiddenFiles]
) )
else {
alert.message = String(format: "Failed to read contents of directory: \(documentsURL)")
pendingAlert = alert
return
}
directories = contents.filter { url in directories = contents.filter { url in
var isDirectory: ObjCBool = false var isDirectory: ObjCBool = false
@@ -181,33 +195,63 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
for dir in directories { for dir in directories {
if !fileManager.fileExists(atPath: dir.appendingPathComponent(metadataFilename).path) { if !fileManager.fileExists(atPath: dir.appendingPathComponent(metadataFilename).path) {
getMetadataFromFilename(path: dir) getMetadataFromFilename(path: dir)
if pendingAlert != nil {
return
}
} }
currentPath = dir currentPath = dir
let data = try! Data(contentsOf: dir.appendingPathComponent(metadataFilename)) guard let data = try? Data(contentsOf: dir.appendingPathComponent(metadataFilename))
else {
alert.message = String(format: "Failed to read contents of metadata: \(dir.appendingPathComponent(metadataFilename))")
pendingAlert = alert
return
}
var byteBuffer = ByteBuffer(data: data) var byteBuffer = ByteBuffer(data: data)
metadata = try! getCheckedRoot(byteBuffer: &byteBuffer) metadata = try? getCheckedRoot(byteBuffer: &byteBuffer)
if metadata == nil {
alert.message = String(format: "Failed to read contents of metadata flatbuffer file: \(dir.appendingPathComponent(metadataFilename))")
pendingAlert = alert
return
}
metadataList[dir] = metadata metadataList[dir] = metadata
loadLocalState() loadLocalState()
let volCovP = ProgressIndices(v: progress.v, c: 0, i: 0) let volCovP = ProgressIndices(v: progress.v, c: 0, i: 0)
let archivePath = getArchiveURL(volCovP.v) let archivePath = getArchiveURL(volCovP.v)
let archive = try! Archive(url: archivePath, accessMode: .read) let archive = try Archive(url: archivePath, accessMode: .read)
let filename = metadata.volumes[volCovP.v].chapters[volCovP.c].images[volCovP.i].filename! let filename = metadata.volumes[volCovP.v].chapters[volCovP.c].images[volCovP.i].filename!
let targetEntry = archive[filename]! guard let targetEntry = archive[filename] else {
alert.message = String(format: "Archive entry does not exist: \(filename)")
pendingAlert = alert
return
}
var extractedData = Data() var extractedData = Data()
_ = try archive.extract(targetEntry) { data in do {
extractedData.append(data) _ = try archive.extract(targetEntry) { data in
extractedData.append(data)
}
} catch {
alert.message = String(format: "Failed to extract data from entry: \(targetEntry.path)")
pendingAlert = alert
return
}
guard let coverImage = UIImage(data: extractedData) else {
alert.message = String(format: "Cover image is nil: \(filename)")
pendingAlert = alert
return
} }
comics.append( comics.append(
Comic( Comic(
cover: UIImage(data: extractedData)!, cover: coverImage,
metadata: metadata, metadata: metadata,
path: dir path: dir
) )
) )
} }
} catch { } catch {
pendingAlert = alert
alert.message = String(format: "Generic failure.")
print("Failed to read directories") print("Failed to read directories")
} }
} }
@@ -263,9 +307,9 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
func getMetadataFromFilename(path: URL) { func getMetadataFromFilename(path: URL) {
// Beautiful, is it not? // Beautiful, is it not?
let patterns: [(NSRegularExpression, NSRegularExpression, Int, Int, Int)] = [ let patterns: [(NSRegularExpression?, NSRegularExpression?, Int, Int, Int)] = [
(try! NSRegularExpression(pattern: #"c([0-9]+(?:x[0-9]+)?) \(v([0-9]+)\) - p([0-9]+(?:-p?[0-9]+)?)"#), try! NSRegularExpression(pattern: #"^(.*) - c([0-9]+(?:x[0-9]+)?) \(v([0-9]+)\) - p([0-9]+(?:-p?[0-9]+)?)"#), 3, 1, 2), (try? NSRegularExpression(pattern: #"c([0-9]+(?:x[0-9]+)?) \(v([0-9]+)\) - p([0-9]+(?:-p?[0-9]+)?)"#), try? NSRegularExpression(pattern: #"^(.*) - c([0-9]+(?:x[0-9]+)?) \(v([0-9]+)\) - p([0-9]+(?:-p?[0-9]+)?)"#), 3, 1, 2),
(try! NSRegularExpression(pattern: "v([0-9]+) p([0-9]+(?:-[0-9]+)?) - c([0-9]+(?:x[0-9]+)?)"), try! NSRegularExpression(pattern: "^(.*) - v([0-9]+) p([0-9]+(?:-[0-9]+)?) - c([0-9]+(?:x[0-9]+)?)"), 2, 3, 1), (try? NSRegularExpression(pattern: "v([0-9]+) p([0-9]+(?:-[0-9]+)?) - c([0-9]+(?:x[0-9]+)?)"), try? NSRegularExpression(pattern: "^(.*) - v([0-9]+) p([0-9]+(?:-[0-9]+)?) - c([0-9]+(?:x[0-9]+)?)"), 2, 3, 1),
] ]
var pattern: NSRegularExpression! = nil var pattern: NSRegularExpression! = nil
var titlePattern: NSRegularExpression! = nil var titlePattern: NSRegularExpression! = nil
@@ -293,6 +337,9 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
var titleValue: String = "" var titleValue: String = ""
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") let volumeDir = path.appendingPathComponent("volumes")
var isDir: ObjCBool = false var isDir: ObjCBool = false
@@ -300,25 +347,42 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
print("Subdirectory volumes not found in \"\(path)\", returning") print("Subdirectory volumes not found in \"\(path)\", returning")
return return
} }
let volumeURLs = try! fileManager.contentsOfDirectory( let volumeURLs = try? fileManager.contentsOfDirectory(
at: volumeDir, at: volumeDir,
includingPropertiesForKeys: [.isRegularFileKey], includingPropertiesForKeys: [.isRegularFileKey],
options: [.skipsHiddenFiles] options: [.skipsHiddenFiles]
).filter { $0.pathExtension == "cbz" } ).filter { $0.pathExtension == "cbz" }
.sorted { $0.lastPathComponent < $1.lastPathComponent } .sorted { $0.lastPathComponent < $1.lastPathComponent }
if volumeURLs == nil {
alert.message = String(format: "failed to read dir: \(volumeDir)")
pendingAlert = alert
return
}
if volumeURLs.isEmpty { if volumeURLs!.isEmpty {
print("found no volumes in volume dir: \(volumeDir)") print("found no volumes in volume dir: \(volumeDir)")
return return
} }
var filenames: [(String, String)] = [] var filenames: [(String, String)] = []
for volumeURL in volumeURLs { for volumeURL in volumeURLs! {
do { do {
let volumeArchive = try Archive(url: volumeURL, accessMode: .read) let volumeArchive = try Archive(url: volumeURL, accessMode: .read)
volumeArchive.map { URL(string: $0.path)!.lastPathComponent }.sorted().forEach{ filenames.append((volumeURL.lastPathComponent, $0)) } var volumeArchiveFiles: [String] = []
for entry in volumeArchive {
// guard let url = URL(string: entry.path) else {
// alert.message = String(format: "failed to create URL from string: \(entry.path)")
// pendingAlert = alert
// return
// }
volumeArchiveFiles.append(entry.path)
}
for filename in volumeArchiveFiles.sorted() {
filenames.append((volumeURL.lastPathComponent, filename))
}
} catch { } catch {
print("Failed to read archive \(volumeURL)") alert.message = String(format: "failed to read archive: \(volumeURL)")
pendingAlert = alert
continue continue
} }
} }
@@ -330,6 +394,16 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
do { do {
for (currentPattern, currentTitlePattern, currentPageRegexPosition, currentChapterRegexPosition, currentVolumeRegexPosition) in patterns { for (currentPattern, currentTitlePattern, currentPageRegexPosition, currentChapterRegexPosition, currentVolumeRegexPosition) in patterns {
guard let currentPattern = currentPattern else {
alert.message = String(format: "failed to get currentPattern")
pendingAlert = alert
continue
}
guard let currentTitlePattern = currentTitlePattern else {
alert.message = String(format: "failed to get currentTitlePattern")
pendingAlert = alert
continue
}
let filename = filenames[0].1 let filename = filenames[0].1
let range = NSRange(filename.startIndex..., in: filename) let range = NSRange(filename.startIndex..., in: filename)
if let match = currentTitlePattern.firstMatch(in: filename, range: range) { if let match = currentTitlePattern.firstMatch(in: filename, range: range) {
@@ -390,25 +464,51 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
if let match = regex.firstMatch(in: filename, range: range) { if let match = regex.firstMatch(in: filename, range: range) {
let chapterStr = (filename as NSString).substring(with: match.range(at: chapterRegexPosition)) let chapterStr = (filename as NSString).substring(with: match.range(at: chapterRegexPosition))
let chapterParts = chapterStr.split(separator: "x", maxSplits: 1) let chapterParts = chapterStr.split(separator: "x", maxSplits: 1)
if chapterParts.count < 1 {
alert.message = String(format: "Did not find chapter number in filename: \(filename)")
pendingAlert = alert
return
}
guard let nChapter0 = UInt32(chapterParts[0]) else {
alert.message = String(format: "Failed to convert chapter number to an int: \(filename)")
pendingAlert = alert
return
}
let chapter: (UInt32, UInt32?) = ( let chapter: (UInt32, UInt32?) = (
UInt32(chapterParts[0])!, chapterParts.count > 1 ? UInt32(chapterParts[1])! : nil nChapter0, chapterParts.count > 1 ? UInt32(chapterParts[1]) : nil
) )
let volume: UInt32 = UInt32((filename as NSString).substring(with: match.range(at: volumeRegexPosition)))!
guard let volume: UInt32 = 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 pageStr = (filename as NSString).substring(with: match.range(at: pageRegexPosition))
let pageParts = pageStr.split(separator: "-", maxSplits: 1) let pageParts = pageStr.split(separator: "-", maxSplits: 1)
guard let nPage = UInt32(pageParts[0]) else {
alert.message = String(format: "failed to read archive: \(filename)")
pendingAlert = alert
return
}
let (page, doublePage) = ( let (page, doublePage) = (
UInt32(pageParts[0])!, pageParts.count > 1 nPage, pageParts.count > 1
) )
let archive = try Archive(url: volumeDir.appendingPathComponent(volumeURL), accessMode: .read) let archive = try Archive(url: volumeDir.appendingPathComponent(volumeURL), accessMode: .read)
let entry = archive[filename]! guard let entry = archive[filename] else {
alert.message = String(format: "failed to read archive: \(filename)")
pendingAlert = alert
return
}
var size = ImageDimensions(width: 0, height: 0) var size = ImageDimensions(width: 0, height: 0)
do { do {
size = try imageDimensions(of: entry, in: archive) size = try imageDimensions(of: entry, in: archive)
} catch { } catch {
print("Failed to get image dimensions of filename: \(filename)") alert.message = String(format: "Failed to get image dimensions of filename: \(filename)")
pendingAlert = alert
return return
} }
let m_filename = builder.create(string: filename) let m_filename = builder.create(string: filename)
@@ -452,8 +552,23 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
currentChapters = [] currentChapters = []
} else if chapter != currentChapter { } else if chapter != currentChapter {
if chapter.0 == currentChapter.0 { if chapter.0 == currentChapter.0 {
if chapter.1 == nil {
alert.message = String(format: "chapter.1 is nil")
pendingAlert = alert
return
}
if chapter.1! != currentChapter.1 ?? 1 {
alert.message = String(format: "chapter != currentChapter")
pendingAlert = alert
return
}
assert(chapter.1! == currentChapter.1 ?? 1) assert(chapter.1! == currentChapter.1 ?? 1)
} else { } else {
if chapter.0 != currentChapter.0 + 1 {
alert.message = String(format: "chapter.0 != currentChapter.0 + 1")
pendingAlert = alert
return
}
assert(chapter.0 == currentChapter.0 + 1) assert(chapter.0 == currentChapter.0 + 1)
} }
@@ -547,7 +662,12 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
) )
builder.finish(offset: metadata) builder.finish(offset: metadata)
try! builder.data.write(to: path.appendingPathComponent(metadataFilename)) do {
try builder.data.write(to: path.appendingPathComponent(metadataFilename))
} catch {
alert.message = String(format: "Failed to write metadata file at: \(metadataFilename)")
pendingAlert = alert
}
} }
func saveLocalState() { func saveLocalState() {