Commit Graph

4729 Commits

Author SHA1 Message Date
zurdi
8a4d286cfa feat(activity): add total sessions label to activity localization files
- Added "total-sessions" key to various language JSON files for activity localization.
- Updated ActivityCard component to reflect changes in the activity view.
- Enhanced Activity view to display a live session counter with a tooltip.
- Introduced virtual scroll debugging to monitor performance in the gallery.
- Adjusted layout styles for better responsiveness and visual consistency across components.
2026-06-22 09:23:39 +00:00
Georges-Antoine Assi
e7d383b285 style(v2): right-align list-view cover in its column
Cover hugs the title side of its fixed-width column (and the skeleton
matches), so the empty space sits on the left and the cover reads as
attached to its title.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 21:43:59 -04:00
Georges-Antoine Assi
41ec6f4de6 fix(v2): give list-view cover its own column so titles align
With natural-aspect covers, the list-row cover lived inside the title cell
and its variable width pushed each row's title/meta to a different x. Add a
dedicated fixed-width (64px) cover column to the shared list grid template —
big enough for any portrait→square game cover — so the title column starts
at the same x on every row. Header and skeleton pick it up via the shared
column config; the cover renders left-aligned at its natural aspect.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 21:33:09 -04:00
Georges-Antoine Assi
44016129b5 feat(v2): list-view covers respect natural aspect; scale placeholder title
- Gallery list view: drop the `fixed` opt-out on its GameCard so the
  row thumbnail renders at the cover's natural aspect (fixed height,
  natural width) like everywhere else. Removes the now-unused `fixed`
  prop / class / CSS branch from GameCard.
- CoverPlaceholder: the title now scales with the cover box (container
  query units, clamp(8px, 8cqmin, 18px), em padding) instead of a fixed
  12px — readable on a tiny list thumb, proportionate on the detail hero.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 21:09:30 -04:00
Georges-Antoine Assi
cdb1f17902 feat(v2): add section headings to HLTB strip and screenshots in overview
The overview's screenshots and How-Long-To-Beat blocks rendered with no
label, unlike the related-games sections. Wrap both in the same labelled
section pattern (renamed `overview-tab__related-*` → `__section-*` since it
now covers non-related blocks too). The HLTB heading is gated on a
`hasHltb` computed so it doesn't show when the strip is empty.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 20:11:33 -04:00
Georges-Antoine Assi
14a7b40475 details cleanup 2026-06-21 20:10:07 -04:00
Georges-Antoine Assi
72fb96ec4c fix(v2): consistent gap between cover and fields in the edit dialog
The edit dialog's hero used a fixed 240px cover column with the cover
centered, so a natural-width cover left variable leftover space — making
the gap to the fields vary by cover shape. Size the column to the cover
(`auto`) so the gap is exactly the grid gap for any cover, and give it a
touch more room (24px).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 19:57:00 -04:00
Georges-Antoine Assi
c8362ed22e feat(v2): use natural cover aspect ratio across remaining surfaces
Extend natural-aspect cover rendering beyond the gallery to the rest of
the app (continue-playing stays a fixed 16:9 hero, by request).

- GameCard size tiers now render fixed-height / natural-width like the
  default card (size just picks the height); covers EditRomDialog (lg)
  and ManageCollectionsDialog (xs) for free. Adds a `fixed` opt-out for
  dense aligned tables.
- GameListRow (compact list view) opts into `fixed` so its cover column
  stays uniform for row alignment.
- Compact fixed-column thumbnails (ScanPlatformRow, DeleteRomDialog,
  RefreshMetadataDialog, ActivityCard) stop cropping (object-fit
  cover → contain): the whole cover shows at its true aspect while the
  slot stays uniform.

