Skip to content

feat: support multiple installed apps per repository (monorepo)#480

Closed
rainxchzed wants to merge 1 commit intomainfrom
ridge-hogback
Closed

feat: support multiple installed apps per repository (monorepo)#480
rainxchzed wants to merge 1 commit intomainfrom
ridge-hogback

Conversation

@rainxchzed
Copy link
Copy Markdown
Member

@rainxchzed rainxchzed commented May 2, 2026

Summary

Remove the one-repo-to-one-app assumption that prevented installing and tracking multiple apps from the same GitHub repository.

Closes #471, Closes #420

Problem

Repos that ship multiple distinct apps in their releases (e.g. ente-io/ente ships Auth + Photos + Locker, Proton ships Mail + VPN + Drive) could only have one app tracked. Installing a second app from the same repo was blocked, and update checking only tracked the first installed asset.

What Changed

Core layer (DAO + Repository):

  • Added getAppsByRepoId() and getAppsByRepoIdAsFlow() list-returning queries to InstalledAppDao alongside existing single-returning queries
  • Added matching methods to InstalledAppsRepository interface and implementation

Badge/status across all screens:

  • Home, Search, DevProfile: associateBy { it.repoId }groupBy { it.repoId } so installed/update badges reflect any tracked app per repo
  • Favourites & Starred: switched to list queries for install status

Details screen:

  • Added installedApps: List<InstalledApp> to DetailsState
  • loadInitial() fetches all installed apps via getAppsByRepoId()
  • observeInstalledApp() uses getAppsByRepoIdAsFlow(), picks primary by assetFilterRegex match

What Already Worked (no changes needed)

  • Background update checker (checkForUpdates per package name)
  • Export/import (keyed by packageName)
  • Advanced settings sheet (asset filter regex + fallback toggle)
  • DB schema (PK is packageName, not repoId)

Follow-up Work

  • Multi-app indicator UI: Show collapsible section in Details when installedApps.size > 1, listing each tracked app
  • SmartInstallButton enhancement: Show "N apps tracked" indicator for monorepo repos

Test with

  • ente-io/ente (ships auth, photos, locker)
  • AChep/keyguard-app (multiple APK variants)
  • nicehash/NiceHashQuickMiner (multiple tools)

Warp conversation
Implementation plan

Co-Authored-By: Oz oz-agent@warp.dev

Summary by CodeRabbit

Release Notes

  • New Features

    • Added support for repositories containing multiple application packages (monorepos)
    • Enhanced self-update detection mechanisms for improved app refresh handling
  • Documentation

    • Added comprehensive architectural documentation and project structure guide

After GitHub Store updates itself, Android does not deliver
ACTION_PACKAGE_REPLACED to the app's own receivers, leaving
isPendingInstall = true permanently in the database.

Changes:
- GithubStoreApp: registerSelfAsInstalledApp() now detects and
  resolves a stale isPendingInstall flag on every cold start by
  querying the system PackageManager.
- PackageEventReceiver: handle ACTION_MY_PACKAGE_REPLACED (the
  Android-sanctioned broadcast for self-updates) with a fallback
  to context.packageName since it carries no data URI.
- AndroidManifest: add a dedicated intent-filter for
  MY_PACKAGE_REPLACED (no data scheme required).

Closes #478

