diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/CreateAccountNode.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/CreateAccountNode.kt index 61b380815f..b17699e6f8 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/CreateAccountNode.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/CreateAccountNode.kt @@ -7,14 +7,18 @@ package io.element.android.features.login.impl.screens.createaccount +import android.app.Activity import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin import dagger.assisted.Assisted import dagger.assisted.AssistedInject 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.inputs import io.element.android.libraries.di.AppScope @@ -31,13 +35,22 @@ class CreateAccountNode @AssistedInject constructor( private val presenter = presenterFactory.create(inputs().url) + private fun onOpenExternalUrl(activity: Activity, darkTheme: Boolean, url: String) { + activity.openUrlInChromeCustomTab(null, darkTheme, url) + } + @Composable override fun View(modifier: Modifier) { + val activity = LocalContext.current as Activity + val isDark = ElementTheme.isLightTheme.not() val state = presenter.present() CreateAccountView( state = state, modifier = modifier, onBackClick = ::navigateUp, + onOpenExternalUrl = { + onOpenExternalUrl(activity, isDark, it) + }, ) } } diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/CreateAccountView.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/CreateAccountView.kt index 7074f935d3..aaa67a80f9 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/CreateAccountView.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/CreateAccountView.kt @@ -9,6 +9,7 @@ package io.element.android.features.login.impl.screens.createaccount import android.annotation.SuppressLint import android.view.ViewGroup +import android.webkit.JsResult import android.webkit.WebChromeClient import android.webkit.WebView 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.TopAppBar import io.element.android.libraries.designsystem.theme.progressIndicatorTrackColor +import timber.log.Timber @OptIn(ExperimentalMaterial3Api::class) @Composable fun CreateAccountView( state: CreateAccountState, onBackClick: () -> Unit, + onOpenExternalUrl: (String) -> Unit, modifier: Modifier = Modifier, ) { Scaffold( @@ -76,9 +79,14 @@ fun CreateAccountView( .fillMaxSize(), state = state, onWebViewCreate = { webView -> - WebViewMessageInterceptor(webView, state.isDebugBuild) { - state.eventSink(CreateAccountEvents.OnMessageReceived(it)) - } + WebViewMessageInterceptor( + webView, + state.isDebugBuild, + onOpenExternalUrl = onOpenExternalUrl, + onMessage = { + state.eventSink(CreateAccountEvents.OnMessageReceived(it)) + }, + ) } ) AnimatedVisibility( @@ -153,6 +161,12 @@ private fun WebView.setup(state: CreateAccountState) { super.onProgressChanged(view, 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( state = state, onBackClick = {}, + onOpenExternalUrl = {}, ) } diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/WebViewMessageInterceptor.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/WebViewMessageInterceptor.kt index eb59ddb858..f07c466736 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/WebViewMessageInterceptor.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/WebViewMessageInterceptor.kt @@ -9,6 +9,7 @@ package io.element.android.features.login.impl.screens.createaccount import android.graphics.Bitmap import android.webkit.JavascriptInterface +import android.webkit.WebResourceRequest import android.webkit.WebView import android.webkit.WebViewClient import androidx.webkit.WebViewCompat @@ -17,6 +18,7 @@ import androidx.webkit.WebViewFeature class WebViewMessageInterceptor( webView: WebView, private val debugLog: Boolean, + private val onOpenExternalUrl: (String) -> Unit, private val onMessage: (String) -> Unit, ) { companion object { @@ -50,6 +52,13 @@ class WebViewMessageInterceptor( 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