Commit graph

94 commits

Author SHA1 Message Date
KhooLy
d2d075ed6b Accept platform services in shared app host 2026-07-13 15:40:38 +03:00
KhooLy
6fa6c81af3 Split shared platform service capabilities 2026-07-13 15:39:51 +03:00
KhooLy
8790838407 Add Android shared services composition root 2026-07-13 15:38:19 +03:00
KhooLy
fa4adcc5d8 Add shared player controls boundary 2026-07-13 15:37:40 +03:00
KhooLy
42f905af62 Add shared profile settings stores 2026-07-13 15:36:57 +03:00
KhooLy
3ecdb37e5a Add shared search and detail stores 2026-07-13 15:36:18 +03:00
KhooLy
dd54966fb8 Include shared app state 2026-07-13 15:16:59 +03:00
KhooLy
cb99b2b1e8 Add shared catalog action boundary 2026-07-13 15:08:20 +03:00
KhooLy
ae73947f4d Link UIKit as an SDK framework 2026-07-13 14:45:57 +03:00
KhooLy
dd0a5fa8ed Use Xcode 26 for Apple CI 2026-07-13 14:32:55 +03:00
KhooLy
72aa45b8c7 Support macOS Bash in Rust build script 2026-07-13 14:16:15 +03:00
KhooLy
091eaeff87 Bootstrap Apple Rust core before Xcode 2026-07-13 14:10:01 +03:00
KhooLy
c9b3dd0c6e Fix tvOS Rust CI target 2026-07-13 14:03:11 +03:00
KhooLy
60094c4e21 Build Apple Rust core in CI 2026-07-13 13:58:40 +03:00
KhooLy
52fae178e5 Link UIKit in the iOS host 2026-07-13 05:04:37 +03:00
KhooLy
47bf2f6e03 Match iOS host to Compose SDK baseline 2026-07-13 04:54:33 +03:00
KhooLy
7410d81380 Align iOS host with Compose runtime 2026-07-13 04:45:08 +03:00
KhooLy
5779930510 Configure Apple host deployment targets 2026-07-13 04:33:29 +03:00
KhooLy
b08dd5a00d Fix Apple framework export and simulator architecture 2026-07-13 04:22:39 +03:00
KhooLy
f9adf9b16f Run Apple framework builds from project root 2026-07-13 04:13:20 +03:00
KhooLy
89ec1abee6 Use Xcode 16 macOS runner for Apple CI 2026-07-13 04:07:06 +03:00
KhooLy
9344497ce4
Create LICENSE 2026-07-13 04:04:24 +03:00
KhooLy
11a3493dbc Match Apple project format to CI Xcode 2026-07-13 04:00:39 +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
31cfd2b931 Add Koin as the DI mechanism for shared code
Hilt is Android/Dagger-only and can't run on Kotlin/Native, so it
can't be used for anything moving into :shared. Koin is the standard
KMP alternative — this wires it up for real: a Koin module
(sharedModule) providing GreetingViewModel via the koin viewmodel DSL,
CmpSmokeTest now resolves it through koinViewModel() instead of
constructing it directly, and AppApplication.onCreate() calls
initSharedKoin() at startup so this isn't just compile-checked dead
code — Koin actually starts alongside Hilt (the two coexist fine,
verified by compiling the full app afterward).

This is the pattern for every ViewModel/ScreenModel that moves to
:shared going forward. HomeViewModel/DetailViewModel themselves stay
Hilt-based in app for now — porting them means porting their
repositories to KMP first, which is separate, larger work.

Verified compiling for android, iosArm64, iosSimulatorArm64, and both
app product flavors still build with Koin initialized at startup.
2026-07-13 03:09:18 +03:00
KhooLy
89ee3eb95f Move DeviceType and card size presets into the shared KMP module
DeviceType/LocalDeviceType/touchClickable and the four poster/
horizontal card size preset functions were pure Compose (no Android
imports beyond foundation.clickable, which is multiplatform) — same
straight move as FluxaColors/FluxaDimensions, same package name, zero
call-site changes across the 38 files that reference them.

This unblocks moving more of the mobile card layout math into :shared
later, since the device-aware sizing helpers no longer live only in
the Android-only app module.

Verified compiling for android, iosArm64, iosSimulatorArm64, and both
app product flavors still build.
2026-07-13 03:02:30 +03:00
KhooLy
ddb556cb27 Move the mobile catalog card to the shared KMP module
Adds CatalogCardUiModel + CatalogCard to :shared: a fully-resolved,
primitive-only render model (Dp/Sp/String/Float, no Meta/UserProfile)
and a Coil3-based composable that draws it, per this project's UI
optimization rule (leaf UI components get small immutable models, not
domain objects). MobileMovieCard.kt in app becomes a thin mapper —
Meta/UserProfile/DeviceType-aware layout math stays Android-side,
producing a CatalogCardUiModel that the shared composable renders.

Pinned coil3 to 3.4.0 (was 3.5.0): 3.5.0's iosarm64/iossimulatorarm64
klibs were built with a newer Kotlin ABI (2.4.0) than this project's
compiler (2.3.20) can consume. Revisit once the project bumps Kotlin.

