diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index ee3fdcab..fa979460 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -161,7 +161,7 @@ kotlin { // implementation(project(":lib:chip-text-field")) // webview - api(libs.compose.webview.multiplatform) + implementation(libs.wvbridge.core) // https://coil-kt.github.io/coil/changelog/ implementation(dependencies.platform(libs.coil.bom)) @@ -208,6 +208,20 @@ kotlin { val desktopMain by getting desktopMain.dependencies { implementation(compose.desktop.currentOs) + implementation( + when { + System.getProperty("os.name").startsWith("Windows") -> libs.wvbridge.platform.windows + + System.getProperty("os.name").startsWith("Linux") -> libs.wvbridge.platform.linux + + System.getProperty("os.name").startsWith("Mac") && System.getProperty("os.arch") in setOf("aarch64", "arm64") -> libs.wvbridge.platform.macos + + else -> error( + "Unsupported desktop runtime for wvbridge: " + + "${System.getProperty("os.name")} ${System.getProperty("os.arch")}", + ) + }, + ) implementation(libs.kotlinx.coroutines.swing) implementation(libs.ktor.client.okhttp) implementation(libs.ktor.client.java) diff --git a/composeApp/src/androidMain/kotlin/top/kagg886/pmf/ui/route/login/v2/LoginScreen.android.kt b/composeApp/src/androidMain/kotlin/top/kagg886/pmf/ui/route/login/v2/LoginScreen.android.kt index 19f2fdc5..6fd04ab0 100644 --- a/composeApp/src/androidMain/kotlin/top/kagg886/pmf/ui/route/login/v2/LoginScreen.android.kt +++ b/composeApp/src/androidMain/kotlin/top/kagg886/pmf/ui/route/login/v2/LoginScreen.android.kt @@ -1,18 +1,5 @@ package top.kagg886.pmf.ui.route.login.v2 -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import io.github.kdroidfilter.webview.web.WebView -import io.github.kdroidfilter.webview.web.WebViewNavigator -import io.github.kdroidfilter.webview.web.WebViewState +import top.kagg886.wvbridge.config.WebViewPlatformConfig -@Composable -internal actual fun WebviewPlatformInstall() { -} - -@Composable -internal actual fun PlatformWebView( - state: WebViewState, - modifier: Modifier, - navigator: WebViewNavigator, -) = WebView(state, modifier, navigator) +actual fun defaultPlatformConfig(): WebViewPlatformConfig = WebViewPlatformConfig() diff --git a/composeApp/src/commonMain/kotlin/top/kagg886/pmf/App.kt b/composeApp/src/commonMain/kotlin/top/kagg886/pmf/App.kt index 1e494075..5a5beb42 100644 --- a/composeApp/src/commonMain/kotlin/top/kagg886/pmf/App.kt +++ b/composeApp/src/commonMain/kotlin/top/kagg886/pmf/App.kt @@ -196,6 +196,7 @@ import top.kagg886.pmf.util.initFileLogger import top.kagg886.pmf.util.logger import top.kagg886.pmf.util.stringResource import top.kagg886.pmf.util.toColorScheme +import top.kagg886.wvbridge.util.LoggerReceiver val LocalNavBackStack = compositionLocalOf> { error("not provided") @@ -613,6 +614,39 @@ fun setupEnv() { - Platform: $currentPlatform """.trimIndent(), ) + + LoggerReceiver.register { level, tag, message -> + // enum class Severity { + // Verbose, + // Debug, + // Info, + // Warn, + // Error, + // Assert, + // } + +// public enum class Level { +// /** Detailed diagnostic output. */ +// VERBOSE, +// +// /** Debug information useful during development. */ +// DEBUG, +// +// /** General informational messages. */ +// INFO, +// +// /** Potentially problematic state that does not stop execution. */ +// WARN, +// +// /** Error state reported by the runtime. */ +// ERROR, +// +// /** Assertion or unrecoverable failure state. */ +// ASSERT +// } + + co.touchlab.kermit.Logger.log(Severity.valueOf(level.name.lowercase().replaceFirstChar { it.uppercase() }), tag, null, message) + } } expect fun openBrowser(link: String) diff --git a/composeApp/src/commonMain/kotlin/top/kagg886/pmf/ui/component/icon/Help.kt b/composeApp/src/commonMain/kotlin/top/kagg886/pmf/ui/component/icon/Help.kt new file mode 100644 index 00000000..82f3e976 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/top/kagg886/pmf/ui/component/icon/Help.kt @@ -0,0 +1,337 @@ +package top.kagg886.pmf.ui.component.icon + +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.unit.dp + +/** + * ================================================ + * Author: iveou + * Created on: 2026/7/2 10:29 + * ================================================ + */ + +val Help: ImageVector by lazy { + ImageVector.Builder( + name = "Help", + defaultWidth = 24.0.dp, + defaultHeight = 24.0.dp, + viewportWidth = 960.0f, + viewportHeight = 960.0f, + ).apply { + // M513.5 -254.5 Q528 -269 528 -290 t-14.5 -35.5 Q499 -340 478 -340 t-35.5 14.5 Q428 -311 428 -290 t14.5 35.5 Q457 -240 478 -240 t35.5 -14.5Z M442 -394 h74 q0 -33 7.5 -52 t42.5 -52 q26 -26 41 -49.5 t15 -56.5 q0 -56 -41 -86 t-97 -30 q-57 0 -92.5 30 T342 -618 l66 26 q5 -18 22.5 -39 t53.5 -21 q32 0 48 17.5 t16 38.5 q0 20 -12 37.5 T506 -526 q-44 39 -54 59 t-10 73Z m38 314 q-83 0 -156 -31.5 T197 -197 q-54 -54 -85.5 -127 T80 -480 q0 -83 31.5 -156 T197 -763 q54 -54 127 -85.5 T480 -880 q83 0 156 31.5 T763 -763 q54 54 85.5 127 T880 -480 q0 83 -31.5 156 T763 -197 q-54 54 -127 85.5 T480 -80Z m0 -80 q134 0 227 -93 t93 -227 q0 -134 -93 -227 t-227 -93 q-134 0 -227 93 t-93 227 q0 134 93 227 t227 93Z m0 -320Z + path( + fill = SolidColor(Color(0xFF1F1F1F)), + ) { + // M 513.5 705.5 + moveTo(x = 513.5f, y = 705.5f) + // Q 528 691 528 670 + quadTo( + x1 = 528.0f, + y1 = 691.0f, + x2 = 528.0f, + y2 = 670.0f, + ) + // t -14.5 -35.5 + reflectiveQuadToRelative( + dx1 = -14.5f, + dy1 = -35.5f, + ) + // Q 499 620 478 620 + quadTo( + x1 = 499.0f, + y1 = 620.0f, + x2 = 478.0f, + y2 = 620.0f, + ) + // t -35.5 14.5 + reflectiveQuadToRelative( + dx1 = -35.5f, + dy1 = 14.5f, + ) + // Q 428 649 428 670 + quadTo( + x1 = 428.0f, + y1 = 649.0f, + x2 = 428.0f, + y2 = 670.0f, + ) + // t 14.5 35.5 + reflectiveQuadToRelative( + dx1 = 14.5f, + dy1 = 35.5f, + ) + // Q 457 720 478 720 + quadTo( + x1 = 457.0f, + y1 = 720.0f, + x2 = 478.0f, + y2 = 720.0f, + ) + // t 35.5 -14.5z + reflectiveQuadToRelative( + dx1 = 35.5f, + dy1 = -14.5f, + ) + close() + // M 442 566 + moveTo(x = 442.0f, y = 566.0f) + // l 74 0 + lineToRelative(dx = 74.0f, dy = 0.0f) + // q 0 -33 7.5 -52 + quadToRelative( + dx1 = 0.0f, + dy1 = -33.0f, + dx2 = 7.5f, + dy2 = -52.0f, + ) + // t 42.5 -52 + reflectiveQuadToRelative( + dx1 = 42.5f, + dy1 = -52.0f, + ) + // q 26 -26 41 -49.5 + quadToRelative( + dx1 = 26.0f, + dy1 = -26.0f, + dx2 = 41.0f, + dy2 = -49.5f, + ) + // t 15 -56.5 + reflectiveQuadToRelative( + dx1 = 15.0f, + dy1 = -56.5f, + ) + // q 0 -56 -41 -86 + quadToRelative( + dx1 = 0.0f, + dy1 = -56.0f, + dx2 = -41.0f, + dy2 = -86.0f, + ) + // t -97 -30 + reflectiveQuadToRelative( + dx1 = -97.0f, + dy1 = -30.0f, + ) + // q -57 0 -92.5 30 + quadToRelative( + dx1 = -57.0f, + dy1 = 0.0f, + dx2 = -92.5f, + dy2 = 30.0f, + ) + // T 342 342 + reflectiveQuadTo( + x1 = 342.0f, + y1 = 342.0f, + ) + // l 66 26 + lineToRelative(dx = 66.0f, dy = 26.0f) + // q 5 -18 22.5 -39 + quadToRelative( + dx1 = 5.0f, + dy1 = -18.0f, + dx2 = 22.5f, + dy2 = -39.0f, + ) + // t 53.5 -21 + reflectiveQuadToRelative( + dx1 = 53.5f, + dy1 = -21.0f, + ) + // q 32 0 48 17.5 + quadToRelative( + dx1 = 32.0f, + dy1 = 0.0f, + dx2 = 48.0f, + dy2 = 17.5f, + ) + // t 16 38.5 + reflectiveQuadToRelative( + dx1 = 16.0f, + dy1 = 38.5f, + ) + // q 0 20 -12 37.5 + quadToRelative( + dx1 = 0.0f, + dy1 = 20.0f, + dx2 = -12.0f, + dy2 = 37.5f, + ) + // T 506 434 + reflectiveQuadTo( + x1 = 506.0f, + y1 = 434.0f, + ) + // q -44 39 -54 59 + quadToRelative( + dx1 = -44.0f, + dy1 = 39.0f, + dx2 = -54.0f, + dy2 = 59.0f, + ) + // t -10 73z + reflectiveQuadToRelative( + dx1 = -10.0f, + dy1 = 73.0f, + ) + close() + // m 38 314 + moveToRelative(dx = 38.0f, dy = 314.0f) + // q -83 0 -156 -31.5 + quadToRelative( + dx1 = -83.0f, + dy1 = 0.0f, + dx2 = -156.0f, + dy2 = -31.5f, + ) + // T 197 763 + reflectiveQuadTo( + x1 = 197.0f, + y1 = 763.0f, + ) + // q -54 -54 -85.5 -127 + quadToRelative( + dx1 = -54.0f, + dy1 = -54.0f, + dx2 = -85.5f, + dy2 = -127.0f, + ) + // T 80 480 + reflectiveQuadTo( + x1 = 80.0f, + y1 = 480.0f, + ) + // q 0 -83 31.5 -156 + quadToRelative( + dx1 = 0.0f, + dy1 = -83.0f, + dx2 = 31.5f, + dy2 = -156.0f, + ) + // T 197 197 + reflectiveQuadTo( + x1 = 197.0f, + y1 = 197.0f, + ) + // q 54 -54 127 -85.5 + quadToRelative( + dx1 = 54.0f, + dy1 = -54.0f, + dx2 = 127.0f, + dy2 = -85.5f, + ) + // T 480 80 + reflectiveQuadTo( + x1 = 480.0f, + y1 = 80.0f, + ) + // q 83 0 156 31.5 + quadToRelative( + dx1 = 83.0f, + dy1 = 0.0f, + dx2 = 156.0f, + dy2 = 31.5f, + ) + // T 763 197 + reflectiveQuadTo( + x1 = 763.0f, + y1 = 197.0f, + ) + // q 54 54 85.5 127 + quadToRelative( + dx1 = 54.0f, + dy1 = 54.0f, + dx2 = 85.5f, + dy2 = 127.0f, + ) + // T 880 480 + reflectiveQuadTo( + x1 = 880.0f, + y1 = 480.0f, + ) + // q 0 83 -31.5 156 + quadToRelative( + dx1 = 0.0f, + dy1 = 83.0f, + dx2 = -31.5f, + dy2 = 156.0f, + ) + // T 763 763 + reflectiveQuadTo( + x1 = 763.0f, + y1 = 763.0f, + ) + // q -54 54 -127 85.5 + quadToRelative( + dx1 = -54.0f, + dy1 = 54.0f, + dx2 = -127.0f, + dy2 = 85.5f, + ) + // T 480 880z + reflectiveQuadTo( + x1 = 480.0f, + y1 = 880.0f, + ) + close() + // m 0 -80 + moveToRelative(dx = 0.0f, dy = -80.0f) + // q 134 0 227 -93 + quadToRelative( + dx1 = 134.0f, + dy1 = 0.0f, + dx2 = 227.0f, + dy2 = -93.0f, + ) + // t 93 -227 + reflectiveQuadToRelative( + dx1 = 93.0f, + dy1 = -227.0f, + ) + // q 0 -134 -93 -227 + quadToRelative( + dx1 = 0.0f, + dy1 = -134.0f, + dx2 = -93.0f, + dy2 = -227.0f, + ) + // t -227 -93 + reflectiveQuadToRelative( + dx1 = -227.0f, + dy1 = -93.0f, + ) + // q -134 0 -227 93 + quadToRelative( + dx1 = -134.0f, + dy1 = 0.0f, + dx2 = -227.0f, + dy2 = 93.0f, + ) + // t -93 227 + reflectiveQuadToRelative( + dx1 = -93.0f, + dy1 = 227.0f, + ) + // q 0 134 93 227 + quadToRelative( + dx1 = 0.0f, + dy1 = 134.0f, + dx2 = 93.0f, + dy2 = 227.0f, + ) + // t 227 93z + reflectiveQuadToRelative( + dx1 = 227.0f, + dy1 = 93.0f, + ) + close() + // m 0 -320z + moveToRelative(dx = 0.0f, dy = -320.0f) + close() + } + }.build() +} diff --git a/composeApp/src/commonMain/kotlin/top/kagg886/pmf/ui/route/login/v2/LoginScreen.kt b/composeApp/src/commonMain/kotlin/top/kagg886/pmf/ui/route/login/v2/LoginScreen.kt index 429b3fa7..be2a8f5b 100644 --- a/composeApp/src/commonMain/kotlin/top/kagg886/pmf/ui/route/login/v2/LoginScreen.kt +++ b/composeApp/src/commonMain/kotlin/top/kagg886/pmf/ui/route/login/v2/LoginScreen.kt @@ -4,34 +4,13 @@ import androidx.compose.animation.AnimatedContent import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Button -import androidx.compose.material3.LinearProgressIndicator -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.material3.TextField -import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.* +import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalUriHandler import androidx.navigation3.runtime.NavKey -import co.touchlab.kermit.Severity -import io.github.kdroidfilter.webview.request.RequestInterceptor -import io.github.kdroidfilter.webview.request.WebRequest -import io.github.kdroidfilter.webview.request.WebRequestInterceptResult -import io.github.kdroidfilter.webview.util.KLogSeverity -import io.github.kdroidfilter.webview.util.KLogSeverity.* -import io.github.kdroidfilter.webview.util.KLogger -import io.github.kdroidfilter.webview.web.LoadingState -import io.github.kdroidfilter.webview.web.WebViewNavigator -import io.github.kdroidfilter.webview.web.WebViewState -import io.github.kdroidfilter.webview.web.rememberWebViewNavigator -import io.github.kdroidfilter.webview.web.rememberWebViewState import kotlinx.serialization.Serializable import org.koin.compose.viewmodel.koinViewModel import org.orbitmvi.orbit.compose.collectAsState @@ -41,12 +20,20 @@ import top.kagg886.pmf.LocalNavBackStack import top.kagg886.pmf.LocalSnackBarHost import top.kagg886.pmf.backend.PlatformEngine import top.kagg886.pmf.backend.pixiv.PixivConfig +import top.kagg886.pmf.openBrowser import top.kagg886.pmf.res.* import top.kagg886.pmf.ui.component.Loading import top.kagg886.pmf.ui.component.guide.GuideScaffold +import top.kagg886.pmf.ui.component.icon.Help import top.kagg886.pmf.ui.route.main.recommend.RecommendRoute import top.kagg886.pmf.util.logger import top.kagg886.pmf.util.stringResource +import top.kagg886.wvbridge.LoadingState +import top.kagg886.wvbridge.WebView +import top.kagg886.wvbridge.config.WebViewConfig +import top.kagg886.wvbridge.config.WebViewPlatformConfig +import top.kagg886.wvbridge.interceptor.InterceptorHandler +import top.kagg886.wvbridge.rememberWebViewController @Serializable data class LoginRoute(val clearOldSession: Boolean = false) : NavKey { @@ -125,7 +112,9 @@ private fun WaitLoginContent(a: LoginViewState, model: LoginScreenViewModel) { mutableStateOf("") } AlertDialog( - onDismissRequest = {}, + onDismissRequest = { + model.clearLoginType() + }, confirmButton = { Button( onClick = { @@ -183,91 +172,64 @@ private fun WaitLoginContent(a: LoginViewState, model: LoginScreenViewModel) { } } +expect fun defaultPlatformConfig(): WebViewPlatformConfig + @Composable private fun WebViewLogin(model: LoginScreenViewModel) { - WebviewPlatformInstall() - val auth = remember { PixivAccountFactory.newAccount(PlatformEngine) } - val state = rememberWebViewState(auth.url) { - customUserAgentString = "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Mobile Safari/537.36 EdgA/135.0.0.0" - } - val webNav = rememberWebViewNavigator( - requestInterceptor = object : RequestInterceptor { - override fun onInterceptUrlRequest( - request: WebRequest, - navigator: WebViewNavigator, - ): WebRequestInterceptResult { - if (request.url.startsWith("pixiv://")) { - model.challengePixivLoginUrl(auth, request.url) - return WebRequestInterceptResult.Reject - } - return WebRequestInterceptResult.Allow - } - }, + val controller = rememberWebViewController( + url = auth.url, + config = WebViewConfig( + userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.7727.56 Safari/537.36", + platform = defaultPlatformConfig(), + ), ) - - DisposableEffect(Unit) { - val log = object : KLogger { - - override fun setMinSeverity(severity: KLogSeverity) = Unit - - override fun log( - severity: KLogSeverity, - tag: String?, - t: Throwable?, - msg: () -> String, - ) { - if (severity == None) return - logger.withTag(tag ?: "ComposeNativeWebView").logBlock( - severity = when (severity) { - Verbose -> Severity.Verbose - Debug -> Severity.Debug - Info -> Severity.Info - Warn -> Severity.Warn - Error -> Severity.Error - Assert -> Severity.Assert - None -> error("Unreachable") - }, - tag = tag ?: "ComposeNativeWebView", - throwable = t, - message = msg, - ) + DisposableEffect(controller) { + val registry = controller.interceptor.registerNavigationInterceptor auth@{ url -> + logger.i("webview intercept url: $url") + if (url.startsWith("pixiv://")) { + model.challengePixivLoginUrl(auth, url) + return@auth InterceptorHandler.Result.Rejected } + return@auth InterceptorHandler.Result.Allowed } - - KLogger.addLogger(log) - KLogger.setMinSeverity(Verbose) - onDispose { - KLogger.removeLogger(log) + registry.close() } } - val progress = remember(state.loadingState) { - when (state.loadingState) { - is LoadingState.Loading -> (state.loadingState as LoadingState.Loading).progress - else -> -1.0f + val progress by remember { + derivedStateOf { + (controller.loadingState as? LoadingState.Loading)?.progress ?: -1f } } Column { + TopAppBar( + title = { + Text(stringResource(Res.string.use_browser_login)) + }, + navigationIcon = { + IconButton(onClick = { model.clearLoginType() }) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, null) + } + }, + actions = { + IconButton( + onClick = { + openBrowser("https://pmf.kagg886.top/docs/main/login.html#%E4%BD%BF%E7%94%A8%E5%B5%8C%E5%85%A5%E5%BC%8F%E6%B5%8F%E8%A7%88%E5%99%A8%E7%99%BB%E5%BD%95") + }, + ) { + Icon(Help, null) + } + }, + ) if (progress in 0.0f..<1.0f) { LinearProgressIndicator(progress = { progress }, modifier = Modifier.fillMaxWidth()) } - PlatformWebView( + WebView( + controller = controller, modifier = Modifier.fillMaxSize(), - state = state, - navigator = webNav, ) } } - -@Composable -internal expect fun WebviewPlatformInstall() - -@Composable -internal expect fun PlatformWebView( - state: WebViewState, - modifier: Modifier = Modifier, - navigator: WebViewNavigator = rememberWebViewNavigator(), -) diff --git a/composeApp/src/commonMain/kotlin/top/kagg886/pmf/ui/route/login/v2/LoginScreenViewModel.kt b/composeApp/src/commonMain/kotlin/top/kagg886/pmf/ui/route/login/v2/LoginScreenViewModel.kt index b58c7068..8072f493 100644 --- a/composeApp/src/commonMain/kotlin/top/kagg886/pmf/ui/route/login/v2/LoginScreenViewModel.kt +++ b/composeApp/src/commonMain/kotlin/top/kagg886/pmf/ui/route/login/v2/LoginScreenViewModel.kt @@ -40,6 +40,12 @@ class LoginScreenViewModel : ContainerHost, Vie } } + fun clearLoginType() = intent { + reduce { + LoginViewState.WaitChooseLogin + } + } + fun challengeRefreshToken(token: String) = intent { val checkingToken = getString(Res.string.checking_token) reduce { diff --git a/composeApp/src/desktopMain/kotlin/top/kagg886/pmf/main.kt b/composeApp/src/desktopMain/kotlin/top/kagg886/pmf/main.kt index 5d694070..e598130b 100644 --- a/composeApp/src/desktopMain/kotlin/top/kagg886/pmf/main.kt +++ b/composeApp/src/desktopMain/kotlin/top/kagg886/pmf/main.kt @@ -40,7 +40,6 @@ import top.kagg886.pmf.util.writeString fun launch(start: () -> NavKey) { setupEnv() stdErrToLogger() - System.setProperty("composewebview.wry.log", "true") SingletonImageLoader.setSafe { ImageLoader.Builder(PlatformContext.INSTANCE).applyCustomConfig().build() } diff --git a/composeApp/src/desktopMain/kotlin/top/kagg886/pmf/ui/route/login/v2/LoginScreen.desktop.kt b/composeApp/src/desktopMain/kotlin/top/kagg886/pmf/ui/route/login/v2/LoginScreen.desktop.kt index c8140054..49c4f777 100644 --- a/composeApp/src/desktopMain/kotlin/top/kagg886/pmf/ui/route/login/v2/LoginScreen.desktop.kt +++ b/composeApp/src/desktopMain/kotlin/top/kagg886/pmf/ui/route/login/v2/LoginScreen.desktop.kt @@ -1,64 +1,19 @@ package top.kagg886.pmf.ui.route.login.v2 -import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.toArgb -import co.touchlab.kermit.Logger -import io.github.kdroidfilter.webview.web.* -import io.github.kdroidfilter.webview.wry.Rgba -import io.github.kdroidfilter.webview.wry.WryWebViewPanel -import io.github.kdroidfilter.webview.wry.setLogEnabled -import top.kagg886.pmf.util.logger +import top.kagg886.pmf.backend.cachePath +import top.kagg886.pmf.util.absolutePath +import top.kagg886.wvbridge.config.WebViewPlatformConfig -@Composable -internal actual fun PlatformWebView( - state: WebViewState, - modifier: Modifier, - navigator: WebViewNavigator, -) = WebView( - state, - modifier, - navigator, - factory = ::defaultWebViewFactory, -) - -fun defaultWebViewFactory(param: WebViewFactoryParam): NativeWebView = when (val content = param.state.content) { - is WebContent.Url -> NativeWebView( - initialUrl = content.url, - bridgeLogger = { Logger.withTag("ComposeNativeLogger - Panel").d(it) }, - backgroundColor = Color.Transparent.toRgba(), - ) - - else -> NativeWebView("about:blank", backgroundColor = Color.Transparent.toRgba()) +private val webviewPath by lazy { + cachePath.resolve("webview").absolutePath() } -@Composable -internal actual fun WebviewPlatformInstall() { - DisposableEffect(Unit) { - val local = WryWebViewPanel.NATIVE_LOGGER - val log = logger.withTag("ComposeNativeLogger - Native") - - setLogEnabled(true) - WryWebViewPanel.LOG_ENABLED = true - WryWebViewPanel.NATIVE_LOGGER = { - log.d(it) - } - - onDispose { - setLogEnabled(false) - WryWebViewPanel.LOG_ENABLED = false - WryWebViewPanel.NATIVE_LOGGER = local - } - } -} - -private fun Color.toRgba(): Rgba { - val argb: Int = this.toArgb() // 0xAARRGGBB (sRGB) - val a: UByte = ((argb ushr 24) and 0xFF).toUByte() - val r: UByte = ((argb ushr 16) and 0xFF).toUByte() - val g: UByte = ((argb ushr 8) and 0xFF).toUByte() - val b: UByte = (argb and 0xFF).toUByte() - return Rgba(r = r, g = g, b = b, a = a) -} +actual fun defaultPlatformConfig(): WebViewPlatformConfig = WebViewPlatformConfig( + windowSetting = WebViewPlatformConfig.Windows( + dataDir = webviewPath.toString(), + ), + linuxSetting = WebViewPlatformConfig.Linux( + dataDir = webviewPath.resolve("data").toString(), + cacheDir = webviewPath.resolve("cache").toString(), + ), +) diff --git a/composeApp/src/iosMain/kotlin/top/kagg886/pmf/ui/route/login/v2/LoginScreen.ios.kt b/composeApp/src/iosMain/kotlin/top/kagg886/pmf/ui/route/login/v2/LoginScreen.ios.kt index 19f2fdc5..6fd04ab0 100644 --- a/composeApp/src/iosMain/kotlin/top/kagg886/pmf/ui/route/login/v2/LoginScreen.ios.kt +++ b/composeApp/src/iosMain/kotlin/top/kagg886/pmf/ui/route/login/v2/LoginScreen.ios.kt @@ -1,18 +1,5 @@ package top.kagg886.pmf.ui.route.login.v2 -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import io.github.kdroidfilter.webview.web.WebView -import io.github.kdroidfilter.webview.web.WebViewNavigator -import io.github.kdroidfilter.webview.web.WebViewState +import top.kagg886.wvbridge.config.WebViewPlatformConfig -@Composable -internal actual fun WebviewPlatformInstall() { -} - -@Composable -internal actual fun PlatformWebView( - state: WebViewState, - modifier: Modifier, - navigator: WebViewNavigator, -) = WebView(state, modifier, navigator) +actual fun defaultPlatformConfig(): WebViewPlatformConfig = WebViewPlatformConfig() diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 66a03d26..a95f201d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,7 +9,6 @@ coil = "3.4.0" chip-textfield = "0.7.2-alpha01" compose-multiplatform = "1.10.3" compose-settings = "3.1.0" -composeWebviewMultiplatform = "1.0.0-beta-02" filekitCompose = "0.13.0" kermit = "2.1.0" koin = "4.2.1" @@ -29,6 +28,8 @@ room = "3.0.0-alpha03" sqliteBundled = "2.6.2" telephoto = "0.19.0" versionCatalogUpdate = "1.1.0" +wvbridge-common = "0.0.5" +wvbridge-platform = "0.0.4" [libraries] aboutlibraries-compose-m3 = { module = "com.mikepenz:aboutlibraries-compose-m3", version.ref = "aboutlibraries" } @@ -58,7 +59,6 @@ compose-settings-extended = { module = "com.github.alorma.compose-settings:ui-ti compose-settings-ui = { module = "com.github.alorma.compose-settings:ui-tiles", version.ref = "compose-settings" } compose-ui = { module = "org.jetbrains.compose.ui:ui", version.ref = "compose-multiplatform" } compose-ui-tooling-preview = { module = "org.jetbrains.compose.ui:ui-tooling-preview", version.ref = "compose-multiplatform" } -compose-webview-multiplatform = { module = "io.github.kdroidfilter:composewebview", version.ref = "composeWebviewMultiplatform" } filekit-compose = { module = "io.github.vinceglb:filekit-dialogs-compose", version.ref = "filekitCompose" } filekit-core = { module = "io.github.vinceglb:filekit-core", version.ref = "filekitCompose" } kermit = { module = "co.touchlab:kermit", version.ref = "kermit" } @@ -86,6 +86,10 @@ orbit-core = { module = "org.orbit-mvi:orbit-compose", version.ref = "orbit" } pixko = { module = "top.kagg886:pixko", version.ref = "pixko" } telephoto-zoomable = { module = "me.saket.telephoto:zoomable", version.ref = "telephoto" } chip-textfield = { module = "io.github.dokar3:chiptextfield-m3", version.ref = "chip-textfield" } +wvbridge-core = { module = "top.kagg886.wvbridge:core", version.ref = "wvbridge-common" } +wvbridge-platform-linux = { module = "top.kagg886.wvbridge:platform-linux", version.ref = "wvbridge-platform" } +wvbridge-platform-macos = { module = "top.kagg886.wvbridge:platform-macos", version.ref = "wvbridge-platform" } +wvbridge-platform-windows = { module = "top.kagg886.wvbridge:platform-windows", version.ref = "wvbridge-platform" } [plugins] aboutlibrariesPlugin = { id = "com.mikepenz.aboutlibraries.plugin", version.ref = "aboutlibraries" }