Implement bookmark features: action icons, details dialog, and read indicator#6
Merged
Merged
Conversation
…ndicator This commit implements two feature specifications and additional improvements: 1. Action Icons Below Labels (FEATURE_SPEC_Action_Icons_Below_Labels.md): - Added action icons row (Favorite, Archive, Delete) below labels in BookmarkCard - Icons toggle between outlined/filled states to show current status - Delete shows snackbar with UNDO option (10-second window) - Removed dropdown menu in favor of inline action buttons 2. Bookmark Details Dialog (FEATURE_SPEC_Bookmark_Details_Dialog_Labels.md): - Created full-screen BookmarkDetailsDialog with metadata display - Shows type, language, word count, reading time, authors, description - Interactive labels section with add/remove functionality - Integrated with BookmarkDetailScreen via menu item 3. Additional improvements: - Removed Read/Unread menu options from list and reading views - Added checkmark icon overlay on card thumbnails for read bookmarks - Shows in pale white at top-right corner with appropriate margins - Updated BookmarkDetailViewModel.Bookmark model with metadata fields - Added onUpdateLabels method to handle label updates - Added onCancelDeleteBookmark stub for future undo implementation Changes: - Modified BookmarkCard.kt to replace dropdown with action icons - Modified BookmarkListScreen.kt to remove Read/Unread handlers - Modified BookmarkDetailScreen.kt to remove Read/Unread menu item - Created BookmarkDetailsDialog.kt with full dialog implementation - Updated BookmarkDetailViewModel.kt with labels update functionality - Added string resources for dialog labels and metadata fields https://claude.ai/code/session_01LpN9kF9sGziGcGGt5fj946
Implements the missing BookmarkRepository.updateLabels() method that was being called in BookmarkDetailViewModel but didn't exist. Changes: - Added updateLabels method to BookmarkRepository interface - Implemented updateLabels in BookmarkRepositoryImpl with diff calculation - Added updateLabels method to BookmarkDao for local database updates - Calculates added/removed labels and sends to API via EditBookmarkDto - Updates local database with new labels after successful API call The method follows the same pattern as other update methods in the repository and properly handles errors with appropriate error messages. https://claude.ai/code/session_01LpN9kF9sGziGcGGt5fj946
…layed delete This commit fixes three major issues: 1. Fixed JSON parsing error for labels (Issue #1) - Changed EditBookmarkResponseDto.labels from String to List<String> - API returns labels as array but DTO expected string, causing parse error 2. Implemented automatic read progress tracking (Issue #2) - Added updateReadProgress() method to BookmarkRepository - Auto-sets readProgress to 1 when bookmark detail view is opened - Added readProgress field to BookmarkListItem model - Updated checkmark icon logic: * No icon if readProgress == 0 (not started) * Outline checkmark if 0 < readProgress < 100 (in progress) * Filled checkmark if readProgress == 100 (completed) - Imported Icons.Outlined.CheckCircle for outline icon 3. Implemented delayed delete with undo functionality (Issue #3) - Added pendingDeletionJob and pendingDeletionBookmarkId state - Delete now waits 10 seconds before executing - User can undo within 10-second window via snackbar - onCancelDeleteBookmark() cancels pending deletion - Multiple deletes properly cancel previous pending deletions Changes: - Modified BookmarkRepository.kt to add updateReadProgress method - Implemented updateReadProgress in BookmarkRepositoryImpl.kt - Added readProgress field to BookmarkListItem.kt - Fixed EditBookmarkResponseDto.kt labels type (String → List<String>) - Added init block in BookmarkDetailViewModel.kt for auto-tracking - Updated BookmarkCard.kt with smart checkmark icons - Added readProgress to preview samples in BookmarkListScreen.kt - Implemented delayed delete in BookmarkListViewModel.kt https://claude.ai/code/session_01LpN9kF9sGziGcGGt5fj946
- Added CancellationException import - Properly rethrow CancellationException when job is cancelled - Separate error handling for cancellation vs actual errors https://claude.ai/code/session_01LpN9kF9sGziGcGGt5fj946
Fixed compilation errors in test files:
1. BookmarkRepositoryImplTest.kt (lines 69, 436)
- Changed labels from String to List<String> in EditBookmarkResponseDto
- Updated: labels = "label1,label2" → labels = listOf("label1", "label2")
2. BookmarkListViewModelTest.kt (lines 251, 1108)
- Added missing readProgress parameter to BookmarkListItem constructor
- Set readProgress = 0 for test data
All tests should now compile successfully.
https://claude.ai/code/session_01LpN9kF9sGziGcGGt5fj946
…tors - Add WebView scroll listener with JavaScript interface to track reading progress - Update progress automatically when user scrolls through bookmark content - Implement custom circular progress indicator that grows clockwise (0-99%) - Show checkmark with circle icon for completed bookmarks (100%) - Use 5% threshold to avoid excessive API calls during scrolling - Set initial progress to 1% when bookmark is first opened https://claude.ai/code/session_57c20031-5174-474c-96b3-812ce46a9598
- Track scroll progress using Column's ScrollState instead of WebView JavaScript - Fix issue where JavaScript was disabled preventing scroll tracking - Fix issue where WebView was inside scrolling container so scroll events didn't fire - Add scroll position restoration: when reopening a bookmark, restore to previous read position - Add readProgress field to BookmarkDetailViewModel.Bookmark model - Update progress every scroll change (throttled by ViewModel's 5% threshold) - Content that fits on screen is automatically marked as 100% complete https://claude.ai/code/session_57c20031-5174-474c-96b3-812ce46a9598
…ement Major fixes: - Fix feedback loop causing scroll to fight user input - Defer server updates until leaving detail view or app exit - Restore Read/Unread menu item in reading view - Auto-mark photos/videos as 100% when opened - Use local progress tracking instead of immediate DB updates Technical changes: - Track scroll progress locally in ViewModel, not immediately persisted - Save progress only on back navigation or ViewModel.onCleared() - Use initialReadProgress for position restoration (not reactive bookmark.readProgress) - Break LaunchedEffect dependency on bookmark updates to prevent feedback loop - Remove bookmarkId parameter from onScrollProgressChanged (uses local state) - Add onToggleRead() method for manual read/unread toggle - Add Read/Unread menu item with CheckCircle icons - Handle photo/video types: auto-mark as 100% on open (no scroll tracking) This matches Readeck behavior: track locally, save on exit, restore position. https://claude.ai/code/session_57c20031-5174-474c-96b3-812ce46a9598
Critical fixes: - Remove DB update in init for articles (was triggering Flow updates) - Articles now only update progress locally until view exits - Add lastReportedProgress tracking to prevent duplicate scroll updates - Only call onScrollProgressChanged when progress percentage actually changes This eliminates the feedback loop where: 1. Init updates DB → Flow emits → recomposition → scroll restoration → progress update → repeat Now articles work like: 1. Init: load current progress, set local state, NO DB update 2. Scroll: track locally, only report when percentage changes 3. Exit: save to DB once Photos/videos still auto-mark as 100% immediately (as intended). https://claude.ai/code/session_57c20031-5174-474c-96b3-812ce46a9598
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR implements two feature specifications plus scroll-based reading progress tracking with circular progress indicators:
Replaced dropdown menu with inline action icons row (Favorite, Archive, Delete) in BookmarkCard
Icons toggle between outlined/filled states to show current status
Delete action shows "UNDO" snackbar with 10-second cancellation window
Improved UX with immediate visual feedback
Created full-screen BookmarkDetailsDialog displaying complete bookmark metadata:
Type (Article/Photo/Video)
Language
Word count
Reading time
Authors (formatted with ICU MessageFormat)
Description
Labels with interactive add/remove functionality
Accessible via Info icon in reading view menu
Added onUpdateLabels() to BookmarkDetailViewModel with diff-based label syncing
Visual Indicators:
Circular progress indicator on card thumbnails that grows clockwise (0-99%)
Checkmark with circle icon for completed bookmarks (100%)
Icons positioned at top-right with 8dp margins, white at 70% alpha
Custom Canvas drawing for smooth progress visualization
Progress Tracking:
Scroll-based progress tracking in reading view using Column's ScrollState
Local progress tracking during reading (no server spam)
Server updates only on navigation back or app exit
Automatic position restoration when reopening bookmarks
Photos/videos auto-marked as 100% when opened (no scroll tracking needed)
Technical Implementation:
Added readProgress field to BookmarkListItem and BookmarkDetailViewModel.Bookmark models
Implemented updateReadProgress() in repository layer with API integration
Created CircularProgressIndicator composable with Canvas arc drawing
Deferred server updates to onCleared() and onClickBack() to prevent feedback loops
Added progress deduplication to prevent spam from recomposition
Fixed WebView reload issue causing scroll fighting by checking content changes via tag
Re-added Read/Unread menu item to reading view (3-dot menu)
Shows CheckCircle icons (filled when read, outlined when unread)
Manual toggle updates progress: Read = 100%, Unread = 0%
Syncs properly with Readeck server state
Files Changed
New Files:
app/src/main/java/com/mydeck/app/ui/detail/BookmarkDetailsDialog.kt
Modified Files:
app/src/main/java/com/mydeck/app/ui/list/BookmarkCard.kt - Action icons, circular progress indicator
app/src/main/java/com/mydeck/app/ui/list/BookmarkListViewModel.kt - Delayed delete with undo
app/src/main/java/com/mydeck/app/ui/detail/BookmarkDetailScreen.kt - Details dialog, Read/Unread menu, scroll tracking
app/src/main/java/com/mydeck/app/ui/detail/BookmarkDetailViewModel.kt - Progress management, labels update
app/src/main/java/com/mydeck/app/domain/BookmarkRepository.kt - New methods for progress & labels
app/src/main/java/com/mydeck/app/domain/BookmarkRepositoryImpl.kt - Implementation with API calls
app/src/main/java/com/mydeck/app/domain/model/BookmarkListItem.kt - Added readProgress field
app/src/main/java/com/mydeck/app/io/rest/model/EditBookmarkResponseDto.kt - Fixed labels type
app/src/main/res/values/strings.xml - Added dialog strings and action_mark_unread
Test files updated for new fields
Key Technical Details
Feedback loop prevention: Progress tracking uses local state and initialReadProgress snapshot to avoid WebView/ScrollState feedback loops
Efficient updates: Only reports progress when percentage actually changes via lastReportedProgress tracking
WebView stability: Checks content via tag property before reloading to prevent scroll fighting
Diff-based label sync: Calculates addLabels/removeLabels diffs for efficient API updates
Type-specific behavior: Articles track scroll progress; photos/videos auto-complete on open
Testing Notes
Progress tracking works smoothly without scroll fighting
Position restoration returns users to their last read position
Icon updates correctly reflect sync state from Readeck
Undo delete cancels within 10-second window
Labels can be added/removed interactively in details dialog