Verified: CatalogCard/CatalogCardUiModel compile for android,
iosArm64, and iosSimulatorArm64; app's mobile and tv flavors both
still build against the rewritten MobileMovieCard.
2026-07-13 03:00:38 +03:00
KhooLy
a3d42a15ca Move FluxaColors/FluxaDimensions into the shared KMP module
First real slice of ui/catalog moving to :shared: both objects were
already pure Compose (Color/dp/sp), no Android imports, so this is a
straight module move with zero call-site changes elsewhere in app —
they keep the same package (com.fluxa.app.ui.catalog), so every
existing same-package and imported reference resolves unchanged
across the module boundary. Verified compiling for android,
iosArm64, and iosSimulatorArm64, and that both app product flavors
still build against it.

Every future shared mobile composable needs this theme foundation,
so it's the natural first thing to move.
2026-07-13 02:52:47 +03:00
KhooLy
395f49a340 Add Compose Multiplatform module
New :shared module with a fluxa.kmp.compose convention plugin (Compose
Multiplatform's runtime/foundation/material3/ui, layered on the
existing fluxa.kmp.library android+iOS target setup) plus a smoke-test
composable proving a real @Composable using Material3 compiles for
android, iosArm64, and iosSimulatorArm64.

This is where ui/catalog/mobile/** screens will move to in the next
phase, sharing the same UI code between Android mobile and iOS.
2026-07-13 02:47:02 +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
20dada92a7 Select high quality trailer variants 2026-07-12 12:59:01 +03:00
KhooLy
35c0c405ac Align mobile trailer and account sync flows 2026-07-12 02:47:24 +03:00
KhooLy
bbd92ca1aa Don't start the torrent watcher when the Rust engine fails to start
startTorrentServer's result was logged as success and the watcher was
started unconditionally, even when the Rust call failed to report
readiness (blank result). Gate both on the actual running state.
2026-07-10 13:06:57 +03:00
KhooLy
b0d15dd8f5 Add gifAutoplayEnabled profile preference 2026-07-10 13:06:54 +03:00
KhooLy
f346048158 Fix unstable LazyColumn keys for streams sharing a URL or title
Two streams with the same playableUrl (or both missing one and sharing a
title) previously collided on the same key, which could cause item state
to leak between rows during scroll/recomposition.
2026-07-10 13:06:51 +03:00
KhooLy
5931a1c0a9 Point fluxa-core references at the FluxaMedia org
The fluxa-core repo moved from KhooLy/fluxa-core to FluxaMedia/fluxa-core;
update the release workflow checkout and README links to match.
2026-07-10 13:06:48 +03:00
KhooLy
b5120f6a27 Fix blank video on some devices caused by uncleared libass overlay surface
The always-mounted NativeLibassSubtitleOverlay SurfaceView sits above the
video SurfaceView (setZOrderMediaOverlay). Its canvas was only ever locked
and cleared when an ASS renderer was active, so with no embedded ASS track
selected the overlay buffer kept whatever garbage content it started with.
On some devices (reported on Redmi/MIUI) that composites as opaque black,
hiding the video behind fully-drawn player controls.
2026-07-10 13:05:56 +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
b3e893b63f Gate torrent stream start behind Wi-Fi-only setting
Adds a real network-transport check (ConnectivityManager) before starting
a torrent stream when Wi-Fi-only is enabled in Settings, refusing to start
on cellular instead of silently ignoring the toggle.

Note: this file already carried unrelated uncommitted engine-resiliency
work (ensureEngineReady/health-check/restart-on-failure) from before this
change — that part isn't mine, it's included here only because it was
already sitting in the working tree and touches the same file.
2026-07-10 02:01:55 +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
3bbbcb206c Delegate TrailerResolver to the shared fluxa-streaming-engine resolver
The Kotlin innertube client had drifted onto deprecated client configs
(ANDROID_TESTSUITE, TVHTML5_SIMPLY_EMBEDDED_PLAYER) that YouTube no
longer accepts. Route through FluxaStreamingNative's new
resolveYoutubeTrailerJson instead, so there's one maintained resolver
shared with the desktop app rather than two independent copies to keep
working. Public API (TrailerResolveResult/TrailerResult/SubtitleInfo)
is unchanged, so callers need no changes.
2026-07-07 20:41:08 +03:00
KhooLy
4c4a98432a Show poster skeletons instead of a spinner while a category loads
Add a reusable shimmer skeleton (FluxaSkeleton) and use it for the
category results grid's initial load, replacing the lone centered
spinner with placeholder poster cards that match the grid layout.
2026-07-05 00:28:47 +03:00
KhooLy
e57f2bbf32 Use FluxaColors tokens for duplicated color literals
Replace raw hex literals that exactly matched existing design tokens
(background, releaseGreen, imdbYellow) with the token references.
2026-07-05 00:15:54 +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
54312af132 Remove code comments from UI layer
Strip inline, block, and doc comments across the ui package to comply
with the project's no-comments rule. Preserves noinspection directives
and string literals containing // (URLs).
2026-07-05 00:09:35 +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