From cb45056c1a311ec652d72a198c089abb66f78669 Mon Sep 17 00:00:00 2001
From: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date: Fri, 30 Dec 2022 17:28:57 +0100
Subject: [PATCH] Mutualizing list fragments and add ended polls tab
---
.../src/main/res/values/strings.xml | 2 +
.../roomprofile/polls/GetPollsUseCase.kt | 9 +-
.../features/roomprofile/polls/PollSummary.kt | 6 ++
.../roomprofile/polls/RoomPollsAction.kt | 4 +-
.../roomprofile/polls/RoomPollsFragment.kt | 1 +
.../polls/RoomPollsPagerAdapter.kt | 8 +-
.../roomprofile/polls/RoomPollsViewModel.kt | 25 ++----
.../polls/active/RoomActivePollsFragment.kt | 70 ++-------------
.../polls/ended/RoomEndedPollsFragment.kt | 34 +++++++
.../RoomPollItem.kt} | 4 +-
.../RoomPollsController.kt} | 43 ++++++---
.../polls/list/RoomPollsListFragment.kt | 90 +++++++++++++++++++
12 files changed, 190 insertions(+), 106 deletions(-)
create mode 100644 vector/src/main/java/im/vector/app/features/roomprofile/polls/ended/RoomEndedPollsFragment.kt
rename vector/src/main/java/im/vector/app/features/roomprofile/polls/{active/ActivePollItem.kt => list/RoomPollItem.kt} (90%)
rename vector/src/main/java/im/vector/app/features/roomprofile/polls/{active/RoomActivePollsController.kt => list/RoomPollsController.kt} (50%)
create mode 100644 vector/src/main/java/im/vector/app/features/roomprofile/polls/list/RoomPollsListFragment.kt
diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml
index 43507e60cee..61203985667 100644
--- a/library/ui-strings/src/main/res/values/strings.xml
+++ b/library/ui-strings/src/main/res/values/strings.xml
@@ -3193,6 +3193,8 @@
Results are only revealed when you end the poll
Active polls
There are no active polls in this room
+ Past polls
+ There are no past polls in this room
Share location
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/polls/GetPollsUseCase.kt b/vector/src/main/java/im/vector/app/features/roomprofile/polls/GetPollsUseCase.kt
index d35d192e041..06915c7b6ad 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/polls/GetPollsUseCase.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/polls/GetPollsUseCase.kt
@@ -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> {
+ fun execute(): Flow> {
// 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> {
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/polls/PollSummary.kt b/vector/src/main/java/im/vector/app/features/roomprofile/polls/PollSummary.kt
index 3eb45c6144f..939ee3ffa02 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/polls/PollSummary.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/polls/PollSummary.kt
@@ -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
}
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/polls/RoomPollsAction.kt b/vector/src/main/java/im/vector/app/features/roomprofile/polls/RoomPollsAction.kt
index 5f074bdd6ff..c18142a3062 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/polls/RoomPollsAction.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/polls/RoomPollsAction.kt
@@ -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
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/polls/RoomPollsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/polls/RoomPollsFragment.kt
index 5c150f43919..95aa5d0d958 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/polls/RoomPollsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/polls/RoomPollsFragment.kt
@@ -67,6 +67,7 @@ class RoomPollsFragment : VectorBaseFragment() {
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() }
}
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/polls/RoomPollsPagerAdapter.kt b/vector/src/main/java/im/vector/app/features/roomprofile/polls/RoomPollsPagerAdapter.kt
index 5472782079c..2dc6fd43698 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/polls/RoomPollsPagerAdapter.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/polls/RoomPollsPagerAdapter.kt
@@ -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 {
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/polls/RoomPollsViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/polls/RoomPollsViewModel.kt
index 7bc06894faf..95cb4717ca0 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/polls/RoomPollsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/polls/RoomPollsViewModel.kt
@@ -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 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
+ }
}
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/polls/active/RoomActivePollsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/polls/active/RoomActivePollsFragment.kt
index 61c7e961bd2..dc735c79bee 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/polls/active/RoomActivePollsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/polls/active/RoomActivePollsFragment.kt
@@ -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(),
- 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) {
- 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
}
}
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/polls/ended/RoomEndedPollsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/polls/ended/RoomEndedPollsFragment.kt
new file mode 100644
index 00000000000..bad1a4e2daf
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/polls/ended/RoomEndedPollsFragment.kt
@@ -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
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/polls/active/ActivePollItem.kt b/vector/src/main/java/im/vector/app/features/roomprofile/polls/list/RoomPollItem.kt
similarity index 90%
rename from vector/src/main/java/im/vector/app/features/roomprofile/polls/active/ActivePollItem.kt
rename to vector/src/main/java/im/vector/app/features/roomprofile/polls/list/RoomPollItem.kt
index 35b1ecd6e11..ac2b9cf3c06 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/polls/active/ActivePollItem.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/polls/list/RoomPollItem.kt
@@ -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(R.layout.item_poll) {
+abstract class RoomPollItem : VectorEpoxyModel(R.layout.item_poll) {
@EpoxyAttribute
lateinit var formattedDate: String
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/polls/active/RoomActivePollsController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/polls/list/RoomPollsController.kt
similarity index 50%
rename from vector/src/main/java/im/vector/app/features/roomprofile/polls/active/RoomActivePollsController.kt
rename to vector/src/main/java/im/vector/app/features/roomprofile/polls/list/RoomPollsController.kt
index 7a7c8186931..e24241f0afa 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/polls/active/RoomActivePollsController.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/polls/list/RoomPollsController.kt
@@ -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>() {
+) : TypedEpoxyController>() {
interface Listener {
fun onPollClicked(pollId: String)
@@ -32,20 +32,39 @@ class RoomActivePollsController @Inject constructor(
var listener: Listener? = null
- override fun buildModels(data: List?) {
+ override fun buildModels(data: List?) {
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)
}
}
}
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/polls/list/RoomPollsListFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/polls/list/RoomPollsListFragment.kt
new file mode 100644
index 00000000000..f408f1c7818
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/polls/list/RoomPollsListFragment.kt
@@ -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(),
+ 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) {
+ roomPollsController.setData(polls)
+ views.roomPollsEmptyTitle.isVisible = polls.isEmpty()
+ }
+
+ override fun onPollClicked(pollId: String) {
+ // TODO navigate to details
+ Timber.d("poll with id $pollId clicked")
+ }
+}