new: add loading overlay for WebView widget while pages load
This commit is contained in:
@@ -1,25 +1,36 @@
|
||||
package bzh.ajaury.chombev.web.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.interop.UIKitView
|
||||
import kotlinx.cinterop.ExperimentalForeignApi
|
||||
import kotlinx.cinterop.ObjCSignatureOverride
|
||||
import platform.CoreGraphics.CGRectZero
|
||||
import platform.Foundation.NSError
|
||||
import platform.Foundation.NSURL
|
||||
import platform.Foundation.NSURLRequest
|
||||
import platform.UIKit.UIUserInterfaceStyle
|
||||
import platform.UIKit.UIUserInterfaceStyle.UIUserInterfaceStyleDark
|
||||
import platform.UIKit.UIUserInterfaceStyle.UIUserInterfaceStyleLight
|
||||
import platform.WebKit.WKNavigation
|
||||
import platform.WebKit.WKNavigationDelegateProtocol
|
||||
import platform.WebKit.WKWebView
|
||||
import platform.WebKit.WKWebViewConfiguration
|
||||
import platform.darwin.NSObject
|
||||
|
||||
@OptIn(ExperimentalForeignApi::class)
|
||||
@Composable
|
||||
actual fun PlatformWebView(
|
||||
url: String,
|
||||
darkTheme: Boolean,
|
||||
onLoadingStateChange: (Boolean) -> Unit,
|
||||
modifier: Modifier,
|
||||
) {
|
||||
// WKWebView holds its navigationDelegate weakly, so keep a strong reference across recompositions.
|
||||
val navigationDelegate = remember { WebViewNavigationDelegate() }
|
||||
navigationDelegate.onLoadingStateChange = onLoadingStateChange
|
||||
|
||||
UIKitView(
|
||||
modifier = modifier,
|
||||
factory = {
|
||||
@@ -27,6 +38,7 @@ actual fun PlatformWebView(
|
||||
frame = CGRectZero.readValue(),
|
||||
configuration = WKWebViewConfiguration(),
|
||||
).apply {
|
||||
navigationDelegate = navigationDelegate
|
||||
setOverrideUserInterfaceStyle(darkTheme.toInterfaceStyle())
|
||||
NSURL.URLWithString(url)?.let { nsUrl ->
|
||||
loadRequest(NSURLRequest(uRL = nsUrl))
|
||||
@@ -40,4 +52,48 @@ actual fun PlatformWebView(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards WKWebView load lifecycle events to [onLoadingStateChange] so the UI can show a loader
|
||||
* while a page is loading and hide it once loading finishes (or fails).
|
||||
*/
|
||||
private class WebViewNavigationDelegate :
|
||||
NSObject(),
|
||||
WKNavigationDelegateProtocol {
|
||||
var onLoadingStateChange: (Boolean) -> Unit = {}
|
||||
|
||||
override fun webView(
|
||||
webView: WKWebView,
|
||||
didStartProvisionalNavigation: WKNavigation?,
|
||||
) {
|
||||
onLoadingStateChange(true)
|
||||
}
|
||||
|
||||
// Shares the (WKWebView, WKNavigation?) Kotlin signature with didStartProvisionalNavigation above.
|
||||
@ObjCSignatureOverride
|
||||
override fun webView(
|
||||
webView: WKWebView,
|
||||
didFinishNavigation: WKNavigation?,
|
||||
) {
|
||||
onLoadingStateChange(false)
|
||||
}
|
||||
|
||||
override fun webView(
|
||||
webView: WKWebView,
|
||||
didFailNavigation: WKNavigation?,
|
||||
withError: NSError,
|
||||
) {
|
||||
onLoadingStateChange(false)
|
||||
}
|
||||
|
||||
// Shares the (WKWebView, WKNavigation?, NSError) Kotlin signature with didFailNavigation above.
|
||||
@ObjCSignatureOverride
|
||||
override fun webView(
|
||||
webView: WKWebView,
|
||||
didFailProvisionalNavigation: WKNavigation?,
|
||||
withError: NSError,
|
||||
) {
|
||||
onLoadingStateChange(false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Boolean.toInterfaceStyle(): UIUserInterfaceStyle = if (this) UIUserInterfaceStyleDark else UIUserInterfaceStyleLight
|
||||
|
||||
Reference in New Issue
Block a user