debug: Reader comprehensive logging — jitter, markRead, loadMore
This commit is contained in:
@@ -94,15 +94,19 @@ final class ReaderViewModel {
|
|||||||
func loadMore() async {
|
func loadMore() async {
|
||||||
guard !isLoadingMore, hasMore else { return }
|
guard !isLoadingMore, hasMore else { return }
|
||||||
isLoadingMore = true
|
isLoadingMore = true
|
||||||
|
print("[READER-DBG] 📥 loadMore START offset=\(offset)")
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let list = try await fetchEntries(offset: offset)
|
let list = try await fetchEntries(offset: offset)
|
||||||
|
let count = list.entries.count
|
||||||
entries.append(contentsOf: list.entries)
|
entries.append(contentsOf: list.entries)
|
||||||
total = list.total
|
total = list.total
|
||||||
offset += list.entries.count
|
offset += count
|
||||||
hasMore = offset < list.total
|
hasMore = offset < list.total
|
||||||
|
print("[READER-DBG] 📥 loadMore END +\(count) total=\(entries.count) hasMore=\(hasMore)")
|
||||||
} catch {
|
} catch {
|
||||||
self.error = error.localizedDescription
|
self.error = error.localizedDescription
|
||||||
|
print("[READER-DBG] 📥 loadMore ERROR: \(error)")
|
||||||
}
|
}
|
||||||
isLoadingMore = false
|
isLoadingMore = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ struct EntryListView: View {
|
|||||||
frame.maxY < 30 else { return }
|
frame.maxY < 30 else { return }
|
||||||
|
|
||||||
markedByScroll.insert(entryId)
|
markedByScroll.insert(entryId)
|
||||||
|
print("[READER-DBG] 📖 markRead id=\(entryId) autoScroll=\(isAutoScrolling) maxY=\(Int(frame.maxY))")
|
||||||
|
|
||||||
if isAutoScrolling {
|
if isAutoScrolling {
|
||||||
// Defer visual update — contentSize changes cause jitter
|
// Defer visual update — contentSize changes cause jitter
|
||||||
|
|||||||
@@ -98,20 +98,36 @@ struct ScrollViewDriver: UIViewRepresentable {
|
|||||||
displayLink = nil
|
displayLink = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var lastTickTime: CFAbsoluteTime = 0
|
||||||
|
private var lastContentSize: CGFloat = 0
|
||||||
|
private var tickCount = 0
|
||||||
|
|
||||||
@objc private func tick(_ link: CADisplayLink) {
|
@objc private func tick(_ link: CADisplayLink) {
|
||||||
guard let sv = scrollView else {
|
guard let sv = scrollView else {
|
||||||
stopAndNotify()
|
stopAndNotify()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let now = CFAbsoluteTimeGetCurrent()
|
||||||
let maxOffset = sv.contentSize.height - sv.bounds.height + sv.contentInset.bottom
|
let maxOffset = sv.contentSize.height - sv.bounds.height + sv.contentInset.bottom
|
||||||
guard maxOffset > 0 else { return }
|
guard maxOffset > 0 else { return }
|
||||||
|
|
||||||
let delta = CGFloat(speed) * 60.0 * CGFloat(link.targetTimestamp - link.timestamp)
|
let delta = CGFloat(speed) * 60.0 * CGFloat(link.targetTimestamp - link.timestamp)
|
||||||
let newY = min(sv.contentOffset.y + delta, maxOffset)
|
let beforeY = sv.contentOffset.y
|
||||||
|
let newY = min(beforeY + delta, maxOffset)
|
||||||
|
|
||||||
sv.contentOffset.y = newY
|
sv.contentOffset.y = newY
|
||||||
|
|
||||||
|
// Jitter detection
|
||||||
|
let wallDelta = lastTickTime > 0 ? (now - lastTickTime) * 1000 : 0
|
||||||
|
let csChanged = sv.contentSize.height != lastContentSize
|
||||||
|
tickCount += 1
|
||||||
|
if csChanged || wallDelta > 25 || tickCount % 180 == 0 {
|
||||||
|
print("[READER-DBG] \(csChanged || wallDelta > 25 ? "⚠️" : "✅") wallΔ=\(String(format:"%.1f",wallDelta))ms y=\(Int(newY)) csH=\(Int(sv.contentSize.height)) csΔ=\(Int(sv.contentSize.height - lastContentSize)) speed=\(String(format:"%.2f",speed)) dist=\(Int(maxOffset - newY))")
|
||||||
|
}
|
||||||
|
lastTickTime = now
|
||||||
|
lastContentSize = sv.contentSize.height
|
||||||
|
|
||||||
originalDelegate?.scrollViewDidScroll?(sv)
|
originalDelegate?.scrollViewDidScroll?(sv)
|
||||||
|
|
||||||
// Trigger load more when within 500pt of bottom
|
// Trigger load more when within 500pt of bottom
|
||||||
|
|||||||
Reference in New Issue
Block a user