Skip to content

Add store page links to game details - #1795

Open
jmarti326 wants to merge 7 commits into
utkarshdalal:masterfrom
jmarti326:feat/store-details-links
Open

Add store page links to game details#1795
jmarti326 wants to merge 7 commits into
utkarshdalal:masterfrom
jmarti326:feat/store-details-links

Conversation

@jmarti326

@jmarti326 jmarti326 commented Aug 7, 2026

Copy link
Copy Markdown

Description

Adds a simple "View on Store" action to game details and the options menu.

Steam tries the Android app first and falls back to the web page. GOG opens its web page. Epic and Amazon stay disabled until they have reliable product links.

I added focused tests for link building and fallback behavior.

Recording

signal-2026-08-06-22-02-18-187.mp4

Screenshot

View on Steam in the Options menu

Type of Change

  • Bug fix
  • Performance / stability improvement
  • Compatibility improvements
  • Other (requires prior approval)

Checklist

  • If I have access to #code-changes, I have discussed this change there and it has been green-lighted. If I do not have access, I have still provided clear context in this PR. If I skip both, I accept that this change may face delays in review, may not be reviewed at all, or may be closed.
  • This change aligns with the current project scope (core functionality, stability, or performance). If not, it has been explicitly approved beforehand.
  • I have attached a recording of the change.
  • I have read and agree to the contribution guidelines in CONTRIBUTING.md.

Summary by cubic

Add an “Open store page” action in game details and the Options menu. Supports Steam (native app with web fallback) and GOG (web); Epic and Amazon remain disabled until we have reliable product links.

  • New Features

    • Resolver/launcher validates URLs and tries native intents (Steam) before opening the canonical web page; tests cover resolution and fallback.
    • UI: header action and Options entry reuse a single localized label; labels show “Open store page”.
    • Failure handling: shows a dialog and lets users copy the canonical link; analytics via PostHog capture store_page_opened with store and route (native/web/failed).
  • Bug Fixes

    • Store links refresh when game metadata updates; GOG link lookup no longer blocks the UI.
    • Shortened Epic display name to “Epic” for consistent labeling.

Written for commit 7e554ac. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added options to open Steam, GOG, and Epic Games Store pages directly from game screens.
    • Uses the native store app when available, with automatic browser fallback.
    • Added a copy-link option when store pages cannot be opened.
    • Added support for custom menu action titles.
  • Bug Fixes

    • Improved handling of unavailable apps, security restrictions, and invalid store links.

@jmarti326
jmarti326 requested a review from utkarshdalal as a code owner August 7, 2026 01:50
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds validated store-page targets for Steam, GOG, and Epic. Library screens expose store actions that try native apps, fall back to web URLs, track outcomes, and support copying failed links.

Changes

Store page links

