Browse Source

Merge branch 'develop' of https://github.com/vector-im/element-x-android-poc into develop

feature/bma/flipper
ganfra 2 years ago
parent
commit
cf25198739
  1. 50
      features/roomlist/src/main/java/io/element/android/x/features/roomlist/RoomListScreen.kt
  2. 30
      features/roomlist/src/main/java/io/element/android/x/features/roomlist/RoomListViewModel.kt
  3. 54
      features/roomlist/src/main/java/io/element/android/x/features/roomlist/components/RoomFilter.kt
  4. 2
      features/roomlist/src/main/java/io/element/android/x/features/roomlist/model/RoomListViewState.kt

50
features/roomlist/src/main/java/io/element/android/x/features/roomlist/RoomListScreen.kt

@ -2,9 +2,16 @@ @@ -2,9 +2,16 @@
package io.element.android.x.features.roomlist
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold
import androidx.compose.material3.TopAppBarDefaults
@ -14,6 +21,7 @@ import androidx.compose.runtime.getValue @@ -14,6 +21,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.compose.collectAsState
@ -22,6 +30,7 @@ import io.element.android.x.core.compose.LogCompositions @@ -22,6 +30,7 @@ import io.element.android.x.core.compose.LogCompositions
import io.element.android.x.designsystem.ElementXTheme
import io.element.android.x.designsystem.components.ProgressDialog
import io.element.android.x.designsystem.components.avatar.AvatarData
import io.element.android.x.features.roomlist.components.RoomFilter
import io.element.android.x.features.roomlist.components.RoomItem
import io.element.android.x.features.roomlist.components.RoomListTopBar
import io.element.android.x.features.roomlist.model.MatrixUser
@ -37,6 +46,7 @@ fun RoomListScreen( @@ -37,6 +46,7 @@ fun RoomListScreen(
) {
val viewModel: RoomListViewModel = mavericksViewModel()
val logoutAction by viewModel.collectAsState(RoomListViewState::logoutAction)
val filter by viewModel.collectAsState(RoomListViewState::filter)
if (logoutAction is Success) {
onSuccessLogout()
return
@ -49,7 +59,9 @@ fun RoomListScreen( @@ -49,7 +59,9 @@ fun RoomListScreen(
matrixUser = matrixUser(),
onRoomClicked = onRoomClicked,
onLogoutClicked = viewModel::logout,
isLoginOut = logoutAction is Loading
isLoginOut = logoutAction is Loading,
filter = filter,
onFilterChanged = viewModel::filterRoom,
)
}
@ -58,10 +70,13 @@ fun RoomListContent( @@ -58,10 +70,13 @@ fun RoomListContent(
roomSummaries: List<RoomListRoomSummary>,
matrixUser: MatrixUser?,
onRoomClicked: (RoomId) -> Unit,
filter: String,
onFilterChanged: (String) -> Unit,
onLogoutClicked: () -> Unit,
isLoginOut: Boolean,
) {
val appBarState = rememberTopAppBarState()
val lazyListState = rememberLazyListState()
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(appBarState)
LogCompositions(tag = "RoomListScreen", msg = "Content")
Scaffold(
@ -70,10 +85,24 @@ fun RoomListContent( @@ -70,10 +85,24 @@ fun RoomListContent(
RoomListTopBar(matrixUser, onLogoutClicked, scrollBehavior)
},
content = { padding ->
LazyColumn(modifier = Modifier.padding(padding)) {
items(roomSummaries) { room ->
RoomItem(room = room) {
onRoomClicked(it)
Column(modifier = Modifier.padding(padding)) {
RoomFilter(
modifier = Modifier
.fillMaxWidth()
.animateContentSize(animationSpec = tween(durationMillis = 300))
.height(if (lazyListState.isScrolled()) 0.dp else 56.dp)
.padding(horizontal = 16.dp, vertical = 4.dp),
filter = filter,
onFilterChanged = onFilterChanged
)
LazyColumn(
modifier = Modifier.weight(1f),
state = lazyListState,
) {
items(roomSummaries) { room ->
RoomItem(room = room) {
onRoomClicked(it)
}
}
}
}
@ -84,6 +113,9 @@ fun RoomListContent( @@ -84,6 +113,9 @@ fun RoomListContent(
}
}
private fun LazyListState.isScrolled(): Boolean {
return firstVisibleItemIndex > 0 || firstVisibleItemScrollOffset > 0
}
@Preview
@Composable
@ -94,7 +126,9 @@ private fun PreviewableRoomListContent() { @@ -94,7 +126,9 @@ private fun PreviewableRoomListContent() {
matrixUser = MatrixUser("User#1", avatarData = AvatarData("U")),
onRoomClicked = {},
onLogoutClicked = {},
isLoginOut = false
filter = "filter",
onFilterChanged = {},
isLoginOut = false,
)
}
}
@ -108,7 +142,9 @@ private fun PreviewableDarkRoomListContent() { @@ -108,7 +142,9 @@ private fun PreviewableDarkRoomListContent() {
matrixUser = MatrixUser("User#1", avatarData = AvatarData("U")),
onRoomClicked = {},
onLogoutClicked = {},
isLoginOut = true
filter = "filter",
onFilterChanged = {},
isLoginOut = true,
)
}
}

30
features/roomlist/src/main/java/io/element/android/x/features/roomlist/RoomListViewModel.kt

@ -14,6 +14,8 @@ import io.element.android.x.matrix.media.MediaResolver @@ -14,6 +14,8 @@ import io.element.android.x.matrix.media.MediaResolver
import io.element.android.x.matrix.room.RoomSummary
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
@ -56,6 +58,14 @@ class RoomListViewModel( @@ -56,6 +58,14 @@ class RoomListViewModel(
}
}
fun filterRoom(filter: String) {
setState {
copy(
filter = filter
)
}
}
private fun handleInit() {
suspend {
val userAvatarUrl = client.loadUserAvatarURLString().getOrNull()
@ -75,15 +85,27 @@ class RoomListViewModel( @@ -75,15 +85,27 @@ class RoomListViewModel(
copy(user = it)
}
client.roomSummaryDataSource().roomSummaries()
.map(::mapRoomSummaries)
.flowOn(Dispatchers.Default)
// Observe the room list and the filter
combine(
client.roomSummaryDataSource().roomSummaries()
.map(::mapRoomSummaries)
.flowOn(Dispatchers.Default),
stateFlow
.map { it.filter }
.distinctUntilChanged(),
) { list, filter ->
if (filter.isEmpty()) {
list
} else {
list.filter { it.name.contains(filter, ignoreCase = true) }
}
}
.execute {
copy(
rooms = when {
it is Loading ||
// Note: this second case will prevent to handle correctly the empty case
(it is Success && it().isEmpty()) -> {
(it is Success && it().isEmpty() && filter.isEmpty()) -> {
// Show fake placeholders to avoid having empty screen
Loading(createFakePlaceHolders())
}

54
features/roomlist/src/main/java/io/element/android/x/features/roomlist/components/RoomFilter.kt

@ -0,0 +1,54 @@ @@ -0,0 +1,54 @@
package io.element.android.x.features.roomlist.components
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Clear
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun RoomFilter(
modifier: Modifier = Modifier,
filter: String,
onFilterChanged: (String) -> Unit
) {
TextField(
modifier = modifier,
value = filter,
onValueChange = onFilterChanged,
//label = {
// Text(text = "Search")
//},
leadingIcon = {
Icon(
imageVector = Icons.Filled.Search,
contentDescription = null
)
},
trailingIcon = if (filter.isNotEmpty()) {
{
IconButton(onClick = { onFilterChanged("") }) {
Icon(
imageVector = Icons.Filled.Clear,
contentDescription = null
)
}
}
} else null
)
}
@Composable
@Preview
private fun RoomFilterPreview() {
RoomFilter(
filter = "",
onFilterChanged = {}
)
}

2
features/roomlist/src/main/java/io/element/android/x/features/roomlist/model/RoomListViewState.kt

@ -7,7 +7,9 @@ import io.element.android.x.matrix.core.RoomId @@ -7,7 +7,9 @@ import io.element.android.x.matrix.core.RoomId
data class RoomListViewState(
val user: Async<MatrixUser> = Uninitialized,
// Will contain the filtered rooms, using ::filter (if filter is not empty)
val rooms: Async<List<RoomListRoomSummary>> = Uninitialized,
val filter: String = "",
val canLoadMore: Boolean = false,
val logoutAction: Async<Unit> = Uninitialized,
val roomsById: Map<RoomId, RoomListRoomSummary> = emptyMap()

Loading…
Cancel
Save