open links inside synth pwa

This commit is contained in:
Fabian Freund
2026-06-01 07:28:13 +02:00
parent 453e1a6c30
commit 997c826812
2 changed files with 76 additions and 5 deletions
@@ -26,6 +26,7 @@ import com.mikepenz.iconics.typeface.IIcon
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import eu.weblibre.flutter_mozilla_components.feature.PwaWindowFeature
import eu.weblibre.flutter_mozilla_components.widget.CustomTabToolbar
import eu.weblibre.flutter_mozilla_components.widget.CustomTabToolbarFeature
import mozilla.components.feature.contextmenu.ContextMenuCandidate
@@ -39,6 +40,7 @@ import mozilla.components.feature.pwa.feature.WebAppActivityFeature
import mozilla.components.feature.pwa.feature.WebAppContentFeature
import mozilla.components.feature.pwa.feature.WebAppHideToolbarFeature
import mozilla.components.feature.pwa.feature.WebAppSiteControlsFeature
import mozilla.components.support.base.feature.LifecycleAwareFeature
import mozilla.components.support.base.feature.UserInteractionHandler
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
import mozilla.components.support.base.log.logger.Logger
@@ -53,7 +55,7 @@ class ExternalAppBrowserFragment : BaseBrowserFragment(), UserInteractionHandler
private val customTabsToolbarFeature = ViewBoundFeatureWrapper<CustomTabToolbarFeature>()
private val contextMenuFeature = ViewBoundFeatureWrapper<ContextMenuFeature>()
private val hideToolbarFeature = ViewBoundFeatureWrapper<WebAppHideToolbarFeature>()
private val windowFeature = ViewBoundFeatureWrapper<CustomTabWindowFeature>()
private val windowFeature = ViewBoundFeatureWrapper<LifecycleAwareFeature>()
private var customTabToolbar: CustomTabToolbar? = null
private var activePopup: PopupWindow? = null
@@ -368,15 +370,23 @@ class ExternalAppBrowserFragment : BaseBrowserFragment(), UserInteractionHandler
components.core.webAppManifestStorage.getManifestCache(url)
} ?: customTab.content.webAppManifest
val isPwaOrTwa = customTab.config.externalAppType == ExternalAppType.PROGRESSIVE_WEB_APP ||
customTab.config.externalAppType == ExternalAppType.TRUSTED_WEB_ACTIVITY
windowFeature.set(
feature = CustomTabWindowFeature(activity, store, sessionId),
feature = if (isPwaOrTwa) {
PwaWindowFeature(
store = store,
loadUrlUseCase = components.useCases.sessionUseCases.loadUrl,
sessionId = sessionId,
)
} else {
CustomTabWindowFeature(activity, store, sessionId)
},
owner = this,
view = view,
)
val isPwaOrTwa = customTab.config.externalAppType == ExternalAppType.PROGRESSIVE_WEB_APP ||
customTab.config.externalAppType == ExternalAppType.TRUSTED_WEB_ACTIVITY
if (isPwaOrTwa) {
hideToolbarFeature.set(
feature = WebAppHideToolbarFeature(
@@ -0,0 +1,61 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package eu.weblibre.flutter_mozilla_components.feature
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.mapNotNull
import mozilla.components.browser.state.action.ContentAction
import mozilla.components.browser.state.selector.findCustomTab
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.concept.engine.EngineSession
import mozilla.components.concept.engine.window.WindowRequest
import mozilla.components.feature.session.SessionUseCases
import mozilla.components.lib.state.ext.flowScoped
import mozilla.components.support.base.feature.LifecycleAwareFeature
/**
* Handles popup/window requests inside a standalone PWA session.
*/
class PwaWindowFeature(
private val store: BrowserStore,
private val loadUrlUseCase: SessionUseCases.DefaultLoadUrlUseCase,
private val sessionId: String,
private val mainDispatcher: CoroutineDispatcher = Dispatchers.Main,
) : LifecycleAwareFeature {
private var scope: CoroutineScope? = null
override fun start() {
scope = store.flowScoped(dispatcher = mainDispatcher) { flow ->
flow.mapNotNull { state -> state.findCustomTab(sessionId) }
.distinctUntilChangedBy { it.content.windowRequest }
.collect { state ->
val windowRequest = state.content.windowRequest
if (windowRequest?.type == WindowRequest.Type.OPEN) {
if (windowRequest.url.isNotBlank()) {
loadUrlUseCase(
windowRequest.url,
sessionId,
EngineSession.LoadUrlFlags.external(),
)
}
store.dispatch(ContentAction.ConsumeWindowRequestAction(sessionId))
}
}
}
}
override fun stop() {
scope?.cancel()
scope = null
}
}