Show current user in the settings and extract code in CurrentUserProvider.

This commit is contained in:
Benoit Marty 2023-06-30 14:26:35 +02:00 committed by Benoit Marty
parent 0c29852d62
commit 002ddf4f3f
12 changed files with 226 additions and 69 deletions

View file

@ -17,23 +17,38 @@
package io.element.android.features.preferences.impl.root package io.element.android.features.preferences.impl.root
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import io.element.android.features.analytics.api.preferences.AnalyticsPreferencesPresenter import io.element.android.features.analytics.api.preferences.AnalyticsPreferencesPresenter
import io.element.android.features.logout.api.LogoutPreferencePresenter import io.element.android.features.logout.api.LogoutPreferencePresenter
import io.element.android.features.rageshake.api.preferences.RageshakePreferencesPresenter import io.element.android.features.rageshake.api.preferences.RageshakePreferencesPresenter
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.core.meta.BuildType import io.element.android.libraries.core.meta.BuildType
import io.element.android.libraries.matrix.api.user.CurrentUserProvider
import io.element.android.libraries.matrix.api.user.MatrixUser
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
class PreferencesRootPresenter @Inject constructor( class PreferencesRootPresenter @Inject constructor(
private val logoutPresenter: LogoutPreferencePresenter, private val logoutPresenter: LogoutPreferencePresenter,
private val rageshakePresenter: RageshakePreferencesPresenter, private val rageshakePresenter: RageshakePreferencesPresenter,
private val analyticsPresenter: AnalyticsPreferencesPresenter, private val analyticsPresenter: AnalyticsPreferencesPresenter,
private val currentUserProvider: CurrentUserProvider,
private val buildType: BuildType, private val buildType: BuildType,
) : Presenter<PreferencesRootState> { ) : Presenter<PreferencesRootState> {
@Composable @Composable
override fun present(): PreferencesRootState { override fun present(): PreferencesRootState {
val matrixUser: MutableState<MatrixUser?> = rememberSaveable {
mutableStateOf(null)
}
LaunchedEffect(Unit) {
initialLoad(matrixUser)
}
val logoutState = logoutPresenter.present() val logoutState = logoutPresenter.present()
val rageshakeState = rageshakePresenter.present() val rageshakeState = rageshakePresenter.present()
val analyticsState = analyticsPresenter.present() val analyticsState = analyticsPresenter.present()
@ -42,8 +57,12 @@ class PreferencesRootPresenter @Inject constructor(
logoutState = logoutState, logoutState = logoutState,
rageshakeState = rageshakeState, rageshakeState = rageshakeState,
analyticsState = analyticsState, analyticsState = analyticsState,
myUser = Async.Uninitialized, myUser = matrixUser.value,
showDeveloperSettings = showDeveloperSettings showDeveloperSettings = showDeveloperSettings
) )
} }
private fun CoroutineScope.initialLoad(matrixUser: MutableState<MatrixUser?>) = launch {
matrixUser.value = currentUserProvider.provide()
}
} }

View file

@ -19,13 +19,12 @@ package io.element.android.features.preferences.impl.root
import io.element.android.features.analytics.api.preferences.AnalyticsPreferencesState import io.element.android.features.analytics.api.preferences.AnalyticsPreferencesState
import io.element.android.features.logout.api.LogoutPreferenceState import io.element.android.features.logout.api.LogoutPreferenceState
import io.element.android.features.rageshake.api.preferences.RageshakePreferencesState import io.element.android.features.rageshake.api.preferences.RageshakePreferencesState
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
data class PreferencesRootState( data class PreferencesRootState(
val logoutState: LogoutPreferenceState, val logoutState: LogoutPreferenceState,
val rageshakeState: RageshakePreferencesState, val rageshakeState: RageshakePreferencesState,
val analyticsState: AnalyticsPreferencesState, val analyticsState: AnalyticsPreferencesState,
val myUser: Async<MatrixUser>, val myUser: MatrixUser?,
val showDeveloperSettings: Boolean val showDeveloperSettings: Boolean
) )

View file

