UX cleanup: DM details screen (#2820)

* UX cleanup: user profile.

- Move send DM to a CTA button.
- Add 'Call' CTA button too when there is a DM with that user and a call is possible.
- Add missing tests.

* Update screenshots

* Add tests for clicking on the avatar

---------

Co-authored-by: ElementBot <benoitm+elementbot@element.io>
This commit is contained in:
Jorge Martin Espinosa 2024-05-08 16:05:02 +02:00 committed by GitHub
parent 0bbb107dea
commit 5dddda64d1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
38 changed files with 396 additions and 56 deletions

View file

@ -16,6 +16,7 @@
package io.element.android.features.userprofile.impl
import android.content.Context
import android.os.Parcelable
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@ -28,6 +29,8 @@ import com.bumble.appyx.navmodel.backstack.operation.push
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode
import io.element.android.features.call.CallType
import io.element.android.features.call.ui.ElementCallActivity
import io.element.android.features.userprofile.api.UserProfileEntryPoint
import io.element.android.features.userprofile.impl.root.UserProfileNode
import io.element.android.features.userprofile.shared.UserProfileNodeHelper
@ -37,9 +40,11 @@ import io.element.android.libraries.architecture.BaseFlowNode
import io.element.android.libraries.architecture.createNode
import io.element.android.libraries.architecture.inputs
import io.element.android.libraries.core.mimetype.MimeTypes
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.media.MediaSource
import io.element.android.libraries.matrix.api.user.CurrentSessionIdHolder
import io.element.android.libraries.mediaviewer.api.local.MediaInfo
import io.element.android.libraries.mediaviewer.api.viewer.MediaViewerNode
import kotlinx.parcelize.Parcelize
@ -48,6 +53,8 @@ import kotlinx.parcelize.Parcelize
class UserProfileFlowNode @AssistedInject constructor(
@Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>,
@ApplicationContext private val context: Context,
private val sessionIdHolder: CurrentSessionIdHolder,
) : BaseFlowNode<UserProfileFlowNode.NavTarget>(
backstack = BackStack(
initialElement = NavTarget.Root,
@ -75,6 +82,10 @@ class UserProfileFlowNode @AssistedInject constructor(
override fun onStartDM(roomId: RoomId) {
plugins<UserProfileEntryPoint.Callback>().forEach { it.onOpenRoom(roomId) }
}
override fun onStartCall(roomId: RoomId) {
ElementCallActivity.start(context, CallType.RoomCall(sessionId = sessionIdHolder.current, roomId = roomId))
}
}
val params = UserProfileNode.UserProfileInputs(userId = inputs<UserProfileEntryPoint.Params>().userId)
createNode<UserProfileNode>(buildContext, listOf(callback, params))

View file

@ -89,7 +89,8 @@ class UserProfileNode @AssistedInject constructor(
modifier = modifier,
goBack = this::navigateUp,
onShareUser = ::onShareUser,
onDMStarted = ::onStartDM,
onDmStarted = ::onStartDM,
onStartCall = callback::onStartCall,
openAvatarPreview = callback::openAvatarPreview,
)
}

View file

@ -66,6 +66,8 @@ class UserProfilePresenter @AssistedInject constructor(
var userProfile by remember { mutableStateOf<MatrixUser?>(null) }
val startDmActionState: MutableState<AsyncAction<RoomId>> = remember { mutableStateOf(AsyncAction.Uninitialized) }
val isBlocked: MutableState<AsyncData<Boolean>> = remember { mutableStateOf(AsyncData.Uninitialized) }
val dmRoomId by userProfilePresenterHelper.getDmRoomId()
val canCall by userProfilePresenterHelper.getCanCall(dmRoomId)
LaunchedEffect(Unit) {
client.ignoredUsersFlow
.map { ignoredUsers -> userId in ignoredUsers }
@ -118,6 +120,8 @@ class UserProfilePresenter @AssistedInject constructor(
startDmActionState = startDmActionState.value,
displayConfirmationDialog = confirmationDialog,
isCurrentUser = client.isMe(userId),
dmRoomId = dmRoomId,
canCall = canCall,
eventSink = ::handleEvents
)
}

View file

@ -64,6 +64,8 @@ class UserProfilePresenterTests {
assertThat(initialState.userName).isEqualTo(matrixUser.displayName)
assertThat(initialState.avatarUrl).isEqualTo(matrixUser.avatarUrl)
assertThat(initialState.isBlocked).isEqualTo(AsyncData.Success(false))
assertThat(initialState.dmRoomId).isEqualTo(A_ROOM_ID)
assertThat(initialState.canCall).isFalse()
}
}