Deliberately unchanged: collection mosaics (composite collage art),
save/state screenshots (16:9, not covers), and the provider cover-picker
comparison grids (uniform tiles aid side-by-side selection).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 19:46:01 -04:00
Georges-Antoine Assi
74ef594609 feat(v2): render the Random Pick cover at its native aspect ratio
Swap the hand-rolled RImg + useCoverArt cover resolution in
RandomPickWidget for the shared GameCover, which measures the image's
natural ratio. The thumbnail now renders at a fixed 70px height with
natural width (no crop), matching the gallery, and the widget's cover
plumbing (coverSrc / coverContain / placeholder fallback) collapses into
GameCover.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 19:24:05 -04:00
Georges-Antoine Assi
662dc89a24 Merge branch 'master' into aspect-ratio-no-no 2026-06-21 19:20:09 -04:00
Georges-Antoine Assi
d1a9dbb4fb refactor(v2): extract gallery cover-ratio measurement into a composable
Move the measured-ratio map, debounced ratioVersion, onCardRatio handler,
and ratioAt resolver out of GalleryShell into useGalleryCoverRatios. The
composable owns its debounce-timer cleanup (onBeforeUnmount), so the shell
no longer tracks ratioBumpTimer. Behaviour is unchanged; adds a unit test
for the dedup / debounce / position→rom→ratio mapping.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 19:10:36 -04:00
Georges-Antoine Assi
84ccba6996 Merge pull request #3308 from tmgast/feature/device-flow-authorization
Add device authorization flow for TV-app-style pairing (RFC 8628)
2026-06-21 19:07:08 -04:00
Georges-Antoine Assi
d5f30d1fab docs(v2): collapse verbose comment blocks from the aspect-ratio work
Tighten the multi-line comments added across GameCover/GameCard/
GalleryShell/useGalleryVirtualItems/useResponsiveColumns and the
packFlowRows test to one or two lines each, keeping the load-bearing
rationale and dropping the prose.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 18:06:23 -04:00
Georges-Antoine Assi
8f25796201 refactor(v2): drop unused rowIndex from gallery row item
Since rows became variable-length contiguous runs, rowIndex was hardcoded
to 0 at both build sites and read nowhere. Remove it so a future reader
doesn't mistake 0 for a meaningful index.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 17:58:17 -04:00
Georges-Antoine Assi
fd7d40aa1a docs(v2): note the gallery ratio cache is intentionally unbounded
ratioByRomId is keyed by rom id so a re-visited platform/collection
re-packs instantly without re-waiting on image loads. It's never pruned,
but each entry is two numbers (a few hundred KB even at tens of thousands
of distinct ROMs), so an LRU ceiling isn't worth it. Document the choice
so it reads as deliberate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 17:55:33 -04:00
Georges-Antoine Assi
e490706028 fix(v2): pin gallery cards to flex-shrink: 0 so covers never crop
The flow-packer sizes a row from cardHeight * ratio (floating point) and
the browser rounds rendered widths, so a "just fits" row can land a hair
over the container. With shrink enabled, fixed-height cards absorb that by
narrowing — cropping the cover via object-fit. Pin shrink to 0 on the
row's children: trades the rare sub-pixel crop for a hair of ragged
overflow, and keeps loading skeletons (default shrink: 1) at packed width.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 17:54:35 -04:00
Georges-Antoine Assi
4724361f6d refactor: remove per-platform cover aspect-ratio setting
The platform aspect_ratio setting is dropped from the UI and the API
(platform update body + response schema) — nothing consumed it for
rendering, and covers now size to their image's natural aspect.

- SettingsTab: remove the cover-style / aspect-ratio picker (and its
  now-dead helpers, CSS, and unused imports); collapse to a single column.
- update_platform: drop the `aspect_ratio` body field; PlatformSchema no
  longer returns it; utils/platforms stops seeding the default.
- Regenerate the affected frontend types (PlatformSchema, update body).

The DB column stays (out of the update/response scope; dropping it would
be a separate destructive migration) but is no longer read or written
through the API.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 17:43:40 -04:00
Georges-Antoine Assi
389025942f changes from bot review 2026-06-21 17:42:25 -04:00
copilot-swe-agent[bot]
c5148222cc fix: gate canRemoveFromContinuePlaying on roms.user.write scope
Co-authored-by: zurdi15 <34356590+zurdi15@users.noreply.github.com>
2026-06-21 21:34:03 +00:00
Georges-Antoine Assi
e9ab144d39 feat(v2): render cover art at its natural aspect ratio
Stop forcing a fixed box ratio on gallery covers. Cards now share one
height and vary in width to match each cover image's natural aspect, with
no cropping.

- GameCover measures the rendered image's natural ratio on load and drives
  its own aspect-ratio from it (style ratio kept only as a pre-load seed);
  emits the measured ratio.
- GameCard default (gallery) card: fixed art height, natural width; size
  tiers and hero keep their fixed footprints. Forwards the ratio event.
- Gallery grid becomes flow-packed wrapping rows: useGalleryVirtualItems
  greedily packs same-height / natural-width cards per row (ragged right),
  measuring ratios client-side (cached by rom id, debounced re-pack). Row
  height stays uniform so RVirtualScroller, AlphaStrip, scroll restoration
  and grid-nav are unchanged.
- useResponsiveColumns additionally exposes usableWidth for width packing.
- Unit tests for packFlowRows.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 17:33:28 -04:00
zurdi
58ecb681ec feat(v2): restore "remove from continue playing" action
The per-user "remove from Continue Playing" option existed in v1's
AdminMenu but was missing in v2. The API, store action
(removeFromContinuePlaying) and data shape were already shared; only
the v2 UI layer and action handler were absent.

- useGameActions: add removeFromContinuePlaying() (clears last_played,
  prunes the cached continue-playing list, snackbar feedback) plus a
  canRemoveFromContinuePlaying gate (only when the ROM has last_played).