Layer / File(s) Summary
Store target contracts and resolution
app/src/main/java/app/gamenative/store/*, app/src/main/java/app/gamenative/ui/data/GameDisplayInfo.kt, app/src/main/java/app/gamenative/ui/screen/library/appscreen/{SteamAppScreen.kt,GOGAppScreen.kt}, app/src/test/java/app/gamenative/store/StorePageResolverTest.kt
Defines target and launch-result models. Validates Steam app IDs and GOG/Epic slugs. Builds canonical URLs and native Steam candidates. Adds targets to provider display data and tests resolver behavior.
Native launch and browser fallback
app/src/main/java/app/gamenative/store/StorePageLauncher.kt, app/src/test/java/app/gamenative/store/StorePageLauncherTest.kt
Attempts native candidates in order. Handles unavailable or rejected activities. Falls back to the canonical browser URL and returns the launch result.
Library actions and failure recovery
app/src/main/java/app/gamenative/ui/screen/library/appscreen/BaseAppScreen.kt, app/src/main/java/app/gamenative/ui/screen/library/LibraryAppScreen.kt, app/src/main/java/app/gamenative/ui/data/{StorePageAction.kt,AppMenuOption.kt}, app/src/main/java/app/gamenative/ui/screen/library/components/GameOptionsPanel.kt, app/src/main/res/values/strings.xml
Adds store actions to menus and content UI. Records native and web routing when analytics is enabled. Shows failure handling with URL copying and confirmation feedback.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant LibraryScreen
  participant BaseAppScreen
  participant StorePageLauncher
  participant NativeStoreApp
  participant Browser
  LibraryScreen->>BaseAppScreen: provide store page action
  BaseAppScreen->>StorePageLauncher: launch store target
  StorePageLauncher->>NativeStoreApp: try native candidate
  NativeStoreApp-->>StorePageLauncher: success or launch failure
  StorePageLauncher->>Browser: open canonical web URL
  Browser-->>StorePageLauncher: success or security failure
  StorePageLauncher-->>BaseAppScreen: return launch result
  BaseAppScreen-->>LibraryScreen: show action or failure dialog
Loading

Possibly related PRs

Suggested reviewers: utkarshdalal

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the main change: adding store page links to game details.
Description check ✅ Passed The description explains the changes, includes recording evidence, identifies the change type, and completes most checklist items.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/store-details-links.md`:
- Around line 28-30: Update the analytics description in the documentation to
state that the store and launch outcome are recorded, including the failed
outcome emitted by BaseAppScreen, while preserving the exclusions for game IDs,
names, URLs, exception text, and package lists.
🪄 Autofix

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 51e993bb-c727-427e-a325-d9e72320ba97

📥 Commits

Reviewing files that changed from the base of the PR and between 78e9343 and bf20235.

📒 Files selected for processing (14)
  • app/src/main/java/app/gamenative/store/StorePageLauncher.kt
  • app/src/main/java/app/gamenative/store/StorePageResolver.kt
  • app/src/main/java/app/gamenative/store/StorePageTarget.kt
  • app/src/main/java/app/gamenative/ui/data/AppMenuOption.kt
  • app/src/main/java/app/gamenative/ui/data/StorePageAction.kt
  • app/src/main/java/app/gamenative/ui/screen/library/LibraryAppScreen.kt
  • app/src/main/java/app/gamenative/ui/screen/library/appscreen/BaseAppScreen.kt
  • app/src/main/java/app/gamenative/ui/screen/library/appscreen/GOGAppScreen.kt
  • app/src/main/java/app/gamenative/ui/screen/library/appscreen/SteamAppScreen.kt
  • app/src/main/java/app/gamenative/ui/screen/library/components/GameOptionsPanel.kt
  • app/src/main/res/values/strings.xml
  • app/src/test/java/app/gamenative/store/StorePageLauncherTest.kt
  • app/src/test/java/app/gamenative/store/StorePageResolverTest.kt
  • docs/store-details-links.md

Comment thread docs/store-details-links.md Outdated
Comment on lines +28 to +30
- When usage analytics are enabled, only the store and successful route type
are recorded. Game IDs, names, URLs, exception text, and package lists are
excluded.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Document failed launch telemetry.

Line 28 says analytics records only a successful route type. BaseAppScreen.kt:1330-1351 also records route = "failed" after a total launch failure. Update the text to say that the store and launch outcome are recorded, or stop emitting the failed event.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/store-details-links.md` around lines 28 - 30, Update the analytics
description in the documentation to state that the store and launch outcome are
recorded, including the failed outcome emitted by BaseAppScreen, while
preserving the exclusions for game IDs, names, URLs, exception text, and package
lists.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 14 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="app/src/main/java/app/gamenative/store/StorePageResolver.kt">

<violation number="1" location="app/src/main/java/app/gamenative/store/StorePageResolver.kt:34">
P3: The GOG and Epic resolvers duplicate the same slug normalization and validation logic, so any allow-list or normalization fix must be applied in two places and can drift between providers; a private shared validated-slug helper would keep this behavior consistent.

(Based on your team's feedback about centralizing shared logic.)</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread app/src/main/res/values/strings.xml Outdated
}

fun gog(slug: String): StorePageTarget? {
val normalizedSlug = slug.trim().lowercase(Locale.ROOT)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The GOG and Epic resolvers duplicate the same slug normalization and validation logic, so any allow-list or normalization fix must be applied in two places and can drift between providers; a private shared validated-slug helper would keep this behavior consistent.

(Based on your team's feedback about centralizing shared logic.)

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/src/main/java/app/gamenative/store/StorePageResolver.kt, line 34:

<comment>The GOG and Epic resolvers duplicate the same slug normalization and validation logic, so any allow-list or normalization fix must be applied in two places and can drift between providers; a private shared validated-slug helper would keep this behavior consistent.

(Based on your team's feedback about centralizing shared logic.) </comment>

<file context>
@@ -0,0 +1,54 @@
+    }
+
+    fun gog(slug: String): StorePageTarget? {
+        val normalizedSlug = slug.trim().lowercase(Locale.ROOT)
+        if (!gogSlugPattern.matches(normalizedSlug)) return null
+
</file context>

Comment thread docs/store-details-links.md Outdated
Comment thread app/src/main/java/app/gamenative/ui/screen/library/appscreen/BaseAppScreen.kt Outdated
Comment thread app/src/test/java/app/gamenative/store/StorePageLauncherTest.kt
@jmarti326

Copy link
Copy Markdown
Author
signal-2026-08-06-22-02-18-187.mp4

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
app/src/test/java/app/gamenative/store/StorePageLauncherTest.kt (1)

74-90: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert that the browser intent is attempted.

This test does not record the intents. A launcher that returns Failed without attempting the browser would still pass. Record each intent and assert that the final intent uses target.canonicalWebUrl.

The launcher contract in app/src/main/java/app/gamenative/store/StorePageLauncher.kt:9-47 attempts native candidates before the browser.

Proposed test improvement
     fun `browser security rejection returns copyable canonical url`() {
         val target = steamTarget()
+        val intents = mutableListOf<Intent>()

         val result = StorePageLauncher.launch(context, target) { intent ->
+            intents += intent
             if (intent.data?.scheme == "steam") {
                 throw ActivityNotFoundException()
             }
             throw SecurityException()
         }

         assertTrue(result is StorePageLaunchResult.Failed)
+        assertEquals(target.canonicalWebUrl, intents.last().dataString)
         assertEquals(
             target.canonicalWebUrl,
             (result as StorePageLaunchResult.Failed).canonicalWebUrl,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/test/java/app/gamenative/store/StorePageLauncherTest.kt` around lines
74 - 90, The test `browser security rejection returns copyable canonical url`
must record the intents passed to `StorePageLauncher.launch` and assert that the
final browser intent uses `target.canonicalWebUrl`, while preserving the
existing native-candidate rejection behavior and failure-result assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@app/src/test/java/app/gamenative/store/StorePageLauncherTest.kt`:
- Around line 74-90: The test `browser security rejection returns copyable
canonical url` must record the intents passed to `StorePageLauncher.launch` and
assert that the final browser intent uses `target.canonicalWebUrl`, while
preserving the existing native-candidate rejection behavior and failure-result
assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5f1b18d0-aa09-417b-83d7-5da763219861

📥 Commits

Reviewing files that changed from the base of the PR and between bf20235 and 6e8e5c8.

📒 Files selected for processing (5)
  • app/src/main/java/app/gamenative/ui/data/GameDisplayInfo.kt
  • app/src/main/java/app/gamenative/ui/screen/library/appscreen/BaseAppScreen.kt
  • app/src/main/java/app/gamenative/ui/screen/library/appscreen/GOGAppScreen.kt
  • app/src/main/java/app/gamenative/ui/screen/library/appscreen/SteamAppScreen.kt
  • app/src/test/java/app/gamenative/store/StorePageLauncherTest.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/src/main/java/app/gamenative/ui/screen/library/appscreen/SteamAppScreen.kt

@jmarti326

Copy link
Copy Markdown
Author
signal-2026-08-07-08-20-06-477_002

@utkarshdalal

Copy link
Copy Markdown
Owner

Hey @jmarti326 - what's the use case you have in mind here? Why would users want to check the store page for games they own?

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