Skip to content

Commit

Permalink
Mutualizing list fragments and add ended polls tab
Browse files Browse the repository at this point in the history
  • Loading branch information
mnaturel committed Jan 5, 2023
1 parent 0b53591 commit cb45056
Show file tree
Hide file tree
Showing 12 changed files with 190 additions and 106 deletions.
2 changes: 2 additions & 0 deletions library/ui-strings/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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>> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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() }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@

package im.vector.app.features.roomprofile.polls

import androidx.annotation.VisibleForTesting
import com.airbnb.mvrx.MavericksViewModelFactory
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
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

Expand All @@ -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)
}
}

override fun onCleared() {
pollsCollectionJob = null
super.onCleared()
init {
observePolls()
}

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
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 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 getEmptyListTitle(): String {
return getString(R.string.room_polls_active_no_item)
}

override fun onPollClicked(pollId: String) {
// TODO navigate to details
Timber.d("poll with id $pollId clicked")
override fun getRoomPollsFilter(): RoomPollsFilterType {
return RoomPollsFilterType.ACTIVE
}
}
Original file line number Diff line number Diff line change
@@ -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
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,38 +14,57 @@
* 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
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)
}

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)
}
}
}
Expand Down
Loading

0 comments on commit cb45056

Please sign in to comment.