Merge pull request #5161 from element-hq/feature/bma/movePushHistory

Move push history entry point from notification settings to developer settings
This commit is contained in:
Benoit Marty 2025-08-14 09:00:31 +02:00 committed by GitHub
commit 35544c848e
13 changed files with 64 additions and 53 deletions

View file

@ -167,7 +167,12 @@ class PreferencesFlowNode @AssistedInject constructor(
createNode<PreferencesRootNode>(buildContext, plugins = listOf(callback)) createNode<PreferencesRootNode>(buildContext, plugins = listOf(callback))
} }
NavTarget.DeveloperSettings -> { NavTarget.DeveloperSettings -> {
createNode<DeveloperSettingsNode>(buildContext) val developerSettingsCallback = object : DeveloperSettingsNode.Callback {
override fun onPushHistoryClick() {
backstack.push(NavTarget.PushHistory)
}
}
createNode<DeveloperSettingsNode>(buildContext, listOf(developerSettingsCallback))
} }
NavTarget.About -> { NavTarget.About -> {
val callback = object : AboutNode.Callback { val callback = object : AboutNode.Callback {
@ -189,10 +194,6 @@ class PreferencesFlowNode @AssistedInject constructor(
override fun onTroubleshootNotificationsClick() { override fun onTroubleshootNotificationsClick() {
backstack.push(NavTarget.TroubleshootNotifications) backstack.push(NavTarget.TroubleshootNotifications)
} }
override fun onPushHistoryClick() {
backstack.push(NavTarget.PushHistory)
}
} }
createNode<NotificationSettingsNode>(buildContext, listOf(notificationSettingsCallback)) createNode<NotificationSettingsNode>(buildContext, listOf(notificationSettingsCallback))
} }

View file

@ -14,6 +14,7 @@ import com.airbnb.android.showkase.models.Showkase
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 com.bumble.appyx.core.plugin.plugins
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
@ -26,6 +27,16 @@ class DeveloperSettingsNode @AssistedInject constructor(
@Assisted plugins: List<Plugin>, @Assisted plugins: List<Plugin>,
private val presenter: DeveloperSettingsPresenter, private val presenter: DeveloperSettingsPresenter,
) : Node(buildContext, plugins = plugins) { ) : Node(buildContext, plugins = plugins) {
interface Callback : Plugin {
fun onPushHistoryClick()
}
private val callbacks = plugins<Callback>()
private fun onPushHistoryClick() {
callbacks.forEach { it.onPushHistoryClick() }
}
@Composable @Composable
override fun View(modifier: Modifier) { override fun View(modifier: Modifier) {
val activity = requireNotNull(LocalActivity.current) val activity = requireNotNull(LocalActivity.current)
@ -39,6 +50,7 @@ class DeveloperSettingsNode @AssistedInject constructor(
state = state, state = state,
modifier = modifier, modifier = modifier,
onOpenShowkase = ::openShowkase, onOpenShowkase = ::openShowkase,
onPushHistoryClick = ::onPushHistoryClick,
onBackClick = ::navigateUp onBackClick = ::navigateUp
) )
} }

View file

@ -42,6 +42,7 @@ import kotlinx.collections.immutable.toPersistentList
fun DeveloperSettingsView( fun DeveloperSettingsView(
state: DeveloperSettingsState, state: DeveloperSettingsState,
onOpenShowkase: () -> Unit, onOpenShowkase: () -> Unit,
onPushHistoryClick: () -> Unit,
onBackClick: () -> Unit, onBackClick: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
@ -57,6 +58,7 @@ fun DeveloperSettingsView(
) { ) {
FeatureListContent(state) FeatureListContent(state)
} }
NotificationCategory(onPushHistoryClick)
ElementCallCategory(state = state) ElementCallCategory(state = state)
PreferenceCategory(title = "Rust SDK") { PreferenceCategory(title = "Rust SDK") {
@ -159,6 +161,18 @@ private fun ElementCallCategory(
} }
} }
@Composable
private fun NotificationCategory(onPushHistoryClick: () -> Unit) {
PreferenceCategory(title = stringResource(id = R.string.screen_notification_settings_title)) {
ListItem(
headlineContent = {
Text(stringResource(R.string.troubleshoot_notifications_entry_point_push_history_title))
},
onClick = onPushHistoryClick,
)
}
}
@Composable @Composable
private fun FeatureListContent( private fun FeatureListContent(
state: DeveloperSettingsState, state: DeveloperSettingsState,
@ -179,6 +193,7 @@ internal fun DeveloperSettingsViewPreview(@PreviewParameter(DeveloperSettingsSta
DeveloperSettingsView( DeveloperSettingsView(
state = state, state = state,
onOpenShowkase = {}, onOpenShowkase = {},
onPushHistoryClick = {},
onBackClick = {} onBackClick = {}
) )
} }

View file

@ -27,7 +27,6 @@ class NotificationSettingsNode @AssistedInject constructor(
interface Callback : Plugin { interface Callback : Plugin {
fun editDefaultNotificationMode(isOneToOne: Boolean) fun editDefaultNotificationMode(isOneToOne: Boolean)
fun onTroubleshootNotificationsClick() fun onTroubleshootNotificationsClick()
fun onPushHistoryClick()
} }
private val callbacks = plugins<Callback>() private val callbacks = plugins<Callback>()
@ -40,10 +39,6 @@ class NotificationSettingsNode @AssistedInject constructor(
callbacks.forEach { it.onTroubleshootNotificationsClick() } callbacks.forEach { it.onTroubleshootNotificationsClick() }
} }
private fun onPushHistoryClick() {
callbacks.forEach { it.onPushHistoryClick() }
}
@Composable @Composable
override fun View(modifier: Modifier) { override fun View(modifier: Modifier) {
val state = presenter.present() val state = presenter.present()
@ -52,7 +47,6 @@ class NotificationSettingsNode @AssistedInject constructor(
onOpenEditDefault = { openEditDefault(isOneToOne = it) }, onOpenEditDefault = { openEditDefault(isOneToOne = it) },
onBackClick = ::navigateUp, onBackClick = ::navigateUp,
onTroubleshootNotificationsClick = ::onTroubleshootNotificationsClick, onTroubleshootNotificationsClick = ::onTroubleshootNotificationsClick,
onPushHistoryClick = ::onPushHistoryClick,
modifier = modifier, modifier = modifier,
) )
} }

View file

@ -51,7 +51,6 @@ fun NotificationSettingsView(
state: NotificationSettingsState, state: NotificationSettingsState,
onOpenEditDefault: (isOneToOne: Boolean) -> Unit, onOpenEditDefault: (isOneToOne: Boolean) -> Unit,
onTroubleshootNotificationsClick: () -> Unit, onTroubleshootNotificationsClick: () -> Unit,
onPushHistoryClick: () -> Unit,
onBackClick: () -> Unit, onBackClick: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
@ -84,7 +83,6 @@ fun NotificationSettingsView(
// onCallsNotificationsChanged = { state.eventSink(NotificationSettingsEvents.SetCallNotificationsEnabled(it)) }, // onCallsNotificationsChanged = { state.eventSink(NotificationSettingsEvents.SetCallNotificationsEnabled(it)) },
onInviteForMeNotificationsChange = { state.eventSink(NotificationSettingsEvents.SetInviteForMeNotificationsEnabled(it)) }, onInviteForMeNotificationsChange = { state.eventSink(NotificationSettingsEvents.SetInviteForMeNotificationsEnabled(it)) },
onTroubleshootNotificationsClick = onTroubleshootNotificationsClick, onTroubleshootNotificationsClick = onTroubleshootNotificationsClick,
onPushHistoryClick = onPushHistoryClick,
) )
} }
AsyncActionView( AsyncActionView(
@ -108,7 +106,6 @@ private fun NotificationSettingsContentView(
// onCallsNotificationsChanged: (Boolean) -> Unit, // onCallsNotificationsChanged: (Boolean) -> Unit,
onInviteForMeNotificationsChange: (Boolean) -> Unit, onInviteForMeNotificationsChange: (Boolean) -> Unit,
onTroubleshootNotificationsClick: () -> Unit, onTroubleshootNotificationsClick: () -> Unit,
onPushHistoryClick: () -> Unit,
) { ) {
val context = LocalContext.current val context = LocalContext.current
val systemSettings: NotificationSettingsState.AppSettings = state.appSettings val systemSettings: NotificationSettingsState.AppSettings = state.appSettings
@ -207,12 +204,6 @@ private fun NotificationSettingsContentView(
}, },
onClick = onTroubleshootNotificationsClick onClick = onTroubleshootNotificationsClick
) )
ListItem(
headlineContent = {
Text(stringResource(R.string.troubleshoot_notifications_entry_point_push_history_title))
},
onClick = onPushHistoryClick
)
} }
if (state.showAdvancedSettings) { if (state.showAdvancedSettings) {
PreferenceCategory(title = stringResource(id = CommonStrings.common_advanced_settings)) { PreferenceCategory(title = stringResource(id = CommonStrings.common_advanced_settings)) {
@ -313,6 +304,5 @@ internal fun NotificationSettingsViewPreview(@PreviewParameter(NotificationSetti
onBackClick = {}, onBackClick = {},
onOpenEditDefault = {}, onOpenEditDefault = {},
onTroubleshootNotificationsClick = {}, onTroubleshootNotificationsClick = {},
onPushHistoryClick = {},
) )
} }

View file

@ -52,6 +52,21 @@ class DeveloperSettingsViewTest {
} }
} }
@Config(qualifiers = "h1500dp")
@Test
fun `clicking on push history notification invokes the expected callback`() {
val eventsRecorder = EventsRecorder<DeveloperSettingsEvents>(expectEvents = false)
ensureCalledOnce {
rule.setDeveloperSettingsView(
state = aDeveloperSettingsState(
eventSink = eventsRecorder
),
onPushHistoryClick = it
)
rule.clickOn(R.string.troubleshoot_notifications_entry_point_push_history_title)
}
}
@Config(qualifiers = "h1500dp") @Config(qualifiers = "h1500dp")
@Test @Test
fun `clicking on element call url open the dialogs and submit emits the expected event`() { fun `clicking on element call url open the dialogs and submit emits the expected event`() {
@ -68,7 +83,7 @@ class DeveloperSettingsViewTest {
eventsRecorder.assertSingle(DeveloperSettingsEvents.SetCustomElementCallBaseUrl("https://call.element.dev")) eventsRecorder.assertSingle(DeveloperSettingsEvents.SetCustomElementCallBaseUrl("https://call.element.dev"))
} }
@Config(qualifiers = "h1200dp") @Config(qualifiers = "h2000dp")
@Test @Test
fun `clicking on open showkase invokes the expected callback`() { fun `clicking on open showkase invokes the expected callback`() {
val eventsRecorder = EventsRecorder<DeveloperSettingsEvents>(expectEvents = false) val eventsRecorder = EventsRecorder<DeveloperSettingsEvents>(expectEvents = false)
@ -97,7 +112,7 @@ class DeveloperSettingsViewTest {
eventsRecorder.assertSingle(DeveloperSettingsEvents.SetTracingLogLevel(LogLevelItem.DEBUG)) eventsRecorder.assertSingle(DeveloperSettingsEvents.SetTracingLogLevel(LogLevelItem.DEBUG))
} }
@Config(qualifiers = "h1700dp") @Config(qualifiers = "h2000dp")
@Test @Test
fun `clicking on clear cache emits the expected event`() { fun `clicking on clear cache emits the expected event`() {
val eventsRecorder = EventsRecorder<DeveloperSettingsEvents>() val eventsRecorder = EventsRecorder<DeveloperSettingsEvents>()
@ -114,12 +129,14 @@ class DeveloperSettingsViewTest {
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setDeveloperSettingsView( private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setDeveloperSettingsView(
state: DeveloperSettingsState, state: DeveloperSettingsState,
onOpenShowkase: () -> Unit = EnsureNeverCalled(), onOpenShowkase: () -> Unit = EnsureNeverCalled(),
onPushHistoryClick: () -> Unit = EnsureNeverCalled(),
onBackClick: () -> Unit = EnsureNeverCalled() onBackClick: () -> Unit = EnsureNeverCalled()
) { ) {
setContent { setContent {
DeveloperSettingsView( DeveloperSettingsView(
state = state, state = state,
onOpenShowkase = onOpenShowkase, onOpenShowkase = onOpenShowkase,
onPushHistoryClick = onPushHistoryClick,
onBackClick = onBackClick, onBackClick = onBackClick,
) )
} }

View file

@ -66,22 +66,6 @@ class NotificationSettingsViewTest {
eventsRecorder.assertSingle(NotificationSettingsEvents.RefreshSystemNotificationsEnabled) eventsRecorder.assertSingle(NotificationSettingsEvents.RefreshSystemNotificationsEnabled)
} }
@Config(qualifiers = "h1024dp")
@Test
fun `clicking on push history notification invokes the expected callback`() {
val eventsRecorder = EventsRecorder<NotificationSettingsEvents>()
ensureCalledOnce {
rule.setNotificationSettingsView(
state = aValidNotificationSettingsState(
eventSink = eventsRecorder
),
onPushHistoryClick = it
)
rule.clickOn(R.string.troubleshoot_notifications_entry_point_push_history_title)
}
eventsRecorder.assertSingle(NotificationSettingsEvents.RefreshSystemNotificationsEnabled)
}
@Config(qualifiers = "h1024dp") @Config(qualifiers = "h1024dp")
@Test @Test
fun `clicking on group chats invokes the expected callback`() { fun `clicking on group chats invokes the expected callback`() {
@ -300,7 +284,6 @@ private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setNotif
state: NotificationSettingsState, state: NotificationSettingsState,
onOpenEditDefault: (isOneToOne: Boolean) -> Unit = EnsureNeverCalledWithParam(), onOpenEditDefault: (isOneToOne: Boolean) -> Unit = EnsureNeverCalledWithParam(),
onTroubleshootNotificationsClick: () -> Unit = EnsureNeverCalled(), onTroubleshootNotificationsClick: () -> Unit = EnsureNeverCalled(),
onPushHistoryClick: () -> Unit = EnsureNeverCalled(),
onBackClick: () -> Unit = EnsureNeverCalled(), onBackClick: () -> Unit = EnsureNeverCalled(),
) { ) {
setContent { setContent {
@ -308,7 +291,6 @@ private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setNotif
state = state, state = state,
onOpenEditDefault = onOpenEditDefault, onOpenEditDefault = onOpenEditDefault,
onTroubleshootNotificationsClick = onTroubleshootNotificationsClick, onTroubleshootNotificationsClick = onTroubleshootNotificationsClick,
onPushHistoryClick = onPushHistoryClick,
onBackClick = onBackClick, onBackClick = onBackClick,
) )
} }

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:7a028014d94f3aa7c0f2a81f00d9b686df19103ed9c0a0f32f09db27c2bdc742 oid sha256:e8c417f2c0b856499c3a1733ef6d7415097a324139621fbbfc8fb9d0fe6d1a82
size 53850 size 46108

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:7a028014d94f3aa7c0f2a81f00d9b686df19103ed9c0a0f32f09db27c2bdc742 oid sha256:e8c417f2c0b856499c3a1733ef6d7415097a324139621fbbfc8fb9d0fe6d1a82
size 53850 size 46108

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:67cb6c4c1135742ddd2ca9def6580dec715fe92fcf1abcbcee133793d6fc5c9f oid sha256:9eda74b1b65aca54f03ed4a07230d49ff6495672747975c5efa1da1c60b29f56
size 52424 size 44657

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:aa42d10fcea58c37f4b4c90fc4b174f31b20abbfd25f926937d58355bbaa89b0 oid sha256:657b03d76516c88bf748b70287b9270266b82064918463c71dab6df7eae23bd5
size 52250 size 44817

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:aa42d10fcea58c37f4b4c90fc4b174f31b20abbfd25f926937d58355bbaa89b0 oid sha256:657b03d76516c88bf748b70287b9270266b82064918463c71dab6df7eae23bd5
size 52250 size 44817

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:2822c565f450ff21fab05751db31d4d8d003fca74aff48802c37a45bf8159015 oid sha256:38f81f8a388f31511ec4b6479e0f188e852d8c5556a38661f5f666e1b191d091
size 50860 size 43357