Commit graph

122 commits

Author SHA1 Message Date
KhooLy
d5f3819ebe Fix shared UI boundary violations from the CMP player overlay migration
checkSharedUiBoundary was failing on master because the July 17 move of
player overlays into shared/commonMain kept imports of data/player domain
types (Meta, Stream, Video, IntroTimestamps, UserProfile, Chapter,
MediaTrack, TorrentStreamStatus, TrailerCue). Relocate the plain value
types into the shared-safe com.fluxa.app.shared.feature.player package,
and replace the remaining domain-object usages with small UI models
(StreamSourceUiModel, SkipSegmentUiModel, NextEpisodePreviewUiModel)
mapped at the Android call sites. Also drops the dead, UserProfile-only
QuickSettingsSidebar/TrackSidebar composables that had no callers.
2026-07-20 15:37:30 +03:00
KhooLy
d88e4226da Wire AppleAddonStoreDataSource to a real Swift-driven state source
Adds AppleAddonStoreSnapshot/AppleInstalledAddonSnapshot and update()
so Swift can push real addon list/error/added-name state back into
the shared Addon Store screen, plus
FluxaApple.setAddonStoreActionHandler/updateAddonStore following the
existing handler-setter pattern.
2026-07-20 15:05:28 +03:00
KhooLy
c35dd1148f Wire ApplePluginsDataSource to a real Swift-driven state source
Adds ApplePluginsSnapshot and update() so Swift can push merged
repository/scraper/settings-sheet state back into the shared Compose
UI, plus FluxaApple.setPluginsActionHandler/updatePlugins following
the existing setSearchHandler/updateSearch pattern. Also fixes
saveScraperSettings to actually forward the settings values.
2026-07-20 14:43:48 +03:00
KhooLy
e0f211e5e1 Fix two pre-existing bugs blocking shared module iOS/tvOS compilation
@JvmSuppressWildcards (TraktModels.kt) and java.util.Locale (PlayerOverlayCards.kt)
are JVM-only and don't resolve under Kotlin/Native. Neither was needed:
the wildcards annotation has no runtime effect Gson relies on, and
uppercase(Locale.ROOT) has a locale-agnostic uppercase() equivalent in
the common stdlib. Verified :shared:compileKotlinIosSimulatorArm64 now
succeeds (previously failed on master too, unrelated to plugin work).
2026-07-20 03:48:16 +03:00
KhooLy
114f36a590 Unify CloudStream and Nuvio plugin management into a shared Plugins feature
Addons now only manages Stremio addons. CloudStream3 repo/plugin state
and the Android-only Nuvio scraper settings screen both move into a new
shared KMP feature (feature/plugins) with a real Android data source
combining PluginRepositoryManager and PluginManager, and an iOS stub
data source pending a follow-up Swift implementation.
2026-07-20 03:44:09 +03:00
KhooLy
ec634a13ec Wire Nuvio-compatible plugin scraper runtime into Android app
Implements PluginHttpClient over OkHttp with SSRF guarding (PluginNetGuard),
wires the FetchPluginManifest effect, adds PluginRepositoryManager for
repository/scraper state, folds plugin-scraper streams into
StreamDiscoveryUseCase, and adds a Plugins settings screen.
2026-07-20 02:28:45 +03:00
KhooLy
f0cf10d757 Add an Upcoming home row split from Continue Watching (off by default)
New setting under Settings > Appearance > Home Screen: when enabled,
Continue Watching items whose next episode/season hasn't released yet
move into their own Upcoming row instead of sitting in Continue
Watching with nothing to resume.

Classification runs async per up-next series item (no active playback
progress): HomeContinueWatchingCoordinator resolves the specific
lastVideoId episode via the existing getSeasonEpisodes fetch, checks
its release date through the new isEpisodeReleased FFI call, and
caches the result by id:lastVideoId. Once known, it triggers a
dynamic-rows refresh so the split applies without blocking the
initial Home paint.

