Merge develop into feature/fga/dagger_setup
This commit is contained in:
commit
c040e18431
214 changed files with 2662 additions and 1833 deletions
|
|
@ -1,13 +1,11 @@
|
|||
package io.element.android.x.features.roomlist
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
|
|
@ -21,4 +19,4 @@ class ExampleInstrumentedTest {
|
|||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("io.element.android.x.features.roomlist.test", appContext.packageName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<manifest>
|
||||
|
||||
</manifest>
|
||||
</manifest>
|
||||
|
|
|
|||
|
|
@ -2,12 +2,18 @@ package io.element.android.x.features.roomlist
|
|||
|
||||
import android.text.format.DateFormat
|
||||
import android.text.format.DateUtils
|
||||
import kotlinx.datetime.*
|
||||
import kotlinx.datetime.TimeZone
|
||||
import java.time.Period
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.*
|
||||
import java.util.Locale
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlinx.datetime.Clock
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.toInstant
|
||||
import kotlinx.datetime.toJavaLocalDate
|
||||
import kotlinx.datetime.toJavaLocalDateTime
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
|
||||
class LastMessageFormatter(
|
||||
private val clock: Clock = Clock.System,
|
||||
|
|
@ -29,7 +35,6 @@ class LastMessageFormatter(
|
|||
DateTimeFormatter.ofPattern(pattern)
|
||||
}
|
||||
|
||||
|
||||
fun format(timestamp: Long?): String {
|
||||
if (timestamp == null) return ""
|
||||
val now: Instant = clock.now()
|
||||
|
|
@ -77,6 +82,4 @@ class LastMessageFormatter(
|
|||
DateUtils.FORMAT_SHOW_WEEKDAY
|
||||
).toString()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ import io.element.android.x.features.roomlist.model.RoomListRoomSummary
|
|||
import io.element.android.x.features.roomlist.model.RoomListViewState
|
||||
import io.element.android.x.features.roomlist.model.stubbedRoomSummaries
|
||||
import io.element.android.x.matrix.core.RoomId
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
@Composable
|
||||
fun RoomListScreen(
|
||||
|
|
@ -53,7 +55,7 @@ fun RoomListScreen(
|
|||
val roomSummaries by viewModel.collectAsState(RoomListViewState::rooms)
|
||||
val matrixUser by viewModel.collectAsState(RoomListViewState::user)
|
||||
RoomListContent(
|
||||
roomSummaries = roomSummaries().orEmpty(),
|
||||
roomSummaries = roomSummaries().orEmpty().toImmutableList(),
|
||||
matrixUser = matrixUser(),
|
||||
onRoomClicked = onRoomClicked,
|
||||
onLogoutClicked = viewModel::logout,
|
||||
|
|
@ -66,16 +68,16 @@ fun RoomListScreen(
|
|||
|
||||
@Composable
|
||||
fun RoomListContent(
|
||||
roomSummaries: List<RoomListRoomSummary>,
|
||||
roomSummaries: ImmutableList<RoomListRoomSummary>,
|
||||
matrixUser: MatrixUser?,
|
||||
onRoomClicked: (RoomId) -> Unit,
|
||||
filter: String,
|
||||
onFilterChanged: (String) -> Unit,
|
||||
onLogoutClicked: () -> Unit,
|
||||
onScrollOver: (IntRange) -> Unit,
|
||||
isLoginOut: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
onRoomClicked: (RoomId) -> Unit = {},
|
||||
onFilterChanged: (String) -> Unit = {},
|
||||
onLogoutClicked: () -> Unit = {},
|
||||
onScrollOver: (IntRange) -> Unit = {},
|
||||
) {
|
||||
|
||||
fun onRoomClicked(room: RoomListRoomSummary) {
|
||||
onRoomClicked(room.roomId)
|
||||
}
|
||||
|
|
@ -104,7 +106,7 @@ fun RoomListContent(
|
|||
}
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
topBar = {
|
||||
RoomListTopBar(
|
||||
matrixUser = matrixUser,
|
||||
|
|
@ -133,7 +135,7 @@ fun RoomListContent(
|
|||
}
|
||||
)
|
||||
if (isLoginOut) {
|
||||
ProgressDialog("Login out...")
|
||||
ProgressDialog(text = "Login out...")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -176,4 +178,3 @@ fun PreviewableDarkRoomListContent() {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,17 +4,15 @@ import com.airbnb.mvrx.*
|
|||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.x.anvilannotations.ContributesViewModel
|
||||
import io.element.android.x.core.data.parallelMap
|
||||
import io.element.android.x.core.coroutine.parallelMap
|
||||
import io.element.android.x.core.di.daggerMavericksViewModelFactory
|
||||
import io.element.android.x.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.x.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.x.di.AppScope
|
||||
import io.element.android.x.di.SessionScope
|
||||
import io.element.android.x.features.roomlist.model.MatrixUser
|
||||
import io.element.android.x.features.roomlist.model.RoomListRoomSummary
|
||||
import io.element.android.x.features.roomlist.model.RoomListRoomSummaryPlaceholders
|
||||
import io.element.android.x.features.roomlist.model.RoomListViewState
|
||||
import io.element.android.x.matrix.Matrix
|
||||
import io.element.android.x.matrix.MatrixClient
|
||||
import io.element.android.x.matrix.media.MediaResolver
|
||||
import io.element.android.x.matrix.room.RoomSummary
|
||||
|
|
@ -112,8 +110,8 @@ class RoomListViewModel @AssistedInject constructor(
|
|||
copy(
|
||||
rooms = when {
|
||||
it is Loading ||
|
||||
// Note: this second case will prevent to handle correctly the empty case
|
||||
(it is Success && it().isEmpty() && filter.isEmpty()) -> {
|
||||
// Note: this second case will prevent to handle correctly the empty case
|
||||
(it is Success && it().isEmpty() && filter.isEmpty()) -> {
|
||||
// Show fake placeholders to avoid having empty screen
|
||||
Loading(RoomListRoomSummaryPlaceholders.createFakeList(size = 16))
|
||||
}
|
||||
|
|
@ -158,5 +156,4 @@ class RoomListViewModel @AssistedInject constructor(
|
|||
.resolve(url, kind = MediaResolver.Kind.Thumbnail(size.value))
|
||||
return AvatarData(name, model, size)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
package io.element.android.x.features.roomlist.components
|
||||
|
||||
import Avatar
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material.ContentAlpha
|
||||
|
|
@ -11,9 +10,23 @@ import androidx.compose.material.icons.filled.ArrowBack
|
|||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.Logout
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.MediumTopAppBar
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
|
|
@ -24,6 +37,7 @@ import androidx.compose.ui.text.font.FontWeight
|
|||
import androidx.compose.ui.unit.sp
|
||||
import io.element.android.x.core.compose.LogCompositions
|
||||
import io.element.android.x.core.compose.textFieldState
|
||||
import io.element.android.x.designsystem.components.avatar.Avatar
|
||||
import io.element.android.x.designsystem.components.dialogs.ConfirmationDialog
|
||||
import io.element.android.x.features.roomlist.model.MatrixUser
|
||||
|
||||
|
|
@ -35,7 +49,6 @@ fun RoomListTopBar(
|
|||
onLogoutClicked: () -> Unit,
|
||||
scrollBehavior: TopAppBarScrollBehavior
|
||||
) {
|
||||
|
||||
LogCompositions(tag = "RoomListScreen", msg = "TopBar")
|
||||
var searchWidgetStateIsOpened by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
|
|
@ -65,20 +78,20 @@ fun RoomListTopBar(
|
|||
scrollBehavior = scrollBehavior,
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SearchRoomListTopBar(
|
||||
text: String,
|
||||
onFilterChanged: (String) -> Unit,
|
||||
onCloseClicked: () -> Unit,
|
||||
scrollBehavior: TopAppBarScrollBehavior
|
||||
scrollBehavior: TopAppBarScrollBehavior,
|
||||
modifier: Modifier = Modifier,
|
||||
onFilterChanged: (String) -> Unit = {},
|
||||
onCloseClicked: () -> Unit = {},
|
||||
) {
|
||||
var filterState by textFieldState(stateValue = text)
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
TopAppBar(
|
||||
modifier = Modifier
|
||||
modifier = modifier
|
||||
.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
title = {
|
||||
TextField(
|
||||
|
|
@ -184,10 +197,13 @@ private fun DefaultRoomListTopBar(
|
|||
)
|
||||
// Log out confirmation dialog
|
||||
ConfirmationDialog(
|
||||
openDialog,
|
||||
isDisplayed = openDialog.value,
|
||||
title = "Log out",
|
||||
content = "Do you confirm you want to log out?",
|
||||
submitText = "Log out",
|
||||
onSubmitClicked = onLogoutClicked,
|
||||
onDismiss = {
|
||||
openDialog.value = false
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,23 @@
|
|||
package io.element.android.x.features.roomlist.components
|
||||
|
||||
import Avatar
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
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.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||
|
|
@ -29,17 +36,17 @@ import androidx.compose.ui.unit.LayoutDirection
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.google.accompanist.placeholder.material.placeholder
|
||||
import io.element.android.x.designsystem.components.avatar.Avatar
|
||||
import io.element.android.x.features.roomlist.model.RoomListRoomSummary
|
||||
|
||||
private val minHeight = 72.dp
|
||||
|
||||
@Composable
|
||||
internal fun RoomSummaryRow(
|
||||
modifier: Modifier = Modifier,
|
||||
room: RoomListRoomSummary,
|
||||
onClick: (RoomListRoomSummary) -> Unit
|
||||
modifier: Modifier = Modifier,
|
||||
onClick: (RoomListRoomSummary) -> Unit = {},
|
||||
) {
|
||||
|
||||
val clickModifier = if (room.isPlaceholder) {
|
||||
modifier
|
||||
} else {
|
||||
|
|
@ -57,7 +64,6 @@ internal fun RoomSummaryRow(
|
|||
) {
|
||||
DefaultRoomSummaryRow(room = room)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -13,4 +13,5 @@ data class RoomListRoomSummary(
|
|||
val timestamp: String? = null,
|
||||
val lastMessage: CharSequence? = null,
|
||||
val avatarData: AvatarData = AvatarData(),
|
||||
val isPlaceholder: Boolean = false,)
|
||||
val isPlaceholder: Boolean = false,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package io.element.android.x.features.roomlist.model
|
|||
|
||||
import io.element.android.x.designsystem.components.avatar.AvatarData
|
||||
|
||||
|
||||
object RoomListRoomSummaryPlaceholders {
|
||||
|
||||
fun create(id: String): RoomListRoomSummary {
|
||||
|
|
@ -23,6 +22,4 @@ object RoomListRoomSummaryPlaceholders {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
package io.element.android.x.features.roomlist.model
|
||||
|
||||
import io.element.android.x.designsystem.components.avatar.AvatarData
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
internal fun stubbedRoomSummaries(): List<RoomListRoomSummary> {
|
||||
return listOf(
|
||||
internal fun stubbedRoomSummaries(): ImmutableList<RoomListRoomSummary> {
|
||||
return persistentListOf(
|
||||
RoomListRoomSummary(
|
||||
name = "Room",
|
||||
hasUnread = true,
|
||||
|
|
@ -22,4 +24,4 @@ internal fun stubbedRoomSummaries(): List<RoomListRoomSummary> {
|
|||
),
|
||||
RoomListRoomSummaryPlaceholders.create("roomId2")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
package io.element.android.x.features.roomlist
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
|
|
@ -14,4 +13,4 @@ class ExampleUnitTest {
|
|||
fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue