Introduce repository and datasource to get list of polls

This commit is contained in:
Maxime NATUREL 2023-01-11 15:56:59 +01:00
parent 11d37e3ecb
commit f7eed93a11
8 changed files with 205 additions and 101 deletions

View File

@ -43,6 +43,7 @@ class RoomPollsViewModel @AssistedInject constructor(
companion object : MavericksViewModelFactory<RoomPollsViewModel, RoomPollsViewState> by hiltMavericksViewModelFactory()
init {
// TODO update canLoadMore in viewState
observePolls()
}
@ -62,8 +63,8 @@ class RoomPollsViewModel @AssistedInject constructor(
private fun handleLoadMore() = withState { viewState ->
viewModelScope.launch {
setState { copy(isLoadingMore = true) }
loadMorePollsUseCase.execute(viewState.roomId)
setState { copy(isLoadingMore = false) }
val result = loadMorePollsUseCase.execute(viewState.roomId)
setState { copy(isLoadingMore = false, canLoadMore = result.canLoadMore) }
}
}
}

View File

@ -20,12 +20,12 @@ 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 load more is possible
// 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,
) : MavericksState {
constructor(roomProfileArgs: RoomProfileArgs) : this(roomId = roomProfileArgs.roomId)

View File

@ -0,0 +1,21 @@
/*
* 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.data
data class LoadMorePollsResult(
val canLoadMore: Boolean,
)

View File

@ -0,0 +1,129 @@
/*
* 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.data
import im.vector.app.features.home.room.detail.timeline.item.PollOptionViewState
import im.vector.app.features.roomprofile.polls.list.ui.PollSummary
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class RoomPollDataSource @Inject constructor() {
// TODO
// unmock using SDK service + add unit tests
// after unmock, expose domain layer model (entity) and do the mapping to PollSummary in the UI layer
fun getPolls(roomId: String): Flow<List<PollSummary>> {
Timber.d("roomId=$roomId")
return flowOf(getActivePolls() + getEndedPolls())
}
private fun getActivePolls(): List<PollSummary.ActivePoll> {
return listOf(
PollSummary.ActivePoll(
id = "id1",
// 2022/06/28 UTC+1
creationTimestamp = 1656367200000,
title = "Which charity would you like to support?"
),
PollSummary.ActivePoll(
id = "id2",
// 2022/06/26 UTC+1
creationTimestamp = 1656194400000,
title = "Which sport should the pupils do this year?"
),
PollSummary.ActivePoll(
id = "id3",
// 2022/06/24 UTC+1
creationTimestamp = 1656021600000,
title = "What type of food should we have at the party?"
),
PollSummary.ActivePoll(
id = "id4",
// 2022/06/22 UTC+1
creationTimestamp = 1655848800000,
title = "What film should we show at the end of the year party?"
),
)
}
private fun getEndedPolls(): List<PollSummary.EndedPoll> {
return listOf(
PollSummary.EndedPoll(
id = "id1-ended",
// 2022/06/28 UTC+1
creationTimestamp = 1656367200000,
title = "Which charity would you like to support?",
totalVotes = 22,
winnerOptions = listOf(
PollOptionViewState.PollEnded(
optionId = "id1",
optionAnswer = "Cancer research",
voteCount = 13,
votePercentage = 13 / 22.0,
isWinner = true,
)
),
),
PollSummary.EndedPoll(
id = "id2-ended",
// 2022/06/26 UTC+1
creationTimestamp = 1656194400000,
title = "Where should we do the offsite?",
totalVotes = 92,
winnerOptions = listOf(
PollOptionViewState.PollEnded(
optionId = "id1",
optionAnswer = "Hawaii",
voteCount = 43,
votePercentage = 43 / 92.0,
isWinner = true,
)
),
),
PollSummary.EndedPoll(
id = "id3-ended",
// 2022/06/24 UTC+1
creationTimestamp = 1656021600000,
title = "What type of food should we have at the party?",
totalVotes = 22,
winnerOptions = listOf(
PollOptionViewState.PollEnded(
optionId = "id1",
optionAnswer = "Brazilian",
voteCount = 13,
votePercentage = 13 / 22.0,
isWinner = true,
)
),
),
)
}
suspend fun loadMorePolls(roomId: String): LoadMorePollsResult {
Timber.d("roomId=$roomId")
// TODO
// mock getting more polls + update the given flow
// unmock using SDK service + add unit tests
delay(5000)
return LoadMorePollsResult(canLoadMore = false)
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.data
import im.vector.app.features.roomprofile.polls.list.ui.PollSummary
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
// TODO add unit tests
class RoomPollRepository @Inject constructor(
private val roomPollDataSource: RoomPollDataSource,
) {
// TODO after unmock, expose domain layer model (entity) and do the mapping to PollSummary in the UI layer
fun getPolls(roomId: String): Flow<List<PollSummary>> {
return roomPollDataSource.getPolls(roomId)
}
suspend fun loadMorePolls(roomId: String): LoadMorePollsResult {
return roomPollDataSource.loadMorePolls(roomId)
}
}

View File

@ -16,104 +16,19 @@
package im.vector.app.features.roomprofile.polls.list.domain
import im.vector.app.features.home.room.detail.timeline.item.PollOptionViewState
import im.vector.app.features.roomprofile.polls.list.data.RoomPollRepository
import im.vector.app.features.roomprofile.polls.list.ui.PollSummary
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import timber.log.Timber
import javax.inject.Inject
// TODO add unit tests
class GetPollsUseCase @Inject constructor() {
class GetPollsUseCase @Inject constructor(
private val roomPollRepository: RoomPollRepository,
) {
// TODO create a repo + datasources (local + remote) with mocked data by passing a room Id
fun execute(roomId: String): Flow<List<PollSummary>> {
// TODO call repository to get flow on polls
Timber.d("roomId=$roomId")
return flowOf(getActivePolls() + getEndedPolls())
return roomPollRepository.getPolls(roomId)
.map { it.sortedByDescending { poll -> poll.creationTimestamp } }
}
private fun getActivePolls(): List<PollSummary.ActivePoll> {
return listOf(
PollSummary.ActivePoll(
id = "id1",
// 2022/06/28 UTC+1
creationTimestamp = 1656367200000,
title = "Which charity would you like to support?"
),
PollSummary.ActivePoll(
id = "id2",
// 2022/06/26 UTC+1
creationTimestamp = 1656194400000,
title = "Which sport should the pupils do this year?"
),
PollSummary.ActivePoll(
id = "id3",
// 2022/06/24 UTC+1
creationTimestamp = 1656021600000,
title = "What type of food should we have at the party?"
),
PollSummary.ActivePoll(
id = "id4",
// 2022/06/22 UTC+1
creationTimestamp = 1655848800000,
title = "What film should we show at the end of the year party?"
),
)
}
private fun getEndedPolls(): List<PollSummary.EndedPoll> {
return listOf(
PollSummary.EndedPoll(
id = "id1-ended",
// 2022/06/28 UTC+1
creationTimestamp = 1656367200000,
title = "Which charity would you like to support?",
totalVotes = 22,
winnerOptions = listOf(
PollOptionViewState.PollEnded(
optionId = "id1",
optionAnswer = "Cancer research",
voteCount = 13,
votePercentage = 13 / 22.0,
isWinner = true,
)
),
),
PollSummary.EndedPoll(
id = "id2-ended",
// 2022/06/26 UTC+1
creationTimestamp = 1656194400000,
title = "Where should we do the offsite?",
totalVotes = 92,
winnerOptions = listOf(
PollOptionViewState.PollEnded(
optionId = "id1",
optionAnswer = "Hawaii",
voteCount = 43,
votePercentage = 43 / 92.0,
isWinner = true,
)
),
),
PollSummary.EndedPoll(
id = "id3-ended",
// 2022/06/24 UTC+1
creationTimestamp = 1656021600000,
title = "What type of food should we have at the party?",
totalVotes = 22,
winnerOptions = listOf(
PollOptionViewState.PollEnded(
optionId = "id1",
optionAnswer = "Brazilian",
voteCount = 13,
votePercentage = 13 / 22.0,
isWinner = true,
)
),
),
)
}
}

View File

@ -16,16 +16,16 @@
package im.vector.app.features.roomprofile.polls.list.domain
import kotlinx.coroutines.delay
import timber.log.Timber
import im.vector.app.features.roomprofile.polls.list.data.LoadMorePollsResult
import im.vector.app.features.roomprofile.polls.list.data.RoomPollRepository
import javax.inject.Inject
// TODO add unit tests
class LoadMorePollsUseCase @Inject constructor() {
class LoadMorePollsUseCase @Inject constructor(
private val roomPollRepository: RoomPollRepository,
) {
suspend fun execute(roomId: String) {
// TODO call repository to load more polls to be published in a flow
Timber.d("roomId=$roomId")
delay(5000)
suspend fun execute(roomId: String): LoadMorePollsResult {
return roomPollRepository.loadMorePolls(roomId)
}
}

View File

@ -50,7 +50,9 @@ class RoomPollsController @Inject constructor(
}
}
buildLoadMoreItem(viewState.isLoadingMore)
if (viewState.canLoadMore) {
buildLoadMoreItem(viewState.isLoadingMore)
}
}
private fun buildActivePollItem(poll: PollSummary.ActivePoll) {