Co-Authored-By: Oz <oz-agent@warp.dev>
@rainxchzed rainxchzed changed the title fix: resolve stuck 'preparing to install' after self-update (#478) feat: support multiple installed apps per repository (monorepo) May 2, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 2, 2026

Caution

Review failed

Pull request was closed or merged during review

Walkthrough

This PR adds support for multiple installed apps per repository to resolve self-update state persistence issues. It updates broadcast handling to detect self-updates, adds multi-app database queries, modifies repository logic to check all non-pending apps, and refactors presentation layers to select primary apps based on asset filters rather than assuming one-to-one repo-to-app mapping.

Changes

Multi-App Installation Support

Layer / File(s) Summary
Documentation & Manifest
AGENTS.md, composeApp/src/androidMain/AndroidManifest.xml
AGENTS.md documents architecture, module layout, and feature checklist. AndroidManifest.xml registers MY_PACKAGE_REPLACED intent-filter for self-update detection.
Broadcast Intent Handling
core/data/src/androidMain/kotlin/zed/rainxch/core/data/services/PackageEventReceiver.kt
Adds ACTION_MY_PACKAGE_REPLACED dispatch path with fallback packageName extraction from context.packageName when intent data is absent. Registers action in intent-filter.
Self-Update Resolution
composeApp/src/androidMain/kotlin/zed/rainxch/githubstore/app/GithubStoreApp.kt
registerSelfAsInstalledApp now resolves stale pending-install flags by calling new resolveSelfPendingInstall helper, which queries PackageMonitor for current system package info, updates DB row, and recalculates version-availability status.
Data Access – Bulk Queries
core/data/src/commonMain/kotlin/zed/rainxch/core/data/local/db/dao/InstalledAppDao.kt
Adds getAppsByRepoId(repoId) and getAppsByRepoIdAsFlow(repoId) to fetch all installed apps for a given repository.
Domain Repository Interface
core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/repository/InstalledAppsRepository.kt
Exposes getAppsByRepoId(repoId): List<InstalledApp> and getAppsByRepoIdAsFlow(repoId): Flow<List<InstalledApp>> for bulk multi-app retrieval.
Repository Implementations
core/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/InstalledAppsRepositoryImpl.kt, FavouritesRepositoryImpl.kt, StarredRepositoryImpl.kt, feature/dev-profile/data/src/.../DeveloperProfileRepositoryImpl.kt
InstalledAppsRepositoryImpl implements new bulk-fetch methods. Favourites, Starred, and DeveloperProfile repos switch to querying all installed apps per repoId and selecting first non-pending app (or checking any { !isPendingInstall }) instead of single-record lookups.
Presentation State & Primary App Selection
feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsState.kt, DetailsViewModel.kt
DetailsState adds installedApps: List<InstalledApp>. DetailsViewModel loads all apps per repo, selects primary by matching primaryAsset.name against each app's assetFilterRegex (fallback: first app), and updates both installedApp and installedApps state.
Search & Home Presentation
feature/home/presentation/src/commonMain/kotlin/.../HomeViewModel.kt, feature/search/presentation/src/commonMain/kotlin/.../SearchViewModel.kt
Switch from associateBy { it.repoId } (single app per repo) to groupBy { it.repoId } (multiple apps per repo). Derive isInstalled and isUpdateAvailable using apps.any { ... } checks instead of single-app methods.

Sequence Diagram

sequenceDiagram
    participant System
    participant PackageEventReceiver
    participant GithubStoreApp
    participant PackageMonitor
    participant InstalledAppsRepository
    participant InstalledAppDao

    System->>PackageEventReceiver: Broadcast MY_PACKAGE_REPLACED
    PackageEventReceiver->>PackageEventReceiver: Extract packageName from intent.data
    PackageEventReceiver->>GithubStoreApp: onPackageInstalled(packageName)
    
    GithubStoreApp->>InstalledAppsRepository: getAppByRepoId(self)
    InstalledAppsRepository-->>GithubStoreApp: existing (with isPendingInstall=true)
    
    GithubStoreApp->>PackageMonitor: Get current package info
    PackageMonitor-->>GithubStoreApp: Package info (version, etc.)
    
    GithubStoreApp->>InstalledAppDao: Update app (set isPendingInstall=false, refresh version)
    InstalledAppDao->>InstalledAppDao: Persist to DB
    InstalledAppDao-->>GithubStoreApp: Success
    
    GithubStoreApp->>GithubStoreApp: Recalculate isUpdateAvailable
    GithubStoreApp-->>System: State resolved
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Hops through pending states, a fuzzy quest complete,
Multiple apps now dance where one app used to greet,
Self-updates bloom at last, no lingering delay,
Asset filters whisper true—the primary app's the way.

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title claims to support multiple installed apps per repository (monorepo), but the primary objectives involve fixing a self-update pending-install state bug (#478). Consider retitling to reflect the main fix: 'fix: resolve stuck pending-install state after self-update' or use a multi-commit title like 'fix/feat: resolve self-update state and add monorepo support'.
Docstring Coverage ⚠️ Warning Docstring coverage is 3.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Out of Scope Changes check ❓ Inconclusive The PR includes substantial multi-app repository support changes (DAO queries, repository APIs, DetailsState, ViewModels) that extend beyond the stated #478 issue scope, though these appear intentional per the commit messages. Clarify whether the monorepo feature is intentional scope for this PR or should be split into a separate PR; if intentional, update the title and description to reflect both fixes.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The PR addresses the core requirements of issue #478: it resolves stale isPendingInstall on cold start, handles ACTION_MY_PACKAGE_REPLACED in the receiver, and adds the manifest intent-filter for self-updates.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ridge-hogback

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.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@rainxchzed
Copy link
Copy Markdown
Member Author

Reopening as a new PR from feat/monorepo-support branch to keep ridge-hogback clean for #478 work.

@rainxchzed rainxchzed closed this May 2, 2026
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.

Allow installing and updating multiple assets from a single repository error in downloading other app from the same repository

1 participant