diff --git a/app/src/main/java/com/fluxa/app/ui/catalog/HomeLibraryCoordinator.kt b/app/src/main/java/com/fluxa/app/ui/catalog/HomeLibraryCoordinator.kt
index 83c5c5d..6fe19ab 100644
--- a/app/src/main/java/com/fluxa/app/ui/catalog/HomeLibraryCoordinator.kt
+++ b/app/src/main/java/com/fluxa/app/ui/catalog/HomeLibraryCoordinator.kt
@@ -1,7 +1,7 @@
package com.fluxa.app.ui.catalog
import android.util.Log
-import com.fluxa.app.core.rust.FluxaCoreStateHandle
+import com.fluxa.app.core.rust.FluxaUniFfiCoreStateHandle
import com.fluxa.app.data.local.*
import com.fluxa.app.data.local.UserProfile
import com.fluxa.app.data.remote.Meta
@@ -36,7 +36,7 @@ internal class HomeLibraryCoordinator(
private val repository: StremioRepository,
private val traktRepository: TraktRepository,
private val scope: CoroutineScope,
- private val coreState: FluxaCoreStateHandle,
+ private val coreState: FluxaUniFfiCoreStateHandle,
private val gson: Gson
) {
private val _state = MutableStateFlow(LibraryUiState())
diff --git a/app/src/main/java/com/fluxa/app/ui/catalog/HomeSearchFocusStateHolder.kt b/app/src/main/java/com/fluxa/app/ui/catalog/HomeSearchFocusStateHolder.kt
index d23fa83..7f598a9 100644
--- a/app/src/main/java/com/fluxa/app/ui/catalog/HomeSearchFocusStateHolder.kt
+++ b/app/src/main/java/com/fluxa/app/ui/catalog/HomeSearchFocusStateHolder.kt
@@ -1,7 +1,7 @@
package com.fluxa.app.ui.catalog
-import com.fluxa.app.core.rust.FluxaCoreNative
-import com.fluxa.app.core.rust.FluxaCoreStateHandle
+import com.fluxa.app.core.rust.FluxaCoreUniFfi
+import com.fluxa.app.core.rust.FluxaUniFfiCoreStateHandle
import com.fluxa.app.data.remote.Meta
import com.google.gson.Gson
import java.io.Closeable
@@ -11,7 +11,7 @@ import kotlinx.coroutines.flow.asStateFlow
class HomeSearchFocusStateHolder(
initialHistory: List,
- private val coreState: FluxaCoreStateHandle = FluxaCoreNative.createAppCoreState(
+ private val coreState: FluxaUniFfiCoreStateHandle = FluxaCoreUniFfi.createAppCoreState(
mapOf(
"homeSearch" to mapOf(
"searchHistory" to initialHistory
diff --git a/app/src/main/java/com/fluxa/app/ui/catalog/HomeViewModel.kt b/app/src/main/java/com/fluxa/app/ui/catalog/HomeViewModel.kt
index 10cc57c..85ee1cc 100644
--- a/app/src/main/java/com/fluxa/app/ui/catalog/HomeViewModel.kt
+++ b/app/src/main/java/com/fluxa/app/ui/catalog/HomeViewModel.kt
@@ -6,7 +6,8 @@ import com.fluxa.app.data.remote.*
import com.fluxa.app.data.repository.*
import com.fluxa.app.core.rust.FluxaAndroidHeadlessEnvironment
import com.fluxa.app.core.rust.FluxaCoreNative
-import com.fluxa.app.core.rust.FluxaCoreStateHandle
+import com.fluxa.app.core.rust.FluxaCoreUniFfi
+import com.fluxa.app.core.rust.FluxaUniFfiCoreStateHandle
import com.fluxa.app.core.rust.FluxaHeadlessRuntimeFactory
import com.fluxa.app.domain.discovery.DiscoverCatalogOption
import com.fluxa.app.domain.discovery.MetadataFeedOption
@@ -71,7 +72,7 @@ class HomeViewModel @Inject constructor(
private val addonListType = object : TypeToken>() {}.type
private val headlessRuntime = FluxaHeadlessRuntimeFactory.createUniFfi(headlessEnvironment)
private val initialSearchHistory = searchHistoryStore.load(null)
- private val coreState: FluxaCoreStateHandle = FluxaCoreNative.createAppCoreState(
+ private val coreState: FluxaUniFfiCoreStateHandle = FluxaCoreUniFfi.createAppCoreState(
mapOf(
"home" to mapOf(
"categories" to emptyList(),
@@ -143,6 +144,7 @@ class HomeViewModel @Inject constructor(
scope = viewModelScope,
gson = gson,
dispatch = ::dispatchHeadless,
+ activeProfile = { currentActiveProfile },
setActiveProfile = { setActiveProfileState(it) },
setWatchlist = ::setWatchlistState,
setContinueWatching = ::setCurrentWatchlistState,
@@ -237,6 +239,16 @@ class HomeViewModel @Inject constructor(
private var currentWatchlist: List = emptyList()
private val _currentContinueWatchingCount = MutableStateFlow(0)
val currentContinueWatchingCount: StateFlow = _currentContinueWatchingCount.asStateFlow()
+ private val _syncingProviders = MutableStateFlow>(emptySet())
+ val syncingProviders: StateFlow> = _syncingProviders.asStateFlow()
+
+ fun setProviderSyncing(provider: String, syncing: Boolean) {
+ _syncingProviders.value = if (syncing) {
+ _syncingProviders.value + provider
+ } else {
+ _syncingProviders.value - provider
+ }
+ }
private var externalContinueWatching: List = emptyList()
private var traktWatchedState: TraktWatchedState = TraktWatchedState()
private var currentActiveProfile: UserProfile? = null
@@ -1086,7 +1098,7 @@ class HomeViewModel @Inject constructor(
cacheSaveJob?.cancel()
cacheSaveJob = viewModelScope.launch(Dispatchers.Default) {
delay(600)
- homeCategoryCache.save(profile, categories)
+ homeCategoryCache.save(profile, categories.filterNot { it.id == "continue_watching" })
}
}
diff --git a/app/src/main/java/com/fluxa/app/ui/catalog/HomeViewModelCoordinatorFactory.kt b/app/src/main/java/com/fluxa/app/ui/catalog/HomeViewModelCoordinatorFactory.kt
index cd62bb1..3c086d8 100644
--- a/app/src/main/java/com/fluxa/app/ui/catalog/HomeViewModelCoordinatorFactory.kt
+++ b/app/src/main/java/com/fluxa/app/ui/catalog/HomeViewModelCoordinatorFactory.kt
@@ -1,7 +1,7 @@
package com.fluxa.app.ui.catalog
import android.content.Context
-import com.fluxa.app.core.rust.FluxaCoreStateHandle
+import com.fluxa.app.core.rust.FluxaUniFfiCoreStateHandle
import com.fluxa.app.data.local.UserProfile
import com.fluxa.app.data.local.WatchlistManager
import com.fluxa.app.data.remote.AddonDescriptor
@@ -19,7 +19,7 @@ class HomeViewModelCoordinatorFactory @Inject constructor() {
repository: StremioRepository,
traktRepository: TraktRepository,
scope: CoroutineScope,
- coreState: FluxaCoreStateHandle,
+ coreState: FluxaUniFfiCoreStateHandle,
gson: Gson
): HomeLibraryCoordinator {
return HomeLibraryCoordinator(repository, traktRepository, scope, coreState, gson)
diff --git a/app/src/main/java/com/fluxa/app/ui/catalog/PlayerScreenState.kt b/app/src/main/java/com/fluxa/app/ui/catalog/PlayerScreenState.kt
index cda62e4..93b500c 100644
--- a/app/src/main/java/com/fluxa/app/ui/catalog/PlayerScreenState.kt
+++ b/app/src/main/java/com/fluxa/app/ui/catalog/PlayerScreenState.kt
@@ -11,8 +11,8 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.media3.ui.AspectRatioFrameLayout
-import com.fluxa.app.core.rust.FluxaCoreNative
-import com.fluxa.app.core.rust.FluxaCoreStateHandle
+import com.fluxa.app.core.rust.FluxaCoreUniFfi
+import com.fluxa.app.core.rust.FluxaUniFfiCoreStateHandle
import com.fluxa.app.data.remote.IntroTimestamps
import com.fluxa.app.data.remote.Stream
import com.fluxa.app.data.remote.Video
@@ -39,7 +39,7 @@ internal class PlayerScreenState(
initialVolume: Int
) {
private val gson = Gson()
- private val coreState: FluxaCoreStateHandle = FluxaCoreNative.createAppCoreState(
+ private val coreState: FluxaUniFfiCoreStateHandle = FluxaCoreUniFfi.createAppCoreState(
mapOf(
"player" to mapOf(
"currentVideoId" to initialVideoId,
@@ -111,7 +111,6 @@ internal class PlayerScreenState(
var showSettings by mutableStateOf(false)
var activeSettingsTab by mutableIntStateOf(0)
- var inlineDelayTarget by mutableStateOf(null)
var audioDelayMs by mutableLongStateOf(0L)
var subtitleDelayMs by mutableLongStateOf(0L)
diff --git a/app/src/test/java/com/fluxa/app/core/rust/FluxaCoreBenchmarkTest.kt b/app/src/test/java/com/fluxa/app/core/rust/FluxaCoreBenchmarkTest.kt
index ca8a7e4..eea1a13 100644
--- a/app/src/test/java/com/fluxa/app/core/rust/FluxaCoreBenchmarkTest.kt
+++ b/app/src/test/java/com/fluxa/app/core/rust/FluxaCoreBenchmarkTest.kt
@@ -407,11 +407,11 @@ class FluxaCoreBenchmarkTest {
!name.contains("cacheTrimPolicy", ignoreCase = true)
}
assertTrue(nativeCacheStorageFunctions.isEmpty())
- assertTrue(nativeFunctionNames.any { it == "cacheEntryPolicyJsonNative" })
- assertTrue(nativeFunctionNames.any { it == "cacheTrimPolicyJsonNative" })
+ assertTrue(nativeFunctionNames.any { it == "cacheEntryPolicy" })
+ assertTrue(nativeFunctionNames.any { it == "cacheTrimPolicy" })
assertFalse(nativeFunctionNames.any { it == "startLocalStreamServerNative" })
assertFalse(nativeFunctionNames.any { it == "stopLocalStreamServerNative" })
- assertTrue(nativeFunctionNames.any { it == "parseManifestJsonNative" })
+ assertTrue(nativeFunctionNames.any { it == "coreInvokeNative" })
}
private fun startStaticServer(payload: ByteArray, requestCount: AtomicInteger): StaticByteServer {
diff --git a/app/src/test/java/com/fluxa/app/core/rust/FluxaCoreUniFfiContractTest.kt b/app/src/test/java/com/fluxa/app/core/rust/FluxaCoreUniFfiContractTest.kt
index 9f54fcc..4839020 100644
--- a/app/src/test/java/com/fluxa/app/core/rust/FluxaCoreUniFfiContractTest.kt
+++ b/app/src/test/java/com/fluxa/app/core/rust/FluxaCoreUniFfiContractTest.kt
@@ -34,4 +34,13 @@ class FluxaCoreUniFfiContractTest {
assertEquals("Movie", meta["name"])
}
}
+
+ @Test
+ fun coreInvokeRoutesCalendarMethodThroughUniFfi() {
+ val value = FluxaCoreUniFfi.coreInvokeValue(
+ "calendarSeasonCandidates",
+ """{"seasonsCount":10,"lastVideoId":"tt1:2:3"}"""
+ )
+ assertEquals("[2,3,10]", value.toString())
+ }
}
diff --git a/data/src/androidMain/kotlin/com/fluxa/app/core/rust/FluxaCoreNative.kt b/data/src/androidMain/kotlin/com/fluxa/app/core/rust/FluxaCoreNative.kt
index 0dd156d..90758de 100644
--- a/data/src/androidMain/kotlin/com/fluxa/app/core/rust/FluxaCoreNative.kt
+++ b/data/src/androidMain/kotlin/com/fluxa/app/core/rust/FluxaCoreNative.kt
@@ -69,6 +69,8 @@ import com.google.gson.stream.JsonReader
import java.io.Closeable
import java.io.StringReader
+private fun urlArgs(url: String): String = JsonObject().apply { addProperty("url", url) }.toString()
+
private fun JsonObject.stringOrNull(key: String): String? =
get(key)?.takeUnless { it.isJsonNull }?.asString
@@ -211,13 +213,6 @@ data class NativeCloudstreamRequest(
val timeoutMs: Long = 0L
)
-// ── calendar_plan ─────────────────────────────────────────────────────────────
-
-data class NativeCalendarNotificationContent(
- val items: List