Skip to content

feat: steam achievements viewer (updated #1511)#1695

Open
VinceBT wants to merge 1 commit into
utkarshdalal:masterfrom
VinceBT:feat/steam-achievements
Open

feat: steam achievements viewer (updated #1511)#1695
VinceBT wants to merge 1 commit into
utkarshdalal:masterfrom
VinceBT:feat/steam-achievements

Conversation

@VinceBT

@VinceBT VinceBT commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Description

This is @phobos665's Steam achievements viewer from #1511, brought up to current master with some refinements on top. Most of the credit here belongs to @phobos665 — the viewer, the data plumbing and the schema handling are all theirs; I rebased the work onto current master and polished the UI and localization.

Quoting the original PR (#1511):

View Steam Achievements in the Game Details Page (LibraryAppScreen).

Also shows a little gold star for those who get 100% of achievements.

Also, this has been made so that it's generic enough to support both Epic & GOG achievements later.

On top of that, this PR:

  • Localizes achievement names/descriptions to the app's language, falling back to English per-string when a game doesn't ship that language.
  • Restyles the game-page block to match the screenshots card — in-card "Achievements ›" title with a chevron, and the whole card is clickable / controller-focusable.
  • Adds a "+N" tile for achievements beyond what fits, with a centered x / y count.
  • Makes the "all achievements" view fullscreen with the same open/close animation as the screenshot gallery, each achievement in its own card instead of divider rows.
  • Adds the achievement strings across all locales.

Implementation note: this replaces the local InfoCard in LibraryAppScreen with the shared ui/component/InfoCard component (a superset that adds onClick/content), so a few neighbouring cards move to it as well.

Recording

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

Adds a Steam achievements viewer to the Game Details page: a compact card with progress and icons, plus a fullscreen list. Text is localized with English fallbacks; icons come from the Steam CDN; fetching uses a 15s timeout and retries for reliability.

  • New Features

    • Achievements card for Steam titles: icon row with grayed locked icons and “+N” overflow, x/y progress, and a gold star at 100%.
    • Fullscreen Achievements view with gallery-style animation and a back header; entries show icon, name, description, and unlock time; unlocked first.
  • Refactors

    • Introduced reusable ui/component/InfoCard (clickable/focusable with chevron) and updated game detail cards to use it.
    • Added ui/data/Achievement, SteamService.fetchAchievementsForDisplay(), SteamUtils.steamLanguageForAppLocale(), and SteamUtils.getBaseAchievementIconUrl(); fetch runs for Steam games in BaseAppScreen (15s timeout, up to 3 attempts with a short delay); added localized strings across all locales.

Written for commit ee695a0. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added Steam achievements to the library app screen, including unlocked/total progress, completion status, and an achievement icon strip.
    • Added a full-screen achievements dialog to view all achievements with descriptions and unlock timestamps.
    • Introduced a reusable card UI component for consistent achievement-related sections.
  • Localization
    • Added localized strings for the Steam achievements section across supported languages, including “unlocked at” messaging and totals.

@VinceBT VinceBT requested a review from utkarshdalal as a code owner July 10, 2026 14:51
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Steam achievements are fetched from Steam, mapped into localized display models, loaded for Steam library items, and shown through an overview row and animated detail dialog. Shared InfoCard rendering and localized achievement resources are also added.

Changes

Steam achievements

Layer / File(s) Summary
Achievement model and Steam locale utilities
app/src/main/java/app/gamenative/ui/data/Achievement.kt, app/src/main/java/app/gamenative/utils/SteamUtils.kt
Defines achievement display fields, unlock-time formatting, Steam icon URL construction, and locale mapping.
Steam achievement fetching
app/src/main/java/app/gamenative/service/SteamService.kt
Fetches expanded Steam achievements with timeout handling, localized and English fallback text, icon URLs, and nullable results.
Achievement state and screen wiring
app/src/main/java/app/gamenative/ui/screen/library/appscreen/BaseAppScreen.kt, app/src/main/java/app/gamenative/ui/screen/library/LibraryAppScreen.kt
Loads achievements asynchronously for Steam items, retries failures, and passes the resulting state into app screen content.
Achievement overview and detail UI
app/src/main/java/app/gamenative/ui/component/InfoCard.kt, app/src/main/java/app/gamenative/ui/screen/library/LibraryAppScreen.kt, app/src/main/res/values*/strings.xml
Adds the achievement summary row, animated detail dialog, reusable InfoCard, and localized achievement labels across supported locales.

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

Sequence Diagram(s)

sequenceDiagram
  participant BaseAppScreen
  participant SteamService
  participant SteamUserStats
  participant AppScreenContent
  participant AchievementsDialog
  BaseAppScreen->>SteamService: fetchAchievementsForDisplay(appId)
  SteamService->>SteamUserStats: fetch expanded achievements
  SteamUserStats-->>SteamService: achievement data
  SteamService-->>BaseAppScreen: List<Achievement> or null
  BaseAppScreen->>AppScreenContent: pass achievements state
  AppScreenContent->>AchievementsDialog: open detailed achievement list
Loading

Possibly related PRs

  • utkarshdalal/GameNative#346: Both changes modify Ukrainian locale resources in values-uk/strings.xml, including achievement-related string definitions.

Suggested reviewers: utkarshdalal, morganwalkup

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.65% 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 is concise and clearly summarizes the main change: a Steam achievements viewer.
Description check ✅ Passed The description follows the required template and is substantive, though the recording is still a placeholder and the checklist is not fully completed.
✨ 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: 7

🧹 Nitpick comments (2)
app/src/main/java/app/gamenative/ui/screen/library/LibraryAppScreen.kt (2)

1250-1250: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate grayMatrix construction in AchievementsRow and AchievementsDialog.

Both composables independently build the same ColorMatrix().apply { setToSaturation(0f) }. Consider hoisting it to a single top-level private val (it's stateless) to avoid the duplication.

Also applies to: 1380-1380

🤖 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/main/java/app/gamenative/ui/screen/library/LibraryAppScreen.kt` at
line 1250, Hoist the duplicated grayscale matrix into a single top-level private
ColorMatrix value, then update both AchievementsRow and AchievementsDialog to
reference it instead of constructing separate instances with remember.

1237-1506: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add contentDescription to achievement icon images for accessibility.

Landscapist's ImageOptions supports a contentDescription field, but none of the three CoilImage calls here (row icons, "+N" stack icon, dialog list icon) set it. Screen-reader users get no label for achievement artwork.

♿ Suggested addition
 CoilImage(
     imageModel = { iconUrl ?: "" },
     imageOptions = ImageOptions(
         contentScale = ContentScale.Crop,
+        contentDescription = ach.displayName ?: ach.name,
         colorFilter = if (ach.isUnlocked) null else ColorFilter.colorMatrix(grayMatrix),
     ),
     ...
 )
🤖 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/main/java/app/gamenative/ui/screen/library/LibraryAppScreen.kt`
around lines 1237 - 1506, Add accessibility labels to all three achievement
CoilImage calls in AchievementsRow and AchievementsDialog by setting
ImageOptions.contentDescription using each achievement’s display name or name,
with a suitable fallback for the stacked “+N” preview icon.
🤖 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 `@app/src/main/java/app/gamenative/service/SteamService.kt`:
- Around line 3074-3113: Update fetchAchievementsForDisplay to rethrow
CancellationException before the generic Exception handler, preserving coroutine
cancellation. Bound the Steam operations, including getUserStats(...).await()
and achievement expansion, with an appropriate coroutine timeout such as
withTimeout, while keeping existing error logging and null fallback behavior.

In `@app/src/main/java/app/gamenative/ui/component/InfoCard.kt`:
- Around line 61-66: Remove the unnecessary rememberCoroutineScope and nested
scope.launch from LaunchedEffect(isFocused); call the suspend
bringIntoViewRequester.bringIntoView() directly when isFocused is true so it
remains tied to the effect lifecycle. Remove the now-unused coroutine scope and
launch imports if they are not used elsewhere.

In `@app/src/main/res/values-de/strings.xml`:
- Around line 1571-1577: Translate the German localization value for the
achievements_total string from “Total” to an appropriate German term, preferably
“Gesamt” or “Insgesamt,” while leaving the other achievement strings unchanged.

In `@app/src/main/res/values-ru/strings.xml`:
- Around line 1558-1563: Translate the achievements_total string in the Russian
resources from the English “Total” to its Russian equivalent, matching the
surrounding Cyrillic translations.

In `@app/src/main/res/values-uk/strings.xml`:
- Around line 1626-1631: Translate the achievements_total string in the
Ukrainian achievements resource block from "Total" to the appropriate Ukrainian
equivalent, keeping the existing string name and resource structure unchanged.

In `@app/src/main/res/values-zh-rCN/strings.xml`:
- Around line 1650-1655: Translate the `achievements_total` string in the Steam
achievements resource block from “Total” to the appropriate Simplified Chinese
text, keeping the existing string name unchanged.

In `@app/src/main/res/values-zh-rTW/strings.xml`:
- Around line 1641-1646: Translate the achievements_total string in the
achievements resource block from “Total” to the appropriate Traditional Chinese
wording, matching the existing zh-rTW translations and the corresponding zh-rCN
resource.

---

Nitpick comments:
In `@app/src/main/java/app/gamenative/ui/screen/library/LibraryAppScreen.kt`:
- Line 1250: Hoist the duplicated grayscale matrix into a single top-level
private ColorMatrix value, then update both AchievementsRow and
AchievementsDialog to reference it instead of constructing separate instances
with remember.
- Around line 1237-1506: Add accessibility labels to all three achievement
CoilImage calls in AchievementsRow and AchievementsDialog by setting
ImageOptions.contentDescription using each achievement’s display name or name,
with a suitable fallback for the stacked “+N” preview icon.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: dc134ec6-8031-43de-91b7-5cca0bb9a71d

📥 Commits

Reviewing files that changed from the base of the PR and between b6fd912 and d605396.

📒 Files selected for processing (21)
  • app/src/main/java/app/gamenative/service/SteamService.kt
  • app/src/main/java/app/gamenative/ui/component/InfoCard.kt
  • app/src/main/java/app/gamenative/ui/data/Achievement.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/utils/SteamUtils.kt
  • app/src/main/res/values-da/strings.xml
  • app/src/main/res/values-de/strings.xml
  • app/src/main/res/values-es/strings.xml
  • app/src/main/res/values-fr/strings.xml
  • app/src/main/res/values-it/strings.xml
  • app/src/main/res/values-ja/strings.xml
  • app/src/main/res/values-ko/strings.xml
  • app/src/main/res/values-pl/strings.xml
  • app/src/main/res/values-pt-rBR/strings.xml
  • app/src/main/res/values-ro/strings.xml
  • app/src/main/res/values-ru/strings.xml
  • app/src/main/res/values-uk/strings.xml
  • app/src/main/res/values-zh-rCN/strings.xml
  • app/src/main/res/values-zh-rTW/strings.xml
  • app/src/main/res/values/strings.xml

Comment thread app/src/main/java/app/gamenative/service/SteamService.kt
Comment thread app/src/main/java/app/gamenative/ui/component/InfoCard.kt
Comment thread app/src/main/res/values-de/strings.xml Outdated
Comment thread app/src/main/res/values-ru/strings.xml Outdated
Comment thread app/src/main/res/values-uk/strings.xml Outdated
Comment thread app/src/main/res/values-zh-rCN/strings.xml Outdated
Comment thread app/src/main/res/values-zh-rTW/strings.xml Outdated
@VinceBT VinceBT force-pushed the feat/steam-achievements branch from d605396 to 3bce1dc Compare July 10, 2026 15:07

@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 and verified against the latest diff

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/service/SteamService.kt">

<violation number="1" location="app/src/main/java/app/gamenative/service/SteamService.kt:3074">
P2: A fetch failure now looks identical to a game with no achievements, so the whole section disappears on transient Steam errors. Surfacing an error state or retrying would keep the details page from silently dropping the feature.</violation>
</file>

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

Re-trigger cubic

Comment thread app/src/main/java/app/gamenative/service/SteamService.kt
}
}

suspend fun fetchAchievementsForDisplay(appId: Int): List<Achievement>? {

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.

P2: A fetch failure now looks identical to a game with no achievements, so the whole section disappears on transient Steam errors. Surfacing an error state or retrying would keep the details page from silently dropping the feature.

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/service/SteamService.kt, line 3074:

<comment>A fetch failure now looks identical to a game with no achievements, so the whole section disappears on transient Steam errors. Surfacing an error state or retrying would keep the details page from silently dropping the feature.</comment>

<file context>
@@ -3070,6 +3071,46 @@ class SteamService : Service(), IChallengeUrlChanged {
             }
         }
 
+        suspend fun fetchAchievementsForDisplay(appId: Int): List<Achievement>? {
+            if (!isConnected) return null
+            return try {
</file context>

Comment thread app/src/main/res/values-ko/strings.xml Outdated
@VinceBT VinceBT force-pushed the feat/steam-achievements branch from 3bce1dc to 092ea9c Compare July 10, 2026 17:37
@VinceBT VinceBT force-pushed the feat/steam-achievements branch from 092ea9c to ee695a0 Compare July 10, 2026 21:20
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.

1 participant