Skip to content

Profile picker overhaul with YouTube import, plus app-wide fixes#24

Merged
windoze95 merged 2 commits into
mainfrom
feature/profile-picker-and-polish
Jun 11, 2026
Merged

Profile picker overhaul with YouTube import, plus app-wide fixes#24
windoze95 merged 2 commits into
mainfrom
feature/profile-picker-and-polish

Conversation

@windoze95

Copy link
Copy Markdown
Owner

Summary

The Netflix-style profile experience, built on windoze95/nullfeed-backend#61, plus a sweep of app-wide fixes.

Profile experience

  • Picker with avatars (imported from YouTube), PIN badges, and a PIN entry dialog (with rate-limit handling)
  • Add Profile wizard: enter a YouTube handle → identity preview (avatar/name/subscribers) → discovered channels they follow as a multi-select → create + follow in one flow. Degrades gracefully when nothing public is found
  • Long-press management: rename, set/remove PIN, re-import avatar, delete — authenticated with an in-memory temporary token that never touches the persistent session
  • Session restore via GET /me (no more PIN bypass or silent logouts on flaky networks; restore races guarded)
  • Server setup: URL normalization + health check before saving

Reliability

  • WebSocket service rewritten: exponential backoff with jitter, intentional-close handling, token auth, 4401 handling, alive on every tab
  • Stable GoRouter via refreshListenable — navigation stack no longer resets on auth changes
  • Riverpod fix: session restore actually works (state was written before provider init)
  • Device downloads: real progress, in-flight guard, stuck-entry recovery, instant list updates

UX polish

  • iPad no longer misdetected as a TV (scrubbing re-enabled); dead tvOS code removed
  • Home: per-row error states with retry; refresh awaits; feeds refresh after the player from any entry point
  • Library: subscribe dialog with loading/error states, unsubscribe, sort, pull-to-refresh
  • Channel detail: back button in all states, smarter Resume (most-recently-watched first), remove/re-download actions
  • Player: offline playback without network, save-on-pause, guarded saves, preview timeout fallback, no double playback
  • New Downloads tab: server downloads with live progress + cancel; device downloads with progress/retry/delete
  • Discover: one-tap subscribe actually works end-to-end
  • Settings: connection test feedback, quality preference applied, WS reconnect on server change

Tests

1 → 69 tests (adds mocktail): API error mapping, WebSocket state machine, auth flows via provider overrides, model serialization, picker/PIN/add-profile widget tests. AGENTS.md drift fixed and synced.

🤖 Generated with Claude Code

windoze95 and others added 2 commits June 11, 2026 10:13
Profile experience:
- Netflix-style picker with avatars, PIN badges, and PIN entry dialog
- Add Profile wizard: import a YouTube handle to pull name/avatar and
  discover channels they follow (multi-select follow on creation)
- Long-press profile management: rename, set/remove PIN, re-import
  avatar, delete (admin rules surfaced)
- Session restore via GET /api/auth/me (no more PIN bypass or silent
  logouts on flaky networks); proper sign-out (server logout + WS
  disconnect)
- Server setup: URL normalization + health check before saving

Reliability:
- WebSocket service rewritten: exponential backoff with jitter,
  intentional-close handling (no more zombie reconnects as the previous
  user), token auth, closed-controller guards
- Stable GoRouter via refreshListenable (navigation stack no longer
  resets on auth state changes)
- Riverpod fix: AuthNotifier.build no longer writes state synchronously
  (session restore actually works now)
- Offline downloads: real progress reporting, stuck-entry recovery,
  race-safe Hive writes, offline-first resume positions

UX polish:
- iPad no longer misdetected as TV (scrubbing re-enabled); dead tvOS
  code removed (native tvOS app covers Apple TV)
- Home: per-row error states with retry, refresh actually awaits reload,
  feeds refresh after returning from the player
- Library: subscribe dialog with loading/error states, unsubscribe via
  long-press, A-Z/recent sort, pull-to-refresh
- Channel detail: back button in all states, retry, smarter Resume,
  remove-from-library and re-download actions
- Player: offline playback without network, progress saved on pause,
  guarded saves (no stuck player on server loss), preview timeout fixes
- New Downloads tab: server downloads with live progress + cancel,
  device downloads with progress/retry/delete
- Settings: connection test feedback, quality preference applied to
  downloads, WS reconnect on server change

Tests: 68 tests (was 1) — API error mapping, WebSocket state machine,
auth flows, model serialization, picker/PIN/add-profile widget tests.
Adds mocktail. AGENTS.md drift fixed and synced.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Pre-login profile management keeps its temporary token in memory and
  passes it per-request — it can no longer leak into the persistent
  session slot (auto-signing into a PIN-protected profile on next
  launch) or clobber a kept-but-unvalidated restorable session
- Session restore guards against races: a stale getMe result can no
  longer wipe a session the user just created by picking a profile
- Device downloads: in-flight guard (double-tap can't corrupt the file),
  entries appear in lists immediately via an onListChanged callback
- WebSocket stays connected on every tab (activated in the nav shell),
  and a 4401 auth reject stops the reconnect loop instead of hammering
  the server with a dead token
- Player: playback can no longer double-start (leaked controller with
  double audio) and an HQ-ready event during preview init is queued
  instead of dropped
- Channel detail download handler: mounted guards (no setState after
  dispose, no leaked polling timer)
- Discover one-tap subscribe fixed end-to-end: Recommendation parses the
  backend's `reason` field, handles are accepted by the subscribe
  endpoint, failures surface via SnackBar without dismissing the
  recommendation or wiping the Library list
- Resume prefers the most-recently-watched in-progress video (new
  last_watched_at field); feeds refresh after returning from the player
  from any entry point

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@windoze95

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@windoze95

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@windoze95 windoze95 merged commit 27d8f71 into main Jun 11, 2026
6 checks passed
@windoze95 windoze95 deleted the feature/profile-picker-and-polish branch June 11, 2026 18:18
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