@ -19,12 +19,11 @@ package io.element.android.features.preferences.impl.root
import io.element.android.features.analytics.api.preferences.aAnalyticsPreferencesState import io.element.android.features.analytics.api.preferences.aAnalyticsPreferencesState
import io.element.android.features.logout.api.aLogoutPreferenceState import io.element.android.features.logout.api.aLogoutPreferenceState
import io.element.android.features.rageshake.api.preferences.aRageshakePreferencesState import io.element.android.features.rageshake.api.preferences.aRageshakePreferencesState
import io.element.android.libraries.architecture.Async
fun aPreferencesRootState() = PreferencesRootState( fun aPreferencesRootState() = PreferencesRootState(
logoutState = aLogoutPreferenceState(), logoutState = aLogoutPreferenceState(),
rageshakeState = aRageshakePreferencesState(), rageshakeState = aRageshakePreferencesState(),
analyticsState = aAnalyticsPreferencesState(), analyticsState = aAnalyticsPreferencesState(),
myUser = Async.Uninitialized, myUser = null,
showDeveloperSettings = true showDeveloperSettings = true
) )

View file

@ -92,5 +92,5 @@ fun PreferencesRootViewDarkPreview(@PreviewParameter(MatrixUserProvider::class)
@Composable @Composable
private fun ContentToPreview(matrixUser: MatrixUser) { private fun ContentToPreview(matrixUser: MatrixUser) {
PreferencesRootView(aPreferencesRootState().copy(myUser = Async.Success(matrixUser))) PreferencesRootView(aPreferencesRootState().copy(myUser = matrixUser))
} }

View file

@ -16,14 +16,10 @@
package io.element.android.features.preferences.impl.user package io.element.android.features.preferences.impl.user
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
@ -32,16 +28,13 @@ import io.element.android.libraries.matrix.ui.components.MatrixUserWithNullProvi
@Composable @Composable
fun UserPreferences( fun UserPreferences(
user: Async<MatrixUser>, user: MatrixUser?,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
when (val userData = user.dataOrNull()) { MatrixUserHeader(
null -> Spacer(modifier = modifier.height(1.dp)) modifier = modifier,
else -> MatrixUserHeader( matrixUser = user
modifier = modifier, )
matrixUser = userData
)
}
} }
@Preview @Preview
@ -56,9 +49,5 @@ internal fun UserPreferencesDarkPreview(@PreviewParameter(MatrixUserWithNullProv
@Composable @Composable
private fun ContentToPreview(matrixUser: MatrixUser?) { private fun ContentToPreview(matrixUser: MatrixUser?) {
if (matrixUser == null) { UserPreferences(matrixUser)
UserPreferences(Async.Uninitialized)
} else {
UserPreferences(Async.Success(matrixUser))
}
} }

View file

@ -28,6 +28,10 @@ import io.element.android.features.rageshake.impl.preferences.DefaultRageshakePr
import io.element.android.features.rageshake.test.rageshake.FakeRageShake import io.element.android.features.rageshake.test.rageshake.FakeRageShake
import io.element.android.features.rageshake.test.rageshake.FakeRageshakeDataStore import io.element.android.features.rageshake.test.rageshake.FakeRageshakeDataStore
import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Async
import io.element.android.libraries.matrix.api.user.CurrentUserProvider
import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.test.AN_AVATAR_URL
import io.element.android.libraries.matrix.test.A_USER_NAME
import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClient
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
@ -35,27 +39,36 @@ import org.junit.Test
class PreferencesRootPresenterTest { class PreferencesRootPresenterTest {
@Test @Test
fun `present - initial state`() = runTest { fun `present - initial state`() = runTest {
val logoutPresenter = DefaultLogoutPreferencePresenter(FakeMatrixClient()) val matrixClient = FakeMatrixClient()
val logoutPresenter = DefaultLogoutPreferencePresenter(matrixClient)
val rageshakePresenter = DefaultRageshakePreferencesPresenter(FakeRageShake(), FakeRageshakeDataStore()) val rageshakePresenter = DefaultRageshakePreferencesPresenter(FakeRageShake(), FakeRageshakeDataStore())
val analyticsPresenter = DefaultAnalyticsPreferencesPresenter(FakeAnalyticsService(), A_BUILD_META) val analyticsPresenter = DefaultAnalyticsPreferencesPresenter(FakeAnalyticsService(), A_BUILD_META)
val presenter = PreferencesRootPresenter( val presenter = PreferencesRootPresenter(
logoutPresenter, logoutPresenter,
rageshakePresenter, rageshakePresenter,
analyticsPresenter, analyticsPresenter,
CurrentUserProvider(matrixClient),
A_BUILD_META.buildType A_BUILD_META.buildType
) )
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
skipItems(1)
val initialState = awaitItem() val initialState = awaitItem()
assertThat(initialState.logoutState.logoutAction).isEqualTo(Async.Uninitialized) assertThat(initialState.myUser).isNull()
assertThat(initialState.analyticsState.isEnabled).isFalse() val loadedState = awaitItem()
assertThat(initialState.rageshakeState.isEnabled).isTrue() assertThat(loadedState.logoutState.logoutAction).isEqualTo(Async.Uninitialized)
assertThat(initialState.rageshakeState.isSupported).isTrue() assertThat(loadedState.analyticsState.isEnabled).isFalse()
assertThat(initialState.rageshakeState.sensitivity).isEqualTo(1.0f) assertThat(loadedState.rageshakeState.isEnabled).isTrue()
assertThat(initialState.myUser).isEqualTo(Async.Uninitialized) assertThat(loadedState.rageshakeState.isSupported).isTrue()
assertThat(initialState.showDeveloperSettings).isEqualTo(true) assertThat(loadedState.rageshakeState.sensitivity).isEqualTo(1.0f)
assertThat(loadedState.myUser).isEqualTo(
MatrixUser(
userId = matrixClient.sessionId,
displayName = A_USER_NAME,
avatarUrl = AN_AVATAR_URL
)
)
assertThat(loadedState.showDeveloperSettings).isEqualTo(true)
} }
} }
} }

View file

@ -26,10 +26,10 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import io.element.android.features.networkmonitor.api.NetworkMonitor
import io.element.android.features.networkmonitor.api.NetworkStatus
import io.element.android.features.leaveroom.api.LeaveRoomEvent import io.element.android.features.leaveroom.api.LeaveRoomEvent
import io.element.android.features.leaveroom.api.LeaveRoomPresenter import io.element.android.features.leaveroom.api.LeaveRoomPresenter
import io.element.android.features.networkmonitor.api.NetworkMonitor
import io.element.android.features.networkmonitor.api.NetworkStatus
import io.element.android.features.roomlist.impl.model.RoomListRoomSummary import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
import io.element.android.features.roomlist.impl.model.RoomListRoomSummaryPlaceholders import io.element.android.features.roomlist.impl.model.RoomListRoomSummaryPlaceholders
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
@ -43,8 +43,8 @@ import io.element.android.libraries.designsystem.utils.collectSnackbarMessageAsS
import io.element.android.libraries.eventformatter.api.RoomLastMessageFormatter import io.element.android.libraries.eventformatter.api.RoomLastMessageFormatter
import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.RoomSummary import io.element.android.libraries.matrix.api.room.RoomSummary
import io.element.android.libraries.matrix.api.user.CurrentUserProvider
import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.api.verification.SessionVerificationService import io.element.android.libraries.matrix.api.verification.SessionVerificationService
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
@ -60,6 +60,7 @@ private const val extendedRangeSize = 40
class RoomListPresenter @Inject constructor( class RoomListPresenter @Inject constructor(
private val client: MatrixClient, private val client: MatrixClient,
private val currentUserProvider: CurrentUserProvider,
private val lastMessageTimestampFormatter: LastMessageTimestampFormatter, private val lastMessageTimestampFormatter: LastMessageTimestampFormatter,
private val roomLastMessageFormatter: RoomLastMessageFormatter, private val roomLastMessageFormatter: RoomLastMessageFormatter,
private val sessionVerificationService: SessionVerificationService, private val sessionVerificationService: SessionVerificationService,
@ -162,13 +163,7 @@ class RoomListPresenter @Inject constructor(
} }
private fun CoroutineScope.initialLoad(matrixUser: MutableState<MatrixUser?>) = launch { private fun CoroutineScope.initialLoad(matrixUser: MutableState<MatrixUser?>) = launch {
val userAvatarUrl = client.loadUserAvatarURLString().getOrNull() matrixUser.value = currentUserProvider.provide()
val userDisplayName = client.loadUserDisplayName().getOrNull()
matrixUser.value = MatrixUser(
userId = UserId(client.sessionId.value),
displayName = userDisplayName,
avatarUrl = userAvatarUrl,
)
} }
private fun updateVisibleRange(range: IntRange) { private fun updateVisibleRange(range: IntRange) {

View file

@ -31,6 +31,7 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.utils.SnackbarDispatcher import io.element.android.libraries.designsystem.utils.SnackbarDispatcher
import io.element.android.libraries.eventformatter.test.FakeRoomLastMessageFormatter import io.element.android.libraries.eventformatter.test.FakeRoomLastMessageFormatter
import io.element.android.libraries.matrix.api.user.CurrentUserProvider
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
import io.element.android.libraries.matrix.test.AN_AVATAR_URL import io.element.android.libraries.matrix.test.AN_AVATAR_URL
import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.AN_EXCEPTION
@ -50,8 +51,10 @@ class RoomListPresenterTests {
@Test @Test
fun `present - should start with no user and then load user with success`() = runTest { fun `present - should start with no user and then load user with success`() = runTest {
val matrixClient = FakeMatrixClient()
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient(), matrixClient,
CurrentUserProvider(matrixClient),
createDateFormatter(), createDateFormatter(),
FakeRoomLastMessageFormatter(), FakeRoomLastMessageFormatter(),
FakeSessionVerificationService(), FakeSessionVerificationService(),
@ -75,11 +78,13 @@ class RoomListPresenterTests {
@Test @Test
fun `present - should start with no user and then load user with error`() = runTest { fun `present - should start with no user and then load user with error`() = runTest {
val matrixClient = FakeMatrixClient(
userDisplayName = Result.failure(AN_EXCEPTION),
userAvatarURLString = Result.failure(AN_EXCEPTION),
)
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient( matrixClient,
userDisplayName = Result.failure(AN_EXCEPTION), CurrentUserProvider(matrixClient),
userAvatarURLString = Result.failure(AN_EXCEPTION),
),
createDateFormatter(), createDateFormatter(),
FakeRoomLastMessageFormatter(), FakeRoomLastMessageFormatter(),
FakeSessionVerificationService(), FakeSessionVerificationService(),
@ -100,8 +105,10 @@ class RoomListPresenterTests {
@Test @Test
fun `present - should filter room with success`() = runTest { fun `present - should filter room with success`() = runTest {
val matrixClient = FakeMatrixClient()
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient(), matrixClient,
CurrentUserProvider(matrixClient),
createDateFormatter(), createDateFormatter(),
FakeRoomLastMessageFormatter(), FakeRoomLastMessageFormatter(),
FakeSessionVerificationService(), FakeSessionVerificationService(),
@ -127,10 +134,12 @@ class RoomListPresenterTests {
@Test @Test
fun `present - load 1 room with success`() = runTest { fun `present - load 1 room with success`() = runTest {
val roomSummaryDataSource = FakeRoomSummaryDataSource() val roomSummaryDataSource = FakeRoomSummaryDataSource()
val matrixClient = FakeMatrixClient(
roomSummaryDataSource = roomSummaryDataSource
)
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient( matrixClient,
roomSummaryDataSource = roomSummaryDataSource CurrentUserProvider(matrixClient),
),
createDateFormatter(), createDateFormatter(),
FakeRoomLastMessageFormatter(), FakeRoomLastMessageFormatter(),
FakeSessionVerificationService(), FakeSessionVerificationService(),
@ -159,10 +168,12 @@ class RoomListPresenterTests {
@Test @Test
fun `present - load 1 room with success and filter rooms`() = runTest { fun `present - load 1 room with success and filter rooms`() = runTest {
val roomSummaryDataSource = FakeRoomSummaryDataSource() val roomSummaryDataSource = FakeRoomSummaryDataSource()
val matrixClient = FakeMatrixClient(
roomSummaryDataSource = roomSummaryDataSource
)
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient( matrixClient,
roomSummaryDataSource = roomSummaryDataSource CurrentUserProvider(matrixClient),
),
createDateFormatter(), createDateFormatter(),
FakeRoomLastMessageFormatter(), FakeRoomLastMessageFormatter(),
FakeSessionVerificationService(), FakeSessionVerificationService(),
@ -197,10 +208,12 @@ class RoomListPresenterTests {
@Test @Test
fun `present - update visible range`() = runTest { fun `present - update visible range`() = runTest {
val roomSummaryDataSource = FakeRoomSummaryDataSource() val roomSummaryDataSource = FakeRoomSummaryDataSource()
val matrixClient = FakeMatrixClient(
roomSummaryDataSource = roomSummaryDataSource
)
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient( matrixClient,
roomSummaryDataSource = roomSummaryDataSource CurrentUserProvider(matrixClient),
),
createDateFormatter(), createDateFormatter(),
FakeRoomLastMessageFormatter(), FakeRoomLastMessageFormatter(),
FakeSessionVerificationService(), FakeSessionVerificationService(),
@ -245,10 +258,12 @@ class RoomListPresenterTests {
@Test @Test
fun `present - handle DismissRequestVerificationPrompt`() = runTest { fun `present - handle DismissRequestVerificationPrompt`() = runTest {
val roomSummaryDataSource = FakeRoomSummaryDataSource() val roomSummaryDataSource = FakeRoomSummaryDataSource()
val matrixClient = FakeMatrixClient(
roomSummaryDataSource = roomSummaryDataSource
)
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient( matrixClient,
roomSummaryDataSource = roomSummaryDataSource CurrentUserProvider(matrixClient),
),
createDateFormatter(), createDateFormatter(),
FakeRoomLastMessageFormatter(), FakeRoomLastMessageFormatter(),
FakeSessionVerificationService().apply { FakeSessionVerificationService().apply {
@ -274,8 +289,10 @@ class RoomListPresenterTests {
@Test @Test
fun `present - sets invite state`() = runTest { fun `present - sets invite state`() = runTest {
val inviteStateFlow = MutableStateFlow(InvitesState.NoInvites) val inviteStateFlow = MutableStateFlow(InvitesState.NoInvites)
val matrixClient = FakeMatrixClient()
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient(), matrixClient,
CurrentUserProvider(matrixClient),
createDateFormatter(), createDateFormatter(),
FakeRoomLastMessageFormatter(), FakeRoomLastMessageFormatter(),
FakeSessionVerificationService(), FakeSessionVerificationService(),
@ -304,8 +321,10 @@ class RoomListPresenterTests {
@Test @Test
fun `present - show context menu`() = runTest { fun `present - show context menu`() = runTest {
val matrixClient = FakeMatrixClient()
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient(), matrixClient,
CurrentUserProvider(matrixClient),
createDateFormatter(), createDateFormatter(),
FakeRoomLastMessageFormatter(), FakeRoomLastMessageFormatter(),
FakeSessionVerificationService(), FakeSessionVerificationService(),
@ -331,8 +350,10 @@ class RoomListPresenterTests {
@Test @Test
fun `present - hide context menu`() = runTest { fun `present - hide context menu`() = runTest {
val matrixClient = FakeMatrixClient()
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient(), matrixClient,
CurrentUserProvider(matrixClient),
createDateFormatter(), createDateFormatter(),
FakeRoomLastMessageFormatter(), FakeRoomLastMessageFormatter(),
FakeSessionVerificationService(), FakeSessionVerificationService(),
@ -363,8 +384,10 @@ class RoomListPresenterTests {
@Test @Test
fun `present - leave room calls into leave room presenter`() = runTest { fun `present - leave room calls into leave room presenter`() = runTest {
val leaveRoomPresenter = LeaveRoomPresenterFake() val leaveRoomPresenter = LeaveRoomPresenterFake()
val matrixClient = FakeMatrixClient()
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient(), matrixClient,
CurrentUserProvider(matrixClient),
createDateFormatter(), createDateFormatter(),
FakeRoomLastMessageFormatter(), FakeRoomLastMessageFormatter(),
FakeSessionVerificationService(), FakeSessionVerificationService(),

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.matrix.api.user
import io.element.android.libraries.matrix.api.MatrixClient
import javax.inject.Inject
class CurrentUserProvider @Inject constructor(
private val matrixClient: MatrixClient,
) {
suspend fun provide(): MatrixUser {
val userAvatarUrl = matrixClient.loadUserAvatarURLString().getOrNull()
val userDisplayName = matrixClient.loadUserDisplayName().getOrNull()
return MatrixUser(
userId = matrixClient.sessionId,
displayName = userDisplayName,
avatarUrl = userAvatarUrl,
)
}
}

View file

@ -16,7 +16,6 @@
package io.element.android.libraries.matrix.ui.components package io.element.android.libraries.matrix.ui.components
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@ -42,13 +41,16 @@ import io.element.android.libraries.theme.ElementTheme
@Composable @Composable
fun MatrixUserHeader( fun MatrixUserHeader(
matrixUser: MatrixUser, matrixUser: MatrixUser?,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onClick: () -> Unit = {}, // onClick: () -> Unit = {},
) { ) {
if (matrixUser == null) {
return MatrixUserHeaderPlaceholder(modifier = modifier)
}
Row( Row(
modifier = modifier modifier = modifier
.clickable(onClick = onClick) // .clickable(onClick = onClick)
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp), .padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically

View file

@ -0,0 +1,82 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.matrix.ui.components
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.atomic.atoms.PlaceholderAtom
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.roomListPlaceholder
import io.element.android.libraries.theme.ElementTheme
@Composable
fun MatrixUserHeaderPlaceholder(
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Box(
modifier = Modifier
.padding(vertical = 12.dp)
.size(AvatarSize.UserPreference.dp)
.background(color = ElementTheme.colors.roomListPlaceholder, shape = CircleShape)
)
Spacer(modifier = Modifier.width(16.dp))
Column(
modifier = Modifier.weight(1f)
) {
PlaceholderAtom(width = 80.dp, height = 7.dp)
Spacer(modifier = Modifier.height(16.dp))
PlaceholderAtom(width = 180.dp, height = 6.dp)
}
}
}
@Preview
@Composable
fun MatrixUserHeaderPlaceholderLightPreview() =
ElementPreviewLight { ContentToPreview() }
@Preview
@Composable
fun MatrixUserHeaderPlaceholderDarkPreview() =
ElementPreviewDark { ContentToPreview() }
@Composable
private fun ContentToPreview() {
MatrixUserHeaderPlaceholder()
}

View file

@ -38,6 +38,7 @@ import io.element.android.libraries.eventformatter.impl.StateContentFormatter
import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import io.element.android.libraries.matrix.api.user.CurrentUserProvider
import io.element.android.services.toolbox.impl.strings.AndroidStringProvider import io.element.android.services.toolbox.impl.strings.AndroidStringProvider
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -60,6 +61,7 @@ class RoomListScreen(
private val stringProvider = AndroidStringProvider(context.resources) private val stringProvider = AndroidStringProvider(context.resources)
private val presenter = RoomListPresenter( private val presenter = RoomListPresenter(
client = matrixClient, client = matrixClient,
currentUserProvider = CurrentUserProvider(matrixClient),
lastMessageTimestampFormatter = DefaultLastMessageTimestampFormatter(dateTimeProvider, dateFormatters), lastMessageTimestampFormatter = DefaultLastMessageTimestampFormatter(dateTimeProvider, dateFormatters),
roomLastMessageFormatter = DefaultRoomLastMessageFormatter( roomLastMessageFormatter = DefaultRoomLastMessageFormatter(
sp = stringProvider, sp = stringProvider,