Mutualizing list fragments and add ended polls tab
This commit is contained in:
parent
0b535910d6
commit
cb45056c1a
@ -3193,6 +3193,8 @@
|
||||
<string name="closed_poll_option_description">Results are only revealed when you end the poll</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>
|
||||
<string name="room_polls_ended">Past polls</string>
|
||||
<string name="room_polls_ended_no_item">There are no past polls in this room</string>
|
||||
|
||||
<!-- Location -->
|
||||
<string name="location_activity_title_static_sharing">Share location</string>
|
||||
|
@ -17,19 +17,16 @@
|
||||
package im.vector.app.features.roomprofile.polls
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
import javax.inject.Inject
|
||||
|
||||
class GetPollsUseCase @Inject constructor() {
|
||||
|
||||
fun execute(filter: RoomPollsFilterType): Flow<List<PollSummary>> {
|
||||
fun execute(): Flow<List<PollSummary>> {
|
||||
// TODO unmock and add unit tests
|
||||
return when (filter) {
|
||||
RoomPollsFilterType.ACTIVE -> getActivePolls()
|
||||
RoomPollsFilterType.ENDED -> emptyFlow()
|
||||
}.map { it.sortedByDescending { poll -> poll.creationTimestamp } }
|
||||
return getActivePolls()
|
||||
.map { it.sortedByDescending { poll -> poll.creationTimestamp } }
|
||||
}
|
||||
|
||||
private fun getActivePolls(): Flow<List<PollSummary.ActivePoll>> {
|
||||
|
@ -22,4 +22,10 @@ sealed interface PollSummary {
|
||||
val creationTimestamp: Long,
|
||||
val title: String,
|
||||
) : PollSummary
|
||||
|
||||
data class EndedPoll(
|
||||
val id: String,
|
||||
val creationTimestamp: Long,
|
||||
val title: String,
|
||||
) : PollSummary
|
||||
}
|
||||
|
@ -18,6 +18,4 @@ package im.vector.app.features.roomprofile.polls
|
||||
|
||||
import im.vector.app.core.platform.VectorViewModelAction
|
||||
|
||||
sealed interface RoomPollsAction : VectorViewModelAction {
|
||||
data class SetFilter(val filter: RoomPollsFilterType) : RoomPollsAction
|
||||
}
|
||||
sealed interface RoomPollsAction : VectorViewModelAction
|
||||
|
@ -67,6 +67,7 @@ class RoomPollsFragment : VectorBaseFragment<FragmentRoomPollsBinding>() {
|
||||
tabLayoutMediator = TabLayoutMediator(views.roomPollsTabs, views.roomPollsViewPager) { tab, position ->
|
||||
when (position) {
|
||||
0 -> tab.text = getString(R.string.room_polls_active)
|
||||
1 -> tab.text = getString(R.string.room_polls_ended)
|
||||
}
|
||||
}.also { it.attach() }
|
||||
}
|
||||
|
@ -19,15 +19,19 @@ package im.vector.app.features.roomprofile.polls
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import im.vector.app.features.roomprofile.polls.active.RoomActivePollsFragment
|
||||
import im.vector.app.features.roomprofile.polls.ended.RoomEndedPollsFragment
|
||||
|
||||
class RoomPollsPagerAdapter(
|
||||
private val fragment: Fragment
|
||||
) : FragmentStateAdapter(fragment) {
|
||||
|
||||
override fun getItemCount() = 1
|
||||
override fun getItemCount() = 2
|
||||
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
return instantiateFragment(RoomActivePollsFragment::class.java.name)
|
||||
return when (position) {
|
||||
0 -> instantiateFragment(RoomActivePollsFragment::class.java.name)
|
||||
else -> instantiateFragment(RoomEndedPollsFragment::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
private fun instantiateFragment(fragmentName: String): Fragment {
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
package im.vector.app.features.roomprofile.polls
|
||||
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.airbnb.mvrx.MavericksViewModelFactory
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
@ -24,7 +23,6 @@ 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 kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
||||
@ -40,24 +38,17 @@ class RoomPollsViewModel @AssistedInject constructor(
|
||||
|
||||
companion object : MavericksViewModelFactory<RoomPollsViewModel, RoomPollsViewState> by hiltMavericksViewModelFactory()
|
||||
|
||||
@VisibleForTesting
|
||||
var pollsCollectionJob: Job? = null
|
||||
|
||||
override fun handle(action: RoomPollsAction) {
|
||||
when (action) {
|
||||
is RoomPollsAction.SetFilter -> handleSetFilter(action.filter)
|
||||
}
|
||||
init {
|
||||
observePolls()
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
pollsCollectionJob = null
|
||||
super.onCleared()
|
||||
}
|
||||
|
||||
private fun handleSetFilter(filter: RoomPollsFilterType) {
|
||||
pollsCollectionJob?.cancel()
|
||||
pollsCollectionJob = getPollsUseCase.execute(filter)
|
||||
private fun observePolls() {
|
||||
getPollsUseCase.execute()
|
||||
.onEach { setState { copy(polls = it) } }
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
override fun handle(action: RoomPollsAction) {
|
||||
// do nothing for now
|
||||
}
|
||||
}
|
||||
|
@ -16,77 +16,19 @@
|
||||
|
||||
package im.vector.app.features.roomprofile.polls.active
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import im.vector.app.R
|
||||
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.databinding.FragmentRoomPollsListBinding
|
||||
import im.vector.app.features.roomprofile.polls.PollSummary
|
||||
import im.vector.app.features.roomprofile.polls.RoomPollsAction
|
||||
import im.vector.app.features.roomprofile.polls.RoomPollsFilterType
|
||||
import im.vector.app.features.roomprofile.polls.RoomPollsViewModel
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import im.vector.app.features.roomprofile.polls.list.RoomPollsListFragment
|
||||
|
||||
@AndroidEntryPoint
|
||||
class RoomActivePollsFragment :
|
||||
VectorBaseFragment<FragmentRoomPollsListBinding>(),
|
||||
RoomActivePollsController.Listener {
|
||||
class RoomActivePollsFragment : RoomPollsListFragment() {
|
||||
|
||||
@Inject
|
||||
lateinit var roomActivePollsController: RoomActivePollsController
|
||||
|
||||
private val viewModel: RoomPollsViewModel by parentFragmentViewModel(RoomPollsViewModel::class)
|
||||
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomPollsListBinding {
|
||||
return FragmentRoomPollsListBinding.inflate(inflater, container, false)
|
||||
override fun getEmptyListTitle(): String {
|
||||
return getString(R.string.room_polls_active_no_item)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setupList()
|
||||
}
|
||||
|
||||
private fun setupList() {
|
||||
roomActivePollsController.listener = this
|
||||
views.roomPollsList.configureWith(roomActivePollsController)
|
||||
views.roomPollsEmptyTitle.text = getString(R.string.room_polls_active_no_item)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
cleanUpList()
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private fun cleanUpList() {
|
||||
views.roomPollsList.cleanup()
|
||||
roomActivePollsController.listener = null
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
viewModel.handle(RoomPollsAction.SetFilter(RoomPollsFilterType.ACTIVE))
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(viewModel) { viewState ->
|
||||
renderList(viewState.polls.filterIsInstance(PollSummary.ActivePoll::class.java))
|
||||
}
|
||||
|
||||
private fun renderList(polls: List<PollSummary.ActivePoll>) {
|
||||
roomActivePollsController.setData(polls)
|
||||
views.roomPollsEmptyTitle.isVisible = polls.isEmpty()
|
||||
}
|
||||
|
||||
override fun onPollClicked(pollId: String) {
|
||||
// TODO navigate to details
|
||||
Timber.d("poll with id $pollId clicked")
|
||||
override fun getRoomPollsFilter(): RoomPollsFilterType {
|
||||
return RoomPollsFilterType.ACTIVE
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2022 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.ended
|
||||
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import im.vector.app.R
|
||||
import im.vector.app.features.roomprofile.polls.RoomPollsFilter
|
||||
import im.vector.app.features.roomprofile.polls.list.RoomPollsListFragment
|
||||
|
||||
@AndroidEntryPoint
|
||||
class RoomEndedPollsFragment : RoomPollsListFragment() {
|
||||
|
||||
override fun getEmptyListTitle(): String {
|
||||
return getString(R.string.room_polls_ended_no_item)
|
||||
}
|
||||
|
||||
override fun getRoomPollsFilter(): RoomPollsFilter {
|
||||
return RoomPollsFilter.ENDED
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.roomprofile.polls.active
|
||||
package im.vector.app.features.roomprofile.polls.list
|
||||
|
||||
import android.widget.TextView
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
@ -26,7 +26,7 @@ import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.app.core.epoxy.onClick
|
||||
|
||||
@EpoxyModelClass
|
||||
abstract class ActivePollItem : VectorEpoxyModel<ActivePollItem.Holder>(R.layout.item_poll) {
|
||||
abstract class RoomPollItem : VectorEpoxyModel<RoomPollItem.Holder>(R.layout.item_poll) {
|
||||
|
||||
@EpoxyAttribute
|
||||
lateinit var formattedDate: String
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.roomprofile.polls.active
|
||||
package im.vector.app.features.roomprofile.polls.list
|
||||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import im.vector.app.core.date.DateFormatKind
|
||||
@ -22,9 +22,9 @@ import im.vector.app.core.date.VectorDateFormatter
|
||||
import im.vector.app.features.roomprofile.polls.PollSummary
|
||||
import javax.inject.Inject
|
||||
|
||||
class RoomActivePollsController @Inject constructor(
|
||||
class RoomPollsController @Inject constructor(
|
||||
val dateFormatter: VectorDateFormatter,
|
||||
) : TypedEpoxyController<List<PollSummary.ActivePoll>>() {
|
||||
) : TypedEpoxyController<List<PollSummary>>() {
|
||||
|
||||
interface Listener {
|
||||
fun onPollClicked(pollId: String)
|
||||
@ -32,20 +32,39 @@ class RoomActivePollsController @Inject constructor(
|
||||
|
||||
var listener: Listener? = null
|
||||
|
||||
override fun buildModels(data: List<PollSummary.ActivePoll>?) {
|
||||
override fun buildModels(data: List<PollSummary>?) {
|
||||
if (data.isNullOrEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
val host = this
|
||||
for (poll in data) {
|
||||
activePollItem {
|
||||
id(poll.id)
|
||||
formattedDate(host.dateFormatter.format(poll.creationTimestamp, DateFormatKind.TIMELINE_DAY_DIVIDER))
|
||||
title(poll.title)
|
||||
clickListener {
|
||||
host.listener?.onPollClicked(poll.id)
|
||||
}
|
||||
when (poll) {
|
||||
is PollSummary.ActivePoll -> buildActivePollItem(poll)
|
||||
is PollSummary.EndedPoll -> buildEndedPollItem(poll)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildActivePollItem(poll: PollSummary.ActivePoll) {
|
||||
val host = this
|
||||
roomPollItem {
|
||||
id(poll.id)
|
||||
formattedDate(host.dateFormatter.format(poll.creationTimestamp, DateFormatKind.TIMELINE_DAY_DIVIDER))
|
||||
title(poll.title)
|
||||
clickListener {
|
||||
host.listener?.onPollClicked(poll.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildEndedPollItem(poll: PollSummary.EndedPoll) {
|
||||
val host = this
|
||||
roomPollItem {
|
||||
id(poll.id)
|
||||
formattedDate(host.dateFormatter.format(poll.creationTimestamp, DateFormatKind.TIMELINE_DAY_DIVIDER))
|
||||
title(poll.title)
|
||||
clickListener {
|
||||
host.listener?.onPollClicked(poll.id)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2022 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
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
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.databinding.FragmentRoomPollsListBinding
|
||||
import im.vector.app.features.roomprofile.polls.PollSummary
|
||||
import im.vector.app.features.roomprofile.polls.RoomPollsFilter
|
||||
import im.vector.app.features.roomprofile.polls.RoomPollsViewModel
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
abstract class RoomPollsListFragment :
|
||||
VectorBaseFragment<FragmentRoomPollsListBinding>(),
|
||||
RoomPollsController.Listener {
|
||||
|
||||
@Inject
|
||||
lateinit var roomPollsController: RoomPollsController
|
||||
|
||||
private val viewModel: RoomPollsViewModel by parentFragmentViewModel(RoomPollsViewModel::class)
|
||||
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomPollsListBinding {
|
||||
return FragmentRoomPollsListBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setupList()
|
||||
}
|
||||
|
||||
abstract fun getEmptyListTitle(): String
|
||||
|
||||
abstract fun getRoomPollsFilter(): RoomPollsFilter
|
||||
|
||||
private fun setupList() {
|
||||
roomPollsController.listener = this
|
||||
views.roomPollsList.configureWith(roomPollsController)
|
||||
views.roomPollsEmptyTitle.text = getEmptyListTitle()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
cleanUpList()
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private fun cleanUpList() {
|
||||
views.roomPollsList.cleanup()
|
||||
roomPollsController.listener = null
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(viewModel) { viewState ->
|
||||
when (getRoomPollsFilter()) {
|
||||
RoomPollsFilter.ACTIVE -> renderList(viewState.polls.filterIsInstance(PollSummary.ActivePoll::class.java))
|
||||
RoomPollsFilter.ENDED -> renderList(viewState.polls.filterIsInstance(PollSummary.EndedPoll::class.java))
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderList(polls: List<PollSummary>) {
|
||||
roomPollsController.setData(polls)
|
||||
views.roomPollsEmptyTitle.isVisible = polls.isEmpty()
|
||||
}
|
||||
|
||||
override fun onPollClicked(pollId: String) {
|
||||
// TODO navigate to details
|
||||
Timber.d("poll with id $pollId clicked")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user