From 69f0dab65e42fe8b2844a62b3eb5bc3945c1f228 Mon Sep 17 00:00:00 2001 From: tapframe <85391825+tapframe@users.noreply.github.com> Date: Tue, 23 Jun 2026 19:43:27 +0530 Subject: [PATCH] feat: local db switch for development --- composeApp/build.gradle.kts | 42 ++++ .../core/build/AppFeaturePolicy.android.kt | 1 + .../core/build/AppFeaturePolicy.android.kt | 1 + .../composeResources/values/strings.xml | 3 + .../nuvio/app/core/build/AppFeaturePolicy.kt | 1 + .../app/core/network/SyncBackendConfig.kt | 4 +- .../app/core/network/SyncBackendRepository.kt | 55 +++++- .../com/nuvio/app/features/auth/AuthScreen.kt | 11 ++ .../features/dev/DebugSyncBackendSwitch.kt | 182 ++++++++++++++++++ .../features/settings/AccountSettingsPage.kt | 20 +- .../core/build/AppFeaturePolicy.desktop.kt | 1 + .../app/core/build/AppFeaturePolicy.ios.kt | 1 + .../app/core/build/AppFeaturePolicy.ios.kt | 1 + 13 files changed, 309 insertions(+), 14 deletions(-) create mode 100644 composeApp/src/commonMain/kotlin/com/nuvio/app/features/dev/DebugSyncBackendSwitch.kt diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index 5d159c4c2..1d971e6a3 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -40,6 +40,9 @@ abstract class GenerateRuntimeConfigsTask : DefaultTask() { @get:Input abstract val syncBackendManifestUrl: Property + @get:Input + abstract val debugBuild: Property + @TaskAction fun generate() { val props = Properties() @@ -140,6 +143,15 @@ abstract class GenerateRuntimeConfigsTask : DefaultTask() { |} """.trimMargin() ) + resolve("AppBuildConfig.kt").writeText( + """ + |package com.nuvio.app.core.build + | + |object AppBuildConfig { + | const val IS_DEBUG_BUILD = ${debugBuild.get()} + |} + """.trimMargin() + ) } outDir.resolve("com/nuvio/app/features/settings").apply { @@ -256,6 +268,35 @@ fun runtimeConfigValue(key: String, fallback: String = ""): String = ?: providers.environmentVariable(key).orNull?.trim()?.takeIf { it.isNotBlank() } ?: fallback +fun booleanConfigValue(key: String): Boolean? { + val rawValue = runtimeLocalProperties.getProperty(key) + ?: providers.environmentVariable(key).orNull + ?: providers.gradleProperty(key).orNull + return rawValue + ?.trim() + ?.lowercase() + ?.let { value -> + when (value) { + "1", "true", "yes", "y", "debug" -> true + "0", "false", "no", "n", "release" -> false + else -> null + } + } +} + +val xcodeConfiguration = providers.environmentVariable("CONFIGURATION").orNull + ?.trim() + ?.lowercase() +val kotlinFrameworkBuildType = providers.environmentVariable("KOTLIN_FRAMEWORK_BUILD_TYPE").orNull + ?.trim() + ?.lowercase() +val inferredDebugBuild = requestedGradleTasks.any { "debug" in it } || + xcodeConfiguration == "debug" || + kotlinFrameworkBuildType == "debug" +val isDebugBuild = booleanConfigValue("NUVIO_DEBUG_BUILD") + ?: booleanConfigValue("nuvio.debugBuild") + ?: inferredDebugBuild + val generateRuntimeConfigs = tasks.register("generateRuntimeConfigs") { outputDir.set(generatedRuntimeConfigDir) localPropertiesFile.set(rootProject.layout.projectDirectory.file("local.properties")) @@ -266,6 +307,7 @@ val generateRuntimeConfigs = tasks.register("generat nuvioSupabaseUrl.set(runtimeConfigValue("NUVIO_SUPABASE_URL")) nuvioSupabaseAnonKey.set(runtimeConfigValue("NUVIO_SUPABASE_ANON_KEY")) syncBackendManifestUrl.set(runtimeConfigValue("SYNC_BACKEND_MANIFEST_URL")) + debugBuild.set(isDebugBuild) } tasks.withType>().configureEach { diff --git a/composeApp/src/androidFull/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.android.kt b/composeApp/src/androidFull/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.android.kt index 996401f6b..62e4aa331 100644 --- a/composeApp/src/androidFull/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.android.kt +++ b/composeApp/src/androidFull/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.android.kt @@ -7,4 +7,5 @@ actual object AppFeaturePolicy { actual val heroTrailerPlaybackSupported: Boolean = true actual val inAppUpdaterEnabled: Boolean = true actual val imdbRatingLogoEnabled: Boolean = true + actual val debugBackendSwitcherEnabled: Boolean = AppBuildConfig.IS_DEBUG_BUILD } diff --git a/composeApp/src/androidPlaystore/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.android.kt b/composeApp/src/androidPlaystore/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.android.kt index 2b308a232..1a639c5cc 100644 --- a/composeApp/src/androidPlaystore/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.android.kt +++ b/composeApp/src/androidPlaystore/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.android.kt @@ -7,4 +7,5 @@ actual object AppFeaturePolicy { actual val heroTrailerPlaybackSupported: Boolean = false actual val inAppUpdaterEnabled: Boolean = false actual val imdbRatingLogoEnabled: Boolean = false + actual val debugBackendSwitcherEnabled: Boolean = AppBuildConfig.IS_DEBUG_BUILD } diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml index e84da9962..008521a52 100644 --- a/composeApp/src/commonMain/composeResources/values/strings.xml +++ b/composeApp/src/commonMain/composeResources/values/strings.xml @@ -19,6 +19,7 @@ Retry Save Saving… + Switch Validate Installing Addons @@ -533,6 +534,8 @@ Anonymous Signed in Sync backend + Switch backend? + Switch to %1$s and sign out? You can sign in again on the selected backend. AMOLED Black Use pure black backgrounds for OLED screens. App Language diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.kt index 8e62eb8ed..55f7c1e16 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.kt @@ -12,4 +12,5 @@ expect object AppFeaturePolicy { val heroTrailerPlaybackSupported: Boolean val inAppUpdaterEnabled: Boolean val imdbRatingLogoEnabled: Boolean + val debugBackendSwitcherEnabled: Boolean } diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/network/SyncBackendConfig.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/network/SyncBackendConfig.kt index ca45da22e..9510e6c17 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/network/SyncBackendConfig.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/network/SyncBackendConfig.kt @@ -45,6 +45,7 @@ data class SyncBackendState( val appliedRevision: String = "", val isLoaded: Boolean = false, val lastManifestError: String? = null, + val isManualDebugOverride: Boolean = false, ) sealed interface SyncBackendRefreshResult { @@ -68,6 +69,7 @@ internal data class StoredSyncBackendSelection( val backend: SyncBackendConfig? = null, val backendId: String = "", val appliedRevision: String = "", + val manualDebugOverride: Boolean = false, ) object SyncBackendDefaults { @@ -113,7 +115,7 @@ internal fun SyncBackendManifest.backendConfigForActiveBackend(): SyncBackendCon ?.takeIf { it.isUsableClientConfig() } } -private fun SyncBackendConfig.isUsableClientConfig(): Boolean = +internal fun SyncBackendConfig.isUsableClientConfig(): Boolean = id in setOf(SYNC_BACKEND_HOSTED_ID, SYNC_BACKEND_NUVIO_ID) && normalizedSupabaseUrl.startsWith("https://") && anonKey.isNotBlank() && diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/network/SyncBackendRepository.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/network/SyncBackendRepository.kt index db3065293..8491efc82 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/network/SyncBackendRepository.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/network/SyncBackendRepository.kt @@ -1,6 +1,7 @@ package com.nuvio.app.core.network import co.touchlab.kermit.Logger +import com.nuvio.app.core.build.AppFeaturePolicy import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -35,23 +36,37 @@ object SyncBackendRepository { .getOrNull() } - val backend = storedSelection - ?.let { selection -> - selection.backendId.ifBlank { selection.backend?.id.orEmpty() } - } - ?.let(SyncBackendDefaults::byId) - ?: SyncBackendDefaults.hosted() + val storedManualDebugOverride = storedSelection?.manualDebugOverride == true + val backend = if (storedManualDebugOverride && !AppFeaturePolicy.debugBackendSwitcherEnabled) { + SyncBackendDefaults.hosted() + } else { + storedSelection + ?.let { selection -> + selection.backendId.ifBlank { selection.backend?.id.orEmpty() } + } + ?.let(SyncBackendDefaults::byId) + ?: SyncBackendDefaults.hosted() + } _state.value = SyncBackendState( selectedBackend = backend, - appliedRevision = storedSelection?.appliedRevision.orEmpty(), + appliedRevision = if (storedManualDebugOverride && !AppFeaturePolicy.debugBackendSwitcherEnabled) { + "" + } else { + storedSelection?.appliedRevision.orEmpty() + }, isLoaded = true, + isManualDebugOverride = storedManualDebugOverride && AppFeaturePolicy.debugBackendSwitcherEnabled, ) } suspend fun refreshFromManifest(): SyncBackendRefreshResult { ensureLoaded() + if (_state.value.isManualDebugOverride && AppFeaturePolicy.debugBackendSwitcherEnabled) { + return SyncBackendRefreshResult.Unchanged + } + val manifestUrl = SyncBackendBootstrapConfig.SWITCH_MANIFEST_URL.trim() if (manifestUrl.isBlank()) { return SyncBackendRefreshResult.NotConfigured @@ -97,19 +112,40 @@ object SyncBackendRepository { revision: String, ): SyncBackendConfig { val normalizedBackend = backend.normalized() - saveSelection(normalizedBackend, revision) + saveSelection(normalizedBackend, revision, manualDebugOverride = false) + return normalizedBackend + } + + fun debugSelectableBackends(): List = + listOf(SyncBackendDefaults.hosted(), SyncBackendDefaults.nuvio()) + .filter { backend -> backend.isUsableClientConfig() } + + fun applyDebugBackendAfterLogout(backend: SyncBackendConfig): SyncBackendConfig? { + if (!AppFeaturePolicy.debugBackendSwitcherEnabled) return null + + val normalizedBackend = backend.normalized() + .takeIf { it.isUsableClientConfig() } + ?: return null + + saveSelection( + backend = normalizedBackend, + revision = DEBUG_MANUAL_REVISION, + manualDebugOverride = true, + ) return normalizedBackend } private fun saveSelection( backend: SyncBackendConfig, revision: String, + manualDebugOverride: Boolean = false, ) { val normalizedBackend = backend.normalized() val payload = json.encodeToString( StoredSyncBackendSelection( backendId = normalizedBackend.id, appliedRevision = revision, + manualDebugOverride = manualDebugOverride, ), ) SyncBackendStorage.saveSelectionPayload(payload) @@ -117,6 +153,9 @@ object SyncBackendRepository { selectedBackend = normalizedBackend, appliedRevision = revision, isLoaded = true, + isManualDebugOverride = manualDebugOverride, ) } + + private const val DEBUG_MANUAL_REVISION = "debug-manual" } diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/auth/AuthScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/auth/AuthScreen.kt index 11e3a9e65..0f84bacca 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/auth/AuthScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/auth/AuthScreen.kt @@ -69,6 +69,8 @@ import com.nuvio.app.core.auth.AuthRepository import com.nuvio.app.core.ui.nuvioOverlayGradientBrush import com.nuvio.app.core.ui.NuvioPrimaryButton import com.nuvio.app.core.ui.NuvioSurfaceCard +import com.nuvio.app.features.dev.DebugSyncBackendSwitch +import com.nuvio.app.features.dev.shouldShowDebugSyncBackendSwitch import kotlinx.coroutines.launch import nuvio.composeapp.generated.resources.Res import nuvio.composeapp.generated.resources.app_logo_wordmark @@ -157,6 +159,15 @@ fun AuthScreen( color = MaterialTheme.colorScheme.onSurfaceVariant, ) + if (shouldShowDebugSyncBackendSwitch()) { + Spacer(modifier = Modifier.height(24.dp)) + DebugSyncBackendSwitch( + modifier = Modifier.fillMaxWidth(), + requireConfirmation = false, + container = true, + ) + } + Spacer(modifier = Modifier.height(48.dp)) NuvioSurfaceCard { diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/dev/DebugSyncBackendSwitch.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/dev/DebugSyncBackendSwitch.kt new file mode 100644 index 000000000..7abe984b7 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/dev/DebugSyncBackendSwitch.kt @@ -0,0 +1,182 @@ +package com.nuvio.app.features.dev + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Switch +import androidx.compose.material3.SwitchDefaults +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.nuvio.app.core.auth.AuthRepository +import com.nuvio.app.core.build.AppFeaturePolicy +import com.nuvio.app.core.network.NetworkStatusRepository +import com.nuvio.app.core.network.SYNC_BACKEND_HOSTED_ID +import com.nuvio.app.core.network.SYNC_BACKEND_NUVIO_ID +import com.nuvio.app.core.network.SupabaseProvider +import com.nuvio.app.core.network.SyncBackendConfig +import com.nuvio.app.core.network.SyncBackendRepository +import com.nuvio.app.core.network.hasSameConnectionIdentity +import com.nuvio.app.core.ui.NuvioStatusModal +import com.nuvio.app.core.ui.NuvioTokens +import com.nuvio.app.core.ui.nuvio +import kotlinx.coroutines.launch +import nuvio.composeapp.generated.resources.Res +import nuvio.composeapp.generated.resources.action_cancel +import nuvio.composeapp.generated.resources.action_switch +import nuvio.composeapp.generated.resources.debug_backend_switch_confirm_message +import nuvio.composeapp.generated.resources.debug_backend_switch_confirm_title +import nuvio.composeapp.generated.resources.settings_account_sync_backend +import org.jetbrains.compose.resources.stringResource + +internal fun shouldShowDebugSyncBackendSwitch(): Boolean = + AppFeaturePolicy.debugBackendSwitcherEnabled && + SyncBackendRepository.debugSelectableBackends().size >= 2 + +@Composable +internal fun DebugSyncBackendSwitch( + modifier: Modifier = Modifier, + requireConfirmation: Boolean, + container: Boolean = false, +) { + if (!shouldShowDebugSyncBackendSwitch()) return + + val backendState by SyncBackendRepository.state.collectAsStateWithLifecycle() + val coroutineScope = rememberCoroutineScope() + val selectableBackends = remember { SyncBackendRepository.debugSelectableBackends() } + val hostedBackend = selectableBackends.firstOrNull { backend -> backend.id == SYNC_BACKEND_HOSTED_ID } + ?: return + val nuvioBackend = selectableBackends.firstOrNull { backend -> backend.id == SYNC_BACKEND_NUVIO_ID } + ?: return + val selectedBackend = backendState.selectedBackend + val nuvioSelected = selectedBackend.id == SYNC_BACKEND_NUVIO_ID + val targetBackend = if (nuvioSelected) hostedBackend else nuvioBackend + val tokens = MaterialTheme.nuvio + var pendingBackend by remember { mutableStateOf(null) } + var isSwitching by remember { mutableStateOf(false) } + + fun switchToBackend(backend: SyncBackendConfig) { + if (isSwitching || selectedBackend.hasSameConnectionIdentity(backend)) return + + isSwitching = true + coroutineScope.launch { + AuthRepository.resetForSyncBackendChange() + .onSuccess { + val appliedBackend = SyncBackendRepository.applyDebugBackendAfterLogout(backend) + if (appliedBackend != null) { + SupabaseProvider.rebuildClient() + NetworkStatusRepository.requestRefresh(force = true) + } + } + pendingBackend = null + isSwitching = false + } + } + + fun requestBackendSwitch(backend: SyncBackendConfig) { + if (selectedBackend.hasSameConnectionIdentity(backend)) return + + if (requireConfirmation) { + pendingBackend = backend + } else { + switchToBackend(backend) + } + } + + val content: @Composable () -> Unit = { + Row( + modifier = Modifier + .fillMaxWidth() + .clickable(enabled = !isSwitching) { requestBackendSwitch(targetBackend) } + .padding(horizontal = 16.dp, vertical = 14.dp), + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Column( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(3.dp), + ) { + Text( + text = stringResource(Res.string.settings_account_sync_backend), + style = MaterialTheme.typography.bodyMedium, + color = tokens.colors.textMuted, + ) + Text( + text = selectedBackend.displayName, + style = MaterialTheme.typography.bodyLarge, + color = tokens.colors.textPrimary, + fontWeight = FontWeight.Medium, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } + if (isSwitching) { + CircularProgressIndicator( + color = tokens.colors.accent, + strokeWidth = NuvioTokens.Border.medium, + ) + } else { + Switch( + checked = nuvioSelected, + onCheckedChange = { checked -> + requestBackendSwitch(if (checked) nuvioBackend else hostedBackend) + }, + colors = SwitchDefaults.colors( + checkedThumbColor = tokens.colors.onAccent, + checkedTrackColor = tokens.colors.accent, + uncheckedThumbColor = tokens.colors.textMuted, + uncheckedTrackColor = tokens.colors.borderDefault, + ), + ) + } + } + } + + if (container) { + Surface( + modifier = modifier.fillMaxWidth(), + color = tokens.colors.surface, + shape = tokens.shapes.compactCard, + border = BorderStroke(tokens.borders.hairline, tokens.colors.borderSubtle), + ) { + content() + } + } else { + Row(modifier = modifier.fillMaxWidth()) { + content() + } + } + + pendingBackend?.let { backend -> + NuvioStatusModal( + title = stringResource(Res.string.debug_backend_switch_confirm_title), + message = stringResource( + Res.string.debug_backend_switch_confirm_message, + backend.displayName, + ), + isVisible = true, + isBusy = isSwitching, + confirmText = stringResource(Res.string.action_switch), + dismissText = stringResource(Res.string.action_cancel), + onConfirm = { switchToBackend(backend) }, + onDismiss = { pendingBackend = null }, + ) + } +} diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/AccountSettingsPage.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/AccountSettingsPage.kt index 205140e42..9c875a37c 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/AccountSettingsPage.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/AccountSettingsPage.kt @@ -29,6 +29,8 @@ import com.nuvio.app.core.network.SyncBackendRepository import com.nuvio.app.core.ui.NuvioPrimaryButton import com.nuvio.app.core.ui.NuvioStatusModal import com.nuvio.app.core.ui.NuvioSurfaceCard +import com.nuvio.app.features.dev.DebugSyncBackendSwitch +import com.nuvio.app.features.dev.shouldShowDebugSyncBackendSwitch import kotlinx.coroutines.launch import nuvio.composeapp.generated.resources.Res import nuvio.composeapp.generated.resources.action_cancel @@ -100,11 +102,19 @@ private fun AccountSettingsBody( } } - Spacer(modifier = Modifier.height(8.dp)) - AccountInfoRow( - label = stringResource(Res.string.settings_account_sync_backend), - value = syncBackendLabel, - ) + if (shouldShowDebugSyncBackendSwitch()) { + Spacer(modifier = Modifier.height(8.dp)) + DebugSyncBackendSwitch( + modifier = Modifier.fillMaxWidth(), + requireConfirmation = true, + ) + } else { + Spacer(modifier = Modifier.height(8.dp)) + AccountInfoRow( + label = stringResource(Res.string.settings_account_sync_backend), + value = syncBackendLabel, + ) + } } NuvioPrimaryButton( diff --git a/composeApp/src/desktopMain/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.desktop.kt b/composeApp/src/desktopMain/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.desktop.kt index 2dda9682e..ebffde7e9 100644 --- a/composeApp/src/desktopMain/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.desktop.kt +++ b/composeApp/src/desktopMain/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.desktop.kt @@ -7,4 +7,5 @@ actual object AppFeaturePolicy { actual val heroTrailerPlaybackSupported: Boolean = false actual val inAppUpdaterEnabled: Boolean = false actual val imdbRatingLogoEnabled: Boolean = true + actual val debugBackendSwitcherEnabled: Boolean = AppBuildConfig.IS_DEBUG_BUILD } diff --git a/composeApp/src/iosAppStore/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.ios.kt b/composeApp/src/iosAppStore/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.ios.kt index 5f7b3114f..37660c9c2 100644 --- a/composeApp/src/iosAppStore/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.ios.kt +++ b/composeApp/src/iosAppStore/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.ios.kt @@ -7,4 +7,5 @@ actual object AppFeaturePolicy { actual val heroTrailerPlaybackSupported: Boolean = false actual val inAppUpdaterEnabled: Boolean = false actual val imdbRatingLogoEnabled: Boolean = false + actual val debugBackendSwitcherEnabled: Boolean = AppBuildConfig.IS_DEBUG_BUILD } diff --git a/composeApp/src/iosFull/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.ios.kt b/composeApp/src/iosFull/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.ios.kt index 670f8092a..2a17ddfd5 100644 --- a/composeApp/src/iosFull/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.ios.kt +++ b/composeApp/src/iosFull/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.ios.kt @@ -7,4 +7,5 @@ actual object AppFeaturePolicy { actual val heroTrailerPlaybackSupported: Boolean = false actual val inAppUpdaterEnabled: Boolean = false actual val imdbRatingLogoEnabled: Boolean = true + actual val debugBackendSwitcherEnabled: Boolean = AppBuildConfig.IS_DEBUG_BUILD }