Poll history : use pager to keep scrolling state when switching filter

This commit is contained in:
ganfra 2023-12-12 14:24:41 +01:00
parent 99e3ac7c63
commit 424e9e266e
6 changed files with 82 additions and 38 deletions

View file

@ -23,6 +23,5 @@ sealed interface PollHistoryEvents {
data object LoadMore : PollHistoryEvents data object LoadMore : PollHistoryEvents
data class PollAnswerSelected(val pollStartId: EventId, val answerId: String) : PollHistoryEvents data class PollAnswerSelected(val pollStartId: EventId, val answerId: String) : PollHistoryEvents
data class PollEndClicked(val pollStartId: EventId) : PollHistoryEvents data class PollEndClicked(val pollStartId: EventId) : PollHistoryEvents
data object EditPoll : PollHistoryEvents
data class OnFilterSelected(val filter: PollHistoryFilter) : PollHistoryEvents data class OnFilterSelected(val filter: PollHistoryFilter) : PollHistoryEvents
} }

View file

@ -41,6 +41,7 @@ class PollHistoryNode @AssistedInject constructor(
PollHistoryView( PollHistoryView(
state = presenter.present(), state = presenter.present(),
modifier = modifier, modifier = modifier,
onEditPoll = {},
goBack = this::navigateUp, goBack = this::navigateUp,
) )
} }

View file

@ -38,7 +38,6 @@ import io.element.android.libraries.matrix.ui.room.rememberPollHistory
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
class PollHistoryPresenter @Inject constructor( class PollHistoryPresenter @Inject constructor(
@ -82,32 +81,23 @@ class PollHistoryPresenter @Inject constructor(
is PollHistoryEvents.PollEndClicked -> appCoroutineScope.launch { is PollHistoryEvents.PollEndClicked -> appCoroutineScope.launch {
endPollAction.execute(pollStartId = event.pollStartId) endPollAction.execute(pollStartId = event.pollStartId)
} }
PollHistoryEvents.EditPoll -> Unit
is PollHistoryEvents.OnFilterSelected -> { is PollHistoryEvents.OnFilterSelected -> {
activeFilter = event.filter activeFilter = event.filter
} }
} }
} }
val currentItems by remember {
derivedStateOf {
when (activeFilter) {
PollHistoryFilter.ONGOING -> pollHistoryItems.ongoing
PollHistoryFilter.PAST -> pollHistoryItems.past
}
}
}
return PollHistoryState( return PollHistoryState(
isLoading = isLoading, isLoading = isLoading,
hasMoreToLoad = paginationState.hasMoreToLoadBackwards, hasMoreToLoad = paginationState.hasMoreToLoadBackwards,
currentItems = currentItems, pollHistoryItems = pollHistoryItems,
activeFilter = activeFilter, activeFilter = activeFilter,
eventSink = ::handleEvents, eventSink = ::handleEvents,
) )
} }
private fun CoroutineScope.loadMore(pollHistory: MatrixTimeline) = launch { private fun CoroutineScope.loadMore(pollHistory: MatrixTimeline) = launch {
Timber.d("LoadMore poll history") pollHistory.paginateBackwards(200)
pollHistory.paginateBackwards(50, 3)
} }
} }

View file

@ -18,12 +18,21 @@ package io.element.android.features.poll.impl.history
import io.element.android.features.poll.impl.history.model.PollHistoryFilter import io.element.android.features.poll.impl.history.model.PollHistoryFilter
import io.element.android.features.poll.impl.history.model.PollHistoryItem import io.element.android.features.poll.impl.history.model.PollHistoryItem
import io.element.android.features.poll.impl.history.model.PollHistoryItems
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
data class PollHistoryState( data class PollHistoryState(
val isLoading: Boolean, val isLoading: Boolean,
val hasMoreToLoad: Boolean, val hasMoreToLoad: Boolean,
val activeFilter: PollHistoryFilter, val activeFilter: PollHistoryFilter,
val currentItems: ImmutableList<PollHistoryItem>, val pollHistoryItems: PollHistoryItems,
val eventSink: (PollHistoryEvents) -> Unit, val eventSink: (PollHistoryEvents) -> Unit,
) ) {
fun pollHistoryForFilter(filter: PollHistoryFilter): ImmutableList<PollHistoryItem> {
return when (filter) {
PollHistoryFilter.ONGOING -> pollHistoryItems.ongoing
PollHistoryFilter.PAST -> pollHistoryItems.past
}
}
}

View file

@ -21,6 +21,7 @@ import io.element.android.features.poll.api.pollcontent.PollContentState
import io.element.android.features.poll.api.pollcontent.aPollContentState import io.element.android.features.poll.api.pollcontent.aPollContentState
import io.element.android.features.poll.impl.history.model.PollHistoryFilter import io.element.android.features.poll.impl.history.model.PollHistoryFilter
import io.element.android.features.poll.impl.history.model.PollHistoryItem import io.element.android.features.poll.impl.history.model.PollHistoryItem
import io.element.android.features.poll.impl.history.model.PollHistoryItems
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
@ -51,7 +52,9 @@ private fun aPollHistoryState(
isLoading = isLoading, isLoading = isLoading,
hasMoreToLoad = hasMoreToLoad, hasMoreToLoad = hasMoreToLoad,
activeFilter = activeFilter, activeFilter = activeFilter,
currentItems = currentItems, pollHistoryItems = PollHistoryItems(
ongoing = currentItems,
past = currentItems,),
eventSink = {}, eventSink = {},
) )

