database: update schema to version 10 to support monorepo asset tracking#407
database: update schema to version 10 to support monorepo asset tracking#407rainxchzed merged 8 commits intomainfrom
Conversation
- Update `AppDatabase` schema to version 10. - Add `assetFilterRegex` (TEXT) and `fallbackToOlderReleases` (INTEGER) columns to the `installed_apps` table. - Implement `MIGRATION_9_10` to handle the database upgrade. - Update `InstalledAppEntity` with new fields to allow filtering assets by regex and falling back to older releases when checking for updates.
- Create `AssetFilter` class to handle compiled, validated regex patterns for filtering assets. - Implement `parse` method to handle user-supplied patterns with validation and case-insensitivity. - Add `matches` using `containsMatchIn` to support casual substring patterns. - Implement `suggestFromAssetName` to automatically derive filter prefixes by stripping version suffixes from filenames.
- Implement `assetFilterRegex` and `fallbackToOlderReleases` in `InstalledApp` to support tracking specific apps within monorepos. - Update `InstalledAppsRepository` to fetch a window of 50 releases (up from 1) to allow falling back to older releases when the latest one does not match the asset filter. - Add `resolveTrackedRelease` logic to match assets against regex filters and architecture requirements across the release window. - Introduce `previewMatchingAssets` to provide a dry-run helper for testing asset filters in the UI. - Update `InstalledAppDao` and database schema (version 10) to persist new filtering fields. - Update `AppsRepository` to support linking apps with initial asset filter configurations. - Add Room migration (MIGRATION_9_10) for the new database columns.
- Introduce `AdvancedAppSettingsBottomSheet` to configure per-app asset filters (regex) and "fallback to older releases" logic. - Add live preview functionality in the advanced settings sheet to visualize asset matching before saving. - Enhance `LinkAppBottomSheet` with an asset filter and fallback toggle during the repository linking process. - Implement automatic filter suggestions during linking based on package names and app titles. - Update `AppsState`, `AppsAction`, and `AppsViewModel` to manage advanced filter state, validation, and debounced preview refreshes. - Add UI indicators to the main app list to highlight apps with active custom filters. - Include new localized strings for filter labels, help text, and validation errors.
Introduce a new set of localized strings to support advanced repository filtering, specifically targeting monorepos with multiple applications. These changes include: - Added labels and descriptions for asset filtering using regular expressions. - Added support for "fallback to older releases," allowing the app to search through previous releases when the most recent one doesn't match the filter. - Added strings for advanced settings, including preview functionality, validation states, and save actions. - Provided consistent translations for these new features across Turkish, Italian, Arabic, Simplified Chinese, Bengali, French, Russian, Japanese, Hindi, Korean, Spanish, and Polish.
WalkthroughAdded per-app asset-name filtering (regex) and optional fallback-to-older-releases across DB, domain, data, repository, and UI layers; introduced AssetFilter utilities, migration to DB version 10, repository preview/save APIs, and advanced-settings UI with live preview and link-time filtering. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant UI as Advanced Settings Sheet
participant VM as ViewModel
participant Repo as InstalledAppsRepository
participant API as GitHub API
User->>UI: Open advanced settings for app
User->>UI: Edit asset filter / toggle fallback
UI->>VM: OnAdvancedFilterChanged / OnAdvancedFallbackToggled
VM->>VM: Validate via AssetFilter.parse()
alt valid
VM->>VM: Clear error, schedule debounce (350ms)
else invalid
VM->>VM: Set filter error
end
Note over VM: After debounce
VM->>VM: set advancedPreviewLoading = true
VM->>Repo: previewMatchingAssets(owner, repo, regex, includePre, fallback)
Repo->>API: Fetch releases (up to 50)
API-->>Repo: Releases + assets
Repo->>Repo: Filter assets by platform + regex, apply fallback logic
Repo-->>VM: MatchingPreview(release?, matchedAssets, regexError?)
VM->>UI: Update preview state (matched assets / message)
UI->>User: Render preview (assets or error)
User->>UI: Click Save
UI->>VM: OnAdvancedSaveFilter
VM->>Repo: setAssetFilter(packageName, regex, fallback)
Repo->>Repo: Update DB (DAO.updateAssetFilter)
Repo-->>VM: Complete
VM->>Repo: checkForUpdates(packageName)
Repo->>API: Fetch releases (with new filter)
Repo-->>VM: Update results
VM->>UI: Dismiss sheet
sequenceDiagram
participant User
participant UI as Add App by Link
participant VM as ViewModel
participant Repo as AppsRepository
participant API as GitHub API
User->>UI: Enter GitHub URL -> Fetch repo
UI->>Repo: request repo info
Repo->>API: Fetch latest release + assets
API-->>Repo: Release & assets
Repo-->>VM: linkInstallableAssets
VM->>VM: Suggest filter (heuristic + AssetFilter.suggestFromAssetName)
VM->>UI: Seed linkAssetFilter
UI->>User: Show asset picker with pre-filled filter
User->>UI: Modify filter / toggle fallback
UI->>VM: OnLinkAssetFilterChanged / OnLinkFallbackToggled
VM->>VM: Validate regex, set filteredLinkAssets (live)
UI->>User: Show filtered assets
User->>UI: Confirm link
UI->>VM: linkAppToRepo(..., assetFilterRegex, fallbackToOlderReleases)
VM->>Repo: Create InstalledApp with filter config
Repo->>Repo: Persist entity
Repo-->>VM: Complete
VM->>UI: Dismiss link sheet
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsViewModel.kt (1)
1329-1391:⚠️ Potential issue | 🟠 MajorBlock invalid link filters before calling
linkAppToRepo().
OnLinkAssetFilterChangedonly markslinkAssetFilterError; both link paths here still persist the raw filter. Because the picker intentionally stays usable on invalid regex, a user can save a broken pattern and later update checks will silently ignore it. Re-parse and trim the draft here, and stop linking when validation fails.Proposed fix
+ val normalizedFilter = _state.value.linkAssetFilter.trim() + val parsedFilter = AssetFilter.parse(normalizedFilter) + if (parsedFilter != null && parsedFilter.isFailure) { + _state.update { + it.copy( + linkDownloadProgress = null, + linkValidationStatus = null, + linkAssetFilterError = "invalid", + ) + } + return@launch + } + if (apkInfo == null) { logger.debug("Could not extract APK info for validation, linking anyway") appsRepository.linkAppToRepo( - deviceApp = selectedApp.toDomain(), - repoInfo = repoInfo.toDomain(), - assetFilterRegex = _state.value.linkAssetFilter.takeIf { it.isNotBlank() }, - fallbackToOlderReleases = _state.value.linkFallbackToOlder, - ) + deviceApp = selectedApp.toDomain(), + repoInfo = repoInfo.toDomain(), + assetFilterRegex = normalizedFilter.takeIf { it.isNotEmpty() }, + fallbackToOlderReleases = _state.value.linkFallbackToOlder, + ) _state.update { it.copy( linkDownloadProgress = null, @@ appsRepository.linkAppToRepo( deviceApp = selectedApp.toDomain(), repoInfo = repoInfo.toDomain(), - assetFilterRegex = _state.value.linkAssetFilter.takeIf { it.isNotBlank() }, + assetFilterRegex = normalizedFilter.takeIf { it.isNotEmpty() }, fallbackToOlderReleases = _state.value.linkFallbackToOlder, )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsViewModel.kt` around lines 1329 - 1391, When attempting to call linkAppToRepo from AppsViewModel (both code paths that currently call appsRepository.linkAppToRepo), validate and normalize the user's draft filter before proceeding: trim _state.value.linkAssetFilter, attempt to compile it as a regex (or otherwise run the same validation used by OnLinkAssetFilterChanged), and if validation fails set linkAssetFilterError in _state and abort (do not call linkAppToRepo); only pass assetFilterRegex = validatedTrimmedFilter.takeIf { it.isNotBlank() } into linkAppToRepo when validation succeeds. Ensure you reference the existing symbols: OnLinkAssetFilterChanged, _state.value.linkAssetFilter, linkAssetFilterError, and linkAppToRepo to locate and fix both link code paths.
🧹 Nitpick comments (2)
feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsRoot.kt (1)
754-774: Expose the active-filter state with more than tint.
hasFilteronly changes the icon color, so screen readers and users who miss the tint get the same control either way. Since this PR adds the list indicator, it should also expose that state via semantics or a small textual/badge cue.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsRoot.kt` around lines 754 - 774, The IconButton currently only reflects active filter state via tint (hasFilter), which is not accessible; update the control to expose the same state through semantics and/or a visible badge/textual cue: add a semantic state or custom property to the IconButton modifier (e.g., Modifier.semantics { contentDescription = advancedFilterDescription; stateDescription = if (hasFilter) "filter active" else "no filter" }) and optionally render a small Badge/Text near the Icon when hasFilter is true; use the existing symbols hasFilter, IconButton, advancedFilterDescription, onAdvancedSettingsClick, app.assetFilterRegex and app.fallbackToOlderReleases to locate where to add the semantics/stateDescription and the visual badge.feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsState.kt (1)
50-59: ReplaceadvancedPreviewMessagestring tokens with a typed state.This field is later matched against raw literals (
"no_match","preview_failed","save_failed") infeature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/components/AdvancedAppSettingsBottomSheet.kt, Lines 279-290. A typo or renamed token will silently fall through to the pending UI. An enum or sealed type would make this exhaustive and safer.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsState.kt` around lines 50 - 59, The advancedPreviewMessage: String? in AppsState should be replaced with a typed sealed class or enum (e.g., AdvancedPreviewMessageState with cases NoMatch, PreviewFailed, SaveFailed, None) to avoid brittle string token matching; update AppsState to use this new type (and a sensible default like AdvancedPreviewMessageState.None), then refactor the match/when in AdvancedAppSettingsBottomSheet to switch over AdvancedPreviewMessageState cases instead of comparing raw literals ("no_match", "preview_failed", "save_failed"), and update any other references (serializers/parcelables/initializers) to construct and consume the new typed state.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@core/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/InstalledAppsRepositoryImpl.kt`:
- Around line 189-219: InstalledAppsRepositoryImpl currently only calls
installedAppsDao.updateLastChecked(...) when no releases or when
resolveTrackedRelease returns null, leaving prior isUpdateAvailable/cached
latest-asset/version stale; add a DAO method (e.g.,
installedAppsDao.clearUpdateMetadata(packageName) or clearUpdateInfo) that
atomically clears isUpdateAvailable and any cached latestAsset/latestVersion
fields, implement that DAO method, and call it in both the releases.isEmpty()
branch and the resolved == null branch (before returning) to ensure saved
stricter filters or no matches remove the old badge/version info.
- Around line 347-358: setAssetFilter currently only persists the regex but must
also immediately re-check the app so badge/update metadata is fresh; after
calling installedAppsDao.updateAssetFilter(packageName, regex = normalized,
fallback = fallbackToOlderReleases) invoke the repository’s existing routine
that recomputes an app’s update state for the given package (the same code path
AppsViewModel currently uses to refresh state) so the badge/metadata is updated
immediately — perform this recheck in the same suspend context, handle
errors/transactional consistency as other repo update flows, and keep
setAssetFilter as the single-entry API for persisting the filter + refreshing
update state.
- Around line 103-123: The catch in
InstalledAppsRepositoryImpl.fetchReleaseWindow currently swallows
CancellationException and treats cancellations as empty results; change the
error handling so cancellation is re-thrown: either add an early rethrow for
kotlinx.coroutines.CancellationException (if e is CancellationException ->
throw) before logging/returning, or split catches (catch CancellationException {
throw } catch (e: Exception) { Logger.e { ... }; return emptyList() }), keeping
the existing Logger.e message and behavior for other exceptions while ensuring
coroutine cancellation propagates.
In
`@core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/repository/InstalledAppsRepository.kt`:
- Around line 54-66: The KDoc for InstalledAppsRepository.setAssetFilter
promises an immediate re-check but InstalledAppsRepositoryImpl.setAssetFilter
currently only persists DAO fields and leaves updateAvailable stale; update the
implementation of InstalledAppsRepositoryImpl.setAssetFilter to, after saving
the regex and fallbackToOlderReleases, call and await
checkForUpdates(packageName) (or the repository's internal method that computes
updateAvailable) so the UI-state is refreshed immediately, and handle/log any
exceptions from that call so persistence still succeeds even if the check fails.
In
`@core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/util/AssetFilter.kt`:
- Around line 65-67: The code currently returns the raw prefix string (variable
prefix) as a regex; instead, escape regex metacharacters and anchor the
suggestion to the start of the string before returning. Replace the return of
prefix.takeIf { it.length >= 2 } with logic that first checks prefix.length >=
2, then builds an anchored, escaped regex like "^" + Regex.escape(prefix) (or
similar) and returns that; keep the same length check and use the
escaped/anchored value so AssetFilter.kt produces literal-prefix-safe
suggestions.
In `@core/presentation/src/commonMain/composeResources/values-pl/strings-pl.xml`:
- Around line 604-616: Replace the two fixed strings with Android plurals to
handle Polish inflection: change asset_filter_visible_count to a <plurals
name="asset_filter_visible_count"> and provide appropriate Polish forms (one,
few, many, other) using placeholders %1$d and %2$d, and change
advanced_preview_release to a <plurals name="advanced_preview_release"> with
forms that include the release name placeholder (%1$s) and the resource count
placeholder (%2$d); update any call sites to use getQuantityString for these
resource IDs. Ensure the plurals keys match the original identifiers
(asset_filter_visible_count, advanced_preview_release) so callers can be updated
without renaming.
In
`@feature/apps/data/src/commonMain/kotlin/zed/rainxch/apps/data/repository/AppsRepositoryImpl.kt`:
- Around line 193-194: exportApps() and importApps() in AppsRepositoryImpl
currently only persist package/repo identity and therefore drop InstalledApp
fields assetFilterRegex and fallbackToOlderReleases; update both functions to
include these two fields when serializing and deserializing InstalledApp so
monorepo settings survive backup/restore. Locate the exportApps() serializer
logic and add assetFilterRegex and fallbackToOlderReleases to the exported
representation for each InstalledApp, and in importApps() read those keys back
into the InstalledApp constructor/mapper so restored apps populate the
InstalledApp.assetFilterRegex and InstalledApp.fallbackToOlderReleases
properties.
In
`@feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/components/LinkAppBottomSheet.kt`:
- Around line 569-583: The code always shows the "asset_filter_no_match" message
when visibleAssets.isEmpty(); change this to distinguish three cases: (1) the
repository has no installable assets (use a new/existing string like
"asset_none_available" or "asset_no_assets" when the full asset list is empty),
(2) the user-entered filter/regex is invalid (catch regex compilation errors and
show a "filter_invalid" message), and (3) the filter matched nothing (keep
"asset_filter_no_match" when there are assets but visibleAssets is empty);
update the branch around visibleAssets.isEmpty() in LinkAppBottomSheet.kt to
check the full asset list (e.g., allAssets or repoAssets), validate the
filter/regex before applying it, and choose the appropriate stringResource
(asset_none_available, filter_invalid, or asset_filter_no_match).
---
Outside diff comments:
In
`@feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsViewModel.kt`:
- Around line 1329-1391: When attempting to call linkAppToRepo from
AppsViewModel (both code paths that currently call
appsRepository.linkAppToRepo), validate and normalize the user's draft filter
before proceeding: trim _state.value.linkAssetFilter, attempt to compile it as a
regex (or otherwise run the same validation used by OnLinkAssetFilterChanged),
and if validation fails set linkAssetFilterError in _state and abort (do not
call linkAppToRepo); only pass assetFilterRegex = validatedTrimmedFilter.takeIf
{ it.isNotBlank() } into linkAppToRepo when validation succeeds. Ensure you
reference the existing symbols: OnLinkAssetFilterChanged,
_state.value.linkAssetFilter, linkAssetFilterError, and linkAppToRepo to locate
and fix both link code paths.
---
Nitpick comments:
In
`@feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsRoot.kt`:
- Around line 754-774: The IconButton currently only reflects active filter
state via tint (hasFilter), which is not accessible; update the control to
expose the same state through semantics and/or a visible badge/textual cue: add
a semantic state or custom property to the IconButton modifier (e.g.,
Modifier.semantics { contentDescription = advancedFilterDescription;
stateDescription = if (hasFilter) "filter active" else "no filter" }) and
optionally render a small Badge/Text near the Icon when hasFilter is true; use
the existing symbols hasFilter, IconButton, advancedFilterDescription,
onAdvancedSettingsClick, app.assetFilterRegex and app.fallbackToOlderReleases to
locate where to add the semantics/stateDescription and the visual badge.
In
`@feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsState.kt`:
- Around line 50-59: The advancedPreviewMessage: String? in AppsState should be
replaced with a typed sealed class or enum (e.g., AdvancedPreviewMessageState
with cases NoMatch, PreviewFailed, SaveFailed, None) to avoid brittle string
token matching; update AppsState to use this new type (and a sensible default
like AdvancedPreviewMessageState.None), then refactor the match/when in
AdvancedAppSettingsBottomSheet to switch over AdvancedPreviewMessageState cases
instead of comparing raw literals ("no_match", "preview_failed", "save_failed"),
and update any other references (serializers/parcelables/initializers) to
construct and consume the new typed state.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: a1bd1ded-bd5f-4136-8d7b-ae893b8b5ea0
📒 Files selected for processing (34)
core/data/schemas/zed.rainxch.core.data.local.db.AppDatabase/10.jsoncore/data/src/androidMain/kotlin/zed/rainxch/core/data/local/db/initDatabase.ktcore/data/src/androidMain/kotlin/zed/rainxch/core/data/local/db/migrations/MIGRATION_9_10.ktcore/data/src/commonMain/kotlin/zed/rainxch/core/data/local/db/AppDatabase.ktcore/data/src/commonMain/kotlin/zed/rainxch/core/data/local/db/dao/InstalledAppDao.ktcore/data/src/commonMain/kotlin/zed/rainxch/core/data/local/db/entities/InstalledAppEntity.ktcore/data/src/commonMain/kotlin/zed/rainxch/core/data/mappers/InstalledAppsMappers.ktcore/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/InstalledAppsRepositoryImpl.ktcore/domain/src/commonMain/kotlin/zed/rainxch/core/domain/model/InstalledApp.ktcore/domain/src/commonMain/kotlin/zed/rainxch/core/domain/repository/InstalledAppsRepository.ktcore/domain/src/commonMain/kotlin/zed/rainxch/core/domain/util/AssetFilter.ktcore/presentation/src/commonMain/composeResources/values-ar/strings-ar.xmlcore/presentation/src/commonMain/composeResources/values-bn/strings-bn.xmlcore/presentation/src/commonMain/composeResources/values-es/strings-es.xmlcore/presentation/src/commonMain/composeResources/values-fr/strings-fr.xmlcore/presentation/src/commonMain/composeResources/values-hi/strings-hi.xmlcore/presentation/src/commonMain/composeResources/values-it/strings-it.xmlcore/presentation/src/commonMain/composeResources/values-ja/strings-ja.xmlcore/presentation/src/commonMain/composeResources/values-ko/strings-ko.xmlcore/presentation/src/commonMain/composeResources/values-pl/strings-pl.xmlcore/presentation/src/commonMain/composeResources/values-ru/strings-ru.xmlcore/presentation/src/commonMain/composeResources/values-tr/strings-tr.xmlcore/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xmlcore/presentation/src/commonMain/composeResources/values/strings.xmlfeature/apps/data/src/commonMain/kotlin/zed/rainxch/apps/data/repository/AppsRepositoryImpl.ktfeature/apps/domain/src/commonMain/kotlin/zed/rainxch/apps/domain/repository/AppsRepository.ktfeature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsAction.ktfeature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsRoot.ktfeature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsState.ktfeature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsViewModel.ktfeature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/components/AdvancedAppSettingsBottomSheet.ktfeature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/components/LinkAppBottomSheet.ktfeature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/mappers/InstalledAppMapper.ktfeature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/model/InstalledAppUi.kt
core/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/InstalledAppsRepositoryImpl.kt
Show resolved
Hide resolved
core/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/InstalledAppsRepositoryImpl.kt
Show resolved
Hide resolved
core/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/InstalledAppsRepositoryImpl.kt
Show resolved
Hide resolved
| /** | ||
| * Persists per-app monorepo settings: an optional regex applied to asset | ||
| * names and whether the update checker should fall back to older | ||
| * releases when the latest one has no matching asset. | ||
| * | ||
| * Implementations should re-check the app for updates immediately so | ||
| * the UI reflects the new state without a manual refresh. | ||
| */ | ||
| suspend fun setAssetFilter( | ||
| packageName: String, | ||
| regex: String?, | ||
| fallbackToOlderReleases: Boolean, | ||
| ) |
There was a problem hiding this comment.
setAssetFilter() promises an immediate refresh that the implementation does not perform.
The KDoc says saving the filter should re-check updates right away, but InstalledAppsRepositoryImpl.setAssetFilter() only persists the DAO fields. That leaves updateAvailable stale until the next explicit/background check. Either trigger checkForUpdates(packageName) as part of this operation or relax this contract and make the caller own the refresh.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/repository/InstalledAppsRepository.kt`
around lines 54 - 66, The KDoc for InstalledAppsRepository.setAssetFilter
promises an immediate re-check but InstalledAppsRepositoryImpl.setAssetFilter
currently only persists DAO fields and leaves updateAvailable stale; update the
implementation of InstalledAppsRepositoryImpl.setAssetFilter to, after saving
the regex and fallbackToOlderReleases, call and await
checkForUpdates(packageName) (or the repository's internal method that computes
updateAvailable) so the UI-state is refreshed immediately, and handle/log any
exceptions from that call so persistence still succeeds even if the check fails.
core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/util/AssetFilter.kt
Outdated
Show resolved
Hide resolved
core/presentation/src/commonMain/composeResources/values-pl/strings-pl.xml
Outdated
Show resolved
Hide resolved
feature/apps/data/src/commonMain/kotlin/zed/rainxch/apps/data/repository/AppsRepositoryImpl.kt
Show resolved
Hide resolved
...ntation/src/commonMain/kotlin/zed/rainxch/apps/presentation/components/LinkAppBottomSheet.kt
Show resolved
Hide resolved
- **Localization & Resources**: - Convert `asset_filter_visible_count` and `advanced_preview_release` to plurals to support proper inflection across all supported languages (English, Arabic, Bengali, Spanish, French, Hindi, Italian, Japanese, Korean, Polish, Russian, Turkish, and Simplified Chinese). - Add `asset_none_available` string for releases with no installable assets. - Update UI components to use `pluralStringResource`. - **Core Data & Logic**: - Add `clearUpdateMetadata` to `InstalledAppDao` to atomically reset update badges and stale metadata when filters no longer match any assets. - Improve `AssetFilter.suggestFromAssetName` to return an escaped, anchored literal-prefix regex (e.g., `^\Qprefix\E`) to prevent metacharacters from breaking searches. - Update `AppsRepository` to include `assetFilterRegex` and `fallbackToOlderReleases` in the export schema (bumped to version 2). - Enhance `AppsViewModel` regex suggestion logic to automatically escape package segments and display name tokens. - **Bug Fixes & Improvements**: - Ensure `checkForUpdates` clears stale metadata when no matching releases are found in the current window. - Fix structured concurrency by ensuring `CancellationException` is propagated during release fetches and filter updates. - Improve "Link App" UI to distinguish between an invalid regex, no matches, and no available assets. - Optimize `setAssetFilter` to perform an internal update check immediately after persisting changes.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
core/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/InstalledAppsRepositoryImpl.kt (1)
385-429: Consider adding CancellationException handling inpreviewMatchingAssets.The
previewMatchingAssetsmethod callsfetchReleaseWindow, which can throwCancellationException. WhilefetchReleaseWindowre-throws it, the exception will propagate up to the ViewModel. This is likely fine since the ViewModel'srefreshAdvancedPreviewhandles it, but for consistency withsetAssetFilter, you might consider explicit handling here too.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@core/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/InstalledAppsRepositoryImpl.kt` around lines 385 - 429, In previewMatchingAssets, wrap the call to fetchReleaseWindow(owner, repo, includePreReleases) in a try/catch that explicitly catches CancellationException and rethrows it (matching the pattern used in setAssetFilter) so coroutine cancellation isn't accidentally swallowed; keep existing behavior for other exceptions (i.e., let them propagate or handle them as before). Reference: previewMatchingAssets and fetchReleaseWindow.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In
`@core/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/InstalledAppsRepositoryImpl.kt`:
- Around line 385-429: In previewMatchingAssets, wrap the call to
fetchReleaseWindow(owner, repo, includePreReleases) in a try/catch that
explicitly catches CancellationException and rethrows it (matching the pattern
used in setAssetFilter) so coroutine cancellation isn't accidentally swallowed;
keep existing behavior for other exceptions (i.e., let them propagate or handle
them as before). Reference: previewMatchingAssets and fetchReleaseWindow.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 35af2806-9467-488d-9d0e-4d266be72bba
📒 Files selected for processing (21)
core/data/src/commonMain/kotlin/zed/rainxch/core/data/local/db/dao/InstalledAppDao.ktcore/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/InstalledAppsRepositoryImpl.ktcore/domain/src/commonMain/kotlin/zed/rainxch/core/domain/model/ExportedApp.ktcore/domain/src/commonMain/kotlin/zed/rainxch/core/domain/util/AssetFilter.ktcore/presentation/src/commonMain/composeResources/values-ar/strings-ar.xmlcore/presentation/src/commonMain/composeResources/values-bn/strings-bn.xmlcore/presentation/src/commonMain/composeResources/values-es/strings-es.xmlcore/presentation/src/commonMain/composeResources/values-fr/strings-fr.xmlcore/presentation/src/commonMain/composeResources/values-hi/strings-hi.xmlcore/presentation/src/commonMain/composeResources/values-it/strings-it.xmlcore/presentation/src/commonMain/composeResources/values-ja/strings-ja.xmlcore/presentation/src/commonMain/composeResources/values-ko/strings-ko.xmlcore/presentation/src/commonMain/composeResources/values-pl/strings-pl.xmlcore/presentation/src/commonMain/composeResources/values-ru/strings-ru.xmlcore/presentation/src/commonMain/composeResources/values-tr/strings-tr.xmlcore/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xmlcore/presentation/src/commonMain/composeResources/values/strings.xmlfeature/apps/data/src/commonMain/kotlin/zed/rainxch/apps/data/repository/AppsRepositoryImpl.ktfeature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsViewModel.ktfeature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/components/AdvancedAppSettingsBottomSheet.ktfeature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/components/LinkAppBottomSheet.kt
✅ Files skipped from review due to trivial changes (6)
- core/presentation/src/commonMain/composeResources/values/strings.xml
- core/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xml
- core/presentation/src/commonMain/composeResources/values-ar/strings-ar.xml
- core/presentation/src/commonMain/composeResources/values-tr/strings-tr.xml
- core/presentation/src/commonMain/composeResources/values-it/strings-it.xml
- core/presentation/src/commonMain/composeResources/values-pl/strings-pl.xml
🚧 Files skipped from review as they are similar to previous changes (8)
- core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml
- core/presentation/src/commonMain/composeResources/values-fr/strings-fr.xml
- core/presentation/src/commonMain/composeResources/values-ru/strings-ru.xml
- core/presentation/src/commonMain/composeResources/values-ko/strings-ko.xml
- core/presentation/src/commonMain/composeResources/values-ja/strings-ja.xml
- core/presentation/src/commonMain/composeResources/values-es/strings-es.xml
- core/presentation/src/commonMain/composeResources/values-hi/strings-hi.xml
- feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/components/AdvancedAppSettingsBottomSheet.kt
AppDatabaseschema to version 10.assetFilterRegex(TEXT) andfallbackToOlderReleases(INTEGER) columns to theinstalled_appstable.MIGRATION_9_10to handle the database upgrade.InstalledAppEntitywith new fields to allow filtering assets by regex and falling back to older releases when checking for updates.Summary by CodeRabbit