Commit Graph
69 Commits
Author SHA1 Message Date
edde746 c3305d2919 fix(tv): paint the floating sidebar panel over content
In TV mode the sidebar menu floated unreadably on top of the home rows,
the artwork and the settings list — two overlapping sets of text with no
panel behind either.

The rail's surface is transparent on TV so the full-bleed backdrop
continues behind a docked rail, which is safe because the shell displaces
content around it. 2.16.0 turned hover/touch expansion into an M3E modal
panel that overlays content at the collapsed offset instead of pushing
it, so there the rail painted nothing and content showed straight
through the menu.

Keep the transparency rule for every docked shape and paint the surface
whenever the rail floats, reusing the predicate that already gates the
overlay corner radius and edge shadow. The fade now shares the width
morph's duration and curve, so a shorter fade cannot strand a fully
grown, fully transparent panel over the content mid-collapse.

Reproducing needs Force TV mode plus a pointer, which is why this
surfaced on a SteamOS box driving a TV and never on Android TV's D-pad
path.

close #2079
2026-08-24 01:15:28 +02:00
edde746 6aaea847a7 fix(tv): stop dropping more than half the frames on D-pad browse
On a 32-bit Amlogic TV box, 57% of UI frames while moving focus along a rail
missed the 16.68 ms budget, and the median frame was already over it at 20.7 ms.
The GPU was idle throughout (raster p90 9.1 ms, zero frames over budget) -- all
of it was main-isolate work, split roughly evenly between layout and semantics.

Five separate causes, all measured:

- The horizontal rail used `itemExtentBuilder`, so `RenderSliverVariedExtentList`
  walked every preceding index on each realized child, in every layout pass, and
  re-resolved the trailing slot inside the closure. Pinning the trailing cell to
  the card extent makes the list uniform, which restores O(1) offset, index and
  max-extent math.
- The sidebar-expand tween wrapped the whole shell with a `LayoutBuilder` inside
  its builder, so ~15 ticks per focus flip rebuilt `SideNavigationRail` -- and its
  non-virtualized child list -- during the layout phase. The tween now wraps only
  the content `Positioned`, matching `SideNavigationBleedBuilder`.
- Each nav item crossfaded through two `Opacity` subtrees, i.e. 14-18 offscreen
  save layers per frame for the whole 250 ms morph. It now fades colour alpha on
  the leaf, the same substitution `AnimatedDimScrim` already documents.
- `HorizontalScrollWithArrows` kept a scroll listener on platforms where its arrow
  chrome is compiled out, so crossing either scroll boundary `setState`d a whole
  rail row of cards. Two full-row rebuild storms per traversal, for arrows that
  cannot appear.
- The rail's semantic proxy rebuilt its label and six closures on every
  `_RailFocusModel` notification, including vertical-scroll flips.

Also: one merged listener per `SettingsBuilder` instead of six, and the media card
semantic label is cached rather than rebuilt and then discarded by the rail's
`ExcludeSemantics`.

Measured on the device, median of three runs: frames over budget 120/212 -> 32/246,
total UI-thread work 4067 ms -> 1845 ms, layout p90 18.2 -> 8.1 ms, build p90
7.95 -> 2.42 ms. The sidebar scenario went from 121/148 frames over budget to
32/184.
2026-08-23 18:13:39 +02:00
edde746 09e0b06e49 fix(tv): unbreak collapsed-rail D-pad traversal, action-bar focus survival, and text-field back handling
With the rail collapsed and Libraries expanded, DOWN from the header landed on a mounted but focus-excluded library node and was swallowed, trapping traversal; the focus order now matches the render exclusion and traversal scans past non-focusable candidates.

An action bar rebuilding on count change disposed every node, silently dropping focus and never notifying the TV host; bindings are now reused by stable identity (external focus node, else debugLabel) and the transition is reported. Positional reuse remains the only option for an unlabeled action, but it applies only while the action-list shape is provably unchanged - catalog detail enrichment inserting Request before a focused Trailer used to hand Trailer's focused binding, focus ring and next Select included, to Request. Those actions also carry stable debugLabels so their focus survives enrichment.

The text field consumed back on KeyDown outside the shared handler, letting one press act twice. It now marks the back coordinator like handleBackKeyAction does and keeps the down-only shape solely on TV, where the closing IME session swallows the matching KeyUp. Because onBack can move focus (empty search field -> sidebar), the orphaned KeyUp would otherwise drive app-level back on the new focus chain, so the field arms BackKeyUpSuppressor; the suppressor gained a hardware-level KeyUp observer that clears the armed state in a microtask after the press ends, removing the long-documented pinning hazard where an unconsumed KeyUp left it swallowing the next press.
2026-08-21 19:23:41 +02:00
edde746 4a1111f435 feat(navigation): restyle sidebar as M3 Expressive navigation rail
The custom sidebar read as an ad-hoc widget: collapsed rows were the
expanded layout clipped to the strip, the libraries tree used a
staircase of indents and mixed row heights, and hover expansion pushed
the whole content area sideways.

