Ensure a Callback and only one is provided in the Plugin. Also reduce boilerplate code in Nodes.
This commit is contained in:
parent
2e8785b36b
commit
be03c50aaf
76 changed files with 374 additions and 741 deletions
|
|
@ -17,7 +17,7 @@ import dev.zacsweers.metro.Assisted
|
|||
import dev.zacsweers.metro.AssistedInject
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.libraries.accountselect.api.AccountSelectEntryPoint
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.architecture.callback
|
||||
|
||||
@ContributesNode(AppScope::class)
|
||||
@AssistedInject
|
||||
|
|
@ -26,23 +26,15 @@ class AccountSelectNode(
|
|||
@Assisted plugins: List<Plugin>,
|
||||
private val presenter: AccountSelectPresenter,
|
||||
) : Node(buildContext, plugins = plugins) {
|
||||
private val callbacks = plugins.filterIsInstance<AccountSelectEntryPoint.Callback>()
|
||||
|
||||
private fun onDismiss() {
|
||||
callbacks.forEach { it.onCancel() }
|
||||
}
|
||||
|
||||
private fun onAccountSelected(sessionId: SessionId) {
|
||||
callbacks.forEach { it.onAccountSelected(sessionId) }
|
||||
}
|
||||
private val callback: AccountSelectEntryPoint.Callback = callback()
|
||||
|
||||
@Composable
|
||||
override fun View(modifier: Modifier) {
|
||||
val state = presenter.present()
|
||||
AccountSelectView(
|
||||
state = state,
|
||||
onDismiss = ::onDismiss,
|
||||
onSelectAccount = ::onAccountSelected,
|
||||
onDismiss = callback::onCancel,
|
||||
onSelectAccount = callback::onAccountSelected,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright 2023, 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.architecture
|
||||
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import com.bumble.appyx.core.plugin.plugins
|
||||
|
||||
inline fun <reified I : Plugin> Node.callback(): I {
|
||||
return requireNotNull(plugins<I>().singleOrNull()) { "Make sure to actually pass a Callback plugin to your node" }
|
||||
}
|
||||
|
|
@ -13,10 +13,10 @@ import androidx.compose.ui.Modifier
|
|||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import com.bumble.appyx.core.plugin.plugins
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.libraries.architecture.callback
|
||||
import io.element.android.libraries.di.RoomScope
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.mediaviewer.impl.gallery.di.LocalMediaItemPresenterFactories
|
||||
|
|
@ -43,28 +43,14 @@ class MediaGalleryNode(
|
|||
fun forward(eventId: EventId)
|
||||
}
|
||||
|
||||
private fun onBackClick() {
|
||||
plugins<Callback>().forEach {
|
||||
it.onBackClick()
|
||||
}
|
||||
}
|
||||
private val callback: Callback = callback()
|
||||
|
||||
override fun onViewInTimelineClick(eventId: EventId) {
|
||||
plugins<Callback>().forEach {
|
||||
it.viewInTimeline(eventId)
|
||||
}
|
||||
callback.viewInTimeline(eventId)
|
||||
}
|
||||
|
||||
override fun onForwardClick(eventId: EventId) {
|
||||
plugins<Callback>().forEach {
|
||||
it.forward(eventId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onItemClick(item: MediaItem.Event) {
|
||||
plugins<Callback>().forEach {
|
||||
it.showItem(item)
|
||||
}
|
||||
callback.forward(eventId)
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
@ -75,8 +61,8 @@ class MediaGalleryNode(
|
|||
val state = presenter.present()
|
||||
MediaGalleryView(
|
||||
state = state,
|
||||
onBackClick = ::onBackClick,
|
||||
onItemClick = ::onItemClick,
|
||||
onBackClick = callback::onBackClick,
|
||||
onItemClick = callback::showItem,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@ import androidx.compose.ui.Modifier
|
|||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import com.bumble.appyx.core.plugin.plugins
|
||||
import com.bumble.appyx.navmodel.backstack.BackStack
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.libraries.architecture.BackstackWithOverlayBox
|
||||
import io.element.android.libraries.architecture.BaseFlowNode
|
||||
import io.element.android.libraries.architecture.callback
|
||||
import io.element.android.libraries.architecture.createNode
|
||||
import io.element.android.libraries.architecture.overlay.Overlay
|
||||
import io.element.android.libraries.architecture.overlay.operation.hide
|
||||
|
|
@ -70,38 +70,22 @@ class MediaGalleryFlowNode(
|
|||
) : NavTarget
|
||||
}
|
||||
|
||||
private fun onBackClick() {
|
||||
plugins<MediaGalleryEntryPoint.Callback>().forEach {
|
||||
it.onBackClick()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onViewInTimeline(eventId: EventId) {
|
||||
plugins<MediaGalleryEntryPoint.Callback>().forEach {
|
||||
it.viewInTimeline(eventId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun forwardEvent(eventId: EventId) {
|
||||
plugins<MediaGalleryEntryPoint.Callback>().forEach {
|
||||
it.forward(eventId)
|
||||
}
|
||||
}
|
||||
private val callback: MediaGalleryEntryPoint.Callback = callback()
|
||||
|
||||
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
|
||||
return when (navTarget) {
|
||||
NavTarget.Root -> {
|
||||
val callback = object : MediaGalleryNode.Callback {
|
||||
override fun onBackClick() {
|
||||
this@MediaGalleryFlowNode.onBackClick()
|
||||
callback.onBackClick()
|
||||
}
|
||||
|
||||
override fun viewInTimeline(eventId: EventId) {
|
||||
this@MediaGalleryFlowNode.onViewInTimeline(eventId)
|
||||
callback.viewInTimeline(eventId)
|
||||
}
|
||||
|
||||
override fun forward(eventId: EventId) {
|
||||
forwardEvent(eventId)
|
||||
callback.forward(eventId)
|
||||
}
|
||||
|
||||
override fun showItem(item: MediaItem.Event) {
|
||||
|
|
@ -132,12 +116,12 @@ class MediaGalleryFlowNode(
|
|||
}
|
||||
|
||||
override fun viewInTimeline(eventId: EventId) {
|
||||
this@MediaGalleryFlowNode.onViewInTimeline(eventId)
|
||||
callback.viewInTimeline(eventId)
|
||||
}
|
||||
|
||||
override fun forwardEvent(eventId: EventId) {
|
||||
// Need to go to the parent because of the overlay
|
||||
this@MediaGalleryFlowNode.forwardEvent(eventId)
|
||||
callback.forward(eventId)
|
||||
}
|
||||
}
|
||||
mediaViewerEntryPoint.nodeBuilder(this, buildContext)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import androidx.compose.ui.Modifier
|
|||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import com.bumble.appyx.core.plugin.plugins
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import io.element.android.annotations.ContributesNode
|
||||
|
|
@ -23,6 +22,7 @@ import io.element.android.compound.colors.SemanticColorsLightDark
|
|||
import io.element.android.compound.theme.ForcedDarkElementTheme
|
||||
import io.element.android.features.enterprise.api.EnterpriseService
|
||||
import io.element.android.features.viewfolder.api.TextFileViewer
|
||||
import io.element.android.libraries.architecture.callback
|
||||
import io.element.android.libraries.architecture.inputs
|
||||
import io.element.android.libraries.audio.api.AudioFocus
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
|
|
@ -57,28 +57,19 @@ class MediaViewerNode(
|
|||
private val enterpriseService: EnterpriseService,
|
||||
) : Node(buildContext, plugins = plugins),
|
||||
MediaViewerNavigator {
|
||||
private val callback: MediaViewerEntryPoint.Callback = callback()
|
||||
private val inputs = inputs<MediaViewerEntryPoint.Params>()
|
||||
|
||||
private fun onDone() {
|
||||
plugins<MediaViewerEntryPoint.Callback>().forEach {
|
||||
it.onDone()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewInTimelineClick(eventId: EventId) {
|
||||
plugins<MediaViewerEntryPoint.Callback>().forEach {
|
||||
it.viewInTimeline(eventId)
|
||||
}
|
||||
callback.viewInTimeline(eventId)
|
||||
}
|
||||
|
||||
override fun onForwardClick(eventId: EventId) {
|
||||
plugins<MediaViewerEntryPoint.Callback>().forEach {
|
||||
it.forwardEvent(eventId)
|
||||
}
|
||||
callback.forwardEvent(eventId)
|
||||
}
|
||||
|
||||
override fun onItemDeleted() {
|
||||
onDone()
|
||||
callback.onDone()
|
||||
}
|
||||
|
||||
private val mediaGallerySource = if (inputs.mode == MediaViewerEntryPoint.MediaViewerMode.SingleMedia) {
|
||||
|
|
@ -153,7 +144,7 @@ class MediaViewerNode(
|
|||
textFileViewer = textFileViewer,
|
||||
modifier = modifier,
|
||||
audioFocus = audioFocus,
|
||||
onBackClick = ::onDone,
|
||||
onBackClick = callback::onDone,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ class IgnoredUsersTest(
|
|||
coroutineScope: CoroutineScope,
|
||||
navigator: NotificationTroubleshootNavigator,
|
||||
) {
|
||||
navigator.openIgnoredUsers()
|
||||
navigator.navigateToBlockedUsers()
|
||||
}
|
||||
|
||||
override suspend fun reset() = delegate.reset()
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class IgnoredUsersTestTest {
|
|||
)
|
||||
val openIgnoredUsersResult = lambdaRecorder<Unit> {}
|
||||
val navigator = object : NotificationTroubleshootNavigator {
|
||||
override fun openIgnoredUsers() = openIgnoredUsersResult()
|
||||
override fun navigateToBlockedUsers() = openIgnoredUsersResult()
|
||||
}
|
||||
sut.quickFix(
|
||||
coroutineScope = backgroundScope,
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@ import dev.zacsweers.metro.Assisted
|
|||
import dev.zacsweers.metro.AssistedInject
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.libraries.architecture.NodeInputs
|
||||
import io.element.android.libraries.architecture.callback
|
||||
import io.element.android.libraries.architecture.inputs
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.roomselect.api.RoomSelectEntryPoint
|
||||
import io.element.android.libraries.roomselect.api.RoomSelectMode
|
||||
|
||||
|
|
@ -35,24 +35,15 @@ class RoomSelectNode(
|
|||
|
||||
private val inputs: Inputs = inputs()
|
||||
private val presenter = presenterFactory.create(inputs.mode)
|
||||
|
||||
private val callbacks = plugins.filterIsInstance<RoomSelectEntryPoint.Callback>()
|
||||
|
||||
private fun onDismiss() {
|
||||
callbacks.forEach { it.onCancel() }
|
||||
}
|
||||
|
||||
private fun onRoomSelected(roomIds: List<RoomId>) {
|
||||
callbacks.forEach { it.onRoomSelected(roomIds) }
|
||||
}
|
||||
private val callback: RoomSelectEntryPoint.Callback = callback()
|
||||
|
||||
@Composable
|
||||
override fun View(modifier: Modifier) {
|
||||
val state = presenter.present()
|
||||
RoomSelectView(
|
||||
state = state,
|
||||
onDismiss = ::onDismiss,
|
||||
onSubmit = ::onRoomSelected,
|
||||
onDismiss = callback::onCancel,
|
||||
onSubmit = callback::onRoomSelected,
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,5 +8,5 @@
|
|||
package io.element.android.libraries.troubleshoot.api.test
|
||||
|
||||
interface NotificationTroubleshootNavigator {
|
||||
fun openIgnoredUsers()
|
||||
fun navigateToBlockedUsers()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,11 +12,11 @@ import androidx.compose.ui.Modifier
|
|||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import com.bumble.appyx.core.plugin.plugins
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import im.vector.app.features.analytics.plan.MobileScreen
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.libraries.architecture.callback
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.troubleshoot.api.NotificationTroubleShootEntryPoint
|
||||
import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootNavigator
|
||||
|
|
@ -31,20 +31,13 @@ class TroubleshootNotificationsNode(
|
|||
factory: TroubleshootNotificationsPresenter.Factory,
|
||||
) : Node(buildContext, plugins = plugins),
|
||||
NotificationTroubleshootNavigator {
|
||||
private val callback: NotificationTroubleShootEntryPoint.Callback = callback()
|
||||
private val presenter = factory.create(
|
||||
navigator = this,
|
||||
)
|
||||
|
||||
private fun onDone() {
|
||||
plugins<NotificationTroubleShootEntryPoint.Callback>().forEach {
|
||||
it.onDone()
|
||||
}
|
||||
}
|
||||
|
||||
override fun openIgnoredUsers() {
|
||||
plugins<NotificationTroubleShootEntryPoint.Callback>().forEach {
|
||||
it.navigateToBlockedUsers()
|
||||
}
|
||||
override fun navigateToBlockedUsers() {
|
||||
callback.navigateToBlockedUsers()
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
@ -53,7 +46,7 @@ class TroubleshootNotificationsNode(
|
|||
val state = presenter.present()
|
||||
TroubleshootNotificationsView(
|
||||
state = state,
|
||||
onBackClick = ::onDone,
|
||||
onBackClick = callback::onDone,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,11 +12,11 @@ import androidx.compose.ui.Modifier
|
|||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import com.bumble.appyx.core.plugin.plugins
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import im.vector.app.features.analytics.plan.MobileScreen
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.libraries.architecture.callback
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
|
@ -31,16 +31,10 @@ class PushHistoryNode(
|
|||
presenterFactory: PushHistoryPresenter.Factory,
|
||||
private val screenTracker: ScreenTracker,
|
||||
) : Node(buildContext, plugins = plugins), PushHistoryNavigator {
|
||||
private fun onDone() {
|
||||
plugins<PushHistoryEntryPoint.Callback>().forEach {
|
||||
it.onDone()
|
||||
}
|
||||
}
|
||||
private val callback: PushHistoryEntryPoint.Callback = callback()
|
||||
|
||||
override fun navigateTo(roomId: RoomId, eventId: EventId) {
|
||||
plugins<PushHistoryEntryPoint.Callback>().forEach {
|
||||
it.navigateToEvent(roomId, eventId)
|
||||
}
|
||||
callback.navigateToEvent(roomId, eventId)
|
||||
}
|
||||
|
||||
private val presenter = presenterFactory.create(this)
|
||||
|
|
@ -51,7 +45,7 @@ class PushHistoryNode(
|
|||
val state = presenter.present()
|
||||
PushHistoryView(
|
||||
state = state,
|
||||
onBackClick = ::onDone,
|
||||
onBackClick = callback::onDone,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ private fun createTroubleshootTestSuite(
|
|||
|
||||
internal fun createTroubleshootNotificationsPresenter(
|
||||
navigator: NotificationTroubleshootNavigator = object : NotificationTroubleshootNavigator {
|
||||
override fun openIgnoredUsers() = lambdaError()
|
||||
override fun navigateToBlockedUsers() = lambdaError()
|
||||
},
|
||||
troubleshootTestSuite: TroubleshootTestSuite = createTroubleshootTestSuite(),
|
||||
): TroubleshootNotificationsPresenter {
|
||||
|
|
|
|||
|
|
@ -13,5 +13,5 @@ import io.element.android.tests.testutils.lambda.lambdaError
|
|||
class FakeNotificationTroubleshootNavigator(
|
||||
private val openIgnoredUsersResult: () -> Unit = { lambdaError() },
|
||||
) : NotificationTroubleshootNavigator {
|
||||
override fun openIgnoredUsers() = openIgnoredUsersResult()
|
||||
override fun navigateToBlockedUsers() = openIgnoredUsersResult()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue