From 0151d92b6a2dd7c1321739b78ec22d56423b4960 Mon Sep 17 00:00:00 2001 From: Antoine Jaury Date: Wed, 8 Jul 2026 14:20:32 +0200 Subject: [PATCH] new: extract WebView feature module --- feature/webview/build.gradle.kts | 50 +++++++++++++++++++ .../chombev/web/ui/PlatformWebView.android.kt | 0 .../web/ui/WebClientDelegatingExtLinks.kt | 0 .../ajaury/chombev/web/di/WebviewModule.kt | 10 ++++ .../bzh/ajaury/chombev/web/model/WebPage.kt | 15 ++++++ .../ajaury/chombev/web/ui/PlatformWebView.kt | 0 .../ajaury/chombev/web/ui/WebViewLoader.kt | 3 +- .../ajaury/chombev/web/ui/WebViewScreen.kt | 4 +- .../chombev/web/ui/WebViewUnavailable.kt | 3 +- .../chombev/web/ui/viewmodel/WebUiState.kt | 0 .../chombev/web/ui/viewmodel/WebViewModel.kt | 2 +- .../chombev/web/ui/PlatformWebView.ios.kt | 11 ++-- .../chombev/web/ui/PlatformWebView.js.kt | 0 .../chombev/web/ui/PlatformWebView.jvm.kt | 0 .../chombev/web/ui/PlatformWebView.wasmJs.kt | 0 settings.gradle.kts | 3 ++ shared/build.gradle.kts | 4 +- .../kotlin/bzh/ajaury/chombev/App.kt | 7 +-- .../kotlin/bzh/ajaury/chombev/di/Modules.kt | 4 +- .../chombev/navigation/MainBottomBar.kt | 5 +- .../bzh/ajaury/chombev/navigation/Route.kt | 1 + .../navigation/{WebPage.kt => WebPages.kt} | 19 +++---- .../bzh/ajaury/chombev/di/KoinModulesTest.kt | 7 ++- 23 files changed, 116 insertions(+), 32 deletions(-) create mode 100644 feature/webview/build.gradle.kts rename {shared => feature/webview}/src/androidMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.android.kt (100%) rename {shared => feature/webview}/src/androidMain/kotlin/bzh/ajaury/chombev/web/ui/WebClientDelegatingExtLinks.kt (100%) create mode 100644 feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/di/WebviewModule.kt create mode 100644 feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/model/WebPage.kt rename {shared => feature/webview}/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.kt (100%) rename {shared => feature/webview}/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/WebViewLoader.kt (94%) rename {shared => feature/webview}/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/WebViewScreen.kt (94%) rename {shared => feature/webview}/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/WebViewUnavailable.kt (96%) rename {shared => feature/webview}/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/viewmodel/WebUiState.kt (100%) rename {shared => feature/webview}/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/viewmodel/WebViewModel.kt (96%) rename {shared => feature/webview}/src/iosMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.ios.kt (88%) rename {shared => feature/webview}/src/jsMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.js.kt (100%) rename {shared => feature/webview}/src/jvmMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.jvm.kt (100%) rename {shared => feature/webview}/src/wasmJsMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.wasmJs.kt (100%) rename shared/src/commonMain/kotlin/bzh/ajaury/chombev/navigation/{WebPage.kt => WebPages.kt} (52%) diff --git a/feature/webview/build.gradle.kts b/feature/webview/build.gradle.kts new file mode 100644 index 0000000..091d58a --- /dev/null +++ b/feature/webview/build.gradle.kts @@ -0,0 +1,50 @@ +plugins { + id("gwenedeg.kmp.library") + id("gwenedeg.compose") + alias(libs.plugins.kotlinSerialization) +} + +kotlin { + androidLibrary { + namespace = "bzh.ajaury.chombev.webview" + } + + sourceSets { + androidMain.dependencies { + implementation(libs.compose.uiToolingPreview) + implementation(libs.androidx.webkit) + } + commonMain.dependencies { + // Core modules + implementation(projects.core.logging) + + // Reads the bundled offline page snapshots and web strings + implementation(projects.data.resources) + + // Serialization: WebPage is carried in the serializable navigation back stack + implementation(libs.kotlinx.serializationJson) + + // UI - Compose + implementation(libs.compose.runtime) + implementation(libs.compose.foundation) + implementation(libs.compose.material3) + implementation(libs.compose.ui) + implementation(libs.compose.uiToolingPreview) + implementation(libs.compose.components.resources) + + // Lifecycle + implementation(libs.lifecycle.viewmodelCompose) + implementation(libs.lifecycle.runtimeCompose) + + // DI + implementation(project.dependencies.platform(libs.koin.bom)) + implementation(libs.koin.core) + implementation(libs.koin.core.viewmodel) + implementation(libs.koin.compose.viewmodel) + } + } +} + +dependencies { + androidRuntimeClasspath(libs.compose.uiTooling) +} diff --git a/shared/src/androidMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.android.kt b/feature/webview/src/androidMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.android.kt similarity index 100% rename from shared/src/androidMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.android.kt rename to feature/webview/src/androidMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.android.kt diff --git a/shared/src/androidMain/kotlin/bzh/ajaury/chombev/web/ui/WebClientDelegatingExtLinks.kt b/feature/webview/src/androidMain/kotlin/bzh/ajaury/chombev/web/ui/WebClientDelegatingExtLinks.kt similarity index 100% rename from shared/src/androidMain/kotlin/bzh/ajaury/chombev/web/ui/WebClientDelegatingExtLinks.kt rename to feature/webview/src/androidMain/kotlin/bzh/ajaury/chombev/web/ui/WebClientDelegatingExtLinks.kt diff --git a/feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/di/WebviewModule.kt b/feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/di/WebviewModule.kt new file mode 100644 index 0000000..e2fb541 --- /dev/null +++ b/feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/di/WebviewModule.kt @@ -0,0 +1,10 @@ +package bzh.ajaury.chombev.web.di + +import bzh.ajaury.chombev.web.ui.viewmodel.WebViewModel +import org.koin.core.module.Module +import org.koin.core.module.dsl.viewModelOf +import org.koin.dsl.module + +val webviewModule: Module = module { + viewModelOf(::WebViewModel) +} diff --git a/feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/model/WebPage.kt b/feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/model/WebPage.kt new file mode 100644 index 0000000..5b3b9aa --- /dev/null +++ b/feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/model/WebPage.kt @@ -0,0 +1,15 @@ +package bzh.ajaury.chombev.web.model + +import kotlinx.serialization.Serializable + +/** + * Web page with a distant and local fallback. + * + * [offlineAsset] is the resource path of a bundled HTML snapshot shown when the online [url] cannot + * be reached, so the page still has content offline. + */ +@Serializable +data class WebPage( + val url: String, + val offlineAsset: String, +) diff --git a/shared/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.kt b/feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.kt similarity index 100% rename from shared/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.kt rename to feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.kt diff --git a/shared/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/WebViewLoader.kt b/feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/WebViewLoader.kt similarity index 94% rename from shared/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/WebViewLoader.kt rename to feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/WebViewLoader.kt index 1462ca4..fcee103 100644 --- a/shared/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/WebViewLoader.kt +++ b/feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/WebViewLoader.kt @@ -9,7 +9,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview -import bzh.ajaury.chombev.theme.ChomBevTheme /** * Full-surface loading overlay shown on top of the embedded web view while a page is loading. The @@ -29,7 +28,7 @@ internal fun WebViewLoader(modifier: Modifier = Modifier) { @Preview @Composable private fun WebViewLoaderPreview() { - ChomBevTheme { + MaterialTheme { WebViewLoader(modifier = Modifier.fillMaxSize()) } } diff --git a/shared/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/WebViewScreen.kt b/feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/WebViewScreen.kt similarity index 94% rename from shared/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/WebViewScreen.kt rename to feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/WebViewScreen.kt index 93f9bc6..3dad18c 100644 --- a/shared/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/WebViewScreen.kt +++ b/feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/WebViewScreen.kt @@ -12,7 +12,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle -import bzh.ajaury.chombev.navigation.WebPage +import bzh.ajaury.chombev.web.model.WebPage import bzh.ajaury.chombev.web.ui.viewmodel.WebUiState import bzh.ajaury.chombev.web.ui.viewmodel.WebViewModel import org.koin.compose.viewmodel.koinViewModel @@ -27,7 +27,7 @@ fun WebViewScreen( page: WebPage, contentPadding: PaddingValues, darkTheme: Boolean = isSystemInDarkTheme(), - viewModel: WebViewModel = koinViewModel(key = page.name) { parametersOf(page) }, + viewModel: WebViewModel = koinViewModel(key = page.url) { parametersOf(page) }, ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() diff --git a/shared/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/WebViewUnavailable.kt b/feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/WebViewUnavailable.kt similarity index 96% rename from shared/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/WebViewUnavailable.kt rename to feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/WebViewUnavailable.kt index eb0745a..7fbbe80 100644 --- a/shared/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/WebViewUnavailable.kt +++ b/feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/WebViewUnavailable.kt @@ -17,7 +17,6 @@ import androidx.compose.ui.unit.dp import bzh.ajaury.chombev.resources.generated.resources.Res import bzh.ajaury.chombev.resources.generated.resources.web_open_in_browser import bzh.ajaury.chombev.resources.generated.resources.web_unavailable_message -import bzh.ajaury.chombev.theme.ChomBevTheme import org.jetbrains.compose.resources.stringResource /** @@ -52,7 +51,7 @@ internal fun WebViewUnavailable( @Preview @Composable private fun WebViewUnavailablePreview() { - ChomBevTheme { + MaterialTheme { WebViewUnavailable(url = "https://ksk.bzh") } } diff --git a/shared/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/viewmodel/WebUiState.kt b/feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/viewmodel/WebUiState.kt similarity index 100% rename from shared/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/viewmodel/WebUiState.kt rename to feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/viewmodel/WebUiState.kt diff --git a/shared/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/viewmodel/WebViewModel.kt b/feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/viewmodel/WebViewModel.kt similarity index 96% rename from shared/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/viewmodel/WebViewModel.kt rename to feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/viewmodel/WebViewModel.kt index 0a3ca0c..f910935 100644 --- a/shared/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/viewmodel/WebViewModel.kt +++ b/feature/webview/src/commonMain/kotlin/bzh/ajaury/chombev/web/ui/viewmodel/WebViewModel.kt @@ -3,8 +3,8 @@ package bzh.ajaury.chombev.web.ui.viewmodel import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import bzh.ajaury.chombev.core.logging.domain.Logger -import bzh.ajaury.chombev.navigation.WebPage import bzh.ajaury.chombev.resources.domain.ResourceReader +import bzh.ajaury.chombev.web.model.WebPage import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow diff --git a/shared/src/iosMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.ios.kt b/feature/webview/src/iosMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.ios.kt similarity index 88% rename from shared/src/iosMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.ios.kt rename to feature/webview/src/iosMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.ios.kt index be80148..713f9b8 100644 --- a/shared/src/iosMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.ios.kt +++ b/feature/webview/src/iosMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.ios.kt @@ -6,6 +6,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.interop.UIKitView import kotlinx.cinterop.ExperimentalForeignApi import kotlinx.cinterop.ObjCSignatureOverride +import kotlinx.cinterop.readValue import platform.CoreGraphics.CGRectZero import platform.Foundation.NSError import platform.Foundation.NSURL @@ -41,7 +42,8 @@ actual fun PlatformWebView( frame = CGRectZero.readValue(), configuration = WKWebViewConfiguration(), ).apply { - navigationDelegate = navigationDelegate + // Qualify with `this` so it targets the web view's property, not the local val above. + this.navigationDelegate = navigationDelegate setOverrideUserInterfaceStyle(darkTheme.toInterfaceStyle()) NSURL.URLWithString(url)?.let { nsUrl -> loadRequest(NSURLRequest(uRL = nsUrl)) @@ -71,6 +73,10 @@ private class WebViewNavigationDelegate : private var showingOffline = false + // The four delegate callbacks below collapse to two Kotlin signatures — (WKWebView, WKNavigation?) + // and (WKWebView, WKNavigation?, NSError) — so every colliding override is marked + // @ObjCSignatureOverride. + @ObjCSignatureOverride override fun webView( webView: WKWebView, didStartProvisionalNavigation: WKNavigation?, @@ -78,7 +84,6 @@ private class WebViewNavigationDelegate : onLoadingStateChange(true) } - // Shares the (WKWebView, WKNavigation?) Kotlin signature with didStartProvisionalNavigation above. @ObjCSignatureOverride override fun webView( webView: WKWebView, @@ -87,6 +92,7 @@ private class WebViewNavigationDelegate : onLoadingStateChange(false) } + @ObjCSignatureOverride override fun webView( webView: WKWebView, didFailNavigation: WKNavigation?, @@ -95,7 +101,6 @@ private class WebViewNavigationDelegate : handleFailure(webView) } - // Shares the (WKWebView, WKNavigation?, NSError) Kotlin signature with didFailNavigation above. @ObjCSignatureOverride override fun webView( webView: WKWebView, diff --git a/shared/src/jsMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.js.kt b/feature/webview/src/jsMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.js.kt similarity index 100% rename from shared/src/jsMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.js.kt rename to feature/webview/src/jsMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.js.kt diff --git a/shared/src/jvmMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.jvm.kt b/feature/webview/src/jvmMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.jvm.kt similarity index 100% rename from shared/src/jvmMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.jvm.kt rename to feature/webview/src/jvmMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.jvm.kt diff --git a/shared/src/wasmJsMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.wasmJs.kt b/feature/webview/src/wasmJsMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.wasmJs.kt similarity index 100% rename from shared/src/wasmJsMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.wasmJs.kt rename to feature/webview/src/wasmJsMain/kotlin/bzh/ajaury/chombev/web/ui/PlatformWebView.wasmJs.kt diff --git a/settings.gradle.kts b/settings.gradle.kts index c1599d7..5e84c6c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -50,3 +50,6 @@ include(":data:preferences") include(":data:records") include(":data:resources") include(":data:subtitle") + +// Feature modules +include(":feature:webview") diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 19eab52..c3c1336 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -30,7 +30,6 @@ kotlin { sourceSets { androidMain.dependencies { implementation(libs.compose.uiToolingPreview) - implementation(libs.androidx.webkit) } commonMain.dependencies { // Core modules @@ -46,6 +45,9 @@ kotlin { implementation(projects.data.resources) implementation(projects.data.subtitle) + // Feature modules + implementation(projects.feature.webview) + implementation(libs.compose.runtime) implementation(libs.compose.foundation) implementation(libs.compose.material3) diff --git a/shared/src/commonMain/kotlin/bzh/ajaury/chombev/App.kt b/shared/src/commonMain/kotlin/bzh/ajaury/chombev/App.kt index 7e81105..34fc3fb 100644 --- a/shared/src/commonMain/kotlin/bzh/ajaury/chombev/App.kt +++ b/shared/src/commonMain/kotlin/bzh/ajaury/chombev/App.kt @@ -16,12 +16,13 @@ import bzh.ajaury.chombev.di.sharedModule import bzh.ajaury.chombev.navigation.MainBottomBar import bzh.ajaury.chombev.navigation.MainTopBar import bzh.ajaury.chombev.navigation.Route -import bzh.ajaury.chombev.navigation.WebPage +import bzh.ajaury.chombev.navigation.WebPages import bzh.ajaury.chombev.player.di.audioPlayerModule import bzh.ajaury.chombev.player.ui.PlayerScreen import bzh.ajaury.chombev.records.ui.RecordsScreen import bzh.ajaury.chombev.subtitle.di.subtitleModule import bzh.ajaury.chombev.theme.ChomBevTheme +import bzh.ajaury.chombev.web.model.WebPage import bzh.ajaury.chombev.web.ui.WebViewScreen import org.koin.compose.KoinApplication import org.koin.dsl.koinConfiguration @@ -81,8 +82,8 @@ fun App() { MainBottomBar( selectedPage = selectedPage, onRecordsClick = { selectMainTab(null) }, - onDeepenClick = { selectMainTab(WebPage.DEEPEN) }, - onAboutClick = { selectMainTab(WebPage.ABOUT) }, + onDeepenClick = { selectMainTab(WebPages.DEEPEN) }, + onAboutClick = { selectMainTab(WebPages.ABOUT) }, ) } }, diff --git a/shared/src/commonMain/kotlin/bzh/ajaury/chombev/di/Modules.kt b/shared/src/commonMain/kotlin/bzh/ajaury/chombev/di/Modules.kt index 9660eec..6f4dcfc 100644 --- a/shared/src/commonMain/kotlin/bzh/ajaury/chombev/di/Modules.kt +++ b/shared/src/commonMain/kotlin/bzh/ajaury/chombev/di/Modules.kt @@ -7,7 +7,7 @@ import bzh.ajaury.chombev.preferences.di.preferencesModule import bzh.ajaury.chombev.records.di.recordsModule import bzh.ajaury.chombev.records.ui.viewmodel.RecordsViewModel import bzh.ajaury.chombev.resources.di.resourcesModule -import bzh.ajaury.chombev.web.ui.viewmodel.WebViewModel +import bzh.ajaury.chombev.web.di.webviewModule import org.koin.core.module.dsl.viewModelOf import org.koin.dsl.module @@ -17,7 +17,7 @@ val sharedModule = module { includes(preferencesModule) includes(recordsModule) includes(resourcesModule) + includes(webviewModule) viewModelOf(::RecordsViewModel) viewModelOf(::PlayerViewModel) - viewModelOf(::WebViewModel) } diff --git a/shared/src/commonMain/kotlin/bzh/ajaury/chombev/navigation/MainBottomBar.kt b/shared/src/commonMain/kotlin/bzh/ajaury/chombev/navigation/MainBottomBar.kt index a3d4bd3..6a96886 100644 --- a/shared/src/commonMain/kotlin/bzh/ajaury/chombev/navigation/MainBottomBar.kt +++ b/shared/src/commonMain/kotlin/bzh/ajaury/chombev/navigation/MainBottomBar.kt @@ -16,6 +16,7 @@ import bzh.ajaury.chombev.resources.generated.resources.nav_about import bzh.ajaury.chombev.resources.generated.resources.nav_deepen import bzh.ajaury.chombev.resources.generated.resources.nav_records import bzh.ajaury.chombev.theme.ChomBevTheme +import bzh.ajaury.chombev.web.model.WebPage import org.jetbrains.compose.resources.stringResource /** @@ -40,13 +41,13 @@ fun MainBottomBar( label = { Text(text = stringResource(Res.string.nav_records)) }, ) NavigationBarItem( - selected = selectedPage == WebPage.DEEPEN, + selected = selectedPage == WebPages.DEEPEN, onClick = onDeepenClick, icon = { Icon(imageVector = Icons.Filled.School, contentDescription = null) }, label = { Text(text = stringResource(Res.string.nav_deepen)) }, ) NavigationBarItem( - selected = selectedPage == WebPage.ABOUT, + selected = selectedPage == WebPages.ABOUT, onClick = onAboutClick, icon = { Icon(imageVector = Icons.Outlined.Info, contentDescription = null) }, label = { Text(text = stringResource(Res.string.nav_about)) }, diff --git a/shared/src/commonMain/kotlin/bzh/ajaury/chombev/navigation/Route.kt b/shared/src/commonMain/kotlin/bzh/ajaury/chombev/navigation/Route.kt index deb175f..1c9058c 100644 --- a/shared/src/commonMain/kotlin/bzh/ajaury/chombev/navigation/Route.kt +++ b/shared/src/commonMain/kotlin/bzh/ajaury/chombev/navigation/Route.kt @@ -1,6 +1,7 @@ package bzh.ajaury.chombev.navigation import androidx.navigation3.runtime.NavKey +import bzh.ajaury.chombev.web.model.WebPage import kotlinx.serialization.Serializable @Serializable diff --git a/shared/src/commonMain/kotlin/bzh/ajaury/chombev/navigation/WebPage.kt b/shared/src/commonMain/kotlin/bzh/ajaury/chombev/navigation/WebPages.kt similarity index 52% rename from shared/src/commonMain/kotlin/bzh/ajaury/chombev/navigation/WebPage.kt rename to shared/src/commonMain/kotlin/bzh/ajaury/chombev/navigation/WebPages.kt index 8ae91cc..9aa12f6 100644 --- a/shared/src/commonMain/kotlin/bzh/ajaury/chombev/navigation/WebPage.kt +++ b/shared/src/commonMain/kotlin/bzh/ajaury/chombev/navigation/WebPages.kt @@ -1,24 +1,17 @@ package bzh.ajaury.chombev.navigation -import kotlinx.serialization.Serializable +import bzh.ajaury.chombev.web.model.WebPage /** * Web destinations reachable from the main bottom navigation bar and shown inside the app. - * - * [offlineAsset] is the resource path of a bundled HTML snapshot shown when the online [url] cannot - * be reached, so the page still has content offline. */ -@Serializable -enum class WebPage( - val url: String, - val offlineAsset: String, -) { - DEEPEN( +object WebPages { + val DEEPEN = WebPage( url = "https://ksk.bzh/fr/chom-bev-approfondir/", offlineAsset = "files/offline_deepen.html", - ), - ABOUT( + ) + val ABOUT = WebPage( url = "https://ksk.bzh/fr/chom-bev-a-propos/", offlineAsset = "files/offline_about.html", - ), + ) } diff --git a/shared/src/jvmTest/kotlin/bzh/ajaury/chombev/di/KoinModulesTest.kt b/shared/src/jvmTest/kotlin/bzh/ajaury/chombev/di/KoinModulesTest.kt index a317d1d..3a0cc09 100644 --- a/shared/src/jvmTest/kotlin/bzh/ajaury/chombev/di/KoinModulesTest.kt +++ b/shared/src/jvmTest/kotlin/bzh/ajaury/chombev/di/KoinModulesTest.kt @@ -2,6 +2,7 @@ package bzh.ajaury.chombev.di import bzh.ajaury.chombev.appModule import bzh.ajaury.chombev.player.di.audioPlayerModule +import bzh.ajaury.chombev.web.model.WebPage import org.koin.core.annotation.KoinExperimentalAPI import org.koin.test.verify.verify import kotlin.test.Test @@ -18,6 +19,10 @@ class KoinModulesTest { @OptIn(KoinExperimentalAPI::class) @Test fun koinConfigurationIsValid() { - appModule.verify() + // WebPage is supplied at call time via parametersOf (WebViewModel), so declare it as a known + // extra type rather than a resolvable definition. + appModule.verify( + extraTypes = listOf(WebPage::class), + ) } }