feat(common-ui): connect scroll view inside web view to top bar (#15)

This commit is contained in:
Diego Beraldin 2023-09-14 22:46:37 +02:00 committed by GitHub
parent 2b3253e7f9
commit 8a6f2ac45f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 59 additions and 7 deletions

View File

@ -8,6 +8,10 @@ import android.webkit.WebViewClient
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
@ -15,9 +19,10 @@ import kotlinx.coroutines.flow.onEach
@SuppressLint("SetJavaScriptEnabled") @SuppressLint("SetJavaScriptEnabled")
@Composable @Composable
actual fun CustomWebView( actual fun CustomWebView(
navigator: WebViewNavigator,
modifier: Modifier,
url: String, url: String,
modifier: Modifier,
navigator: WebViewNavigator,
scrollConnection: NestedScrollConnection?,
) { ) {
var webView: WebView? = null var webView: WebView? = null
@ -29,6 +34,7 @@ actual fun CustomWebView(
}.launchIn(this) }.launchIn(this)
} }
val density = LocalDensity.current.density
AndroidView( AndroidView(
modifier = modifier, modifier = modifier,
factory = { context -> factory = { context ->
@ -44,7 +50,17 @@ actual fun CustomWebView(
} }
settings.javaScriptEnabled = true settings.javaScriptEnabled = true
setOnScrollChangeListener { _, scrollX, scrollY, oldScrollX, oldScrollY ->
scrollConnection?.onPreScroll(
available = Offset(
x = (oldScrollX - scrollX) / density,
y = (oldScrollY - scrollY) / density,
), source = NestedScrollSource.Drag
)
}
loadUrl(url) loadUrl(url)
webView = this webView = this
} }
}, },

View File

@ -2,10 +2,12 @@ package com.github.diegoberaldin.raccoonforlemmy.core.commonui.components
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
@Composable @Composable
expect fun CustomWebView( expect fun CustomWebView(
navigator: WebViewNavigator = rememberWebViewNavigator(),
modifier: Modifier = Modifier,
url: String, url: String,
modifier: Modifier = Modifier,
navigator: WebViewNavigator = rememberWebViewNavigator(),
scrollConnection: NestedScrollConnection? = null,
) )

View File

@ -10,6 +10,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
@ -28,10 +29,12 @@ class WebViewScreen(
@Composable @Composable
override fun Content() { override fun Content() {
val navigator = remember { getNavigationCoordinator().getRootNavigator() } val navigator = remember { getNavigationCoordinator().getRootNavigator() }
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
Scaffold( Scaffold(
topBar = { topBar = {
TopAppBar( TopAppBar(
title = {}, title = {},
scrollBehavior = scrollBehavior,
navigationIcon = { navigationIcon = {
Image( Image(
modifier = Modifier.onClick { modifier = Modifier.onClick {
@ -68,6 +71,7 @@ class WebViewScreen(
CustomWebView( CustomWebView(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
navigator = webNavigator, navigator = webNavigator,
scrollConnection = scrollBehavior.nestedScrollConnection,
url = url, url = url,
) )
} }

View File

@ -2,12 +2,23 @@ package com.github.diegoberaldin.raccoonforlemmy.core.commonui.components
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.interop.UIKitView import androidx.compose.ui.interop.UIKitView
import androidx.compose.ui.platform.LocalDensity
import kotlinx.cinterop.readValue import kotlinx.cinterop.readValue
import kotlinx.cinterop.useContents
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import platform.CoreGraphics.CGRectZero import platform.CoreGraphics.CGRectZero
import platform.UIKit.UIScrollView
import platform.UIKit.UIScrollViewDelegateProtocol
import platform.WebKit.WKNavigation import platform.WebKit.WKNavigation
import platform.WebKit.WKNavigationDelegateProtocol import platform.WebKit.WKNavigationDelegateProtocol
import platform.WebKit.WKWebView import platform.WebKit.WKWebView
@ -16,9 +27,10 @@ import platform.darwin.NSObject
@Composable @Composable
actual fun CustomWebView( actual fun CustomWebView(
navigator: WebViewNavigator,
modifier: Modifier,
url: String, url: String,
modifier: Modifier,
navigator: WebViewNavigator,
scrollConnection: NestedScrollConnection?,
) { ) {
var webView: WKWebView? = null var webView: WKWebView? = null
@ -30,6 +42,10 @@ actual fun CustomWebView(
}.launchIn(this) }.launchIn(this)
} }
val density = LocalDensity.current.density
var lastOffsetX by remember { mutableStateOf(0f) }
var lastOffsetY by remember { mutableStateOf(0f) }
UIKitView( UIKitView(
factory = { factory = {
val config = WKWebViewConfiguration().apply { val config = WKWebViewConfiguration().apply {
@ -42,7 +58,6 @@ actual fun CustomWebView(
userInteractionEnabled = true userInteractionEnabled = true
allowsBackForwardNavigationGestures = true allowsBackForwardNavigationGestures = true
val navigationDelegate = object : NSObject(), WKNavigationDelegateProtocol { val navigationDelegate = object : NSObject(), WKNavigationDelegateProtocol {
override fun webView( override fun webView(
webView: WKWebView, webView: WKWebView,
didFinishNavigation: WKNavigation?, didFinishNavigation: WKNavigation?,
@ -51,6 +66,21 @@ actual fun CustomWebView(
} }
} }
this.navigationDelegate = navigationDelegate this.navigationDelegate = navigationDelegate
this.scrollView.delegate = object : NSObject(), UIScrollViewDelegateProtocol {
override fun scrollViewDidScroll(scrollView: UIScrollView) {
scrollView.contentOffset.useContents {
val offsetX = (lastOffsetX - x).toFloat() / density
val offsetY = (lastOffsetY - y).toFloat() / density
scrollConnection?.onPreScroll(
available = Offset(offsetX, offsetY),
source = NestedScrollSource.Drag,
)
lastOffsetX = x.toFloat()
lastOffsetY = y.toFloat()
}
}
}
}.also { }.also {
webView = it webView = it
} }