Rebuild the rail on M3 Expressive geometry: collapsed destinations are
icon-only 56x32 pills centered in an 80px strip (48px icon-only on TV),
expanded rows are fixed-height destinations with a full-width stadium
indicator, and the two layouts crossfade/lerp during the width morph
instead of clipping. The libraries section is flattened into full-width
destination rows under a chevron header at standard destination
metrics, hover/touch expansion overlays content as a rounded, shadowed
panel over a dimmed scrim instead of pushing it, and rail width, item
morphs, content translate, and bleed all share one duration/curve.
2026-08-19 09:11:18 +02:00
edde746 5f6d9dc610 fix(navigation): keep the sidebar Libraries section collapsed across restarts
Collapsing Libraries in the sidebar only lasted until the app closed. The
next launch always came back expanded, which buries the rest of the nav
menu for anyone running a lot of libraries.

The expansion flag was plain widget state on SideNavigationRailState. It
survived tab navigation only because MainScreen pins the rail with a
GlobalKey, and died on relaunch, profile switch or a layout change. It now
lives in the librariesSectionExpanded preference, so the rail reads and
writes the persisted value and follows a settings reset or import too.

close #1896
2026-08-13 21:44:25 +02:00
edde746 9d13584c00 feat(settings): add appearance toggle to hide the Explore tab
The Explore tab appears for every Plex-backed profile because the Plex
Discover catalog source connects implicitly, with no way to opt out
short of a Jellyfin-only profile. Add a Show Explore Tab switch to
Appearance > Navigation that hides the tab in the bottom navigation and
side rail. UI-only: catalog sources stay connected so watchlist
surfaces keep working while the tab is hidden.

close #1844
2026-08-09 17:14:47 +02:00
edde746 4eaf4423a1 refactor: share focus chrome and simplify the TV picker and browse paths
Focus chrome was implemented twice, once in the focusable wrapper and once
in the focus builders; both now go through FocusChrome. TvColorPicker's
channel row was a copy of TvNumberSpinner and is now that widget in compact
density.

Also trims unused helpers and fields and simplifies the Jellyfin browse
paths.
2026-07-26 06:09:49 +02:00
edde746 e4db04fa62 fix: align UI focus and sheet behavior 2026-07-13 11:28:32 +02:00
edde746 2101f1d7f0 perf: isolate focus and media rebuilds 2026-07-12 19:00:11 +02:00
edde746 18835d92dd refactor(navigation): reuse library icon mapping 2026-07-12 08:42:20 +02:00
edde746 04daf89a20 feat(explore): Explore tab with catalog detail, search, and Seerr requests 2026-07-10 07:10:15 +02:00
edde746 49d4b433a7 fix(music): show now-playing rail item only on TV
Desktop already has the mini-player as the way back into the
now-playing screen; the rail item is redundant there.
2026-07-06 15:56:01 +02:00
edde746 7d6a747aa7 feat(music): now-playing, mini-player, queue and lyrics UI
Persistent mini-player over the profile navigator (route-aware
suppression, bottom-bar inset), slide-up now-playing screen with
mobile/desktop/TV layouts (blurred-art background, pause shape morphs,
dpad seek chain), queue sheet with reorder/remove/jump, synced lyrics
view, TV rail now-playing item, sleep timer, and audio playlist
playback. Adds download affordances on music surfaces.
2026-07-05 21:50:11 +02:00
edde746 6af4289289 fix(tv): keep sidebar focused when Back returns to the home tab
Backing out to home selected the home tab but let focusActiveTabIfReady
steal real focus into the content while _isSidebarFocused stayed true,
leaving the rail stuck expanded over a shifted content box that clipped
the end of every hub row. Skip the content-focus grab while the sidebar
owns focus, move the sidebar focus ring to the Home item on back-to-home,
and self-heal the flag whenever the content scope actually gains focus.

