Skip to content

Web Audio: full player (seek, skip, repeat, shuffle, queue) + add-to-playlist / create playlist like mobile #21

Description

@ehsan6sha

Summary

Replace the bare audio dialog on the web app (files.fx.land/app/) with a full mobile-style audio player, and let users add tracks to playlists / create playlists from the web (cloud-backed, cross-device with the native app).

Today web audio plays in MediaPreviewDialog (just_audio setUrl(blobUrl) + play/pause + a position label only). The web playlists page is view-only ("create in the app"). This brings web to parity with the native audio_player_screen.dart.

Native reference

  • lib/features/viewer/screens/audio_player_screen.dart + lib/core/services/audio_player_service.dart: now-playing, seek slider, play/pause, skip prev/next, rewind/forward 10s, repeat (off/one/all), shuffle (keeps current track), reorderable queue, add-to-playlist. Engine: just_audio (web-supported) with a hand-rolled queue (not ConcatenatingAudioSource); repeat/shuffle are framework-agnostic logic.
  • Playlists are cloud-backed encrypted JSON at user-playlists/<id>.json in playlists-v8 (write) / playlists (legacy, read-merged), format = Playlist.toJson(). Native writes via FulaApiService.encryptAndUpload(...). Web already READS them (WebFeatures.loadPlaylists()).

Web plan

  • New full-screen WebAudioPlayer (via Dialog.fullscreen, consistent with the image/text previews) replacing MediaPreviewDialog for AUDIO (video stays on Chewie). Now-playing, seek slider, play/pause, skip prev/next, rewind/forward 10s, repeat toggle, shuffle toggle, queue list, add-to-playlist, download.
  • WebAudioController (ChangeNotifier + just_audio): a QUEUE = the current folder's audio files (start at the tapped track); on play/skip download bytes → Blob URL → setUrl → play; aggressively revoke old blob URLs (queue means many over time); prefetch the next track. On complete, advance per repeat/shuffle. Pure queue/repeat/shuffle transitions extracted to a VM-tested logic file.
  • Cloud playlist WRITE (additive web service): "create playlist" and "add to playlist" build Playlist.toJson() and call the SAME shared encryptAndUpload(writeBucket('playlists'), 'user-playlists/<id>.json', data, kek, contentType: 'application/json') native uses — so native + web read each other's playlists. "Add to existing" = load → append (dedup by path) → bump updatedAt → re-upload the single per-id object. Never deletes, never touches tombstones.
  • Unify the playlist-detail play path onto the new player (queue = the playlist's tracks) so there aren't two divergent audio UIs.

Safety

  • Write path is encryption/data-format-adjacent + read-modify-write — additive only (calls the shared method with native-identical bucket/key/format/contentType), guardrails: only ever PUT one user-playlists/<id>.json, never delete, never write tombstones. Independent review by Copilot (Codex/Cursor rate-limited).
  • Pure logic (queue transitions, playlist JSON build/append) VM-unit-tested; the just_audio/blob glue is verified live.

Acceptance

  • Tapping an audio file opens a full player: seek, play/pause, skip prev/next across the folder queue, rewind/forward, repeat, shuffle.
  • "Add to playlist" (create new / add to existing) persists to cloud; the playlist then shows the track on web AND in the native app.
  • No regression to video playback, downloads, or the Recent strip. analyze + unit tests + web build green; live.

Part of the mobile->web parity work.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions