feat(favorites): Add line filtering to favorite stops#8
Conversation
This commit adds a new Product Requirement Document (PRD) that outlines the feature for allowing users to filter bus lines on their favorite stops. The document details the goals, implementation plan, data model changes, UI/UX considerations, and success criteria for the feature.
This commit introduces the ability for users to filter which bus lines are displayed for each of their favorite stops. Key Changes: - A new `selectedLineIds` field has been added to the `FavoriteStop` model, as well as to the corresponding `FavoriteStopEntity` and `ApiFavoriteStop` data classes. This field stores a list of line IDs that the user wants to see for a specific favorite stop. - A database migration has been added to increase the database version to 10 and add the new `selectedLineIds` column (of type `TEXT`) to the `favorites` table. Existing favorite stops will have a `NULL` value, which is interpreted as all lines being selected. - The `FavoriteStop` domain model now includes an `isLineSelected` helper function to check if a specific line should be displayed based on the user's selection.
Implement Step 2 of line filtering feature - update domain models and repositories to handle line selections. - Add FavoriteStopEntity.fromEntity() extension to centralize conversion - Update LocalFavoriteRepository mappings to include selectedLineIds - Update RemoteAndLocalFavoriteRepository mappings to include selectedLineIds - Convert List<LineId>? (entity) to Set<LineId>? (domain) in all mappings - Maintain backward compatibility with null meaning all lines selected
This commit introduces the ability for users to filter bus lines directly from the "Edit Favorites" screen. Users can now tap on line indicators to select or deselect which lines they want to see for each favorite stop. Key Changes: - A new `SelectableLineIndicator` composable has been created to handle the selection UI, including animations and a checkmark for selected lines. - The `EditFavoriteListItem` now manages the state of selected lines and passes changes up to the `EditFavoritesScreen`. - Haptic feedback is provided when a user selects or deselects a line. - A new analytics event, `EditFavoriteLineClicked`, is tracked to monitor feature usage.
Implement Step 4 of line filtering feature - apply line selections to filter arrivals on home screen. - Add filtering logic in FavoriteItemViewModel - Handle three cases: null (all lines), empty (no API call), specific lines (filter) - Early return for empty selection to skip unnecessary polling - Add filterBySelectedLines() helper extension function - Update FavoriteListItem UI - Show only shimmer for selected lines during loading - Handle empty line selection state (no shimmer indicators) - Fix ViewModel key to include selectedLineIds - Ensures ViewModel recreates when line selections change - Fixes issue where changes weren't reflected until app restart
Fix crash when deserializing empty selectedLineIds from database. When selectedLineIds is an empty list, it gets serialized as empty string. The deserializer was trying to parse "" as integers, causing NumberFormatException and infinite crash loop. - Add empty string check in IntListConverter.deserialize() - Return empty list for empty string input - Prevents crash when favorites have no lines selected
Fix sync logic to properly update favorites when fields change on server. Previous logic only handled additions/removals, not updates. When selectedLineIds (or other fields) changed on the server, local versions were never updated. New strategy (server wins): - Replace all local favorites with server versions - Keep local-only favorites and upload them to server - Server version always takes precedence for conflicts This ensures line selections, custom names, and custom icons sync properly across devices.
There was a problem hiding this comment.
Pull request overview
This PR adds line filtering functionality to favorite stops, allowing users to select which bus lines they want to monitor for each favorite. The feature includes database changes, domain model updates, interactive UI in the Edit Favorites screen, and server synchronization support while maintaining full backward compatibility.
Key Changes:
- Added
selectedLineIdsfield throughout the data stack (database, domain, API) with nullable type for backward compatibility - Implemented interactive line selection UI with visual feedback and animations in Edit Favorites screen
- Filter arrivals and skip API calls based on selected lines on the home screen
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
Clicks.kt |
Added analytics event for line selection toggles |
DI.kt |
Injected Analytics dependency into EditFavoritesViewModel |
EditFavoritesViewModel.kt |
Added analytics tracking method |
EditFavoritesScreen.kt |
Implemented interactive line selection UI with animations and haptic feedback |
FavoriteListItem.kt |
Updated ViewModel key and shimmer logic to respect line selections |
FavoriteItemViewModel.kt |
Added filtering logic to skip API calls and filter arrivals by selected lines |
FavoriteStop.kt |
Added selectedLineIds field and isLineSelected() helper method |
RemoteAndLocalFavoriteRepository.kt |
Updated sync strategy to use server-wins approach and refactored mapping |
LocalFavoriteRepository.kt |
Refactored to use new fromEntity() extension function |
TypeConverters.kt |
Fixed bug in IntListConverter.deserialize() to handle empty strings |
SevibusDatabase.kt |
Incremented database version and added AutoMigration |
Entities.kt |
Added selectedLineIds field and created fromEntity() extension |
ApiModels.kt |
Added selectedLineIds field to DTO |
Stubs.kt |
Updated test data to include line selections |
10.json |
Database schema for version 10 |
PRD_LINE_FILTERING.md |
Product requirements document |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…teRepository.kt Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…voriteListItem.kt Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| var selectedLines by remember(favorite.selectedLineIds, favorite.stop.lines) { | ||
| mutableStateOf(favorite.selectedLineIds ?: favorite.stop.lines.map { it.id }.toSet()) | ||
| } |
There was a problem hiding this comment.
The selected lines state is not updated when favorite changes through onLineSelectionChanged callback. When the parent updates favoritesLocalList, the remember key includes favorite.selectedLineIds but favorite is a lambda parameter that refers to the original instance. This could cause the UI state to become out of sync with the updated favorite. Consider using LaunchedEffect to observe changes or restructure the state management.
…voriteListItem.kt Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Fix state synchronization issue identified in PR review where local state could become out of sync with parent state. Previous implementation maintained duplicate state (local mutableStateOf + parent list), causing potential desync when parent updates. Now derives selectedLines directly from favorite parameter, making parent the single source of truth. - Remove local selectedLines mutableState - Derive selectedLines from favorite.selectedLineIds - Remove redundant local state assignment - Simplifies state management and prevents sync bugs
Summary
Adds the ability to filter favorite stops by specific bus lines. Users can now select which lines they want to see arrivals for on the home screen, reducing visual clutter and focusing on relevant information.
Changes
Database Layer
selectedLineIdscolumn toFavoriteStopEntity(nullableList<LineId>)IntListConverterfor Room serialization (List ↔ comma-separated String)IntListConverter.deserialize()to handle empty stringsDomain Layer
selectedLineIds: Set<LineId>?toFavoriteStopdomain modelisLineSelected()helper with three-state logic:null→ all lines selected (backward compatibility)isEmpty()→ no lines selectedcontains(lineId)→ specific lines selectedFavoriteStopEntity.fromEntity()extension for clean DTO mappingUI - Edit Favorites Screen
CLOCK_TICK) on line toggleSelectableLineIndicatorcomposable for reusabilityUI - Home Screen (For You)
selectedLineIdsinFavoriteItemViewModelselectedLineIds(ensures UI updates on change)API Integration
selectedLineIds: List<LineId>?toFavoriteStopDtoRemoteAndLocalFavoriteRepository:Analytics
EditFavoriteLineClicked(isSelected: Boolean)eventTesting
nullshow all lines)Screenshots
Breaking Changes
None. Fully backward compatible with existing favorites.