Ensure a Callback and only one is provided in the Plugin. Also reduce boilerplate code in Nodes.

This commit is contained in:
Benoit Marty 2025-10-30 09:14:41 +01:00 committed by Benoit Marty
parent 2e8785b36b
commit be03c50aaf
76 changed files with 374 additions and 741 deletions

View file

@ -13,7 +13,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 com.bumble.appyx.navmodel.backstack.BackStack
import com.bumble.appyx.navmodel.backstack.operation.pop
import com.bumble.appyx.navmodel.backstack.operation.push
@ -38,6 +37,7 @@ import io.element.android.features.preferences.impl.user.editprofile.EditUserPro
import io.element.android.libraries.architecture.BackstackView
import io.element.android.libraries.architecture.BaseFlowNode
import io.element.android.libraries.architecture.appyx.canPop
import io.element.android.libraries.architecture.callback
import io.element.android.libraries.architecture.createNode
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.matrix.api.core.EventId
@ -116,20 +116,22 @@ class PreferencesFlowNode(
data object OssLicenses : NavTarget
}
private val callback: PreferencesEntryPoint.Callback = callback()
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
return when (navTarget) {
NavTarget.Root -> {
val callback = object : PreferencesRootNode.Callback {
override fun navigateToAddAccount() {
plugins<PreferencesEntryPoint.Callback>().forEach { it.navigateToAddAccount() }
callback.navigateToAddAccount()
}
override fun navigateToBugReport() {
plugins<PreferencesEntryPoint.Callback>().forEach { it.navigateToBugReport() }
callback.navigateToBugReport()
}
override fun navigateToSecureBackup() {
plugins<PreferencesEntryPoint.Callback>().forEach { it.navigateToSecureBackup() }
callback.navigateToSecureBackup()
}
override fun navigateToAnalyticsSettings() {
@ -241,7 +243,7 @@ class PreferencesFlowNode(
}
override fun navigateToEvent(roomId: RoomId, eventId: EventId) {
plugins<PreferencesEntryPoint.Callback>().forEach { it.navigateToEvent(roomId, eventId) }
callback.navigateToEvent(roomId, eventId)
}
})
.build()
@ -249,7 +251,7 @@ class PreferencesFlowNode(
is NavTarget.EditDefaultNotificationSetting -> {
val callback = object : EditDefaultNotificationSettingNode.Callback {
override fun navigateToRoomNotificationSettings(roomId: RoomId) {
plugins<PreferencesEntryPoint.Callback>().forEach { it.navigateToRoomNotificationSettings(roomId) }
callback.navigateToRoomNotificationSettings(roomId)
}
}
val input = EditDefaultNotificationSettingNode.Inputs(navTarget.isOneToOne)
@ -271,7 +273,7 @@ class PreferencesFlowNode(
NavTarget.SignOut -> {
val callBack: LogoutEntryPoint.Callback = object : LogoutEntryPoint.Callback {
override fun navigateToSecureBackup() {
plugins<PreferencesEntryPoint.Callback>().forEach { it.navigateToSecureBackup() }
callback.navigateToSecureBackup()
}
}
logoutEntryPoint.nodeBuilder(this, buildContext)

View file

@ -19,6 +19,7 @@ import dev.zacsweers.metro.AssistedInject
import io.element.android.annotations.ContributesNode
import io.element.android.compound.theme.ElementTheme
import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTab
import io.element.android.libraries.architecture.callback
import io.element.android.libraries.di.SessionScope
@ContributesNode(SessionScope::class)
@ -32,6 +33,8 @@ class AboutNode(
fun navigateToOssLicenses()
}
private val callback: Callback = callback()
private fun onElementLegalClick(
activity: Activity,
darkTheme: Boolean,
@ -51,9 +54,7 @@ class AboutNode(
onElementLegalClick = { elementLegal ->
onElementLegalClick(activity, isDark, elementLegal)
},
onOpenSourceLicensesClick = {
plugins.filterIsInstance<Callback>().forEach { it.navigateToOssLicenses() }
},
onOpenSourceLicensesClick = callback::navigateToOssLicenses,
modifier = modifier
)
}

View file

@ -14,10 +14,10 @@ import com.airbnb.android.showkase.models.Showkase
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.designsystem.showkase.getBrowserIntent
import io.element.android.libraries.di.SessionScope
@ -32,11 +32,7 @@ class DeveloperSettingsNode(
fun navigateToPushHistory()
}
private val callbacks = plugins<Callback>()
private fun navigateToPushHistory() {
callbacks.forEach { it.navigateToPushHistory() }
}
private val callback: Callback = callback()
@Composable
override fun View(modifier: Modifier) {
@ -51,7 +47,7 @@ class DeveloperSettingsNode(
state = state,
modifier = modifier,
onOpenShowkase = ::openShowkase,
onPushHistoryClick = ::navigateToPushHistory,
onPushHistoryClick = callback::navigateToPushHistory,
onBackClick = ::navigateUp
)
}

View file

@ -12,10 +12,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.SessionScope
@ContributesNode(SessionScope::class)
@ -30,24 +30,16 @@ class NotificationSettingsNode(
fun navigateToTroubleshootNotifications()
}
private val callbacks = plugins<Callback>()
private fun navigateToEditDefaultNotificationSetting(isOneToOne: Boolean) {
callbacks.forEach { it.navigateToEditDefaultNotificationSetting(isOneToOne) }
}
private fun navigateToTroubleshootNotifications() {
callbacks.forEach { it.navigateToTroubleshootNotifications() }
}
private val callback: Callback = callback()
@Composable
override fun View(modifier: Modifier) {
val state = presenter.present()
NotificationSettingsView(
state = state,
onOpenEditDefault = ::navigateToEditDefaultNotificationSetting,
onOpenEditDefault = callback::navigateToEditDefaultNotificationSetting,
onBackClick = ::navigateUp,
onTroubleshootNotificationsClick = ::navigateToTroubleshootNotifications,
onTroubleshootNotificationsClick = callback::navigateToTroubleshootNotifications,
modifier = modifier,
)
}

View file

@ -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 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
@ -36,20 +36,16 @@ class EditDefaultNotificationSettingNode(
val isOneToOne: Boolean
) : NodeInputs
private val callback: Callback = callback()
private val inputs = inputs<Inputs>()
private val callbacks = plugins<Callback>()
private val presenter = presenterFactory.create(inputs.isOneToOne)
private fun navigateToRoomNotificationSettings(roomId: RoomId) {
callbacks.forEach { it.navigateToRoomNotificationSettings(roomId) }
}
@Composable
override fun View(modifier: Modifier) {
val state = presenter.present()
EditDefaultNotificationSettingView(
state = state,
openRoomNotificationSettings = { navigateToRoomNotificationSettings(it) },
openRoomNotificationSettings = callback::navigateToRoomNotificationSettings,
onBackClick = ::navigateUp,
modifier = modifier,
)

View file

@ -14,7 +14,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
@ -22,6 +21,7 @@ import io.element.android.compound.theme.ElementTheme
import io.element.android.features.logout.api.direct.DirectLogoutEvents
import io.element.android.features.logout.api.direct.DirectLogoutView
import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTab
import io.element.android.libraries.architecture.callback
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.matrix.api.user.MatrixUser
@ -50,37 +50,7 @@ class PreferencesRootNode(
fun startAccountDeactivationFlow()
}
private fun onAddAccount() {
plugins<Callback>().forEach { it.navigateToAddAccount() }
}
private fun onOpenBugReport() {
plugins<Callback>().forEach { it.navigateToBugReport() }
}
private fun onSecureBackupClick() {
plugins<Callback>().forEach { it.navigateToSecureBackup() }
}
private fun onOpenDeveloperSettings() {
plugins<Callback>().forEach { it.navigateToDeveloperSettings() }
}
private fun onOpenAdvancedSettings() {
plugins<Callback>().forEach { it.navigateToAdvancedSettings() }
}
private fun onOpenLabs() {
plugins<Callback>().forEach { it.navigateToLabs() }
}
private fun onOpenAnalytics() {
plugins<Callback>().forEach { it.navigateToAnalyticsSettings() }
}
private fun onOpenAbout() {
plugins<Callback>().forEach { it.navigateToAbout() }
}
private val callback: Callback = callback()
private fun onManageAccountClick(
activity: Activity,
@ -96,30 +66,6 @@ class PreferencesRootNode(
}
}
private fun onOpenNotificationSettings() {
plugins<Callback>().forEach { it.navigateToNotificationSettings() }
}
private fun onOpenLockScreenSettings() {
plugins<Callback>().forEach { it.navigateToLockScreenSettings() }
}
private fun onOpenUserProfile(matrixUser: MatrixUser) {
plugins<Callback>().forEach { it.navigateToUserProfile(matrixUser) }
}
private fun onOpenBlockedUsers() {
plugins<Callback>().forEach { it.navigateToBlockedUsers() }
}
private fun onSignOutClick() {
plugins<Callback>().forEach { it.startSignOutFlow() }
}
private fun onOpenAccountDeactivation() {
plugins<Callback>().forEach { it.startAccountDeactivationFlow() }
}
@Composable
override fun View(modifier: Modifier) {
val state = presenter.present()
@ -129,27 +75,27 @@ class PreferencesRootNode(
state = state,
modifier = modifier,
onBackClick = this::navigateUp,
onAddAccountClick = this::onAddAccount,
onOpenRageShake = this::onOpenBugReport,
onOpenAnalytics = this::onOpenAnalytics,
onOpenAbout = this::onOpenAbout,
onSecureBackupClick = this::onSecureBackupClick,
onOpenDeveloperSettings = this::onOpenDeveloperSettings,
onOpenAdvancedSettings = this::onOpenAdvancedSettings,
onOpenLabs = this::onOpenLabs,
onAddAccountClick = callback::navigateToAddAccount,
onOpenRageShake = callback::navigateToBugReport,
onOpenAnalytics = callback::navigateToAnalyticsSettings,
onOpenAbout = callback::navigateToAbout,
onSecureBackupClick = callback::navigateToSecureBackup,
onOpenDeveloperSettings = callback::navigateToDeveloperSettings,
onOpenAdvancedSettings = callback::navigateToAdvancedSettings,
onOpenLabs = callback::navigateToLabs,
onManageAccountClick = { onManageAccountClick(activity, it, isDark) },
onOpenNotificationSettings = this::onOpenNotificationSettings,
onOpenLockScreenSettings = this::onOpenLockScreenSettings,
onOpenUserProfile = this::onOpenUserProfile,
onOpenBlockedUsers = this::onOpenBlockedUsers,
onOpenNotificationSettings = callback::navigateToNotificationSettings,
onOpenLockScreenSettings = callback::navigateToLockScreenSettings,
onOpenUserProfile = callback::navigateToUserProfile,
onOpenBlockedUsers = callback::navigateToBlockedUsers,
onSignOutClick = {
if (state.directLogoutState.canDoDirectSignOut) {
state.directLogoutState.eventSink(DirectLogoutEvents.Logout(ignoreSdkError = false))
} else {
onSignOutClick()
callback.startSignOutFlow()
}
},
onDeactivateClick = this::onOpenAccountDeactivation
onDeactivateClick = callback::startAccountDeactivationFlow
)
directLogoutView.Render(state = state.directLogoutState)