Browse Source

RoomList: simple implementation of setRange

feature/bma/flipper
ganfra 2 years ago
parent
commit
a75b906414
  1. 30
      features/roomlist/src/main/java/io/element/android/x/features/roomlist/RoomListScreen.kt
  2. 7
      features/roomlist/src/main/java/io/element/android/x/features/roomlist/RoomListViewModel.kt
  3. 137
      features/roomlist/src/main/java/io/element/android/x/features/roomlist/components/RoomSummaryRow.kt
  4. 13
      libraries/matrix/src/main/java/io/element/android/x/matrix/MatrixClient.kt
  5. 21
      libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomSummaryDataSource.kt

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

@ -13,7 +13,9 @@ import androidx.compose.material3.Scaffold @@ -13,7 +13,9 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.tooling.preview.Preview
@ -25,7 +27,7 @@ import io.element.android.x.core.compose.LogCompositions @@ -25,7 +27,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.RoomItem
import io.element.android.x.features.roomlist.components.RoomSummaryRow
import io.element.android.x.features.roomlist.components.RoomListTopBar
import io.element.android.x.features.roomlist.model.MatrixUser
import io.element.android.x.features.roomlist.model.RoomListRoomSummary
@ -56,6 +58,7 @@ fun RoomListScreen( @@ -56,6 +58,7 @@ fun RoomListScreen(
isLoginOut = logoutAction is Loading,
filter = filter,
onFilterChanged = viewModel::filterRoom,
onScrollOver = viewModel::updateVisibleRange
)
}
@ -67,12 +70,31 @@ fun RoomListContent( @@ -67,12 +70,31 @@ fun RoomListContent(
filter: String,
onFilterChanged: (String) -> Unit,
onLogoutClicked: () -> Unit,
onScrollOver: (IntRange) -> Unit,
isLoginOut: Boolean,
) {
fun onRoomClicked(room: RoomListRoomSummary) {
onRoomClicked(room.roomId)
}
val appBarState = rememberTopAppBarState()
val lazyListState = rememberLazyListState()
val visibleRange by remember {
derivedStateOf {
val layoutInfo = lazyListState.layoutInfo
val firstItemIndex = layoutInfo.visibleItemsInfo.firstOrNull()?.index ?: 0
val size = layoutInfo.visibleItemsInfo.size
firstItemIndex until firstItemIndex + size
}
}
if (!lazyListState.isScrollInProgress) {
onScrollOver(visibleRange)
}
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(appBarState)
LogCompositions(tag = "RoomListScreen", msg = "Content")
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
@ -91,9 +113,7 @@ fun RoomListContent( @@ -91,9 +113,7 @@ fun RoomListContent(
state = lazyListState,
) {
items(roomSummaries) { room ->
RoomItem(room = room) {
onRoomClicked(it)
}
RoomSummaryRow(room = room, onClick = ::onRoomClicked)
}
}
}
@ -120,6 +140,7 @@ private fun PreviewableRoomListContent() { @@ -120,6 +140,7 @@ private fun PreviewableRoomListContent() {
filter = "filter",
onFilterChanged = {},
isLoginOut = false,
onScrollOver = {}
)
}
}
@ -136,6 +157,7 @@ private fun PreviewableDarkRoomListContent() { @@ -136,6 +157,7 @@ private fun PreviewableDarkRoomListContent() {
filter = "filter",
onFilterChanged = {},
isLoginOut = true,
onScrollOver = {}
)
}
}

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

