Skip to content

Commit

Permalink
Hide "Collect data" button when the job has no more tasks to complete (
Browse files Browse the repository at this point in the history
…#2598)

* Default to first index if startId is not found.

* Show error when there are no more tasks for this job.

* Remove "Collect Data" if an job has no non-LOI tasks.

* Add note

* Factor out first task ID.

* Refactor task ID for readability

---------

Co-authored-by: Gino Miceli <228050+gino-m@users.noreply.github.com>
Co-authored-by: Shobhit Agarwal <ashobhit@google.com>
  • Loading branch information
3 people authored Aug 13, 2024
1 parent cde332e commit be28c1a
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ data class Job(

/** Returns true if the job has one or more tasks. */
fun hasTasks() = tasks.values.isNotEmpty()

/** Returns whether the job has non-LOI tasks. */
fun hasNonLoiTasks() = tasks.values.count { !it.isAddLoiTask } > 0
}

fun Job.getDefaultColor(): Int =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,14 @@ internal constructor(
return currentIndex to size
}

/** Returns the index of the task ID, or -1 if null or not found. */
private fun getIndexOfTask(taskId: String?) =
if (taskId == null) {
-1
} else {
tasks.indexOfFirst { it.id == taskId }
}

/**
* Retrieves the current task sequence given the inputs and conditions set on the tasks. Setting a
* start ID will always generate a sequence with the start ID as the first element, and if
Expand All @@ -321,17 +329,16 @@ internal constructor(
if (tasks.isEmpty()) {
error("Can't generate sequence for empty task list")
}

val task = tasks.filter { it.id == (startId ?: tasks[0].id) }

// TODO(#2539): Cleanup once https://github.com/google/ground-android/issues/2539 is resolved.
if (task.isEmpty()) {
error(
"Unable to find a task with id startId=$startId, firstTaskId=${tasks[0].id}, allTasks=${tasks.map { it.id }}"
)
}

val startIndex = tasks.indexOf(task.first())
val startIndex =
getIndexOfTask(startId).let {
if (it < 0) {
// Default to 0 if startId is not found or is null.
if (startId != null) Timber.w("startId, $startId, was not found. Defaulting to 0")
0
} else {
it
}
}
return if (reversed) {
tasks.subList(0, startIndex + 1).reversed()
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class HomeScreenMapContainerFragment : AbstractMapContainerFragment() {
val canUserSubmitData = userRepository.canUserSubmitData()

// Handle collect button clicks
adapter.setCollectDataListener { onCollectData(canUserSubmitData, it) }
adapter.setCollectDataListener { onCollectData(canUserSubmitData, hasValidTasks(it), it) }

// Bind data for cards
mapContainerViewModel.getMapCardUiData().launchWhenStartedAndCollect { (mapCards, loiCount) ->
Expand All @@ -90,15 +90,32 @@ class HomeScreenMapContainerFragment : AbstractMapContainerFragment() {
map.featureClicks.launchWhenStartedAndCollect { mapContainerViewModel.onFeatureClicked(it) }
}

private fun hasValidTasks(cardUiData: MapCardUiData) =
when (cardUiData) {
// LOI tasks are filtered out of the tasks list for pre-defined tasks.
is MapCardUiData.LoiCardUiData ->
cardUiData.loi.job.tasks.values.count { !it.isAddLoiTask } > 0
is MapCardUiData.AddLoiCardUiData -> cardUiData.job.tasks.values.isNotEmpty()
}

/** Invoked when user clicks on the map cards to collect data. */
private fun onCollectData(canUserSubmitData: Boolean, cardUiData: MapCardUiData) {
if (canUserSubmitData) {
navigateToDataCollectionFragment(cardUiData)
} else {
private fun onCollectData(
canUserSubmitData: Boolean,
hasTasks: Boolean,
cardUiData: MapCardUiData,
) {
if (!canUserSubmitData) {
// Skip data collection screen if the user can't submit any data
// TODO(#1667): Revisit UX for displaying view only mode
ephemeralPopups.ErrorPopup().show(getString(R.string.collect_data_viewer_error))
return
}
if (!hasTasks) {
// NOTE(#2539): The DataCollectionFragment will crash if there are no tasks.
ephemeralPopups.ErrorPopup().show(getString(R.string.no_tasks_error))
return
}
navigateToDataCollectionFragment(cardUiData)
}

/** Updates the given [TextView] with the submission count for the given [LocationOfInterest]. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,9 @@ class MapCardAdapter(
with(binding) {
loiName.text = loiHelper.getDisplayLoiName(loi)
jobName.text = loiHelper.getJobName(loi)
// NOTE(#2539): The DataCollectionFragment will crash if there are no non-LOI tasks.
collectData.visibility =
if (canUserSubmitData && loi.job.hasTasks()) View.VISIBLE else View.GONE
if (canUserSubmitData && loi.job.hasNonLoiTasks()) View.VISIBLE else View.GONE
updateSubmissionCount(loi, submissions)
}
}
Expand Down
1 change: 1 addition & 0 deletions ground/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
<string name="drop_a_pin_tooltip_text">Drag your map until the center pin is on the desired location</string>
<string name="current_location">Current location:</string>
<string name="loading">Loading…</string>
<string name="no_tasks_error">This job has no more tasks to complete</string>
<string name="collect_data_viewer_error">Can’t collect data as user is a VIEWER</string>
<string name="offline_map_imagery">Offline map imagery</string>
<string name="offline_map_imagery_pref_description">Hide or show downloaded imagery</string>
Expand Down

0 comments on commit be28c1a

Please sign in to comment.