Open external url (like terms and condition) in a Custom Chrome Tab, and disable to "Leave page" dialog.

This commit is contained in:
Benoit Marty 2024-09-13 22:03:06 +02:00 committed by Benoit Marty
parent bed7776674
commit 3f06664d88
3 changed files with 40 additions and 3 deletions

View file

@ -7,14 +7,18 @@
package io.element.android.features.login.impl.screens.createaccount package io.element.android.features.login.impl.screens.createaccount
import android.app.Activity
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.core.plugin.Plugin
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode import io.element.android.anvilannotations.ContributesNode
import io.element.android.compound.theme.ElementTheme
import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTab
import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.NodeInputs
import io.element.android.libraries.architecture.inputs import io.element.android.libraries.architecture.inputs
import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.AppScope
@ -31,13 +35,22 @@ class CreateAccountNode @AssistedInject constructor(
private val presenter = presenterFactory.create(inputs<Inputs>().url) private val presenter = presenterFactory.create(inputs<Inputs>().url)
private fun onOpenExternalUrl(activity: Activity, darkTheme: Boolean, url: String) {
activity.openUrlInChromeCustomTab(null, darkTheme, url)
}
@Composable @Composable
override fun View(modifier: Modifier) { override fun View(modifier: Modifier) {
val activity = LocalContext.current as Activity
val isDark = ElementTheme.isLightTheme.not()
val state = presenter.present() val state = presenter.present()
CreateAccountView( CreateAccountView(
state = state, state = state,
modifier = modifier, modifier = modifier,
onBackClick = ::navigateUp, onBackClick = ::navigateUp,
onOpenExternalUrl = {
onOpenExternalUrl(activity, isDark, it)
},
) )
} }
} }

View file

@ -9,6 +9,7 @@ package io.element.android.features.login.impl.screens.createaccount
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.view.ViewGroup import android.view.ViewGroup
import android.webkit.JsResult
import android.webkit.WebChromeClient import android.webkit.WebChromeClient
import android.webkit.WebView import android.webkit.WebView
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
@ -41,12 +42,14 @@ import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.designsystem.theme.progressIndicatorTrackColor import io.element.android.libraries.designsystem.theme.progressIndicatorTrackColor
import timber.log.Timber
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun CreateAccountView( fun CreateAccountView(
state: CreateAccountState, state: CreateAccountState,
onBackClick: () -> Unit, onBackClick: () -> Unit,
onOpenExternalUrl: (String) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
Scaffold( Scaffold(
@ -76,9 +79,14 @@ fun CreateAccountView(
.fillMaxSize(), .fillMaxSize(),
state = state, state = state,
onWebViewCreate = { webView -> onWebViewCreate = { webView ->
WebViewMessageInterceptor(webView, state.isDebugBuild) { WebViewMessageInterceptor(
state.eventSink(CreateAccountEvents.OnMessageReceived(it)) webView,
} state.isDebugBuild,
onOpenExternalUrl = onOpenExternalUrl,
onMessage = {
state.eventSink(CreateAccountEvents.OnMessageReceived(it))
},
)
} }
) )
AnimatedVisibility( AnimatedVisibility(
@ -153,6 +161,12 @@ private fun WebView.setup(state: CreateAccountState) {
super.onProgressChanged(view, newProgress) super.onProgressChanged(view, newProgress)
state.eventSink(CreateAccountEvents.SetPageProgress(newProgress)) state.eventSink(CreateAccountEvents.SetPageProgress(newProgress))
} }
override fun onJsBeforeUnload(view: WebView?, url: String?, message: String?, result: JsResult?): Boolean {
Timber.w("onJsBeforeUnload, cancelling the dialog, we will open external links in a Custom Chrome Tab")
result?.confirm()
return true
}
} }
} }
@ -162,5 +176,6 @@ internal fun CreateAccountViewPreview(@PreviewParameter(CreateAccountStateProvid
CreateAccountView( CreateAccountView(
state = state, state = state,
onBackClick = {}, onBackClick = {},
onOpenExternalUrl = {},
) )
} }

View file

@ -9,6 +9,7 @@ package io.element.android.features.login.impl.screens.createaccount
import android.graphics.Bitmap import android.graphics.Bitmap
import android.webkit.JavascriptInterface import android.webkit.JavascriptInterface
import android.webkit.WebResourceRequest
import android.webkit.WebView import android.webkit.WebView
import android.webkit.WebViewClient import android.webkit.WebViewClient
import androidx.webkit.WebViewCompat import androidx.webkit.WebViewCompat
@ -17,6 +18,7 @@ import androidx.webkit.WebViewFeature
class WebViewMessageInterceptor( class WebViewMessageInterceptor(
webView: WebView, webView: WebView,
private val debugLog: Boolean, private val debugLog: Boolean,
private val onOpenExternalUrl: (String) -> Unit,
private val onMessage: (String) -> Unit, private val onMessage: (String) -> Unit,
) { ) {
companion object { companion object {
@ -50,6 +52,13 @@ class WebViewMessageInterceptor(
null null
) )
} }
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
request ?: return super.shouldOverrideUrlLoading(view, request)
// Load the URL in a Chrome Custom Tab, and return true to cancel the load
onOpenExternalUrl(request.url.toString())
return true
}
} }
// Use WebMessageListener if supported, otherwise use JavascriptInterface // Use WebMessageListener if supported, otherwise use JavascriptInterface