- GameActionsList: surface the action as an RMenuItem in the more-menu.
- locales: add snackbar-removed-from-playing and
  snackbar-remove-from-playing-failed to all locales (translated for
  es/de/fr/it/pt/ru, English placeholder elsewhere).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 20:44:40 +00:00
Georges-Antoine Assi
765d2a29fe fix settings.json 2026-06-21 16:31:17 -04:00
Georges-Antoine Assi
77970f6379 Merge branch 'master' into feature/device-flow-authorization 2026-06-21 16:25:39 -04:00
Zurdi
dbc6139752 Merge pull request #3570 from rommapp/chore/extract-files-layout
refactor: unify upload UX across GameDetails subtabs
2026-06-21 21:21:35 +02:00
Zurdi
ee33bf1b71 Merge pull request #3569 from rommapp/feat/share-savestates
feat: share saves & states with other users
2026-06-21 21:18:34 +02:00
zurdi
7c82965825 docs: address copilot review comments on PR #3570
Refresh stale doc comments that didn't keep pace with the refactor:

- `global.css` r-v2-asset-fade — list AssetList / AssetStrip / FileRow
  / ScreenshotsTab / SoundtrackPanel as the consumers (was: just
  AssetList / AssetStrip).
- `SaveDataTab.vue` section-head comment — drop the "subtitle" mention
  (subtitle was removed in this PR).
- `FilesTab.vue` file header — section header now hosts Upload only;
  Download-all / Copy-link moved to the selection toolbar (select-all
  then act). Updated the file-level summary and the content-column
  bullet list to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-21 18:18:00 +00:00
zurdi
d3bc224900 refactor: unify upload UX across GameDetails subtabs
Move every upload affordance out of the sidebar's collapsible action
panel into a section header at the top of each panel, matching
ScreenshotsSubtab. Sidebars become navigation-only.

Touched subtabs:
- SaveDataTab (Saves + States) — Upload per Mine section header.
- MediaTab Manual — header hosts the entry selector + Upload only;
  Delete + Redownload move into the PDF viewer's toolbar via new
  PdfViewer `deletable` / `redownloadable` props.
- MediaTab Soundtrack — header with just Upload.
- MediaTab — reorder subtabs so Screenshots sits above Soundtrack.
- FilesTab — header with Upload only (Download all / Copy link
  dropped; equivalent via select-all + selection toolbar).
- ScreenshotsSubtab + SaveDataTab — drop the redundant "Private to
  you until you make them public" subtitle and i18n keys.

Add a distinct entrance animation for dense, data-row content:
`r-v2-asset-fade` (fade + 14px rise, no scale, no overshoot, 320ms,
24ms stagger). Applied to AssetList / AssetStrip rows, FileRow,
screenshot thumbnails and soundtrack track rows so they cascade in
on first paint, separate from the bouncier `r-v2-card-fade` reserved
for hero cards.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-21 17:23:40 +00:00
Georges-Antoine Assi
49f2b1659c Merge pull request #3272 from rommapp/claude/user-game-activity-monitoring-Mqb1v
Add real-time activity tracking for active game sessions
2026-06-21 12:02:58 -04:00
zurdi
91640c36ec fix: address copilot review comments on PR #3569
* i18n `rom.cant-toggle-visibility` is interpolated with `{error}` in
  SaveDataTab but the strings dropped the placeholder, hiding the
  backend error detail from the snackbar. Add `{error}` to every locale
  (en_US source + es_ES translated, others English placeholder).
* `RSliderBtnGroup` badge visibility check did not handle the string
  `"0"` / `""` cases allowed by the `string | number | null` type.
  Extract a `showBadge` helper and use it in both the router-link and
  RBtn branches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-21 15:55:23 +00:00
zurdi
1e902a966f style: align visibility toggle color across saves, states & screenshots
Notes already paints the lock button primary when private and muted when
public; bring screenshots and the new saves/states toggles to the same
binding so the three visibility surfaces read consistently.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-21 15:45:39 +00:00
zurdi
47b198c61c style: apply eslint --fix to share-savestates refactor
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-21 15:22:43 +00:00
Georges-Antoine Assi
c6c7ce9ea6 cleanup 2026-06-21 11:13:30 -04:00
Georges-Antoine Assi
0460133992 Secure activity identity, cut Redis churn, remove v1 activity
Backend:
- Resolve the acting user from the authenticated socket session on
  connect instead of trusting the client-supplied user_id, so a client
  can no longer spoof a "now playing" session for another user. Only
  rom_id/device_id come from the payload.
- Emit activity:update/clear through the already-initialised socket
  server instead of opening (and leaking) a fresh AsyncRedisManager per
  REST heartbeat.
