Skip to content

Conversation

@andreia-ferreira
Copy link
Collaborator

@andreia-ferreira andreia-ferreira commented Feb 4, 2026

Fixes #3437

This PR refactors the task action buttons fully to Jetpack Compose, implementing the previously created TaskFooter and TaskButton components.

The main changes consist on:

  • deleting task_frag_action_buttons.xml, the old TaskButton and removed its usage from task fragment layouts
  • implemented the components created in the previous PR
  • ViewModel updates: updated visibility of methods that were previously public in order to be used by the fragments; unit tests were also added
  • updated task fragments to integrate the new Compose-based action buttons

This modernizes the UI implementation for task navigation and actions, improving maintainability and testability. The functionality itself should be the same, not interfering with the user experience:

Before:

Screen_recording_20260209_152821.webm

After:

after.webm

@shobhitagarwal1612 PTAL?

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @andreia-ferreira, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the task action button implementation across the data collection flow. The primary goal was to modernize the button UI and logic by migrating to Jetpack Compose and centralizing state management within ViewModels. This change improves maintainability, testability, and sets the stage for more flexible UI development by decoupling button presentation from fragment logic and task position determination.

Highlights

  • Jetpack Compose Migration for Task Buttons: The task action buttons have been fully migrated to Jetpack Compose, replacing the previous imperative UI management with a declarative approach. This involves removing the old TaskButton class and task_frag_action_buttons.xml layout, and introducing new Composable functions like TaskButton and TaskFooter.
  • Centralized Button State Management: Button states (visibility, enabled status) are now managed declaratively within each AbstractTaskViewModel via a StateFlow<List<ButtonActionState>>. This allows ViewModels to define and update their button configurations dynamically, simplifying UI logic in fragments.
  • Decoupling Task Position Logic: A new TaskPositionInterface has been introduced to abstract away the logic for determining if a task is the first or last in a sequence. This interface is now passed to AbstractTaskViewModel during initialization, reducing direct dependencies on DataCollectionViewModel for task position checks.
  • Refactored Button Logic into ViewModels: Task-specific button creation and behavior, previously handled in AbstractTaskFragment, have been moved into their respective AbstractTaskViewModel subclasses. This includes methods like getPreviousButton, getNextButton, getSkipButton, and onButtonClick, promoting better separation of concerns.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • app/src/main/java/org/groundplatform/android/ui/datacollection/DataCollectionViewModel.kt
    • Updated initialize method to pass a TaskPositionInterface object to AbstractTaskViewModel.
    • Changed isFirstPosition and isLastPositionWithValue methods to private and added null-safe calls.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/components/ButtonActionState.kt
    • Added new data class ButtonActionState to encapsulate button action, enabled status, and visibility.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/components/InstructionsDialog.kt
    • Renamed and moved to app/src/main/java/org/groundplatform/android/ui/datacollection/components/ui/InstructionsDialog.kt.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/components/LoiNameDialog.kt
    • Renamed and moved to app/src/main/java/org/groundplatform/android/ui/datacollection/components/ui/LoiNameDialog.kt.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/components/TaskButton.kt
    • Removed the old imperative TaskButton class.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/components/TaskView.kt
    • Updated actionButtonsContainer type from TaskFragActionButtonsBinding to ComposeView.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/components/TextTaskInput.kt
    • Renamed and moved to app/src/main/java/org/groundplatform/android/ui/datacollection/components/ui/TextTaskInput.kt.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/components/ui/TaskButton.kt
    • Added new Composable TaskButton function for declarative button rendering.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/components/ui/TaskFooter.kt
    • Added new Composable TaskFooter function to render a row of task buttons based on ButtonActionState list.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/AbstractMapTaskViewModel.kt
    • Changed class modifier from open to abstract.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/AbstractTaskFragment.kt
    • Removed imperative button management methods (addPreviousButton, addNextButton, addSkipButton, addUndoButton, addButton, onCreateActionButtons, onActionButtonsCreated, onValueChanged).
    • Updated renderButtons to use the new TaskFooter Composable and observe viewModel.taskActionButtonStates.
    • Added handleButtonClick to delegate button click events to the ViewModel.
    • Removed buttonDataList and ButtonData inner class.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/AbstractTaskViewModel.kt
    • Changed class modifier from open to abstract.
    • Introduced taskActionButtonStates as a StateFlow to manage button states.
    • Added TaskPositionInterface to initialize method.
    • Added helper methods (getPreviousButton, getNextButton, getSkipButton, getUndoButton) to create ButtonActionState objects.
    • Added onButtonClick method to handle button actions delegated from the fragment.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/TaskPositionInterface.kt
    • Added new interface TaskPositionInterface to define methods for checking task position (isFirst, isLastWithValue).
  • app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/instruction/InstructionTaskFragment.kt
    • Removed onCreateActionButtons override.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/instruction/InstructionTaskViewModel.kt
    • Overrode getButtonStates to define specific buttons for instruction tasks.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/location/CaptureLocationTaskFragment.kt
    • Removed onCreateActionButtons override.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/location/CaptureLocationTaskViewModel.kt
    • Overrode taskActionButtonStates to dynamically generate button states based on capture enablement and task data.
    • Added getCaptureLocationButton and overrode onButtonClick to handle CAPTURE_LOCATION action.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/multiplechoice/MultipleChoiceTaskViewModel.kt
    • Updated initialize method to accept TaskPositionInterface.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/photo/PhotoTaskFragment.kt
    • Removed onCreateActionButtons override.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/photo/PhotoTaskViewModel.kt
    • Overrode getButtonStates to define specific buttons for photo tasks.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/point/DropPinTaskFragment.kt
    • Removed onCreateActionButtons override.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/point/DropPinTaskViewModel.kt
    • Overrode taskActionButtonStates to dynamically generate button states for drop pin tasks.
    • Overrode onButtonClick to handle DROP_PIN action.
    • Updated initialize method to accept TaskPositionInterface.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/polygon/DrawAreaTaskFragment.kt
    • Removed imperative button management and related fields (completeButton, addPointButton, nextButton).
    • Updated onTaskViewAttached to observe camera movement events from the ViewModel.
  • app/src/main/java/org/groundplatform/android/ui/datacollection/tasks/polygon/DrawAreaTaskViewModel.kt
    • Introduced _cameraMoveEvents channel for one-shot camera movement events.
    • Overrode taskActionButtonStates to dynamically generate button states for drawing area tasks, including UNDO, REDO, ADD_POINT, and COMPLETE.
    • Overrode onButtonClick to handle UNDO, REDO, ADD_POINT, and COMPLETE actions.
    • Updated initialize method to accept TaskPositionInterface.
  • app/src/main/res/layout/task_frag_action_buttons.xml
    • Removed this XML layout file, as button rendering is now handled by Compose.
  • app/src/main/res/layout/task_frag_with_combined_header.xml
    • Replaced <include> for action buttons with <androidx.compose.ui.platform.ComposeView>.
  • app/src/main/res/layout/task_frag_with_header.xml
    • Replaced <include> for action buttons with <androidx.compose.ui.platform.ComposeView>.
  • app/src/test/java/org/groundplatform/android/FakeData.kt
    • Added isRequired parameter to newTask factory function for better test control.
  • app/src/test/java/org/groundplatform/android/ui/datacollection/TaskFragmentRunner.kt
    • Updated import for LOI_NAME_TEXT_FIELD_TEST_TAG to the new ui subpackage.
  • app/src/test/java/org/groundplatform/android/ui/datacollection/components/ui/TaskButtonTest.kt
    • Added new Compose UI tests for the TaskButton Composable.
  • app/src/test/java/org/groundplatform/android/ui/datacollection/components/ui/TaskFooterTest.kt
    • Added new Compose UI tests for the TaskFooter Composable.
  • app/src/test/java/org/groundplatform/android/ui/datacollection/tasks/AbstractTaskViewModelTest.kt
    • Added new tests for AbstractTaskViewModel to verify default button state logic.
  • app/src/test/java/org/groundplatform/android/ui/datacollection/tasks/BaseTaskFragmentTest.kt
    • Updated assertFragmentHasButtons to accept ButtonActionState objects and verify enabled/visible states.
    • Modified setupTaskFragment to pass isFirstPosition and isLastPosition to the ViewModel initialization.
  • app/src/test/java/org/groundplatform/android/ui/datacollection/tasks/date/DateTaskFragmentTest.kt
    • Updated button assertions to use ButtonActionState.
  • app/src/test/java/org/groundplatform/android/ui/datacollection/tasks/instruction/InstructionTaskFragmentTest.kt
    • Updated button assertions to use ButtonActionState.
  • app/src/test/java/org/groundplatform/android/ui/datacollection/tasks/instruction/InstructionTaskViewModelTest.kt
    • Added new tests for InstructionTaskViewModel to verify button order.
  • app/src/test/java/org/groundplatform/android/ui/datacollection/tasks/location/CaptureLocationTaskFragmentTest.kt
    • Updated button assertions to use ButtonActionState.
  • app/src/test/java/org/groundplatform/android/ui/datacollection/tasks/location/CaptureLocationTaskViewModelTest.kt
    • Added new tests for CaptureLocationTaskViewModel to verify button states and actions.
  • app/src/test/java/org/groundplatform/android/ui/datacollection/tasks/multiplechoice/MultipleChoiceTaskFragmentTest.kt
    • Updated button assertions to use ButtonActionState and removed mockito mocks for isFirstPosition and isLastPosition.
  • app/src/test/java/org/groundplatform/android/ui/datacollection/tasks/number/NumberTaskFragmentTest.kt
    • Updated button assertions to use ButtonActionState.
  • app/src/test/java/org/groundplatform/android/ui/datacollection/tasks/photo/PhotoTaskFragmentTest.kt
    • Updated button assertions to use ButtonActionState.
  • app/src/test/java/org/groundplatform/android/ui/datacollection/tasks/photo/PhotoTaskViewModelTest.kt
    • Added new tests for PhotoTaskViewModel to verify button states and actions.
  • app/src/test/java/org/groundplatform/android/ui/datacollection/tasks/point/DropPinTaskViewModelTest.kt
    • Added new tests for DropPinTaskViewModel to verify button states and actions.
  • app/src/test/java/org/groundplatform/android/ui/datacollection/tasks/polygon/DrawAreaTaskFragmentTest.kt
    • Updated button assertions to use ButtonActionState.
  • app/src/test/java/org/groundplatform/android/ui/datacollection/tasks/polygon/DrawAreaTaskViewModelTest.kt
    • Added new tests for DrawAreaTaskViewModel to verify button states and actions, including undo/redo and polygon completion.
  • app/src/test/java/org/groundplatform/android/ui/datacollection/tasks/text/TextTaskFragmentTest.kt
    • Updated button assertions to use ButtonActionState.
  • app/src/test/java/org/groundplatform/android/ui/datacollection/tasks/time/TimeTaskFragmentTest.kt
    • Updated button assertions to use ButtonActionState.
  • e2eTest/src/main/java/org/groundplatform/android/e2etest/robots/DataCollectionRobot.kt
    • Updated import for LOI_NAME_TEXT_FIELD_TEST_TAG to the new ui subpackage.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request is a significant and well-executed refactoring of the task button handling logic. It moves away from a stateful TaskButton class towards a more declarative, Compose-idiomatic approach using a stateless TaskButton composable and a new TaskFooter. The state management is now centralized in the AbstractTaskViewModel and its subclasses, using StateFlow to drive the UI, which is a great improvement for maintainability and testability. The decoupling of DataCollectionViewModel from task ViewModels via the TaskPositionInterface is also a solid design choice. I've found one issue in the DrawAreaTaskViewModel related to reactive state updates for the buttons, which could lead to a stale UI.

