mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-03-18 20:29:10 +03:00
Render specific empty list message when loading more is still possible
This commit is contained in:
parent
b03b207c82
commit
ec65564800
12 changed files with 163 additions and 30 deletions
|
@ -3199,8 +3199,16 @@
|
|||
<string name="unable_to_decrypt_some_events_in_poll">Due to decryption errors, some votes may not be counted</string>
|
||||
<string name="room_polls_active">Active polls</string>
|
||||
<string name="room_polls_active_no_item">There are no active polls in this room</string>
|
||||
<plurals name="room_polls_active_no_item_for_loaded_period">
|
||||
<item quantity="one">"There are no active polls for the past day.\nLoad more polls to view polls for previous days."</item>
|
||||
<item quantity="other">"There are no active polls for the past %1$d days.\nLoad more polls to view polls for previous days."</item>
|
||||
</plurals>
|
||||
<string name="room_polls_ended">Past polls</string>
|
||||
<string name="room_polls_ended_no_item">There are no past polls in this room</string>
|
||||
<plurals name="room_polls_ended_no_item_for_loaded_period">
|
||||
<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_load_more">Load more polls</string>
|
||||
|
||||
<!-- Location -->
|
||||
|
|
|
@ -23,6 +23,7 @@ import dagger.assisted.AssistedInject
|
|||
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||
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 kotlinx.coroutines.flow.launchIn
|
||||
|
@ -32,6 +33,7 @@ import kotlinx.coroutines.launch
|
|||
class RoomPollsViewModel @AssistedInject constructor(
|
||||
@Assisted initialState: RoomPollsViewState,
|
||||
private val getPollsUseCase: GetPollsUseCase,
|
||||
private val getLoadedPollsStatusUseCase: GetLoadedPollsStatusUseCase,
|
||||
private val loadMorePollsUseCase: LoadMorePollsUseCase,
|
||||
) : VectorViewModel<RoomPollsViewState, RoomPollsAction, RoomPollsViewEvent>(initialState) {
|
||||
|
||||
|
@ -43,8 +45,20 @@ class RoomPollsViewModel @AssistedInject constructor(
|
|||
companion object : MavericksViewModelFactory<RoomPollsViewModel, RoomPollsViewState> by hiltMavericksViewModelFactory()
|
||||
|
||||
init {
|
||||
// TODO update canLoadMore in viewState
|
||||
updateLoadedPollStatus(initialState.roomId)
|
||||
observePolls()
|
||||
// TODO
|
||||
// call use case to sync polls until now = initial loading
|
||||
}
|
||||
|
||||
private fun updateLoadedPollStatus(roomId: String) {
|
||||
val loadedPollsStatus = getLoadedPollsStatusUseCase.execute(roomId)
|
||||
setState {
|
||||
copy(
|
||||
canLoadMore = loadedPollsStatus.canLoadMore,
|
||||
nbLoadedDays = loadedPollsStatus.nbLoadedDays
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun observePolls() = withState { viewState ->
|
||||
|
@ -64,7 +78,13 @@ class RoomPollsViewModel @AssistedInject constructor(
|
|||
viewModelScope.launch {
|
||||
setState { copy(isLoadingMore = true) }
|
||||
val result = loadMorePollsUseCase.execute(viewState.roomId)
|
||||
setState { copy(isLoadingMore = false, canLoadMore = result.canLoadMore) }
|
||||
setState {
|
||||
copy(
|
||||
isLoadingMore = false,
|
||||
canLoadMore = result.canLoadMore,
|
||||
nbLoadedDays = result.nbLoadedDays,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ data class RoomPollsViewState(
|
|||
val polls: List<PollSummary> = emptyList(),
|
||||
val isLoadingMore: Boolean = false,
|
||||
val canLoadMore: Boolean = true,
|
||||
val nbLoadedDays: Int = 0,
|
||||
) : MavericksState {
|
||||
|
||||
constructor(roomProfileArgs: RoomProfileArgs) : this(roomId = roomProfileArgs.roomId)
|
||||
|
|
|
@ -24,8 +24,12 @@ import im.vector.app.features.roomprofile.polls.list.ui.RoomPollsListFragment
|
|||
@AndroidEntryPoint
|
||||
class RoomActivePollsFragment : RoomPollsListFragment() {
|
||||
|
||||
override fun getEmptyListTitle(): String {
|
||||
return getString(R.string.room_polls_active_no_item)
|
||||
override fun getEmptyListTitle(canLoadMore: Boolean, nbLoadedDays: Int): String {
|
||||
return if (canLoadMore) {
|
||||
stringProvider.getQuantityString(R.plurals.room_polls_active_no_item_for_loaded_period, nbLoadedDays, nbLoadedDays)
|
||||
} else {
|
||||
getString(R.string.room_polls_active_no_item)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getRoomPollsType(): RoomPollsType {
|
||||
|
|
|
@ -24,8 +24,12 @@ import im.vector.app.features.roomprofile.polls.list.ui.RoomPollsListFragment
|
|||
@AndroidEntryPoint
|
||||
class RoomEndedPollsFragment : RoomPollsListFragment() {
|
||||
|
||||
override fun getEmptyListTitle(): String {
|
||||
return getString(R.string.room_polls_ended_no_item)
|
||||
override fun getEmptyListTitle(canLoadMore: Boolean, nbLoadedDays: Int): String {
|
||||
return if (canLoadMore) {
|
||||
stringProvider.getQuantityString(R.plurals.room_polls_ended_no_item_for_loaded_period, nbLoadedDays, nbLoadedDays)
|
||||
} else {
|
||||
getString(R.string.room_polls_ended_no_item)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getRoomPollsType(): RoomPollsType {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package im.vector.app.features.roomprofile.polls.list.data
|
||||
|
||||
data class LoadMorePollsResult(
|
||||
data class LoadedPollsStatus(
|
||||
val canLoadMore: Boolean,
|
||||
val nbLoadedDays: Int,
|
||||
)
|
|
@ -41,6 +41,32 @@ class RoomPollDataSource @Inject constructor() {
|
|||
return pollsFlow.asSharedFlow()
|
||||
}
|
||||
|
||||
fun getLoadedPollsStatus(roomId: String): LoadedPollsStatus {
|
||||
Timber.d("roomId=$roomId")
|
||||
return LoadedPollsStatus(
|
||||
canLoadMore = canLoadMore(),
|
||||
nbLoadedDays = fakeLoadCounter * 30,
|
||||
)
|
||||
}
|
||||
|
||||
private fun canLoadMore(): Boolean {
|
||||
return fakeLoadCounter < 2
|
||||
}
|
||||
|
||||
suspend fun loadMorePolls(roomId: String): LoadedPollsStatus {
|
||||
// TODO
|
||||
// unmock using SDK service + add unit tests
|
||||
delay(3000)
|
||||
fakeLoadCounter++
|
||||
when (fakeLoadCounter) {
|
||||
1 -> polls.addAll(getActivePollsPart1() + getEndedPollsPart1())
|
||||
2 -> polls.addAll(getActivePollsPart2() + getEndedPollsPart2())
|
||||
else -> Unit
|
||||
}
|
||||
pollsFlow.emit(polls)
|
||||
return getLoadedPollsStatus(roomId)
|
||||
}
|
||||
|
||||
private fun getActivePollsPart1(): List<PollSummary.ActivePoll> {
|
||||
return listOf(
|
||||
PollSummary.ActivePoll(
|
||||
|
@ -132,19 +158,4 @@ class RoomPollDataSource @Inject constructor() {
|
|||
),
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun loadMorePolls(roomId: String): LoadMorePollsResult {
|
||||
Timber.d("roomId=$roomId")
|
||||
// TODO
|
||||
// unmock using SDK service + add unit tests
|
||||
delay(3000)
|
||||
fakeLoadCounter++
|
||||
when (fakeLoadCounter) {
|
||||
1 -> polls.addAll(getActivePollsPart1() + getEndedPollsPart1())
|
||||
2 -> polls.addAll(getActivePollsPart2() + getEndedPollsPart2())
|
||||
else -> Unit
|
||||
}
|
||||
pollsFlow.emit(polls)
|
||||
return LoadMorePollsResult(canLoadMore = fakeLoadCounter < 2)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,11 @@ class RoomPollRepository @Inject constructor(
|
|||
return roomPollDataSource.getPolls(roomId)
|
||||
}
|
||||
|
||||
suspend fun loadMorePolls(roomId: String): LoadMorePollsResult {
|
||||
fun getLoadedPollsStatus(roomId: String): LoadedPollsStatus {
|
||||
return roomPollDataSource.getLoadedPollsStatus(roomId)
|
||||
}
|
||||
|
||||
suspend fun loadMorePolls(roomId: String): LoadedPollsStatus {
|
||||
return roomPollDataSource.loadMorePolls(roomId)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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.LoadedPollsStatus
|
||||
import im.vector.app.features.roomprofile.polls.list.data.RoomPollRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
// TODO add unit tests
|
||||
class GetLoadedPollsStatusUseCase @Inject constructor(
|
||||
private val roomPollRepository: RoomPollRepository,
|
||||
) {
|
||||
|
||||
fun execute(roomId: String): LoadedPollsStatus {
|
||||
return roomPollRepository.getLoadedPollsStatus(roomId)
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package im.vector.app.features.roomprofile.polls.list.domain
|
||||
|
||||
import im.vector.app.features.roomprofile.polls.list.data.LoadMorePollsResult
|
||||
import im.vector.app.features.roomprofile.polls.list.data.LoadedPollsStatus
|
||||
import im.vector.app.features.roomprofile.polls.list.data.RoomPollRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -25,7 +25,7 @@ class LoadMorePollsUseCase @Inject constructor(
|
|||
private val roomPollRepository: RoomPollRepository,
|
||||
) {
|
||||
|
||||
suspend fun execute(roomId: String): LoadMorePollsResult {
|
||||
suspend fun execute(roomId: String): LoadedPollsStatus {
|
||||
return roomPollRepository.loadMorePolls(roomId)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,9 +23,11 @@ import android.view.ViewGroup
|
|||
import androidx.core.view.isVisible
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.core.epoxy.onClick
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.databinding.FragmentRoomPollsListBinding
|
||||
import im.vector.app.features.roomprofile.polls.RoomPollsAction
|
||||
import im.vector.app.features.roomprofile.polls.RoomPollsType
|
||||
|
@ -35,7 +37,6 @@ import timber.log.Timber
|
|||
import javax.inject.Inject
|
||||
|
||||
// TODO add and render blocking loader view
|
||||
// TODO add and render missing empty view when load more is possible
|
||||
abstract class RoomPollsListFragment :
|
||||
VectorBaseFragment<FragmentRoomPollsListBinding>(),
|
||||
RoomPollsController.Listener {
|
||||
|
@ -43,6 +44,9 @@ abstract class RoomPollsListFragment :
|
|||
@Inject
|
||||
lateinit var roomPollsController: RoomPollsController
|
||||
|
||||
@Inject
|
||||
lateinit var stringProvider: StringProvider
|
||||
|
||||
private val viewModel: RoomPollsViewModel by parentFragmentViewModel(RoomPollsViewModel::class)
|
||||
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomPollsListBinding {
|
||||
|
@ -52,16 +56,26 @@ abstract class RoomPollsListFragment :
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setupList()
|
||||
setupLoadMoreButton()
|
||||
}
|
||||
|
||||
abstract fun getEmptyListTitle(): String
|
||||
abstract fun getEmptyListTitle(canLoadMore: Boolean, nbLoadedDays: Int): String
|
||||
|
||||
abstract fun getRoomPollsType(): RoomPollsType
|
||||
|
||||
private fun setupList() {
|
||||
private fun setupList() = withState(viewModel) { viewState ->
|
||||
roomPollsController.listener = this
|
||||
views.roomPollsList.configureWith(roomPollsController)
|
||||
views.roomPollsEmptyTitle.text = getEmptyListTitle()
|
||||
views.roomPollsEmptyTitle.text = getEmptyListTitle(
|
||||
canLoadMore = viewState.canLoadMore,
|
||||
nbLoadedDays = viewState.nbLoadedDays,
|
||||
)
|
||||
}
|
||||
|
||||
private fun setupLoadMoreButton() {
|
||||
views.roomPollsLoadMoreWhenEmpty.onClick {
|
||||
onLoadMoreClicked()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
@ -84,7 +98,14 @@ abstract class RoomPollsListFragment :
|
|||
|
||||
private fun renderList(viewState: RoomPollsViewState) {
|
||||
roomPollsController.setData(viewState)
|
||||
views.roomPollsEmptyTitle.text = getEmptyListTitle(
|
||||
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.roomPollsLoadMoreWhenEmptyProgress.isEnabled = !viewState.isLoadingMore
|
||||
}
|
||||
|
||||
override fun onPollClicked(pollId: String) {
|
||||
|
|
|
@ -26,11 +26,39 @@
|
|||
android:gravity="center"
|
||||
android:textAppearance="@style/TextAppearance.Vector.Body"
|
||||
android:textColor="?vctr_content_secondary"
|
||||
android:textSize="17sp"
|
||||
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:text="@string/room_polls_active_no_item"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/roomPollsLoadMoreWhenEmpty"
|
||||
style="@style/Widget.Vector.Button.Text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/layout_horizontal_margin"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/room_polls_load_more"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/roomPollsEmptyTitle"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/roomPollsLoadMoreWhenEmptyProgress"
|
||||
style="?android:attr/progressBarStyle"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="9dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/roomPollsLoadMoreWhenEmpty"
|
||||
app:layout_constraintStart_toEndOf="@id/roomPollsLoadMoreWhenEmpty"
|
||||
app:layout_constraintTop_toTopOf="@id/roomPollsLoadMoreWhenEmpty"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/roomPollsEmptyGuideline"
|
||||
|
|
Loading…
Add table
Reference in a new issue