Skip to content

Commit 4a6d001

Browse files
reduce code duplication
1 parent 7990a46 commit 4a6d001

File tree

11 files changed

+55
-111
lines changed

11 files changed

+55
-111
lines changed

app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/AbstractTaskViewModel.kt

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,13 @@
1515
*/
1616
package org.groundplatform.android.ui.datacollection.tasks
1717

18+
import androidx.lifecycle.viewModelScope
1819
import kotlinx.coroutines.flow.MutableStateFlow
20+
import kotlinx.coroutines.flow.SharingStarted
1921
import kotlinx.coroutines.flow.StateFlow
2022
import kotlinx.coroutines.flow.asStateFlow
23+
import kotlinx.coroutines.flow.map
24+
import kotlinx.coroutines.flow.stateIn
2125
import kotlinx.coroutines.flow.update
2226
import org.groundplatform.android.R
2327
import org.groundplatform.android.model.job.Job
@@ -37,7 +41,11 @@ abstract class AbstractTaskViewModel internal constructor() : AbstractViewModel(
3741
private val _taskDataFlow: MutableStateFlow<TaskData?> = MutableStateFlow(null)
3842
val taskTaskData: StateFlow<TaskData?> = _taskDataFlow.asStateFlow()
3943

40-
abstract val taskActionButtonStates: StateFlow<List<ButtonActionState>>
44+
open val taskActionButtonStates: StateFlow<List<ButtonActionState>> by lazy {
45+
taskTaskData
46+
.map { getButtonStates(it) }
47+
.stateIn(viewModelScope, SharingStarted.Lazily, emptyList())
48+
}
4149

4250
lateinit var task: Task
4351
private lateinit var taskPositionInterface: TaskPositionInterface
@@ -53,6 +61,16 @@ abstract class AbstractTaskViewModel internal constructor() : AbstractViewModel(
5361
setValue(taskData)
5462
}
5563

64+
/**
65+
* Returns the list of button states for the given task data.
66+
*
67+
* By default it returns a list of [ButtonAction.PREVIOUS], [ButtonAction.SKIP] (if applicable),
68+
* [ButtonAction.NEXT]/[ButtonAction.DONE]. Override this method to customize button
69+
* configuration.
70+
*/
71+
protected open fun getButtonStates(taskData: TaskData?): List<ButtonActionState> =
72+
listOf(getPreviousButton(), getSkipButton(taskData), getNextButton(taskData))
73+
5674
/** Checks if the current value is valid and updates error value. */
5775
fun validate(): Int? = validate(task, taskTaskData.value)
5876

@@ -87,14 +105,14 @@ abstract class AbstractTaskViewModel internal constructor() : AbstractViewModel(
87105

88106
fun hasNoData(): Boolean = taskTaskData.value.isNullOrEmpty()
89107

90-
fun getPreviousButtonState(): ButtonActionState =
108+
fun getPreviousButton(): ButtonActionState =
91109
ButtonActionState(
92110
action = ButtonAction.PREVIOUS,
93111
isEnabled = !taskPositionInterface.isFirst(),
94112
isVisible = true,
95113
)
96114

97-
fun getNextButtonState(taskData: TaskData?, hideIfEmpty: Boolean = false): ButtonActionState {
115+
fun getNextButton(taskData: TaskData?, hideIfEmpty: Boolean = false): ButtonActionState {
98116
val isVisible = if (hideIfEmpty) taskData.isNotNullOrEmpty() else true
99117
return if (taskPositionInterface.isLastWithValue(taskData)) {
100118
ButtonActionState(
@@ -111,14 +129,14 @@ abstract class AbstractTaskViewModel internal constructor() : AbstractViewModel(
111129
}
112130
}
113131

114-
fun getSkipButtonState(taskData: TaskData?): ButtonActionState =
132+
fun getSkipButton(taskData: TaskData?): ButtonActionState =
115133
ButtonActionState(
116134
action = ButtonAction.SKIP,
117135
isEnabled = isTaskOptional(),
118136
isVisible = isTaskOptional() && taskData.isNullOrEmpty(),
119137
)
120138

121-
fun getUndoButtonState(
139+
fun getUndoButton(
122140
taskData: TaskData?,
123141
isVisible: Boolean = taskData.isNotNullOrEmpty(),
124142
): ButtonActionState =

app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/date/DateTaskViewModel.kt

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,12 @@
1515
*/
1616
package org.groundplatform.android.ui.datacollection.tasks.date
1717

18-
import androidx.lifecycle.viewModelScope
1918
import java.util.Date
2019
import javax.inject.Inject
21-
import kotlinx.coroutines.flow.SharingStarted
22-
import kotlinx.coroutines.flow.StateFlow
23-
import kotlinx.coroutines.flow.map
24-
import kotlinx.coroutines.flow.stateIn
2520
import org.groundplatform.android.model.submission.DateTimeTaskData.Companion.fromMillis
26-
import org.groundplatform.android.ui.datacollection.components.refactor.ButtonActionState
2721
import org.groundplatform.android.ui.datacollection.tasks.AbstractTaskViewModel
2822

2923
class DateTaskViewModel @Inject constructor() : AbstractTaskViewModel() {
30-
override val taskActionButtonStates: StateFlow<List<ButtonActionState>> by lazy {
31-
taskTaskData
32-
.map { listOf(getPreviousButtonState(), getSkipButtonState(it), getNextButtonState(it)) }
33-
.stateIn(viewModelScope, SharingStarted.Lazily, emptyList())
34-
}
3524

3625
fun updateResponse(date: Date) {
3726
setValue(fromMillis(date.time))

app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/instruction/InstructionTaskViewModel.kt

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,13 @@
1515
*/
1616
package org.groundplatform.android.ui.datacollection.tasks.instruction
1717

18-
import androidx.lifecycle.viewModelScope
1918
import javax.inject.Inject
20-
import kotlinx.coroutines.flow.SharingStarted
21-
import kotlinx.coroutines.flow.StateFlow
22-
import kotlinx.coroutines.flow.map
23-
import kotlinx.coroutines.flow.stateIn
19+
import org.groundplatform.android.model.submission.TaskData
2420
import org.groundplatform.android.ui.datacollection.components.refactor.ButtonActionState
2521
import org.groundplatform.android.ui.datacollection.tasks.AbstractTaskViewModel
2622

27-
@Suppress("EmptyClassBlock")
2823
class InstructionTaskViewModel @Inject constructor() : AbstractTaskViewModel() {
29-
override val taskActionButtonStates: StateFlow<List<ButtonActionState>> by lazy {
30-
taskTaskData
31-
.map { listOf(getPreviousButtonState(), getNextButtonState(it)) }
32-
.stateIn(viewModelScope, SharingStarted.Lazily, emptyList())
33-
}
24+
25+
override fun getButtonStates(taskData: TaskData?): List<ButtonActionState> =
26+
listOf(getPreviousButton(), getNextButton(taskData))
3427
}

app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/location/CaptureLocationTaskViewModel.kt

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import kotlinx.coroutines.flow.SharingStarted
2525
import kotlinx.coroutines.flow.StateFlow
2626
import kotlinx.coroutines.flow.asStateFlow
2727
import kotlinx.coroutines.flow.combine
28-
import kotlinx.coroutines.flow.distinctUntilChanged
2928
import kotlinx.coroutines.flow.map
3029
import kotlinx.coroutines.flow.stateIn
3130
import kotlinx.coroutines.flow.update
@@ -56,14 +55,13 @@ class CaptureLocationTaskViewModel @Inject constructor() : AbstractMapTaskViewMo
5655
override val taskActionButtonStates: StateFlow<List<ButtonActionState>> by lazy {
5756
combine(isCaptureEnabled, taskTaskData) { captureEnabled, taskData ->
5857
listOf(
59-
getPreviousButtonState(),
60-
getSkipButtonState(taskData),
61-
getUndoButtonState(taskData),
62-
getCaptureLocationButtonState(captureEnabled, taskData),
63-
getNextButtonState(taskData, hideIfEmpty = true),
58+
getPreviousButton(),
59+
getSkipButton(taskData),
60+
getUndoButton(taskData),
61+
getCaptureLocationButton(captureEnabled, taskData),
62+
getNextButton(taskData, hideIfEmpty = true),
6463
)
6564
}
66-
.distinctUntilChanged()
6765
.stateIn(viewModelScope, SharingStarted.Lazily, emptyList())
6866
}
6967

@@ -90,7 +88,7 @@ class CaptureLocationTaskViewModel @Inject constructor() : AbstractMapTaskViewMo
9088
}
9189
}
9290

93-
private fun getCaptureLocationButtonState(
91+
private fun getCaptureLocationButton(
9492
captureEnabled: Boolean,
9593
taskData: TaskData?,
9694
): ButtonActionState =

app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/multiplechoice/MultipleChoiceTaskViewModel.kt

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,9 @@
1515
*/
1616
package org.groundplatform.android.ui.datacollection.tasks.multiplechoice
1717

18-
import androidx.lifecycle.viewModelScope
1918
import javax.inject.Inject
2019
import kotlinx.coroutines.flow.MutableStateFlow
21-
import kotlinx.coroutines.flow.SharingStarted
2220
import kotlinx.coroutines.flow.StateFlow
23-
import kotlinx.coroutines.flow.map
24-
import kotlinx.coroutines.flow.stateIn
2521
import kotlinx.coroutines.flow.update
2622
import org.groundplatform.android.R
2723
import org.groundplatform.android.common.Constants
@@ -32,18 +28,11 @@ import org.groundplatform.android.model.submission.TaskData
3228
import org.groundplatform.android.model.task.MultipleChoice.Cardinality.SELECT_MULTIPLE
3329
import org.groundplatform.android.model.task.Option
3430
import org.groundplatform.android.model.task.Task
35-
import org.groundplatform.android.ui.datacollection.components.refactor.ButtonActionState
3631
import org.groundplatform.android.ui.datacollection.tasks.AbstractTaskViewModel
3732
import org.groundplatform.android.ui.datacollection.tasks.TaskPositionInterface
3833

3934
class MultipleChoiceTaskViewModel @Inject constructor() : AbstractTaskViewModel() {
4035

41-
override val taskActionButtonStates: StateFlow<List<ButtonActionState>> by lazy {
42-
taskTaskData
43-
.map { listOf(getPreviousButtonState(), getSkipButtonState(it), getNextButtonState(it)) }
44-
.stateIn(viewModelScope, SharingStarted.Lazily, emptyList())
45-
}
46-
4736
private val _items: MutableStateFlow<List<MultipleChoiceItem>> = MutableStateFlow(emptyList())
4837
val items: StateFlow<List<MultipleChoiceItem>> = _items
4938

app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/number/NumberTaskViewModel.kt

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,15 @@ package org.groundplatform.android.ui.datacollection.tasks.number
1717

1818
import androidx.lifecycle.LiveData
1919
import androidx.lifecycle.asLiveData
20-
import androidx.lifecycle.viewModelScope
2120
import javax.inject.Inject
22-
import kotlinx.coroutines.flow.SharingStarted
23-
import kotlinx.coroutines.flow.StateFlow
2421
import kotlinx.coroutines.flow.filterIsInstance
2522
import kotlinx.coroutines.flow.map
26-
import kotlinx.coroutines.flow.stateIn
2723
import org.groundplatform.android.model.submission.NumberTaskData
2824
import org.groundplatform.android.model.submission.TaskData
29-
import org.groundplatform.android.ui.datacollection.components.refactor.ButtonActionState
3025
import org.groundplatform.android.ui.datacollection.tasks.AbstractTaskViewModel
3126

3227
class NumberTaskViewModel @Inject constructor() : AbstractTaskViewModel() {
3328

34-
override val taskActionButtonStates: StateFlow<List<ButtonActionState>> by lazy {
35-
taskTaskData
36-
.map { listOf(getPreviousButtonState(), getSkipButtonState(it), getNextButtonState(it)) }
37-
.stateIn(viewModelScope, SharingStarted.Lazily, emptyList())
38-
}
39-
4029
/** Transcoded text to be displayed for the current [TaskData]. */
4130
val responseText: LiveData<String> =
4231
taskTaskData.filterIsInstance<NumberTaskData?>().map { it?.number ?: "" }.asLiveData()

app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/photo/PhotoTaskViewModel.kt

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,13 @@ import androidx.lifecycle.viewModelScope
2222
import java.io.IOException
2323
import javax.inject.Inject
2424
import kotlinx.coroutines.Dispatchers
25-
import kotlinx.coroutines.flow.SharingStarted
26-
import kotlinx.coroutines.flow.StateFlow
2725
import kotlinx.coroutines.flow.filterIsInstance
2826
import kotlinx.coroutines.flow.map
29-
import kotlinx.coroutines.flow.stateIn
3027
import kotlinx.coroutines.launch
3128
import kotlinx.coroutines.withContext
3229
import org.groundplatform.android.data.remote.firebase.FirebaseStorageManager
3330
import org.groundplatform.android.model.submission.PhotoTaskData
31+
import org.groundplatform.android.model.submission.TaskData
3432
import org.groundplatform.android.model.submission.isNotNullOrEmpty
3533
import org.groundplatform.android.repository.UserMediaRepository
3634
import org.groundplatform.android.ui.datacollection.components.refactor.ButtonActionState
@@ -40,19 +38,6 @@ import timber.log.Timber
4038
class PhotoTaskViewModel @Inject constructor(private val userMediaRepository: UserMediaRepository) :
4139
AbstractTaskViewModel() {
4240

43-
override val taskActionButtonStates: StateFlow<List<ButtonActionState>> by lazy {
44-
taskTaskData
45-
.map {
46-
listOf(
47-
getPreviousButtonState(),
48-
getUndoButtonState(it),
49-
getSkipButtonState(it),
50-
getNextButtonState(it),
51-
)
52-
}
53-
.stateIn(viewModelScope, SharingStarted.Lazily, emptyList())
54-
}
55-
5641
/**
5742
* Task id waiting for a photo result. As only one photo result is returned at a time, we can
5843
* directly map it 1:1 with the task waiting for a photo result.
@@ -73,6 +58,14 @@ class PhotoTaskViewModel @Inject constructor(private val userMediaRepository: Us
7358

7459
val isPhotoPresent: LiveData<Boolean> = taskTaskData.map { it.isNotNullOrEmpty() }.asLiveData()
7560

61+
override fun getButtonStates(taskData: TaskData?): List<ButtonActionState> =
62+
listOf(
63+
getPreviousButton(),
64+
getUndoButton(taskData),
65+
getSkipButton(taskData),
66+
getNextButton(taskData),
67+
)
68+
7669
suspend fun createImageFileUri(): Uri {
7770
val file = userMediaRepository.createImageFile(task.id)
7871
return userMediaRepository.getUriForFile(file)

app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/point/DropPinTaskViewModel.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ constructor(
5555
taskTaskData
5656
.map {
5757
listOf(
58-
getPreviousButtonState(),
59-
getSkipButtonState(it),
60-
getUndoButtonState(it),
58+
getPreviousButton(),
59+
getSkipButton(it),
60+
getUndoButton(it),
6161
getDropPinButtonState(it),
62-
getNextButtonState(it, hideIfEmpty = true),
62+
getNextButton(it, hideIfEmpty = true),
6363
)
6464
}
6565
.stateIn(viewModelScope, SharingStarted.Lazily, emptyList())

app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/polygon/DrawAreaTaskViewModel.kt

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -150,13 +150,13 @@ internal constructor(
150150
combine(taskTaskData, merge(draftArea, draftUpdates)) { taskData, currentFeature ->
151151
val isClosed = (currentFeature?.geometry as? LineString)?.isClosed() ?: false
152152
listOfNotNull(
153-
getPreviousButtonState(),
154-
getSkipButtonState(taskData),
155-
getUndoButtonState(taskData, true),
156-
getRedoButtonState(taskData),
157-
getAddPointButtonState(isClosed, isTooClose.value),
153+
getPreviousButton(),
154+
getSkipButton(taskData),
155+
getUndoButton(taskData, true),
156+
getRedoButton(taskData),
157+
getAddPointButton(isClosed, isTooClose.value),
158158
getCompleteButton(isClosed, isMarkedComplete.value, hasSelfIntersection),
159-
getNextButtonState(taskData).takeIf { isMarkedComplete() },
159+
getNextButton(taskData).takeIf { isMarkedComplete() },
160160
)
161161
}
162162
.stateIn(viewModelScope, SharingStarted.Lazily, emptyList())
@@ -422,24 +422,21 @@ internal constructor(
422422
vibrationHelper.vibrate()
423423
}
424424

425-
private fun getRedoButtonState(taskData: TaskData?): ButtonActionState =
425+
private fun getRedoButton(taskData: TaskData?): ButtonActionState =
426426
ButtonActionState(
427427
action = ButtonAction.REDO,
428428
isEnabled = redoVertexStack.isNotEmpty() && taskData.isNotNullOrEmpty(),
429429
isVisible = true,
430430
)
431431

432-
private fun getAddPointButtonState(
433-
isPolygonClosed: Boolean,
434-
isTooClose: Boolean,
435-
): ButtonActionState =
432+
private fun getAddPointButton(isPolygonClosed: Boolean, isTooClose: Boolean): ButtonActionState =
436433
ButtonActionState(
437434
action = ButtonAction.ADD_POINT,
438435
isEnabled = !isPolygonClosed && !isTooClose,
439436
isVisible = !isPolygonClosed,
440437
)
441438

442-
fun getCompleteButton(
439+
private fun getCompleteButton(
443440
isClosed: Boolean,
444441
isMarkedComplete: Boolean,
445442
hasSelfIntersection: Boolean,

app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/text/TextTaskViewModel.kt

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,18 @@ package org.groundplatform.android.ui.datacollection.tasks.text
1717

1818
import androidx.lifecycle.LiveData
1919
import androidx.lifecycle.asLiveData
20-
import androidx.lifecycle.viewModelScope
2120
import javax.inject.Inject
22-
import kotlinx.coroutines.flow.SharingStarted
23-
import kotlinx.coroutines.flow.StateFlow
2421
import kotlinx.coroutines.flow.filterIsInstance
2522
import kotlinx.coroutines.flow.map
26-
import kotlinx.coroutines.flow.stateIn
2723
import org.groundplatform.android.R
2824
import org.groundplatform.android.common.Constants
2925
import org.groundplatform.android.model.submission.TaskData
3026
import org.groundplatform.android.model.submission.TextTaskData
3127
import org.groundplatform.android.model.task.Task
32-
import org.groundplatform.android.ui.datacollection.components.refactor.ButtonActionState
3328
import org.groundplatform.android.ui.datacollection.tasks.AbstractTaskViewModel
3429

3530
class TextTaskViewModel @Inject constructor() : AbstractTaskViewModel() {
3631

37-
override val taskActionButtonStates: StateFlow<List<ButtonActionState>> by lazy {
38-
taskTaskData
39-
.map { listOf(getPreviousButtonState(), getSkipButtonState(it), getNextButtonState(it)) }
40-
.stateIn(viewModelScope, SharingStarted.Lazily, emptyList())
41-
}
42-
4332
/** Transcoded text to be displayed for the current [TaskData]. */
4433
val responseText: LiveData<String> =
4534
taskTaskData.filterIsInstance<TextTaskData?>().map { it?.text ?: "" }.asLiveData()

0 commit comments

Comments
 (0)