HomeCatalogFeedCoordinator/HomeDynamicRowsCoordinator partition the
Continue Watching list into continue_watching/upcoming HomeCategory
rows via the new isUpcoming lambda, gated by
UserProfile.upcomingRowEnabled (resolved through the Rust safe-prefs
struct like every other appearance toggle). HomeCategoryPolicy's
isContinueWatchingCategory()-gated behavior (card layout, action-row
treatment, title passthrough) now also covers the upcoming row so it
renders with the same horizontal episode-card treatment.
2026-07-20 00:06:38 +03:00
KhooLy
6f6378a915 Add a visible D-pad add-to-library action on Search results for TV
CatalogCard's onLongClick had no discoverable remote equivalent — a
D-pad user had no visible way to know holding a button might do
something. Add a small focusable '+' badge on each search result card
on TV that triggers the same PosterActionSheet action as long-press.
2026-07-19 23:32:17 +03:00
KhooLy
0f9d97adc7 Add focus rings and initial focus to Detail/Discover picker sheets
Detail's season-picker ModalBottomSheet and Discover's filter
ModalBottomSheet both had trigger chips and row items styled with
plain .clickable and no focus feedback, plus no initial focus when the
sheet opened. Add focus rings to trigger/rows and request focus on the
selected row on open, same fix already applied to TvAuthScreen.
Library's collection-rename AlertDialog already used stock Material3
widgets with adequate focus support; just add initial focus to its
text field.
2026-07-19 23:30:06 +03:00
KhooLy
f1413e71c9 Give CategoryResultsScreen TV-appropriate spacing
Reached from every 'see all' row on Home/Discover; had no deviceType
awareness at all. Add TV padding/type-scale/grid sizing in line with
the other Tv*Screen wrappers. Card focus rings come from the
CatalogCard fix already landed.
2026-07-19 23:27:14 +03:00
KhooLy
bc486ebd41 Add focus ring and initial focus to ProfileListScreen
ProfileGridItem/AddProfileGridItem had no focus indicator and the
screen (the sole content right after login) never requested initial
focus, so a D-pad had nothing to land on. Add a focus ring to both and
request focus on the first profile when the list appears.
2026-07-19 23:26:22 +03:00
KhooLy
b908423630 Add D-pad focus rings to AddonStoreScreen
The per-addon action row (configure/refresh/move-up/move-down/remove)
packed 5 Material IconButtons with no way to tell which was focused.
Replace with a shared AddonIconButton that shows a clear focus state,
and add the same treatment to the back button, repo cards, and
CloudStream plugin rows.
2026-07-19 23:25:02 +03:00
KhooLy
0508ab94cb Add D-pad focus rings across Settings row primitives
SettingsRows.kt had zero focus styling on any interactive element
(toggle switch aside): choice/nav/action/connection rows, the stepper
+/- buttons, ordered-toggle checkbox and reorder buttons, color
swatches, and the secret-field reveal toggle. Add a shared
settingsFocusRing() modifier and apply it across the row primitives so
the whole settings tree gets consistent focus feedback in one place,
plus fix the TV category rail row and accent-color swatches in
SettingsScreen.kt directly.
2026-07-19 23:22:55 +03:00
KhooLy
e3436d2979 Add D-pad focus rings to catalog cards, player controls, and track picker
CatalogCard.kt disabled default indication with nothing put back, so
every catalog grid on TV (Home, Search, Discover, Library,
CategoryResults, LibraryFolderDetail) was navigable but silently
invisible when focused. Add a border/scale focus ring at the shared
component level instead of duplicating it per-screen.