close #1411
2026-07-04 20:56:04 +02:00
edde746 b11c63f557 fix: restore sidebar focus visibility 2026-06-18 04:29:34 +02:00
edde746 d6487e24c9 fix(tv): keep sidebar transparent 2026-06-14 14:53:56 +02:00
edde746 349b5b0513 fix(tv): stop playback behind menu 2026-06-14 06:27:00 +02:00
edde746 145881318e fix: harden server-scoped state 2026-06-04 13:47:06 +02:00
edde746 74b8dc4561 refactor: type server identifiers 2026-06-01 11:06:03 +02:00
edde746 487c7b87f6 fix(nav): hide active sidebar background during focus 2026-05-22 02:21:06 +02:00
edde746 2ebd730201 fix(tv): displace content beside sidebar 2026-05-22 00:14:16 +02:00
edde746 0dd7d7c522 feat(tv): push content beside sidebar 2026-05-21 21:01:14 +02:00
edde746 743a8668ec feat(tv): refine sidebar backdrop 2026-05-21 17:04:23 +02:00
edde746 f565684842 fix(ci): stabilize analyzer and linux builds 2026-05-20 19:10:46 +02:00
edde746 7d60875e19 fix(tv): refine browse rail layout 2026-05-19 19:30:57 +02:00
edde746 5a68711f7b feat(ui): add pointer cursors to clickable controls
close #1068
2026-05-18 15:56:41 +02:00
edde746 955bc9548c refactor: adopt shared mixins, helpers, and sliver widgets 2026-05-05 03:06:56 +02:00
edde746 ed4be7b96d refactor: strip obvious comments 2026-05-04 22:40:18 +02:00
edde746 810f1e5da5 fix: stabilize hidden library focus traversal 2026-05-02 10:03:36 +02:00
edde746 130e0d6f40 refactor: streamline settings bindings 2026-05-02 08:44:27 +02:00
edde746 f03c84e8dc fix: group mobile library dropdown by server 2026-05-01 07:55:15 +02:00
edde746 31d2d9dc98 feat: jellyfin 2026-05-01 01:20:36 +02:00
edde746 52b70a0080 perf(mediaquery): use scoped accessors (sizeOf, paddingOf, etc.) 2026-04-25 12:30:53 +02:00
edde746 3d023962e1 feat: server grouping, hidden-library browsing
close #557, close #827
2026-04-24 19:11:25 +02:00
edde746 2479e1faaa feat: tvos support 2026-04-24 14:11:24 +02:00
edde746 ca5d87143b feat: global fullscreen toggle (F11 + sidebar)
close #907
2026-04-23 07:43:46 +02:00
edde746 3da51f9d64 chore: pre-commit ci hook, dart format 2026-04-18 12:40:35 +02:00
edde746 db6161d84e refactor: replace numeric tab indexes with NavigationTabId 2026-03-15 22:31:54 +01:00
edde746 551be5bbef feat: dynamic library tabs and shared library navigation
- Replace hardcoded 4-tab system with data-driven visible tab list
- Shared libraries show only Browse + Playlists tabs
- Fix dpad navigation for shared libraries (no hidden tab targets)
- Switch to TickerProviderStateMixin to support tab controller recreation
- Navigate to library screen when tapping shared library sections
- Persist tab selection by name instead of index
2026-03-15 21:36:17 +01:00
edde746 8f50da4a75 fix: resolve all dart analyze warnings
- Migrate RadioListTile to RadioGroup API (Flutter 3.32+)
- Guard BuildContext usage across async gaps
- Use const BorderRadius.all / EdgeInsets.all constructors
- Extract nested ternaries into helpers
- Prefer .first over [0], ??= over if-null assignment
- Prefix unused FocusNode params with _
- Add library directive for dangling doc comments
2026-02-23 13:50:56 +01:00
edde746 b419ff5507 fix: custom dpad navigation for sidenav
close #479
2026-02-18 07:55:16 +01:00
edde746 1770109ff9 fix: support touch input for sidebar expand/collapse
close #466
2026-02-16 00:01:44 +01:00
edde746 04438c8e45 refactor: code quality & format 2026-02-15 04:07:09 +01:00
edde746 9184bb8d40 Merge branch 'live-tv'
# Conflicts:
#	lib/i18n/strings.g.dart
#	lib/i18n/strings_de.g.dart
#	lib/i18n/strings_en.g.dart
#	lib/i18n/strings_es.g.dart
#	lib/i18n/strings_fr.g.dart
#	lib/i18n/strings_it.g.dart
#	lib/i18n/strings_ko.g.dart
#	lib/i18n/strings_nl.g.dart
#	lib/i18n/strings_sv.g.dart
#	lib/i18n/strings_zh.g.dart
#	lib/screens/main_screen.dart
#	lib/services/plex_client.dart
#	lib/widgets/video_controls/desktop_video_controls.dart
2026-02-14 22:29:16 +01:00
edde746 4fc98426ff feat: connection recovery on mobile resume and endpoint exhaustion 2026-02-14 22:11:00 +01:00
edde746 403b1f6776 feat: live tv 2026-02-11 16:27:49 +01:00
edde746 6e9b78e5b5 fix: missing translations, simplify translations 2026-02-10 21:37:27 +01:00
edde746 731102357d fix: correct sidebar focus restore
close #357
2026-02-04 08:29:29 +01:00
edde746 5c00ab9132 fix: skip focus on collapsed library items
close #336
2026-01-26 02:00:40 +01:00
edde746 9d37443e4e feat: open sidenav with left 2026-01-25 01:43:10 +01:00