fix: improve reading position calculation to reach 100%

- Add 5px threshold to detect when scrolled to bottom
- Set position to exactly 1.0 (100%) when within 5px of bottom
- Remove upper limit on saving positions (now saves 100% completion)
- Always save when reaching 100% completion (important milestone)
- Don't restore position for completed articles (100%), start from top
- Better handling of edge cases in position detection
- Matches ReadingProgressIndicator calculation logic
This commit is contained in:
Gigi
2025-10-15 22:39:51 +02:00
parent 6ef0a6dd71
commit f4a227e40a
2 changed files with 22 additions and 9 deletions

View File

@@ -224,7 +224,7 @@ const ContentPanel: React.FC<ContentPanelProps> = ({
articleIdentifier articleIdentifier
) )
if (savedPosition && savedPosition.position > 0.05 && savedPosition.position < 0.95) { if (savedPosition && savedPosition.position > 0.05 && savedPosition.position < 1) {
console.log('🎯 [ContentPanel] Restoring position:', Math.round(savedPosition.position * 100) + '%') console.log('🎯 [ContentPanel] Restoring position:', Math.round(savedPosition.position * 100) + '%')
// Wait for content to be fully rendered before scrolling // Wait for content to be fully rendered before scrolling
setTimeout(() => { setTimeout(() => {
@@ -240,7 +240,11 @@ const ContentPanel: React.FC<ContentPanelProps> = ({
console.log('✅ [ContentPanel] Restored to position:', Math.round(savedPosition.position * 100) + '%', 'scrollTop:', scrollTop) console.log('✅ [ContentPanel] Restored to position:', Math.round(savedPosition.position * 100) + '%', 'scrollTop:', scrollTop)
}, 500) // Give content time to render }, 500) // Give content time to render
} else if (savedPosition) { } else if (savedPosition) {
console.log('⏭️ [ContentPanel] Position out of range (5-95%):', Math.round(savedPosition.position * 100) + '%') if (savedPosition.position === 1) {
console.log('✅ [ContentPanel] Article completed (100%), starting from top')
} else {
console.log('⏭️ [ContentPanel] Position too early (<5%):', Math.round(savedPosition.position * 100) + '%')
}
} }
} catch (error) { } catch (error) {
console.error('❌ [ContentPanel] Failed to load reading position:', error) console.error('❌ [ContentPanel] Failed to load reading position:', error)

View File

@@ -29,11 +29,15 @@ export const useReadingPosition = ({
const scheduleSave = useCallback((currentPosition: number) => { const scheduleSave = useCallback((currentPosition: number) => {
if (!syncEnabled || !onSave) return if (!syncEnabled || !onSave) return
// Don't save if position is too low (< 5%) or too high (> 95%) // Don't save if position is too low (< 5%)
if (currentPosition < 0.05 || currentPosition > 0.95) return if (currentPosition < 0.05) return
// Don't save if position hasn't changed significantly (less than 1%) // Don't save if position hasn't changed significantly (less than 1%)
if (Math.abs(currentPosition - lastSavedPosition.current) < 0.01) return // But always save if we've reached 100% (completion)
const hasSignificantChange = Math.abs(currentPosition - lastSavedPosition.current) >= 0.01
const hasReachedCompletion = currentPosition === 1 && lastSavedPosition.current < 1
if (!hasSignificantChange && !hasReachedCompletion) return
// Clear existing timer // Clear existing timer
if (saveTimerRef.current) { if (saveTimerRef.current) {
@@ -57,8 +61,8 @@ export const useReadingPosition = ({
saveTimerRef.current = null saveTimerRef.current = null
} }
// Save if position is meaningful // Save if position is meaningful (>= 5%)
if (position >= 0.05 && position <= 0.95) { if (position >= 0.05) {
lastSavedPosition.current = position lastSavedPosition.current = position
onSave(position) onSave(position)
} }
@@ -77,8 +81,13 @@ export const useReadingPosition = ({
const documentHeight = document.documentElement.scrollHeight const documentHeight = document.documentElement.scrollHeight
// Calculate position based on how much of the content has been scrolled through // Calculate position based on how much of the content has been scrolled through
const scrollProgress = Math.min(scrollTop / (documentHeight - windowHeight), 1) // Add a small threshold (5px) to account for rounding and make it easier to reach 100%
const clampedProgress = Math.max(0, Math.min(1, scrollProgress)) const maxScroll = documentHeight - windowHeight
const scrollProgress = maxScroll > 0 ? scrollTop / maxScroll : 0
// If we're within 5px of the bottom, consider it 100%
const isAtBottom = scrollTop + windowHeight >= documentHeight - 5
const clampedProgress = isAtBottom ? 1 : Math.max(0, Math.min(1, scrollProgress))
setPosition(clampedProgress) setPosition(clampedProgress)
onPositionChange?.(clampedProgress) onPositionChange?.(clampedProgress)