PlayerControlBtn/SeekIconButton/the play-pause circle in
PlayerControlsChrome.kt were focusable() on TV but never changed
appearance on focus. TrackItem in PlayerSidebarShell.kt (source/audio/
subtitle/episode picker) had the same problem. Both now show a clear
focus state.
2026-07-19 23:19:18 +03:00
KhooLy
9b75f68331 Hide nav chrome on Auth and ProfileList screens
showNavigationBar was hardcoded true with no per-destination gating, so
both the mobile bottom bar and the new TV sidebar rendered on top of
the pre-login Auth/ProfileList screens, where there's no session yet
to navigate Home/Library/etc into.
2026-07-19 21:00:57 +03:00
KhooLy
6896b9665b Add a D-pad-focusable TvAuthScreen for Android TV login
AuthScreen had no TV variant and no explicit focus handling, so a
remote's D-pad had nothing reliable to land on or move between during
login. TvAuthScreen mirrors the same AuthStage state machine but adds
visible focus rings on every interactive element, requests initial
focus on the primary action per stage, and centers the form in a
fixed-width column instead of mobile's edge-to-edge layout.
2026-07-19 20:53:47 +03:00
KhooLy
3dbb3942d3 Replace mobile bottom nav bar with a D-pad sidebar on Android TV
FluxaNavigationBar was a touch-oriented pill bar rendered unconditionally
for every device type, including TV, with no deviceType gate. Add
TvSidebarNav as a proper left-edge D-pad rail for TV and reserve
horizontal (not vertical) space for it; drop TvCatalogHomeScreen's
redundant top icon row now that the sidebar owns navigation.
2026-07-19 20:50:52 +03:00
KhooLy
ac09f5c342 Push Liquid Glass further toward true lensed glass
Add a radial progressive blur (stronger in the center, tapering at
the edges) so the surface reads as a lensed bulge rather than a flat
uniform blur, layer a top-inner-glow-to-bottom-inner-shadow gradient
behind the icons for real inner depth, and brighten inactive
icons/labels to 78% white for readability.
2026-07-19 19:34:21 +03:00
KhooLy
b1b787f8a7 Tighten Liquid Glass separation, depth, and active-state clarity
Replace the single weak white tint with a proper dark scrim + faint
sheen (via HazeStyle's tints list) so busy content behind the bar
stops fighting with the icons, add a real drop shadow beneath the bar
for layered depth, brighten the top-edge highlight, give the selected
icon a two-layer accent-colored glow instead of a plain white blob,
and give the Home row extra bottom content inset (nav bar height + 20dp)
in Liquid Glass mode so the last row of text clears the bar instead of
sitting under it.
2026-07-19 19:29:17 +03:00
KhooLy
f4706f1c3d Refine Liquid Glass nav bar toward true iOS-style material
Lighter backdrop fill and overall effect alpha so more content bleeds
through, a vertical-gradient edge (white top highlight fading to a
dark bottom inner shadow) instead of a flat border, a soft radial
"lens" glow behind the selected icon, and brighter inactive icons
(68% white) for readability against the lighter glass.
2026-07-19 19:20:50 +03:00
KhooLy
e2f1350f75 Use real backdrop blur for Liquid Glass mode via Haze
Pulls in dev.chrisbanes.haze 1.7.2 (Android + iOS klibs, matching the
shared module's targets) and swaps the earlier translucency-only
fallback for genuine hardware-accelerated background blur: the screen
content is marked as a hazeSource, and the nav bar reads it through
hazeEffect with a tinted, noisy glass style.
2026-07-19 19:07:58 +03:00
KhooLy
0e3d57b7a5 Add Liquid Glass appearance mode for the bottom navigation bar
New opt-in Appearance toggle (default off), mirroring how amoledMode
is wired through UserProfile and both settings data sources. Enabling
it swaps the nav bar's flat fill for a translucent frosted surface
with a soft top-light gradient and a hairline glass-edge border.
2026-07-19 18:59:54 +03:00
KhooLy
7ad3aa9fac Merge IntroDB/AniSkip toggles into one Skip Intro/Outro/Recap setting
Both sources fed the same skip-segments pipeline and were always
toggled together in practice, so collapse them into a single
useSkipSegments flag on SettingsPlaybackUiModel. Both the Android and
Apple settings data sources still write/read the two underlying
useIntroDb/useAniSkip flags in lockstep, so the merge stays UI-level
and existing profiles keep working.
2026-07-19 18:53:35 +03:00
KhooLy
944484323a Add settings toggle to disable Content Warnings overlay
Adds contentWarningsEnabled to the playback settings model, defaulting
to true, and gates both the parents-guide fetch and the overlay
display in PlayerScreen behind it.
2026-07-19 18:48:46 +03:00
KhooLy
eaef1fb4eb Thread trailer URL from detail state into DetailUiModel
Adds trailerUrl to DetailUiState and DetailUiModel so the detail
screen's data source can pass the resolved trailer through, and
adds the missing HeroPageChanged branch to CatalogHomeStore's
no-op action list.
2026-07-19 17:12:37 +03:00
KhooLy
35f9c67092 Reorganize Home/Detail appearance settings into drill-down sections
Home Screen and Detail Screen settings now split into dedicated
sub-pages (Hero Banner, Continue Watching, Navigation for Home;
Hero Banner, Episodes for Detail) instead of one long mixed page,
so a specific setting is reachable by name instead of scrolling.

Also removes the dead "Trailer on Hero" toggle in Detail Screen
settings, which persisted a value but was never read by any
consuming code — it just duplicated the real "Trailer on Detail
Hero" setting and caused exactly this kind of navigation confusion.
2026-07-19 15:58:20 +03:00
KhooLy
a858cadfd6 Migrate Android trailer resolution to fluxa-core and fix hero playback UI
- Route YouTube trailer resolution through the shared headless engine
  (headless_engine/trailer.rs) instead of a hand-rolled Innertube client
  in TrailerResolver, mirroring what fluxa-desktop already does. Wire
  the two HTTP effect kinds (fetchYoutubeTrailerWatchConfig/Player) as a
  generic passthrough in FluxaAndroidHeadlessEnvironment.
- Wire HeroTrailerVideoSurface's ExoPlayer through
  TrailerResolver.mediaDataSourceFactory() so trailer playback actually
  gets the browser UA + Range header YouTube's CDN requires — this was
  the root cause of the black-screen hero trailer.
- Fix AndroidCatalogHomeDataSource pinning the active billboard movie to
  index 0 of heroItems on every index change, which desynced the pager's
  page index from item identity and made forward swipes visually snap
  back to the previous item.
- Hide synopsis/metadata/play button and shrink the logo while a hero
  trailer plays, soften the bottom scrim so it doesn't black out most of
  the video, and add trailer subtitles (selection/normalize/parse) via
  the same fluxa-core functions fluxa-desktop uses, rendered as a
  position-synced overlay above the shrunk logo.
2026-07-19 02:30:59 +03:00
KhooLy
757d19e8f4 Improve calendar defaults and navigation icons 2026-07-18 18:04:41 +03:00
KhooLy
62d20e23c4 Refine mobile navigation and poster actions 2026-07-18 17:56:43 +03:00
KhooLy
909425202a Improve calendar library and catalog experiences 2026-07-18 16:52:38 +03:00
KhooLy
9a75c888f5 Add continue watching source preference and Nuvio account sync improvements
Adds a per-profile continue-watching source preference (Fluxa/Stremio/
Nuvio/Trakt/Simkl/AniList), a background worker to push playback
progress to Nuvio instead of pushing inline, dedup of mark-watched
pushes against already-watched episodes, and general Nuvio account
import/merge fixes.
2026-07-18 15:02:19 +03:00
KhooLy
ad06eb94f5 Add subtitle format labels and container track IDs; rework inline delay controls
Removes the standalone inline audio/subtitle delay adjust pill and
its state, and adds MediaTrack.subtitleFormatLabel/containerTrackId
so subtitle tracks can be labeled by codec (SRT/ASS/VTT/TTML/PGS/DVB/
VOBSUB).
2026-07-18 15:01:46 +03:00
KhooLy
0fa3ef723e Collapse bottom action row space while scrubbing
The row under the seekbar exited with fade and slide only, so its
layout space stayed reserved until the animation finished and then
snapped away. While scrubbing, the seekbar was therefore held up in
its buttons-visible position and the time and thumbnail preview
anchored above it floated high over empty space. The row now shrinks
vertically as it fades, taking its spacing with it, so the seekbar
settles to the bottom and the preview stays snug above it.
2026-07-17 17:59:52 +03:00
KhooLy
35ae8ea14a Fix adjust slider lag, drop fade-on-drag, and stop live seeking while scrubbing
Opacity sliders wrote the profile on every drag frame, which is what
made them stutter; they now hold a local live value that drives the
sample cue and only commit to the profile on release. With the panel
usable during drags, the fade-to-15% behavior is removed and the sample
cue moves lower (20dp from the bottom) instead.

The seek preview thumbnail system seeked the real player whenever a
drag paused over an uncached bucket, so scrubbing caused audible
jumps mid-drag. It now serves cached frames only, keeping the
background capture loop; the actual seek happens solely on seekbar
release, which the seekbar already implemented.
2026-07-17 17:50:08 +03:00
KhooLy
f9d4e664fe Keep subtitle preview visible under a compact top-right adjust card
The adjust card stacked its slider blocks two lines tall, making the
content roughly the full height of a landscape phone screen, so even
top-anchored it buried the sample cue. Slider items collapse to single
rows (title, slider, percent) and the card anchors top-right instead of
top-center, clearing the bottom-center subtitle zone both vertically
and horizontally.
2026-07-17 17:42:59 +03:00
KhooLy
01b85c0f1b Stop player menus leaking drags to volume gestures and make adjust page scroll
Drags on a sheet, card, or the speed popup were only consumed when a
child (slider, list) handled them; anything else bubbled up to the
player's volume/brightness drag layer, so swiping on the subtitle
adjust panel changed the volume. The shell root and the speed popup now
consume all unhandled drag gestures, while child scrollables and
sliders keep priority. The adjust page content also becomes vertically
scrollable since it can overflow the top-anchored card on short
landscape screens.
2026-07-17 17:40:38 +03:00
KhooLy
b4751da22e Move adjust entry to category headers and keep subtitles visible while adjusting
The adjust entry no longer scrolls with the track lists: each category
header (column label in the two-column card, the tab row in portrait)
carries a small tune icon. Audio's icon opens the inline delay pill
directly; the subtitles icon opens the adjust panel.

The adjust panel now anchors to the top of the screen with a near-zero
scrim so the bottom-center subtitle area stays visible, and while a
slider is being dragged the whole card fades to 15% opacity. A sample
cue styled with the live text/background/outline opacity values renders
at the subtitle position whenever the panel is open, so there is always
something to judge adjustments against.
2026-07-17 17:36:23 +03:00
KhooLy
d0207f50c6 Redesign player menus: anchored speed popup, combined tracks card, inline delay pill
Every player menu previously shared one full-chrome sidebar shell. The
shell now renders a translucent 24dp-radius card (0xE6101418, no
border) that fades in with a short upward drift, centered in landscape,
with no subtitle line and no close button; portrait keeps the bottom
sheet with its drag handle. Headers only render when a title or back
action exists.

Speed is no longer a sheet: it is a compact popup near the controls
that scales and fades in from its corner over a light scrim, listing
plain speed rows with the current one checked.

Audio and subtitles merge into a single Netflix-style two-column card
in landscape (portrait keeps the segmented tabs). Audio delay and
subtitle delay leave the card entirely: selecting them collapses the
menu to a floating pill over the video with -/value/+ controls so the
sync effect is visible live while adjusting. Subtitle styling keeps the
in-card adjust page.
2026-07-17 17:26:56 +03:00
KhooLy
0262acd528 Turn landscape player sheets into content-hugging floating cards
The landscape sheet stretched full height and flush to the screen edge,
so short menus like Audio or Speed left a huge empty void below their
rows. Side sheets are now 340dp floating cards (400dp on TV) rounded on
all corners, vertically centered with a 16dp edge margin, sized to
their content with a viewport-bounded max height. The slide-in
animation accounts for the margin, and the header is tightened with a
smaller, quieter close button.
2026-07-17 17:12:21 +03:00
KhooLy
5b153bfd3b Declutter player settings sheets
The sheets opened with an all-caps title, an instruction sentence, a
panel spanning almost half the screen, and two-line rows where every
speed carried a redundant Slower/Faster label. Titles are now title
case (Audio, Subtitles, Playback speed), the instruction line is gone,
the landscape sheet narrows from 46% to 38% width capped at 400dp,
rows tighten to 46dp with single-line speed entries (only 1x keeps a
Normal label), and mono/stereo channel counts render as words instead
of 1.0/2.0.
2026-07-17 17:07:59 +03:00
KhooLy
481aeb63e8 Restyle sidebar track rows with rounded selection highlight
Rows in the player sheets were flat full-bleed text with a 4dp inset;
the only selection cue was the trailing check. Rows are now rounded
12dp containers with a subtle white highlight behind the selected one,
matching ripple bounds, and the header subtitle is slightly larger.
2026-07-17 16:58:00 +03:00
KhooLy
7f93efbd41 Polish player sidebar open/close and unify speed menu
The sidebar previously entered with a fade plus a 44px nudge and
disappeared instantly on close. It now slides the full distance from
its edge (right for side sheets, bottom for bottom sheets) with the
scrim fading in sync, and close requests play the exit animation
before the panel is removed, including swipe-to-dismiss. Panel height
changes between tabs are animated instead of snapping.

The mobile speed menu drops its bordered chip grid in favor of the
same checkmarked rows used by the audio, subtitle, and source lists.
2026-07-17 16:55:54 +03:00
KhooLy
bdc4ab6b9a Redesign player controls chrome and sidebar layout
Reworks the player overlay chrome, sidebar shell, settings and
source sidebars, mark-segment sidebar, and mobile dialogs, plus
new dimension/icon tokens and i18n strings for the redesign.
2026-07-17 16:03:54 +03:00
KhooLy
83f452da15 Use spring animation for bottom nav icon scale
Swaps the flat tween for a medium-bouncy spring so the selected tab
icon overshoots slightly on scale-up instead of growing linearly.
2026-07-17 16:03:40 +03:00
KhooLy
8df4874b0a Fix hero indicator dots not tracking swipe position
The 5-dot sliding window re-centered on the current page every swipe,
so the highlighted dot's position within the window stayed constant
while paging through the middle of the list. Show one dot per item
instead since the hero caps at 8 items.
2026-07-17 16:03:25 +03:00
KhooLy
3440831ed1 Preserve per-tab scroll position across bottom nav switches
Wrap the screen AnimatedContent in a SaveableStateHolder keyed by
screen so each destination's LazyColumn/LazyList state survives being
switched away from and back to, instead of resetting to the top.
2026-07-17 06:18:44 +03:00
KhooLy
8f459a0f76 Redesign bottom nav bar and home screen scroll/hero UX
Bottom bar now overlays content edge-to-edge with a scrim background
and top hairline instead of reserving fixed space, gains labels,
FluxaIcons, selection animation, and a calendar badge for new
releases. Home screen's filter/notification/avatar bar is pinned and
fades in as the hero scrolls past instead of scrolling away with it.
Hero auto-swipe now pauses during user interaction, gained a Play
button, capped height, and windowed dot indicators. Row "view all"
now navigates to the category grid instead of silently loading more
into the row.
2026-07-17 06:17:18 +03:00
KhooLy
e773f3438b Redesign Settings navigation, IA, and visuals; fix Add-ons UX
Settings:
- Replace the single-level category state with a real back stack
  (lifted into FluxaAppState) so back navigation goes up one level
  instead of always jumping to the hub, with hardware back wired
  through MainActivity.
- Scroll position is now keyed per category instead of shared/leaking
  across pages, and nested pages show their own titles.
- Split Notifications and TMDB feature toggles out of Account into
  their own pages instead of an accordion and an overloaded
  TmdbAccountChanged action bundling unrelated fields.
- Downloads settings page no longer duplicates Library's live download
  list; it links out to it instead.
- Add a lightweight settings search (SettingsSearch.kt) over a static
  index of rows.
- TV renders Settings as a two-pane list-detail layout.
- Introduce SettingsGroupCard and restructure every settings page
  from a flat row list into grouped inset cards, restyle the search
  field and choice-picker dialog to match the app's black/white
  aesthetic instead of default Material styling, and merge the
  redundant avatar/account rows on the hub.
- Add-ons settings page now only launches the real add-ons screen
  directly (dropped the redundant "Manage Add-ons" middle page and
  the torrent preferences that lived there).

Add-ons store:
- Validate pasted manifest URLs by actually fetching them before
  installing, instead of accepting any string that pattern-matched
  as a manifest path; show an inline error on failure and a
  confirmation dialog on success.
- Replace the bare "+" icon button with a labeled Add button.

Also strips emoji baked into a few i18n strings (CloudStream repo/
plugin headers, premiere notification) per project convention.
2026-07-17 05:47:52 +03:00
KhooLy
d6232b9bd6 Fix episode tap not navigating to source selection
Tapping an episode card only updated the selected-episode state without
emitting a navigation event, so nothing visibly happened until Play was
pressed. DetailStore now emits SelectSources on EpisodeSelected, and
selectedEpisodeId is tracked via a StateFlow instead of a plain var so
the selection highlight updates immediately instead of lagging behind
an unrelated state emission.
2026-07-17 05:47:37 +03:00
KhooLy
b6fa1cbdb9 Show sources progressively and render full stream name/title in cards 2026-07-17 01:22:32 +03:00