Commit graph

18 commits

Author SHA1 Message Date
KhooLy
db10acd3b2 Route Screen.Detail through shared CMP Detail screen on Android mobile
Adds season/episode picker and sources list to the shared Detail
composable, switches FluxaAppState's selectedDetail to carry a
DetailRequestUiModel directly (instead of a full CatalogItemUiModel)
so the standalone Screen.Detail route can seed it without going
through a catalog item first, and threads a detailRequest +
onDetailNavigationEvent pair through FluxaAppHost.

AppRoutesHost now builds a DetailRequestUiModel from Screen.Detail and
hands the shared Detail screen's navigation decisions (play a
specific stream vs. go pick sources, based on cs3: id prefixes) back
to Screen.Player / Screen.Sources, reconstructing the full Stream
object via AndroidDetailDataSource.resolveStream() so headers/
subtitles aren't lost. TV still uses the legacy DetailRoute for now.
2026-07-14 13:06:39 +03:00
KhooLy
7b8a5c61bf Fix missing Discover catalogs and add dynamic content types (movie/series/anime)
Diagnosed against NuvioMobile's open-source discover implementation
(same addons, more catalogs visible there). Two real gaps:

1. buildDiscoverCatalogOptions() excluded any catalog requiring an
   extra parameter beyond genre. Nuvio's equivalent (supportsDiscover())
   explicitly whitelists "skip" (pagination) as never blocking a
   catalog even when required — Fluxa's filter didn't, silently
   dropping every catalog that declares skip as required, which is a
   common Stremio addon SDK convention. Added "skip" to the allowed set.

2. The Type filter (movie/series) was hardcoded in the shared Discover
   UI instead of derived from what addons actually expose. Nuvio builds
   its type list from distinct catalog types across installed addons,
   which is why "anime" shows up there. Added a new
   buildDiscoverContentTypes() helper (same extras filter, minus the
   "all"/type restriction), threaded contentTypes through the
   readDiscoverCatalogFilters effect, Rust's DiscoverState (new field,
   needed since the effect completion flows back through the engine's
   own state, not directly to Kotlin), HomeViewModel, and the shared
   DiscoverUiState/DiscoverScreen, with a movie/series fallback so the
   dropdown isn't empty before the first fetch completes.
2026-07-13 22:48:20 +03:00
KhooLy
a57e5f3312 Fix mobile shell reload storm and restore Discover's dropdown/grid/search UI
AppRoutesHost was mounting a fresh FluxaAppHost per Screen navigation,
so every tab switch among Home/Search/Discover/Calendar recreated
CatalogHomeStore and re-triggered CatalogAction.Refresh, which force-
reloads the whole Home catalog over the network regardless of which
tab was actually opened. Hoist the shared shell out of AnimatedContent
so it stays mounted across those four screens and only remounts when
leaving them entirely (Detail/Sources/Player/Settings/etc., same as
before).

Discover regressions from the last pass, now fixed to match native:
- Filter chips replaced with dropdown menus (DropdownMenu/MenuItem)
  matching native's Type/Catalog/Genre picker pattern.
- Grid restored to a fixed 3-column layout instead of adaptive sizing.
- Added the inline search box native's Explore screen has, reusing
  SearchResultRows/SearchResults (now internal, not private) so typing
  in Discover shows grouped search results instead of the filtered
  browse grid, same as native.
2026-07-13 21:12:10 +03:00
KhooLy
3dae079b3f Migrate mobile Search, Discover, and Calendar screens onto shared CMP UI
Wires Screen.Search/Explore/Calendar to FluxaAppHost on mobile, same
pattern as Home. TV keeps using the existing native screens untouched.

To preserve native feature parity in the shared UI:
- Search: per-addon grouped result rows (was a flat grid), a clear
  history action, and a query-specific "no results for X" message with
  a recent-history fallback, matching native's MobileSearchScreen.
- Discover: filter chips are now a scrollable LazyRow instead of a
  plain Row, avoiding the same overflow-wrap bug fixed on Home's row
  headers when there are many genre options.
- Calendar: added month navigation (prev/next + localized month
  title), day-grouped list headers via the existing cross-platform
  localizedShortMonthDay/localizedMonthTitle helpers, replacing the
  flat undated list.