View file

@ -17,6 +17,7 @@
package io.element.android.features.poll.impl.history package io.element.android.features.poll.impl.history
import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.consumeWindowInsets
@ -26,11 +27,15 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SingleChoiceSegmentedButtonRow import androidx.compose.material3.SingleChoiceSegmentedButtonRow
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
@ -50,14 +55,29 @@ import io.element.android.libraries.designsystem.theme.components.Surface
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.EventId
import kotlinx.collections.immutable.ImmutableList
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
@Composable @Composable
fun PollHistoryView( fun PollHistoryView(
state: PollHistoryState, state: PollHistoryState,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onEditPoll: (EventId) -> Unit,
goBack: () -> Unit, goBack: () -> Unit,
) { ) {
fun onLoadMore() {
state.eventSink(PollHistoryEvents.LoadMore)
}
fun onAnswerSelected(pollStartId: EventId, answerId: String) {
state.eventSink(PollHistoryEvents.PollAnswerSelected(pollStartId, answerId))
}
fun onPollEnd(pollStartId: EventId) {
state.eventSink(PollHistoryEvents.PollEndClicked(pollStartId))
}
Scaffold( Scaffold(
modifier = modifier, modifier = modifier,
topBar = { topBar = {
@ -79,6 +99,12 @@ fun PollHistoryView(
.padding(padding) .padding(padding)
.consumeWindowInsets(padding) .consumeWindowInsets(padding)
) { ) {
val pagerState = rememberPagerState(state.activeFilter.ordinal, 0f) {
PollHistoryFilter.entries.size
}
LaunchedEffect(state.activeFilter) {
pagerState.scrollToPage(state.activeFilter.ordinal)
}
PollHistoryFilterButtons( PollHistoryFilterButtons(
activeFilter = state.activeFilter, activeFilter = state.activeFilter,
onFilterSelected = { state.eventSink(PollHistoryEvents.OnFilterSelected(it)) }, onFilterSelected = { state.eventSink(PollHistoryEvents.OnFilterSelected(it)) },
@ -86,10 +112,25 @@ fun PollHistoryView(
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp), .padding(horizontal = 16.dp, vertical = 8.dp),
) )
PollHistoryList( HorizontalPager(
state = state, state = pagerState,
modifier = Modifier.fillMaxSize() userScrollEnabled = false,
) modifier = modifier.fillMaxSize()
) { page ->
val filter = PollHistoryFilter.entries[page]
val pollHistoryItems = state.pollHistoryForFilter(filter)
PollHistoryList(
pollHistoryItems = pollHistoryItems,
hasMoreToLoad = state.hasMoreToLoad,
isLoading = state.isLoading,
onAnswerSelected = ::onAnswerSelected,
onPollEdit = onEditPoll,
onPollEnd = ::onPollEnd,
onLoadMore = ::onLoadMore,
modifier = Modifier.fillMaxSize(),
)
}
} }
} }
} }
@ -116,36 +157,36 @@ private fun PollHistoryFilterButtons(
@Composable @Composable
private fun PollHistoryList( private fun PollHistoryList(
state: PollHistoryState, pollHistoryItems: ImmutableList<PollHistoryItem>,
hasMoreToLoad: Boolean,
isLoading: Boolean,
onAnswerSelected: (pollStartId: EventId, answerId: String) -> Unit,
onPollEdit: (pollStartId: EventId) -> Unit,
onPollEnd: (pollStartId: EventId) -> Unit,
onLoadMore: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
val lazyListState = rememberLazyListState()
LazyColumn( LazyColumn(
state = lazyListState,
modifier = modifier, modifier = modifier,
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
) { ) {
items(state.currentItems) { pollHistoryItem -> items(pollHistoryItems) { pollHistoryItem ->
PollHistoryItemRow( PollHistoryItemRow(
pollHistoryItem = pollHistoryItem, pollHistoryItem = pollHistoryItem,
onAnswerSelected = fun(pollStartId: EventId, answerId: String) { onAnswerSelected = onAnswerSelected,
state.eventSink(PollHistoryEvents.PollAnswerSelected(pollStartId, answerId)) onPollEdit = onPollEdit,
}, onPollEnd = onPollEnd,
onPollEdit = {
state.eventSink(PollHistoryEvents.EditPoll)
},
onPollEnd = {
state.eventSink(PollHistoryEvents.PollEndClicked(it))
},
modifier = Modifier.padding(vertical = 8.dp, horizontal = 16.dp) modifier = Modifier.padding(vertical = 8.dp, horizontal = 16.dp)
) )
} }
if (state.hasMoreToLoad) { if (hasMoreToLoad) {
item { item {
Button( Button(
text = "Load more", text = "Load more",
showProgress = state.isLoading, showProgress = isLoading,
onClick = { onClick = onLoadMore,
state.eventSink(PollHistoryEvents.LoadMore)
},
modifier = Modifier.padding(vertical = 24.dp), modifier = Modifier.padding(vertical = 24.dp),
) )
} }
@ -190,6 +231,7 @@ internal fun PollHistoryViewPreview(
) = ElementPreview { ) = ElementPreview {
PollHistoryView( PollHistoryView(
state = state, state = state,
onEditPoll = {},
goBack = {}, goBack = {},
) )
} }