fix: Use total content height for read progress calculation

Added ContentHeightPreferenceKey to track the total ScrollView content height.

The bug: Progress was calculated using only webViewHeight - containerHeight,
which ignores the header, title, and other content above the webview.

The fix: Use total content height (header + title + webview + archive section)
instead of just webViewHeight for accurate progress calculation.

Changes:
- Added ContentHeightPreferenceKey preference key
- Added contentHeight state variable
- Added background GeometryReader to VStack to measure total content height
- Changed progress calculation: contentHeight - containerHeight (not webViewHeight)

Applied to both BookmarkDetailLegacyView and BookmarkDetailView2.
This commit is contained in:
Ilyas Hallak 2025-10-10 20:27:17 +02:00
parent 4595a9b69f
commit bef6a9dc2f
2 changed files with 34 additions and 2 deletions

View File

@ -9,6 +9,14 @@ struct ScrollOffsetPreferenceKey: PreferenceKey {
}
}
// PreferenceKey for content height tracking
struct ContentHeightPreferenceKey: PreferenceKey {
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
}
struct BookmarkDetailLegacyView: View {
let bookmarkId: String
@Binding var useNativeWebView: Bool
@ -17,6 +25,7 @@ struct BookmarkDetailLegacyView: View {
@State private var viewModel: BookmarkDetailViewModel
@State private var webViewHeight: CGFloat = 300
@State private var contentHeight: CGFloat = 0
@State private var showingFontSettings = false
@State private var showingLabelsSheet = false
@State private var readingProgress: Double = 0.0
@ -113,16 +122,27 @@ struct BookmarkDetailLegacyView: View {
.frame(maxWidth: .infinity)
}
}
.background(
GeometryReader { contentGeo in
Color.clear.preference(
key: ContentHeightPreferenceKey.self,
value: contentGeo.size.height
)
}
)
}
.coordinateSpace(name: "scrollView")
.clipped()
.ignoresSafeArea(edges: .top)
.scrollPosition($scrollPosition)
.onPreferenceChange(ContentHeightPreferenceKey.self) { height in
contentHeight = height
}
.onPreferenceChange(ScrollOffsetPreferenceKey.self) { offset in
// Calculate progress from scroll offset
let scrollOffset = -offset.y // Negative because scroll goes down
let containerHeight = geometry.size.height
let maxOffset = webViewHeight - containerHeight
let maxOffset = contentHeight - containerHeight
guard maxOffset > 0 else { return }

View File

@ -10,6 +10,7 @@ struct BookmarkDetailView2: View {
@State private var viewModel: BookmarkDetailViewModel
@State private var webViewHeight: CGFloat = 300
@State private var contentHeight: CGFloat = 0
@State private var showingFontSettings = false
@State private var showingLabelsSheet = false
@State private var readingProgress: Double = 0.0
@ -120,16 +121,27 @@ struct BookmarkDetailView2: View {
.frame(maxWidth: .infinity)
}
}
.background(
GeometryReader { contentGeo in
Color.clear.preference(
key: ContentHeightPreferenceKey.self,
value: contentGeo.size.height
)
}
)
}
.coordinateSpace(name: "scrollView")
.clipped()
.ignoresSafeArea(edges: .top)
.scrollPosition($scrollPosition)
.onPreferenceChange(ContentHeightPreferenceKey.self) { height in
contentHeight = height
}
.onPreferenceChange(ScrollOffsetPreferenceKey.self) { offset in
// Calculate progress from scroll offset
let scrollOffset = -offset.y
let containerHeight = geometry.size.height
let maxOffset = webViewHeight - containerHeight
let maxOffset = contentHeight - containerHeight
guard maxOffset > 0 else { return }