Deliberately not replicated (documented simplification, not a bug):
native's Search and Explore screens each embed a blended search+browse
UX (explore filters shown pre-typing in Search; inline search box in
Explore). Shared keeps Search and Discover as clean separate screens
since both capabilities are still fully reachable via their own tabs.
Also skipped: Explore's list/grid view toggle, swipe-to-change-month
and the day-grid calendar view (list view covers the same data).
2026-07-13 21:02:25 +03:00
KhooLy
45c45b0ce6 Add Apple multiplatform foundation 2026-07-13 03:47:45 +03:00
KhooLy
a1ccbefc96 Add portable locale-aware calendar text formatting to :core
java.text.DateFormatSymbols/SimpleDateFormat are JVM-only, so the
calendar screens' weekday names, month titles, and short dates
couldn't move to KMP as-is. Adds an expect/actual trio in :core
(localizedShortWeekdayNames, localizedMonthTitle, localizedShortMonthDay)
— Android actual keeps the existing DateFormatSymbols/SimpleDateFormat
behavior, iOS actual uses NSDateFormatter/NSCalendar/NSLocale.

MobileCalendarDateUtils.kt's shortWeekdays/monthTitle/
formatCalendarListDate now delegate to these instead of doing the
java.text work directly — same signatures, so all 6 call sites
(TvCalendarScreen + 5 mobile calendar files) are untouched. This is
groundwork only: buildMonthCells/shiftMonth still use java.util.Calendar
and the calendar screens themselves aren't ported — that needs the
screens' JavaCalendar-typed state converted to kotlinx-datetime, a
separate, larger change.

Verified compiling for android, iosArm64, iosSimulatorArm64, and both
app product flavors still build.
2026-07-13 03:14:27 +03:00
KhooLy
b976f28fd1 Convert core module to Kotlin Multiplatform
Phase 0 of the iOS migration: core now targets android, iosArm64, and
iosSimulatorArm64 via a new fluxa.kmp.library convention plugin.
AppStrings and the TTL cache lose their JVM-only dependencies
(org.json, java.time, java.util.concurrent) in favor of
kotlinx-serialization, kotlinx-datetime, and small expect/actual
platform shims, with Locale-returning APIs kept as Android-only
extension functions since only Android UI consumes them today.
2026-07-13 02:30:20 +03:00
KhooLy
35c0c405ac Align mobile trailer and account sync flows 2026-07-12 02:47:24 +03:00
KhooLy
a1e5173a7a Add chapter-based skip toggle, JP audio preference, autoplay countdown, and auto-retry-next-source
- Use Chapters for Skipping: gates the existing chapter-derived skip
  segment fallback (already computed by deriveSkipSegmentsFromChapters)
  behind a new toggle instead of applying it unconditionally. Also
  brought TV's Skip Segments section up to parity with mobile (IntroDB +
  API key, AniSkip, chapter toggle, auto-skip), since TV was missing all
  but auto-skip.
- Japanese audio for anime: overrides the resolved preferred audio
  language to "ja" for anime-genre content when enabled, at the single
  entry point both audio and subtitle track resolution already share.
- Autoplay countdown: the next-episode card now counts down and fires
  automatically, instead of only advancing on click.
- Auto-retry next source: extends the existing Cloudstream-only
  auto-fallback-on-error path to also apply generally when enabled.
2026-07-10 02:43:32 +03:00
KhooLy
a98521bea1 Expose Stremio and Nuvio account entry points from Settings
Both onConnectStremio and MobileNuvioLoginView already existed but had no
UI trigger anywhere in Settings — onConnectStremio was a dead parameter
never invoked, and the Nuvio login view was only reachable from the
initial onboarding screen. Added a Stremio connection tile (TV + mobile)
and a Nuvio import row (mobile only, since TV's login screen has no
Nuvio path) that reuse the existing Screen.Login(startOnNuvio) navigation
already used by onboarding.
2026-07-10 02:29:17 +03:00
KhooLy
42422ea8a5 Add AniList account sync (OAuth2 connect/disconnect)
Mirrors the existing Trakt/MyAnimeList/Simkl connection pattern: a
fluxa://oauth/anilist deep link, authorize-URL launch, token exchange
through a new ExternalOAuthClient.exchangeAnilistCode call, and profile
fields (anilistAccessToken/RefreshToken/TokenExpiresAt) merged via the
existing authExchangeRequested headless effect. Adds a matching
AuthProvider::Anilist arm in fluxa_core's token_merge_plan_json so the
shared Rust merge path recognizes the new provider too.

