fix: better local state handling
This commit is contained in:
@@ -21,10 +21,10 @@ enum ReadProgress: Codable {
|
||||
case scroll(CGPoint)
|
||||
}
|
||||
|
||||
struct ProgressIndices {
|
||||
var v: Int
|
||||
var c: Int
|
||||
var i: Int
|
||||
struct ProgressIndices: Codable {
|
||||
var v: Int = 0
|
||||
var c: Int = 0
|
||||
var i: Int = 0
|
||||
}
|
||||
|
||||
enum PageTurnMode: Codable, CaseIterable {
|
||||
@@ -43,11 +43,13 @@ struct GlobalState: Codable {
|
||||
var comicName: String?
|
||||
}
|
||||
|
||||
/// nil indicates a default should be used, aka what is in settings.
|
||||
struct LocalState: Codable {
|
||||
var progress: ReadProgress
|
||||
var progress: ProgressIndices = ProgressIndices()
|
||||
var mode: PageTurnMode?
|
||||
var backgroundColor: String?
|
||||
var useDefaultPageTurnMode: Bool
|
||||
var aniListTracking: Bool
|
||||
var aniListTracking: Bool = false
|
||||
var scrollPos: CGPoint = CGPoint()
|
||||
}
|
||||
|
||||
struct Settings: Codable {
|
||||
@@ -63,7 +65,6 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
var readerView = UIView()
|
||||
|
||||
@IBOutlet var scrollingCollectionView: UICollectionView!
|
||||
var scrollPos: CGPoint!
|
||||
var hasSetContentOffset = false
|
||||
|
||||
var pendingAlert: UIAlertController?
|
||||
@@ -72,16 +73,13 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
let dragRangeForFullBrightness: CGFloat = 300
|
||||
|
||||
var imageView = UIImageView()
|
||||
var mode = PageTurnMode.leftToRight
|
||||
var useDefaultPageTurnMode = true
|
||||
var useDefaultBackgroundColor = true
|
||||
var metadataList: [URL: Metadata] = [:]
|
||||
// directory name is key, indexPath.item can change.
|
||||
var state: [String: LocalState] = [:]
|
||||
var metadata: Metadata!
|
||||
var progress = ProgressIndices(v: 0, c: 0, i: 0)
|
||||
var currentPath: URL!
|
||||
var lastLayoutSize: CGSize = .zero
|
||||
var aniListToken: String? = getAniListToken()
|
||||
var aniListTracking: [Int: Bool] = [:]
|
||||
var currentItemIndex = 0
|
||||
|
||||
var leftTap: UITapGestureRecognizer!
|
||||
@@ -126,9 +124,9 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
if let alert = pendingAlert {
|
||||
present(alert, animated: false, completion: nil)
|
||||
}
|
||||
if !hasSetContentOffset, scrollPos != nil {
|
||||
if !hasSetContentOffset, let scrollPos = state[currentPath.lastPathComponent]?.scrollPos {
|
||||
let screenSize = UIScreen.main.bounds.size
|
||||
var offset = scrollPos!
|
||||
var offset = scrollPos
|
||||
if screenSize.width > screenSize.height {
|
||||
offset.y *= (screenSize.width / screenSize.height)
|
||||
}
|
||||
@@ -142,6 +140,20 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func getMode() -> PageTurnMode {
|
||||
if let state = state[currentPath.lastPathComponent] {
|
||||
return state.mode ?? settings.defaultPageTurnMode
|
||||
}
|
||||
return settings.defaultPageTurnMode
|
||||
}
|
||||
|
||||
func getProgress() -> ProgressIndices {
|
||||
if let state = state[currentPath.lastPathComponent] {
|
||||
return state.progress
|
||||
}
|
||||
return ProgressIndices()
|
||||
}
|
||||
|
||||
func setup() {
|
||||
do {
|
||||
if try fileManager.contentsOfDirectory(atPath: documentsURL.path).isEmpty {
|
||||
@@ -170,7 +182,6 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
readerView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
||||
readerView.widthAnchor.constraint(equalTo: view.widthAnchor),
|
||||
])
|
||||
mode = settings.defaultPageTurnMode
|
||||
setupScrollingCollectionView()
|
||||
loadComics()
|
||||
setupImageView()
|
||||
@@ -285,7 +296,7 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
}
|
||||
metadataList[dir] = metadata
|
||||
loadLocalState()
|
||||
let volCovP = ProgressIndices(v: progress.v, c: 0, i: 0)
|
||||
let volCovP = ProgressIndices(v: state[currentPath.lastPathComponent]!.progress.v, c: 0, i: 0)
|
||||
let archivePath = getArchiveURL(volCovP.v)
|
||||
let archive = try Archive(url: archivePath, accessMode: .read)
|
||||
let filename = metadata.volumes[volCovP.v].chapters[volCovP.c].images[volCovP.i].filename!
|
||||
@@ -772,37 +783,30 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
}
|
||||
|
||||
func saveLocalState() {
|
||||
guard let currentDir = currentPath?.lastPathComponent else { print("did not save currentPath nil"); return }
|
||||
guard let currentState = state[currentDir] else { print("did not save currentState nil"); return }
|
||||
let progress = currentState.progress
|
||||
let mode = currentState.mode
|
||||
let color = readerView.backgroundColor ?? .black
|
||||
let aniListTracking = currentState.aniListTracking
|
||||
|
||||
let screenSize = UIScreen.main.bounds.size
|
||||
var scrollOffset = scrollingCollectionView.contentOffset
|
||||
if screenSize.width > screenSize.height {
|
||||
scrollOffset.y *= (screenSize.height / screenSize.width)
|
||||
}
|
||||
var newProgress =
|
||||
ReadProgress.leftToRight(
|
||||
volumeIndex: progress.v, chapterIndex: progress.c,
|
||||
imageIndex: progress.i
|
||||
)
|
||||
// TODO: Calucate the offset based on progress, to allow seamless switching.
|
||||
if mode != .scroll {}
|
||||
|
||||
switch mode {
|
||||
case .leftToRight:
|
||||
newProgress = ReadProgress.leftToRight(
|
||||
volumeIndex: progress.v, chapterIndex: progress.c,
|
||||
imageIndex: progress.i
|
||||
)
|
||||
case .rightToLeft: newProgress = ReadProgress.rightToLeft(
|
||||
volumeIndex: progress.v, chapterIndex: progress.c,
|
||||
imageIndex: progress.i
|
||||
)
|
||||
case .scroll: newProgress = ReadProgress.scroll(scrollOffset)
|
||||
}
|
||||
queue.async {
|
||||
do {
|
||||
try JSONEncoder().encode(
|
||||
LocalState(
|
||||
progress: newProgress, backgroundColor: self.convertColorToString(color),
|
||||
useDefaultPageTurnMode: self.useDefaultPageTurnMode,
|
||||
aniListTracking: self.aniListTracking[self.currentItemIndex] ?? false
|
||||
progress: progress,
|
||||
mode: mode,
|
||||
backgroundColor: self.convertColorToString(color),
|
||||
aniListTracking: aniListTracking,
|
||||
scrollPos: scrollOffset
|
||||
)
|
||||
).write(
|
||||
to: self.currentPath.appendingPathComponent("state.json")
|
||||
@@ -814,59 +818,22 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
}
|
||||
|
||||
func loadLocalState() {
|
||||
if state[currentPath.lastPathComponent] != nil { return }
|
||||
do {
|
||||
let path = currentPath.appendingPathComponent("state.json").path
|
||||
if !fileManager.fileExists(atPath: path) {
|
||||
progress = ProgressIndices(v: 0, c: 0, i: 0)
|
||||
mode = settings.defaultPageTurnMode
|
||||
state[currentPath.lastPathComponent] = LocalState()
|
||||
return
|
||||
}
|
||||
let json = try Data(String(contentsOfFile: path).utf8)
|
||||
let local = try JSONDecoder().decode(LocalState.self, from: json)
|
||||
useDefaultPageTurnMode = local.useDefaultPageTurnMode
|
||||
aniListTracking[currentItemIndex] = local.aniListTracking
|
||||
switch local.progress {
|
||||
case let .leftToRight(volumeIndex, chapterIndex, imageIndex):
|
||||
progress.v = volumeIndex
|
||||
progress.c = chapterIndex
|
||||
progress.i = imageIndex
|
||||
mode = useDefaultPageTurnMode ? settings.defaultPageTurnMode : .leftToRight
|
||||
case let .rightToLeft(volumeIndex, chapterIndex, imageIndex):
|
||||
progress.v = volumeIndex
|
||||
progress.c = chapterIndex
|
||||
progress.i = imageIndex
|
||||
mode = useDefaultPageTurnMode ? settings.defaultPageTurnMode : .rightToLeft
|
||||
case let .scroll(point):
|
||||
if scrollPos == nil {
|
||||
scrollPos = point
|
||||
let screenSize = UIScreen.main.bounds.size
|
||||
var scrollOffset = point
|
||||
if screenSize.width > screenSize.height {
|
||||
scrollOffset.y *= (screenSize.width / screenSize.height)
|
||||
}
|
||||
if let indexPath = scrollingCollectionView.indexPathForItem(at: scrollOffset) {
|
||||
var theProgress = ProgressIndices(v: 0, c: 0, i: 0)
|
||||
for _ in 0 ..< indexPath.item {
|
||||
theProgress = getProgressIndicesFromTurn(
|
||||
turn: .next, progress: theProgress
|
||||
)
|
||||
}
|
||||
progress = theProgress
|
||||
}
|
||||
}
|
||||
mode = useDefaultPageTurnMode ? settings.defaultPageTurnMode : .scroll
|
||||
}
|
||||
if let color = local.backgroundColor {
|
||||
readerView.backgroundColor = convertStringToColor(color)
|
||||
useDefaultBackgroundColor = false
|
||||
} else {
|
||||
readerView.backgroundColor = convertStringToColor(settings.defaultReadingBackgroundColor)
|
||||
useDefaultBackgroundColor = true
|
||||
}
|
||||
state[currentPath.lastPathComponent] = local
|
||||
} catch let decodingError as DecodingError {
|
||||
print(decodingError.errorDescription!)
|
||||
print("Failed to decode state.json, setting default: \(decodingError.errorDescription ?? "")")
|
||||
state[currentPath.lastPathComponent] = LocalState()
|
||||
} catch {
|
||||
print("Unexpected error: \(error)")
|
||||
print("Failed to decode state.json, setting default: \(error)")
|
||||
state[currentPath.lastPathComponent] = LocalState()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -899,8 +866,9 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
for _ in 0 ..< indexPath.item {
|
||||
newProgress = getProgressIndicesFromTurn(turn: .next, progress: newProgress)
|
||||
}
|
||||
guard let progress = state[currentPath.lastPathComponent]?.progress else { return }
|
||||
aniListProgressUpdate(progress: progress, newProgress: newProgress)
|
||||
progress = newProgress
|
||||
state[currentPath.lastPathComponent]!.progress = newProgress
|
||||
}
|
||||
if scrollingCollectionView.isHidden == false {
|
||||
saveLocalState()
|
||||
@@ -912,10 +880,11 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
guard view.bounds.size != lastLayoutSize else { return }
|
||||
lastLayoutSize = UIScreen.main.bounds.size
|
||||
if scrollingCollectionView.isHidden
|
||||
|| mode != .scroll
|
||||
|| getMode() != .scroll
|
||||
|| scrollingCollectionView.contentSize == .zero
|
||||
{
|
||||
if metadata == nil { return }
|
||||
let progress = getProgress()
|
||||
imageLoader.loadImage(
|
||||
archiveURL: getArchiveURL(progress.v),
|
||||
filename: getImagePath(progress),
|
||||
@@ -936,6 +905,7 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
if let path = getPathFromComicName(name: name) {
|
||||
currentPath = path
|
||||
metadata = metadataList[path]
|
||||
let mode = getMode()
|
||||
|
||||
globalState.comicName = metadata.title
|
||||
saveGlobalState()
|
||||
@@ -1187,7 +1157,9 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
|
||||
let point = gesture.location(in: comicCollectionView)
|
||||
guard let indexPath = comicCollectionView.indexPathForItem(at: point) else { return }
|
||||
currentPath = comics[indexPath.item].path
|
||||
|
||||
loadLocalState()
|
||||
comicOptionLongPressed(indexPath)
|
||||
}
|
||||
|
||||
@@ -1196,7 +1168,7 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
}
|
||||
|
||||
@objc func handleLeftTap() {
|
||||
switch mode {
|
||||
switch getMode() {
|
||||
case .rightToLeft: changeImage(turn: .next)
|
||||
case .leftToRight: changeImage(turn: .previous)
|
||||
case .scroll: break
|
||||
@@ -1204,7 +1176,7 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
}
|
||||
|
||||
@objc func handleRightTap() {
|
||||
switch mode {
|
||||
switch getMode() {
|
||||
case .rightToLeft: changeImage(turn: .previous)
|
||||
case .leftToRight: changeImage(turn: .next)
|
||||
case .scroll: break
|
||||
@@ -1214,13 +1186,13 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
@objc func handleSwipe(_ gesture: UISwipeGestureRecognizer) {
|
||||
switch gesture.direction {
|
||||
case .left:
|
||||
switch mode {
|
||||
switch getMode() {
|
||||
case .rightToLeft: changeImage(turn: .previous)
|
||||
case .leftToRight: changeImage(turn: .next)
|
||||
case .scroll: break
|
||||
}
|
||||
case .right:
|
||||
switch mode {
|
||||
switch getMode() {
|
||||
case .rightToLeft: changeImage(turn: .next)
|
||||
case .leftToRight: changeImage(turn: .previous)
|
||||
case .scroll: break
|
||||
@@ -1280,13 +1252,14 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
|
||||
func changeImage(turn: PageTurn) {
|
||||
let scaling = UIView.ContentMode.scaleAspectFit
|
||||
let progress = getProgress()
|
||||
var newProgress = progress
|
||||
newProgress = getProgressIndicesFromTurn(turn: turn, progress: newProgress)
|
||||
if newProgress.v == progress.v, newProgress.c == progress.c, newProgress.i == progress.i {
|
||||
return
|
||||
}
|
||||
aniListProgressUpdate(progress: progress, newProgress: newProgress)
|
||||
progress = newProgress
|
||||
state[currentPath.lastPathComponent]!.progress = newProgress
|
||||
updateInfo()
|
||||
let path = getImagePath(progress)
|
||||
|
||||
@@ -1326,6 +1299,7 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
|
||||
func updateInfo() {
|
||||
if metadata == nil { return }
|
||||
let progress = getProgress()
|
||||
|
||||
var text = "\(metadata.title ?? "")\n"
|
||||
|
||||
@@ -1427,6 +1401,8 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
}
|
||||
|
||||
func setImages() {
|
||||
let mode = getMode()
|
||||
let progress = getProgress()
|
||||
let scaling: UIView.ContentMode = mode == .scroll ? .scaleAspectFill : .scaleAspectFit
|
||||
imageLoader.loadImage(
|
||||
archiveURL: getArchiveURL(progress.v),
|
||||
@@ -1560,7 +1536,7 @@ extension ViewController: UICollectionViewDataSource, UICollectionViewDelegateFl
|
||||
else {
|
||||
return ScrollingImageCell()
|
||||
}
|
||||
if mode != .scroll { return cell }
|
||||
if getMode() != .scroll { return cell }
|
||||
if metadata == nil {
|
||||
print("metadata is nil, should probably not be the case")
|
||||
return cell
|
||||
@@ -1571,6 +1547,7 @@ extension ViewController: UICollectionViewDataSource, UICollectionViewDelegateFl
|
||||
newProgress = getProgressIndicesFromTurn(turn: .next, progress: newProgress)
|
||||
}
|
||||
}
|
||||
let progress = getProgress()
|
||||
imageLoader.loadImage(
|
||||
archiveURL: getArchiveURL(progress.v),
|
||||
filename: getImagePath(newProgress),
|
||||
@@ -2244,11 +2221,12 @@ extension ViewController {
|
||||
return SettingsMenuItem(
|
||||
title: title,
|
||||
children: nil, action: { [self] in
|
||||
self.useDefaultBackgroundColor = color == nil
|
||||
self.state[currentPath.lastPathComponent]!.backgroundColor = color == nil
|
||||
? nil : convertColorToString(color!)
|
||||
colorHandler(color ?? self.convertStringToColor(settings.defaultReadingBackgroundColor))
|
||||
self.dismiss(animated: false)
|
||||
}, selected: { [self] in
|
||||
if self.useDefaultBackgroundColor { return color == nil }
|
||||
if self.state[currentPath.lastPathComponent]!.backgroundColor == nil { return color == nil }
|
||||
return color == self.readerView.backgroundColor && color != nil
|
||||
}
|
||||
)
|
||||
@@ -2266,7 +2244,7 @@ extension ViewController {
|
||||
self.dismiss(animated: false)
|
||||
},
|
||||
selected: { [self] in
|
||||
return self.mode == pageTurnMode
|
||||
return self.getMode() == pageTurnMode
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -2284,14 +2262,12 @@ extension ViewController {
|
||||
return SettingsMenuItem(
|
||||
title: title,
|
||||
children: nil, action: { [self] in
|
||||
self.useDefaultPageTurnMode = pageTurnMode == nil
|
||||
let mode = pageTurnMode ?? self.settings.defaultPageTurnMode
|
||||
let mode = getMode()
|
||||
pageTurnHandler(mode)
|
||||
self.dismiss(animated: false)
|
||||
},
|
||||
selected: { [self] in
|
||||
if self.useDefaultPageTurnMode { return pageTurnMode == nil }
|
||||
return self.mode == pageTurnMode && pageTurnMode != nil
|
||||
return self.getMode() == pageTurnMode
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -2334,9 +2310,11 @@ extension ViewController {
|
||||
|
||||
private func makePageTurnTree() -> [SettingsMenuItem] {
|
||||
return pageTurnDefaultItems { [self] pageTurnMode in
|
||||
let mode = getMode()
|
||||
let progress = getProgress()
|
||||
if mode == pageTurnMode { return }
|
||||
let scrollSwitch = mode != .scroll && pageTurnMode != .scroll
|
||||
mode = pageTurnMode
|
||||
state[currentPath.lastPathComponent]!.mode = pageTurnMode
|
||||
saveLocalState()
|
||||
if scrollSwitch { return }
|
||||
let archiveURL = getArchiveURL(progress.v)
|
||||
@@ -2426,7 +2404,7 @@ extension ViewController {
|
||||
case .updateStatus: children = aniListUpdateStatusItems(indexPath)
|
||||
case .fetchMetadata: _ = 0
|
||||
case .track:
|
||||
if aniListTracking[indexPath.item] ?? false {
|
||||
if state[currentPath.lastPathComponent]!.aniListTracking {
|
||||
title += " (Enabled)"
|
||||
} else {
|
||||
title += " (Disabled)"
|
||||
@@ -2435,14 +2413,14 @@ extension ViewController {
|
||||
return ComicOptionItem(
|
||||
title: title, children: children,
|
||||
destructive: false, available: { true },
|
||||
action: { [weak self] in
|
||||
action: { [self] in
|
||||
if action == .track {
|
||||
var v = self?.aniListTracking[indexPath.item] ?? false
|
||||
var v = self.state[currentPath.lastPathComponent]!.aniListTracking
|
||||
v.toggle()
|
||||
self?.aniListTracking[indexPath.item] = v
|
||||
self?.saveLocalState()
|
||||
self.state[self.currentPath.lastPathComponent]!.aniListTracking = v
|
||||
self.saveLocalState()
|
||||
}
|
||||
self?.dismiss(animated: false)
|
||||
self.dismiss(animated: false)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user