feat(#433): achievements tab — full dashboard parity (#450)

* feat(#433): achievements 1:1 parity with dashboard

- Expanded model: AchievementsResponse now carries header stats
  (unlockedCount, discoveredCount, secretCount, totalCount, isStale,
  scanMeta/ScanStatus) and per-achievement fields (unlockedAt, secret, criteria)
- Added API endpoints: scan-status, rescan, reset-state, recent-unlocks
- Created AchievementIcon emoji mapper for all Lucide icon names
- Rewrote ViewModel with full state: scan tracking, recent unlocks,
  category/state filtering, rescan/reset actions with loading states
- Rewrote Screen: header stats row, scan status chip, stale indicator,
  category + state filter chips, recent unlocks section, expandable
  criteria, icon emoji, unlocked glow border, overflow menu with
  rescan/reset, reset confirmation dialog
- Added 30 string resources for all new UI elements

* fix: resolve CI compilation errors in achievements module

- Replace progress_pct references with correct Kotlin field progressPct (Achievement model uses @SerializedName for snake_case, Kotlin field is camelCase)

- Add missing onStart/onError parameters to safeLaunchLoad calls in loadScanStatus() and loadRecentUnlocks()

* fix: remove top padding on achievements tab content

* fix: remove redundant paddingValues on achievement LazyColumn

---------

Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
M57andM57 authored and GitHub committed 2026-07-02 23:48:44 +03:00
1 parent 2bceac7ab3
commit f887146056
6 files changed
+941 -108

No files matched your search

@@ -28,7 +28,9 @@ import com.m57.hermescontrol.data.model.PluginsHubResponse
import com.m57.hermescontrol.data.model.ProfileSoulResponse
import com.m57.hermescontrol.data.model.ProfilesResponse
import com.m57.hermescontrol.data.model.RawConfigResponse
import com.m57.hermescontrol.data.model.RecentUnlock
import com.m57.hermescontrol.data.model.SaveSkillContentRequest
import com.m57.hermescontrol.data.model.ScanStatus
import com.m57.hermescontrol.data.model.SessionListResponse
import com.m57.hermescontrol.data.model.SessionMessagesResponse
import com.m57.hermescontrol.data.model.SetActiveProfileRequest
@@ -180,6 +182,18 @@ interface HermesApiService {
@GET("api/plugins/hermes-achievements/achievements")
suspend fun getAchievements(): Response<AchievementsResponse>
@GET("api/plugins/hermes-achievements/scan-status")
suspend fun getAchievementScanStatus(): Response<ScanStatus>
@POST("api/plugins/hermes-achievements/rescan")
suspend fun rescanAchievements(): Response<AchievementsResponse>
@POST("api/plugins/hermes-achievements/reset-state")
suspend fun resetAchievementState(): Response<Unit>
@GET("api/plugins/hermes-achievements/recent-unlocks")
suspend fun getRecentUnlocks(): Response<List<RecentUnlock>>
@GET("api/pairing")
suspend fun getPairing(): Response<PairingResponse>