@andreia-ferreira andreia-ferreira force-pushed the andreia/3437/implement-refactor branch from 4e3e0a9 to c35604c Compare February 6, 2026 10:10
@codecov
Copy link

codecov bot commented Feb 6, 2026

Codecov Report

❌ Patch coverage is 56.75676% with 16 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.57%. Comparing base (eea47cc) to head (3ac2aca).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
...android/ui/datacollection/components/TaskButton.kt 0.00% 9 Missing ⚠️
...android/ui/datacollection/components/TaskFooter.kt 68.75% 5 Missing ⚠️
...droid/ui/datacollection/DataCollectionViewModel.kt 71.42% 0 Missing and 2 partials ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master    #3525      +/-   ##
============================================
+ Coverage     70.54%   70.57%   +0.03%     
+ Complexity     1639     1615      -24     
============================================
  Files           327      326       -1     
  Lines          8975     8861     -114     
  Branches        990      976      -14     
============================================
- Hits           6331     6254      -77     
+ Misses         2048     2024      -24     
+ Partials        596      583      -13     
Files with missing lines Coverage Δ
...ction/tasks/instruction/InstructionTaskFragment.kt 92.85% <ø> (-0.90%) ⬇️
...tion/tasks/instruction/InstructionTaskViewModel.kt 100.00% <ø> (ø)
...tion/tasks/location/CaptureLocationTaskFragment.kt 65.95% <ø> (-5.23%) ⬇️
...ion/tasks/location/CaptureLocationTaskViewModel.kt 90.24% <100.00%> (+5.24%) ⬆️
...ui/datacollection/tasks/photo/PhotoTaskFragment.kt 60.93% <ø> (-2.30%) ⬇️
...i/datacollection/tasks/photo/PhotoTaskViewModel.kt 92.10% <ø> (ø)
.../datacollection/tasks/point/DropPinTaskFragment.kt 95.45% <ø> (-1.10%) ⬇️
...datacollection/tasks/point/DropPinTaskViewModel.kt 91.83% <ø> (+4.08%) ⬆️
...tacollection/tasks/polygon/DrawAreaTaskFragment.kt 78.26% <ø> (+4.57%) ⬆️
...acollection/tasks/polygon/DrawAreaTaskViewModel.kt 81.63% <100.00%> (+0.60%) ⬆️
... and 3 more

... and 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@andreia-ferreira andreia-ferreira marked this pull request as ready for review February 9, 2026 17:23
@auto-assign auto-assign bot requested a review from sufyanAbbasi February 9, 2026 17:23
@andreia-ferreira andreia-ferreira requested review from shobhitagarwal1612 and removed request for sufyanAbbasi February 9, 2026 17:24
Copy link
Member

@shobhitagarwal1612 shobhitagarwal1612 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing! ✨

@andreia-ferreira andreia-ferreira merged commit 155e1ac into master Feb 10, 2026
9 checks passed
@andreia-ferreira andreia-ferreira deleted the andreia/3437/implement-refactor branch February 10, 2026 12:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Code health] Refactor TaskButton implementation

2 participants