- Collapse get_all_active's per-key GET into a single MGET.
- Drop the pure pass-through _build_activity_entry helper.

Frontend:
- Remove all activity emits from the v1 EmulatorJS Player; the v2 shell
  is the single driver of the activity lifecycle.
- Remove activity from the v1 UI entirely (Activity view, ActivityBtn,
  ActivePlayers on game details, navigation, and the now-v2-only route).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 11:12:18 -04:00
androosio
b96a1dda2a fix: guard SiblingBadge against missing sibling_roms
The `scan:scanning_rom` socket emit strips `sibling_roms` from the rom
payload, so a freshly-scanned rom can reach SiblingBadge with the field
undefined (despite the schema typing it as required). Reading
`.length`/`.map` then threw `TypeError: Cannot read properties of
undefined (reading 'length')`, crashing the gallery during a scan while
"Group ROMs" was enabled.

Default `sibling_roms` to an empty list (a `siblings` computed). REST
payloads always include it (possibly empty), so only the socket path was
affected.

Closes #3567

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 17:11:16 +02:00
zurdi
44dd203058 feat: add AssetList and AssetStrip components for managing saves and states
- Introduced AssetList.vue for displaying a vertical list of saves with detailed information.
- Added AssetStrip.vue for a horizontal strip of state tiles, supporting selection and management modes.
- Created stories for AssetStrip to demonstrate various states and scenarios.
- Enhanced RSliderBtnGroup to include a badge for displaying counts next to labels.
- Updated EmulatorJS.vue to utilize the new AssetList and AssetStrip components, including badge counts for saves and states.
2026-06-21 14:14:55 +00:00
zurdi
9106c3721e feat: add visibility toggle for saves and states, enhance community sections
- Introduced new API endpoints for updating visibility of saves and states.
- Added `is_public` property to `SaveSchema` and `StateSchema`.
- Created new models for user saves and states with visibility attributes.
- Updated the `SaveDataTab` component to differentiate between "Mine" and "Community" sections.
- Implemented visibility toggle functionality for user saves and states.
- Enhanced localization files to include new strings for visibility actions.
2026-06-21 14:00:02 +00:00
Georges-Antoine Assi
8aaa52bcb2 wire up v2 ui 2026-06-21 08:07:00 -04:00
nendo
812491f68c Refine device authorization flow
- device/init returns a relative verification_path; the client joins it
  with its own origin
- Render the v2 approval screen via the named v2 router outlet (was blank)
- DevicePair: RSpinner, keyboard-accessible scope chips, scrollable scopes;
  DevicePairShell uses always-light overlay tokens (no hex)
2026-06-21 10:57:48 +09:00
Georges-Antoine Assi
429e718a14 add ui for v2 2026-06-20 21:09:11 -04:00
Georges-Antoine Assi
1caa6386c2 Translate activity.json into all locales
Add activity.json translations for every non-en_US locale and add the
matching `activity` key (added with the activity feature but left
English-only) to each common.json, so check_i18n_locales.py passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 13:48:47 -04:00
Georges-Antoine Assi
892a1b18e1 Merge branch 'master' into claude/user-game-activity-monitoring-Mqb1v 2026-06-20 13:42:11 -04:00
zurdi
33a98d32a5 style: adjust tooltip padding for better visual alignment 2026-06-20 16:14:17 +00:00
zurdi
b94badf502 Merge remote-tracking branch 'refs/remotes/origin/master' 2026-06-20 16:12:45 +00:00
zurdi
b7a7f6a5e3 feat: enhance user permissions and UI elements for better access control 2026-06-20 16:12:05 +00:00
Zurdi
cce2587024 Merge pull request #3557 from rommapp/feat/logs-view
feat: real-time backend logs view
2026-06-20 17:54:23 +02:00
zurdi
78cac11913 feat: add DISABLE_LOGS_VIEWER configuration and implement checks in logs endpoints and frontend 2026-06-20 15:48:58 +00:00
zurdi
78eef900b9 feat: update logs endpoint to require 'logs.read' scope and adjust related authorization checks 2026-06-20 09:55:10 +00:00
Zurdi
26c853f1cd Merge pull request #3554 from rommapp/feat/add-debug-overlay
feat: Add debug overlay
2026-06-20 11:23:19 +02:00
zurdi
90777d5cbb refactor: address Copilot review on debug overlay
- Lazy-load DebugOverlay via defineAsyncComponent so its chunk (and the
  vueuse perf hooks it pulls in) stays out of the default bundle until the
  developer toggle is enabled.
- Add useDebugMode unit tests mirroring useCrtMode: default-off, persisted
  restore, write-through, and singleton sharing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 09:21:43 +00:00
Georges-Antoine Assi
0e016eca9b Merge branch 'master' into claude/user-game-activity-monitoring-Mqb1v 2026-06-19 21:11:05 -04:00