@ -66,6 +66,13 @@ class RoomListViewModel( @@ -66,6 +66,13 @@ class RoomListViewModel(
}
}
fun updateVisibleRange(range: IntRange) {
viewModelScope.launch {
if (range.isEmpty()) return@launch
client.roomSummaryDataSource().setSlidingSyncRange(range)
}
}
private fun handleInit() {
suspend {
val userAvatarUrl = client.loadUserAvatarURLString().getOrNull()

137
features/roomlist/src/main/java/io/element/android/x/features/roomlist/components/RoomSummaryRow.kt

@ -0,0 +1,137 @@ @@ -0,0 +1,137 @@
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.shape.CircleShape
import androidx.compose.foundation.shape.GenericShape
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.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Alignment.Companion.CenterVertically
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.google.accompanist.placeholder.material.placeholder
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
) {
val clickModifier = if (room.isPlaceholder) {
Modifier
} else {
Modifier.clickable(
onClick = { onClick(room) },
indication = rememberRipple(),
interactionSource = remember { MutableInteractionSource() }
)
}
Box(
modifier = modifier
.fillMaxWidth()
.heightIn(min = minHeight)
.then(clickModifier)
) {
DefaultRoomSummaryRow(modifier = modifier, room = room)
}
}
@Composable
internal fun DefaultRoomSummaryRow(
modifier: Modifier = Modifier,
room: RoomListRoomSummary,
) {
val placeholderShape = PlaceholderShape()
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp)
.height(IntrinsicSize.Min),
verticalAlignment = CenterVertically
) {
Avatar(
room.avatarData,
modifier = Modifier.placeholder(room.isPlaceholder, shape = CircleShape)
)
Column(
modifier = Modifier
.padding(start = 12.dp, end = 4.dp, top = 12.dp, bottom = 12.dp)
.alignByBaseline()
.weight(1f)
) {
// Name
Text(
modifier = Modifier
.placeholder(room.isPlaceholder, shape = placeholderShape),
fontSize = 16.sp,
fontWeight = FontWeight.SemiBold,
text = room.name,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
// Last Message
Text(
modifier = Modifier.placeholder(room.isPlaceholder, shape = placeholderShape),
text = room.lastMessage?.toString().orEmpty(),
color = MaterialTheme.colorScheme.secondary,
fontSize = 14.sp,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
// Timestamp and Unread
Column(
modifier = Modifier
.alignByBaseline(),
) {
Text(
modifier = Modifier.placeholder(room.isPlaceholder, shape = placeholderShape),
fontSize = 12.sp,
text = room.timestamp ?: "",
color = MaterialTheme.colorScheme.secondary,
)
Spacer(modifier.size(4.dp))
val unreadIndicatorColor =
if (room.hasUnread) MaterialTheme.colorScheme.primary else Color.Transparent
Box(
modifier = Modifier
.size(12.dp)
.clip(CircleShape)
.background(unreadIndicatorColor)
.align(Alignment.End),
)
}
}
}
@Composable
fun PlaceholderShape(): GenericShape {
return GenericShape { size, _ ->
val rect = Rect(
0f,
size.height / 4,
size.width,
size.height - size.height / 4
)
addRect(rect)
}
}

13
libraries/matrix/src/main/java/io/element/android/x/matrix/MatrixClient.kt

@ -44,19 +44,19 @@ class MatrixClient internal constructor( @@ -44,19 +44,19 @@ class MatrixClient internal constructor(
.requiredState(
requiredState = listOf(
RequiredState(key = "m.room.avatar", value = ""),
RequiredState(key = "m.room.name", value = ""),
RequiredState(key = "m.room.encryption", value = ""),
)
)
.name(name = "HomeScreenView")
.syncMode(mode = SlidingSyncMode.FULL_SYNC)
.syncMode(mode = SlidingSyncMode.SELECTIVE)
.addRange(0u, 10u)
.build()
private val slidingSync = client
.slidingSync()
.homeserver("https://slidingsync.lab.element.dev")
.withCommonExtensions()
.coldCache("ElementX")
//.coldCache("ElementX")
.addView(slidingSyncView)
.build()
@ -66,7 +66,8 @@ class MatrixClient internal constructor( @@ -66,7 +66,8 @@ class MatrixClient internal constructor(
slidingSyncObserverProxy.updateSummaryFlow,
slidingSync,
slidingSyncView,
dispatchers
dispatchers,
::onRestartSync
)
private var slidingSyncObserverToken: StoppableSpawn? = null
@ -77,6 +78,10 @@ class MatrixClient internal constructor( @@ -77,6 +78,10 @@ class MatrixClient internal constructor(
client.setDelegate(clientDelegate)
}
private fun onRestartSync(){
slidingSyncObserverToken = slidingSync.sync()
}
fun getRoom(roomId: String): MatrixRoom? {
val slidingSyncRoom = slidingSync.getRoom(roomId) ?: return null
val room = slidingSyncRoom.fullRoom() ?: return null

21
libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomSummaryDataSource.kt

@ -12,6 +12,7 @@ import java.util.* @@ -12,6 +12,7 @@ import java.util.*
interface RoomSummaryDataSource {
fun roomSummaries(): Flow<List<RoomSummary>>
fun setSlidingSyncRange(range: IntRange)
}
internal class RustRoomSummaryDataSource(
@ -19,7 +20,8 @@ internal class RustRoomSummaryDataSource( @@ -19,7 +20,8 @@ internal class RustRoomSummaryDataSource(
private val slidingSync: SlidingSync,
private val slidingSyncView: SlidingSyncView,
private val coroutineDispatchers: CoroutineDispatchers,
private val roomSummaryDetailsFactory: RoomSummaryDetailsFactory = RoomSummaryDetailsFactory()
private val onRestartSync: () -> Unit,
private val roomSummaryDetailsFactory: RoomSummaryDetailsFactory = RoomSummaryDetailsFactory(),
) : RoomSummaryDataSource, Closeable {
private val coroutineScope = CoroutineScope(SupervisorJob() + coroutineDispatchers.io)
@ -69,6 +71,12 @@ internal class RustRoomSummaryDataSource( @@ -69,6 +71,12 @@ internal class RustRoomSummaryDataSource(
return roomSummaries.sample(50)
}
override fun setSlidingSyncRange(range: IntRange) {
Timber.v("setVisibleRange=$range")
slidingSyncView.setRange(range.first.toUInt(), range.last.toUInt())
onRestartSync()
}
private suspend fun didReceiveSyncUpdate(summary: UpdateSummary) {
Timber.v("UpdateRooms with identifiers: ${summary.rooms}")
if (state.value != SlidingSyncState.LIVE) {
@ -140,11 +148,12 @@ internal class RustRoomSummaryDataSource( @@ -140,11 +148,12 @@ internal class RustRoomSummaryDataSource(
)
}
private suspend fun updateRoomSummaries(block: MutableList<RoomSummary>.() -> Unit) = withContext(coroutineDispatchers.diffUpdateDispatcher){
val mutableRoomSummaries = roomSummaries.value.toMutableList()
block(mutableRoomSummaries)
roomSummaries.value = mutableRoomSummaries
}
private suspend fun updateRoomSummaries(block: MutableList<RoomSummary>.() -> Unit) =
withContext(coroutineDispatchers.diffUpdateDispatcher) {
val mutableRoomSummaries = roomSummaries.value.toMutableList()
block(mutableRoomSummaries)
roomSummaries.value = mutableRoomSummaries
}
fun SlidingSyncViewRoomsListDiff.isInvalidation(): Boolean {
return when (this) {

Loading…
Cancel
Save