Connect/disconnect tiles added to both TV and mobile Settings, folded
into the existing multi-provider "Disconnect" action.

Note: app/build.gradle.kts also carries a small pre-existing uncommitted
fix (rustCrateDir path) unrelated to this change, included here only
because it was already sitting in the working tree on the same file.
2026-07-10 02:23:39 +03:00
KhooLy
5a96828bed Add torrent speed/Wi-Fi-only settings rows and thread Wi-Fi-only into the torrent effect
Adds the missing torrentSpeedPreset settings row (the field already
controlled preload size) and a new Wi-Fi-only toggle. The Android-side
gating for Wi-Fi-only lives in TorrentStreamManager.startStream (see the
next commit); this piece wires the active profile's torrentWifiOnly flag
through the startTorrentStream headless effect.

torrentMaxConnections and torrentCachePreset are intentionally left
unexposed: the underlying rqbit torrent engine has no per-torrent
connection-count cap or disk-cache-size knob to back them, so a toggle
for either would be a no-op.
2026-07-10 02:01:50 +03:00
KhooLy
cffda2dad9 Add settings rows for notifications, auto-updates, subtitle shadow, and home hero trailer autoplay
These profile fields (notificationsEnabled, automaticUpdates, subtitleShadow,
trailerOnHomeHeroEnabled/DelaySeconds) already drove real behavior but had no
visible Settings UI on TV or mobile. Also gates the background update-check
loop in MainActivity behind automaticUpdates, and wires a TV "Check for
updates" action mirroring the existing mobile flow.
2026-07-09 23:00:59 +03:00
KhooLy
6fcf675761 Add content descriptions to icon-only buttons
Give back, search, cast, picture-in-picture, external-player, and
calendar month-navigation buttons localized accessibility labels so
TalkBack announces their action. Adds the supporting common.* i18n keys.
2026-07-05 00:14:12 +03:00
KhooLy
56e2697dfa Fill missing and untranslated Turkish i18n strings
Add missing auto.connect key and translate 33 settings, player, and
notification strings that were still showing English in the Turkish locale.
2026-07-05 00:04:52 +03:00
KhooLy
05083b3f0b Improve plugin auto-update: failure reporting, deduplication, separate notification IDs
- Return UpdateReport(updatedPlugins, failedPlugins) from auto-updater so failures
  are tracked separately from successes
- Show a distinct notification when one or more plugins fail to update, using
  separate notification IDs so the success and failure toasts don't stomp each other
- Add installKey() to Plugin for stable deduplication by (name, repositoryUrl) pair;
  use it in isPluginInstalled to avoid duplicate installs on re-run
- Add i18n keys notification.plugins_update_failed_title/body in en-US and tr-TR
2026-07-03 12:52:50 +03:00
KhooLy
adf7700f7d Fix mpv/ExoPlayer audio passthrough, channel layout, AO, and DV track selection
mpv:
- Set ao=audiotrack explicitly so the AudioTrack output is guaranteed
  (avoids openSLES which lacks encoded passthrough)
- Add audio-channels=7.1,5.1,stereo so mpv negotiates multichannel
  instead of defaulting to auto-safe stereo downmix
- Build audio-spdif at init time by querying AudioManager output device
  encodings; only advertises AC3/E-AC3/DTS/DTS-HD/TrueHD formats the
  device actually reports

ExoPlayer:
- Guard setVideoEffects(emptyList()) behind a videoEffectsActive flag:
  only call it when IptPqc2ToneMapEffect was actually installed, never
  on a clean path — the empty-list call triggers the GL VideoFrameProcessor
  pipeline in media3 1.10.1 which tone-maps HDR even for an empty effect list
- detectPreferredVideoMimeType now accepts Context and checks display +
  decoder DV capability first; on fully DV-capable devices it returns
  VIDEO_DOLBY_VISION so DV variant tracks are preferred rather than
  deprioritized behind H.265/H.264
2026-07-03 03:51:49 +03:00
KhooLy
348c4ad4bb Clean up mobile settings visuals and align them with design tokens 2026-07-02 01:15:47 +03:00