Handle sync when landing on the screen

This commit is contained in:
Maxime NATUREL 2023-01-12 15:36:05 +01:00
parent ec65564800
commit c91761240a
9 changed files with 103 additions and 17 deletions

View File

@ -3209,6 +3209,7 @@
<item quantity="one">"There are no past polls for the past day.\nLoad more polls to view polls for previous days."</item>
<item quantity="other">"There are no past polls for the past %1$d days.\nLoad more polls to view polls for previous days."</item>
</plurals>
<string name="room_polls_wait_for_display">Displaying polls</string>
<string name="room_polls_load_more">Load more polls</string>
<!-- Location -->

View File

@ -26,6 +26,7 @@ import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.roomprofile.polls.list.domain.GetLoadedPollsStatusUseCase
import im.vector.app.features.roomprofile.polls.list.domain.GetPollsUseCase
import im.vector.app.features.roomprofile.polls.list.domain.LoadMorePollsUseCase
import im.vector.app.features.roomprofile.polls.list.domain.SyncPollsUseCase
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
@ -35,6 +36,7 @@ class RoomPollsViewModel @AssistedInject constructor(
private val getPollsUseCase: GetPollsUseCase,
private val getLoadedPollsStatusUseCase: GetLoadedPollsStatusUseCase,
private val loadMorePollsUseCase: LoadMorePollsUseCase,
private val syncPollsUseCase: SyncPollsUseCase,
) : VectorViewModel<RoomPollsViewState, RoomPollsAction, RoomPollsViewEvent>(initialState) {
@AssistedFactory
@ -46,9 +48,8 @@ class RoomPollsViewModel @AssistedInject constructor(
init {
updateLoadedPollStatus(initialState.roomId)
syncPolls(initialState.roomId)
observePolls()
// TODO
// call use case to sync polls until now = initial loading
}
private fun updateLoadedPollStatus(roomId: String) {
@ -61,6 +62,14 @@ class RoomPollsViewModel @AssistedInject constructor(
}
}
private fun syncPolls(roomId: String) {
viewModelScope.launch {
setState { copy(isSyncing = true) }
syncPollsUseCase.execute(roomId)
setState { copy(isSyncing = false) }
}
}
private fun observePolls() = withState { viewState ->
getPollsUseCase.execute(viewState.roomId)
.onEach { setState { copy(polls = it) } }

View File

@ -20,13 +20,13 @@ import com.airbnb.mvrx.MavericksState
import im.vector.app.features.roomprofile.RoomProfileArgs
import im.vector.app.features.roomprofile.polls.list.ui.PollSummary
// TODO parameter to know whether initial loading is in progress
data class RoomPollsViewState(
val roomId: String,
val polls: List<PollSummary> = emptyList(),
val isLoadingMore: Boolean = false,
val canLoadMore: Boolean = true,
val nbLoadedDays: Int = 0,
val isSyncing: Boolean = false,
) : MavericksState {
constructor(roomProfileArgs: RoomProfileArgs) : this(roomId = roomProfileArgs.roomId)

View File

@ -158,4 +158,11 @@ class RoomPollDataSource @Inject constructor() {
),
)
}
suspend fun syncPolls(roomId: String) {
Timber.d("roomId=$roomId")
// TODO
// unmock using SDK service + add unit tests
delay(3000)
}
}

View File

@ -37,4 +37,8 @@ class RoomPollRepository @Inject constructor(
suspend fun loadMorePolls(roomId: String): LoadedPollsStatus {
return roomPollDataSource.loadMorePolls(roomId)
}
suspend fun syncPolls(roomId: String) {
return roomPollDataSource.syncPolls(roomId)
}
}

View File

@ -0,0 +1,32 @@
/*
* 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 im.vector.app.features.roomprofile.polls.list.domain
import im.vector.app.features.roomprofile.polls.list.data.RoomPollRepository
import javax.inject.Inject
/**
* Sync the polls of a given room from last manual loading (see LoadMorePollsUseCase) until now.
*/
class SyncPollsUseCase @Inject constructor(
private val roomPollRepository: RoomPollRepository,
) {
suspend fun execute(roomId: String) {
roomPollRepository.syncPolls(roomId)
}
}

View File

@ -39,7 +39,7 @@ class RoomPollsController @Inject constructor(
override fun buildModels(viewState: RoomPollsViewState?) {
val polls = viewState?.polls
if (polls.isNullOrEmpty()) {
if (polls.isNullOrEmpty() || viewState.isSyncing) {
return
}

View File

@ -36,7 +36,7 @@ import im.vector.app.features.roomprofile.polls.RoomPollsViewState
import timber.log.Timber
import javax.inject.Inject
// TODO add and render blocking loader view
// TODO handle errors during load more or sync
abstract class RoomPollsListFragment :
VectorBaseFragment<FragmentRoomPollsListBinding>(),
RoomPollsController.Listener {
@ -93,7 +93,14 @@ abstract class RoomPollsListFragment :
RoomPollsType.ACTIVE -> viewState.polls.filterIsInstance(PollSummary.ActivePoll::class.java)
RoomPollsType.ENDED -> viewState.polls.filterIsInstance(PollSummary.EndedPoll::class.java)
}
renderList(viewState.copy(polls = filteredPolls))
val updatedViewState = viewState.copy(polls = filteredPolls)
renderList(updatedViewState)
renderSyncingView(updatedViewState)
}
private fun renderSyncingView(viewState: RoomPollsViewState) {
views.roomPollsSyncingTitle.isVisible = viewState.isSyncing
views.roomPollsSyncingProgress.isVisible = viewState.isSyncing
}
private fun renderList(viewState: RoomPollsViewState) {
@ -102,9 +109,10 @@ abstract class RoomPollsListFragment :
canLoadMore = viewState.canLoadMore,
nbLoadedDays = viewState.nbLoadedDays,
)
views.roomPollsEmptyTitle.isVisible = viewState.polls.isEmpty()
views.roomPollsLoadMoreWhenEmpty.isVisible = viewState.polls.isEmpty()
views.roomPollsLoadMoreWhenEmptyProgress.isVisible = viewState.polls.isEmpty() && viewState.isLoadingMore
views.roomPollsEmptyTitle.isVisible = viewState.polls.isEmpty() && !viewState.isSyncing
views.roomPollsLoadMoreWhenEmpty.isVisible = viewState.polls.isEmpty() && viewState.canLoadMore && !viewState.isSyncing
views.roomPollsLoadMoreWhenEmptyProgress.isVisible = viewState.polls.isEmpty() && viewState.canLoadMore &&
viewState.isLoadingMore && !viewState.isSyncing
views.roomPollsLoadMoreWhenEmptyProgress.isEnabled = !viewState.isLoadingMore
}

View File

@ -17,6 +17,34 @@
tools:itemCount="5"
tools:listitem="@layout/item_poll" />
<ProgressBar
android:id="@+id/roomPollsSyncingProgress"
style="?android:attr/progressBarStyle"
android:layout_width="16dp"
android:layout_height="16dp"
android:indeterminateTint="?vctr_content_secondary"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/roomPollsSyncingTitle"
app:layout_constraintEnd_toStartOf="@id/roomPollsSyncingTitle"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/roomPollsSyncingTitle" />
<TextView
android:id="@+id/roomPollsSyncingTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="9dp"
android:layout_marginEnd="@dimen/layout_horizontal_margin"
android:gravity="center"
android:text="@string/room_polls_wait_for_display"
android:textAppearance="@style/TextAppearance.Vector.Body"
android:textColor="?vctr_content_secondary"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/roomPollsSyncingProgress"
app:layout_constraintTop_toTopOf="@id/roomPollsTitleGuideline" />
<TextView
android:id="@+id/roomPollsEmptyTitle"
android:layout_width="0dp"
@ -30,9 +58,8 @@
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/roomPollsEmptyGuideline"
tools:text="@string/room_polls_active_no_item"
tools:visibility="visible" />
app:layout_constraintTop_toTopOf="@id/roomPollsTitleGuideline"
tools:text="@string/room_polls_active_no_item" />
<Button
android:id="@+id/roomPollsLoadMoreWhenEmpty"
@ -45,8 +72,7 @@
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/roomPollsEmptyTitle"
tools:visibility="visible" />
app:layout_constraintTop_toBottomOf="@id/roomPollsEmptyTitle" />
<ProgressBar
android:id="@+id/roomPollsLoadMoreWhenEmptyProgress"
@ -57,11 +83,10 @@
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/roomPollsLoadMoreWhenEmpty"
app:layout_constraintStart_toEndOf="@id/roomPollsLoadMoreWhenEmpty"
app:layout_constraintTop_toTopOf="@id/roomPollsLoadMoreWhenEmpty"
tools:visibility="visible" />
app:layout_constraintTop_toTopOf="@id/roomPollsLoadMoreWhenEmpty" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/roomPollsEmptyGuideline"
android:id="@+id/roomPollsTitleGuideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"