Skip to content

Implement bookmark features: action icons, details dialog, and read indicator#6

Merged
NateEaton merged 11 commits into
mainfrom
claude/implement-bookmark-features-0w07E
Jan 29, 2026
Merged

Implement bookmark features: action icons, details dialog, and read indicator#6
NateEaton merged 11 commits into
mainfrom
claude/implement-bookmark-features-0w07E

Conversation

@NateEaton

@NateEaton NateEaton commented Jan 29, 2026

Copy link
Copy Markdown
Owner

Summary
This PR implements two feature specifications plus scroll-based reading progress tracking with circular progress indicators:

  1. Action Icons Below Labels (FEATURE_SPEC_Action_Icons_Below_Labels.md)
    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
  2. Bookmark Details Dialog (FEATURE_SPEC_Bookmark_Details_Dialog_Labels.md)
    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
  3. Reading Progress Tracking & Circular Progress Indicators
    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
  4. Read/Unread Toggle
    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

claude and others added 11 commits January 28, 2026 20:04
…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
@NateEaton NateEaton merged commit d3672c4 into main Jan 29, 2026
3 checks passed
@NateEaton NateEaton deleted the claude/implement-bookmark-features-0w07E branch February 20, 2026 17:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants