mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-02 12:07:28 +00:00
Add profile editor, member invite and status banners (#4)
* feat(healthchat): add profile editor, member invite and status banners Native 13-field profile editor with diff-only saves and avatar upload through the HealthChat API (replaces the upstream display-name editor), email invitation for approved accounts, and non-dismissible account status banners in settings and the member directory. * fix(healthchat): satisfy detekt and konsist rules Konsist presenter helper shape, no '=' in state parameter docs, present-tense invite callback, and complete renderer KDoc.
This commit is contained in:
@@ -70,6 +70,7 @@ dependencies {
|
||||
implementation(projects.libraries.sessionStorage.api)
|
||||
implementation(projects.libraries.uiUtils)
|
||||
implementation(projects.libraries.fullscreenintent.api)
|
||||
implementation(projects.features.healthchat.api)
|
||||
implementation(projects.features.rageshake.api)
|
||||
implementation(projects.features.lockscreen.api)
|
||||
implementation(projects.features.analytics.api)
|
||||
|
||||
+15
-8
@@ -21,6 +21,7 @@ import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.features.deactivation.api.AccountDeactivationEntryPoint
|
||||
import io.element.android.features.healthchat.api.HealthChatEntryPoint
|
||||
import io.element.android.features.licenses.api.OpenSourceLicensesEntryPoint
|
||||
import io.element.android.features.lockscreen.api.LockScreenEntryPoint
|
||||
import io.element.android.features.logout.api.LogoutEntryPoint
|
||||
@@ -36,7 +37,6 @@ import io.element.android.features.preferences.impl.moderation.ModerationAndSafe
|
||||
import io.element.android.features.preferences.impl.notifications.NotificationSettingsNode
|
||||
import io.element.android.features.preferences.impl.notifications.edit.EditDefaultNotificationSettingNode
|
||||
import io.element.android.features.preferences.impl.root.PreferencesRootNode
|
||||
import io.element.android.features.preferences.impl.user.editprofile.EditUserProfileNode
|
||||
import io.element.android.libraries.architecture.BackstackView
|
||||
import io.element.android.libraries.architecture.BaseFlowNode
|
||||
import io.element.android.libraries.architecture.appyx.canPop
|
||||
@@ -65,6 +65,8 @@ class PreferencesFlowNode(
|
||||
private val logoutEntryPoint: LogoutEntryPoint,
|
||||
private val openSourceLicensesEntryPoint: OpenSourceLicensesEntryPoint,
|
||||
private val accountDeactivationEntryPoint: AccountDeactivationEntryPoint,
|
||||
// HealthChat fork: the native 13-field profile editor.
|
||||
private val healthChatEntryPoint: HealthChatEntryPoint,
|
||||
) : BaseFlowNode<PreferencesFlowNode.NavTarget>(
|
||||
backstack = BackStack(
|
||||
initialElement = plugins.filterIsInstance<PreferencesEntryPoint.Params>().first().initialElement.toNavTarget(),
|
||||
@@ -341,13 +343,18 @@ class PreferencesFlowNode(
|
||||
createNode<MediaSettingsNode>(buildContext)
|
||||
}
|
||||
is NavTarget.UserProfile -> {
|
||||
val inputs = EditUserProfileNode.Inputs(navTarget.matrixUser)
|
||||
val callback = object : EditUserProfileNode.Callback {
|
||||
override fun onDone() {
|
||||
backstack.pop()
|
||||
}
|
||||
}
|
||||
createNode<EditUserProfileNode>(buildContext, listOf(inputs, callback))
|
||||
// HealthChat fork: the native 13-field editor replaces the upstream
|
||||
// display-name editor (the server derives the display name).
|
||||
healthChatEntryPoint.createNode(
|
||||
parentNode = this,
|
||||
buildContext = buildContext,
|
||||
params = HealthChatEntryPoint.Params(HealthChatEntryPoint.InitialTarget.EditOwnProfile),
|
||||
callback = object : HealthChatEntryPoint.Callback {
|
||||
override fun onDone() {
|
||||
backstack.pop()
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
NavTarget.LockScreenSettings -> {
|
||||
lockScreenEntryPoint.createNode(
|
||||
|
||||
+11
-1
@@ -19,6 +19,7 @@ import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.features.healthchat.api.HealthChatAccountStatusRenderer
|
||||
import io.element.android.features.preferences.impl.account.PreferencesAccountCallback
|
||||
import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTab
|
||||
import io.element.android.libraries.architecture.callback
|
||||
@@ -33,6 +34,8 @@ class PreferencesRootNode(
|
||||
@Assisted plugins: List<Plugin>,
|
||||
private val presenter: PreferencesRootPresenter,
|
||||
private val emojiPickerRenderer: EmojiPickerRenderer,
|
||||
// HealthChat fork: renders the account status banners.
|
||||
private val healthChatAccountStatusRenderer: HealthChatAccountStatusRenderer,
|
||||
) : Node(buildContext, plugins = plugins) {
|
||||
interface Callback : PreferencesAccountCallback, Plugin {
|
||||
fun navigateToAddAccount()
|
||||
@@ -90,7 +93,14 @@ class PreferencesRootNode(
|
||||
onOpenNotificationSettings = callback::navigateToNotificationSettings,
|
||||
onEditProfileClick = callback::navigateToUserProfile,
|
||||
onSignOutClick = callback::startSignOutFlow,
|
||||
onDeactivateClick = callback::startAccountDeactivationFlow
|
||||
onDeactivateClick = callback::startAccountDeactivationFlow,
|
||||
healthChatAccountStatus = {
|
||||
healthChatAccountStatusRenderer.Render(
|
||||
onCompleteProfileClick = { callback.navigateToUserProfile(state.myUser) },
|
||||
includePendingApproval = true,
|
||||
modifier = Modifier,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -99,6 +99,8 @@ fun PreferencesRootView(
|
||||
onSignOutClick: () -> Unit,
|
||||
onDeactivateClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
// HealthChat fork: account status banners, rendered by features/healthchat.
|
||||
healthChatAccountStatus: @Composable () -> Unit = {},
|
||||
) {
|
||||
val snackbarHostState = rememberSnackbarHostState(snackbarMessage = state.snackbarMessage)
|
||||
|
||||
@@ -134,6 +136,8 @@ fun PreferencesRootView(
|
||||
thickness = 8.dp,
|
||||
color = ElementTheme.colors.bgSubtleSecondary,
|
||||
)
|
||||
// HealthChat fork: account status banners head the account section.
|
||||
healthChatAccountStatus()
|
||||
// Account settings section
|
||||
PreferencesAccountView(
|
||||
state = state.preferencesAccountState,
|
||||
|
||||
+1
@@ -49,6 +49,7 @@ class DefaultPreferencesEntryPointTest {
|
||||
logoutEntryPoint = FakeLogoutEntryPoint(),
|
||||
openSourceLicensesEntryPoint = FakeOpenSourceLicensesEntryPoint(),
|
||||
accountDeactivationEntryPoint = FakeAccountDeactivationEntryPoint(),
|
||||
healthChatEntryPoint = { _, _, _, _ -> lambdaError() },
|
||||
)
|
||||
}
|
||||
val callback = object : PreferencesEntryPoint.Callback {
|
||||
|
||||
Reference in New Issue
Block a user