Skip to content

Commit ff74695

Browse files
Migrate MultipleChoiceTaskFragment to use TaskScreen Component (#3652)
- Extract the multiple-choice task UI into a new `MultipleChoiceTaskScreen` Composable. - Migrate `MultipleChoiceTaskFragment` to use `createComposeView`, integrating `MultipleChoiceTaskScreen` for rendering. - Update the fragment to delegate action handling and footer position updates to the new screen component. - Move the task body rendering logic from `MultipleChoiceTaskFragment` to `MultipleChoiceTaskContent`. - Replace `MultipleChoiceTaskFragmentTest` with `MultipleChoiceTaskScreenTest`, migrating tests to use `composeTestRule`.
1 parent 506ca77 commit ff74695

File tree

4 files changed

+428
-350
lines changed

4 files changed

+428
-350
lines changed

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

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,12 @@
1515
*/
1616
package org.groundplatform.android.ui.datacollection.tasks.multiplechoice
1717

18-
import androidx.compose.foundation.layout.Box
19-
import androidx.compose.foundation.layout.padding
20-
import androidx.compose.foundation.lazy.LazyColumn
21-
import androidx.compose.foundation.lazy.items
22-
import androidx.compose.foundation.lazy.rememberLazyListState
23-
import androidx.compose.material3.MaterialTheme
24-
import androidx.compose.runtime.Composable
25-
import androidx.compose.runtime.getValue
26-
import androidx.compose.ui.Modifier
27-
import androidx.compose.ui.platform.testTag
28-
import androidx.lifecycle.compose.collectAsStateWithLifecycle
18+
import android.os.Bundle
19+
import android.view.LayoutInflater
20+
import android.view.ViewGroup
2921
import dagger.hilt.android.AndroidEntryPoint
3022
import org.groundplatform.android.ui.datacollection.tasks.AbstractTaskFragment
31-
import org.groundplatform.ui.theme.sizes
23+
import org.groundplatform.android.util.createComposeView
3224

3325
const val MULTIPLE_CHOICE_LIST_TEST_TAG = "multiple choice items test tag"
3426

@@ -39,22 +31,15 @@ const val MULTIPLE_CHOICE_LIST_TEST_TAG = "multiple choice items test tag"
3931
@AndroidEntryPoint
4032
class MultipleChoiceTaskFragment : AbstractTaskFragment<MultipleChoiceTaskViewModel>() {
4133

42-
@Composable
43-
override fun TaskBody() {
44-
val list by viewModel.items.collectAsStateWithLifecycle()
45-
val scrollState = rememberLazyListState()
46-
47-
Box(modifier = Modifier.padding(horizontal = MaterialTheme.sizes.taskViewPadding)) {
48-
LazyColumn(Modifier.testTag(MULTIPLE_CHOICE_LIST_TEST_TAG), state = scrollState) {
49-
items(list, key = { it.option.id }) { item ->
50-
MultipleChoiceItemView(
51-
item = item,
52-
isLastIndex = list.indexOf(item) == list.lastIndex,
53-
toggleItem = { viewModel.onItemToggled(it) },
54-
otherValueChanged = { viewModel.onOtherTextChanged(it) },
55-
)
56-
}
57-
}
58-
}
34+
override fun onCreateView(
35+
inflater: LayoutInflater,
36+
container: ViewGroup?,
37+
savedInstanceState: Bundle?,
38+
) = createComposeView {
39+
MultipleChoiceTaskScreen(
40+
viewModel = viewModel,
41+
onFooterPositionUpdated = { saveFooterPosition(it) },
42+
onAction = { handleTaskScreenAction(it) },
43+
)
5944
}
6045
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.groundplatform.android.ui.datacollection.tasks.multiplechoice
17+
18+
import androidx.compose.foundation.layout.Box
19+
import androidx.compose.foundation.layout.padding
20+
import androidx.compose.foundation.lazy.LazyColumn
21+
import androidx.compose.foundation.lazy.items
22+
import androidx.compose.foundation.lazy.rememberLazyListState
23+
import androidx.compose.material3.MaterialTheme
24+
import androidx.compose.material3.Surface
25+
import androidx.compose.runtime.Composable
26+
import androidx.compose.runtime.getValue
27+
import androidx.compose.ui.Modifier
28+
import androidx.compose.ui.platform.testTag
29+
import androidx.compose.ui.tooling.preview.Preview
30+
import androidx.lifecycle.compose.collectAsStateWithLifecycle
31+
import org.groundplatform.android.R
32+
import org.groundplatform.android.ui.common.ExcludeFromJacocoGeneratedReport
33+
import org.groundplatform.android.ui.datacollection.components.TaskHeader
34+
import org.groundplatform.android.ui.datacollection.tasks.TaskScreen
35+
import org.groundplatform.android.ui.datacollection.tasks.TaskScreenAction
36+
import org.groundplatform.domain.model.task.MultipleChoice.Cardinality
37+
import org.groundplatform.domain.model.task.Option
38+
import org.groundplatform.ui.theme.AppTheme
39+
import org.groundplatform.ui.theme.sizes
40+
41+
@Composable
42+
fun MultipleChoiceTaskScreen(
43+
viewModel: MultipleChoiceTaskViewModel,
44+
onFooterPositionUpdated: (Float) -> Unit,
45+
onAction: (TaskScreenAction) -> Unit,
46+
) {
47+
val taskActionButtonsStates by viewModel.taskActionButtonStates.collectAsStateWithLifecycle()
48+
val list by viewModel.items.collectAsStateWithLifecycle()
49+
50+
TaskScreen(
51+
taskHeader =
52+
TaskHeader(label = viewModel.task.label, iconResId = R.drawable.ic_question_answer),
53+
taskActionButtonsStates = taskActionButtonsStates,
54+
onFooterPositionUpdated = onFooterPositionUpdated,
55+
onAction = onAction,
56+
taskBody = {
57+
MultipleChoiceTaskContent(
58+
list = list,
59+
onItemToggled = { viewModel.onItemToggled(it) },
60+
onOtherValueChanged = { viewModel.onOtherTextChanged(it) },
61+
)
62+
},
63+
)
64+
}
65+
66+
@Composable
67+
internal fun MultipleChoiceTaskContent(
68+
list: List<MultipleChoiceItem>,
69+
onItemToggled: (MultipleChoiceItem) -> Unit,
70+
onOtherValueChanged: (String) -> Unit,
71+
) {
72+
val scrollState = rememberLazyListState()
73+
74+
Box(modifier = Modifier.padding(horizontal = MaterialTheme.sizes.taskViewPadding)) {
75+
LazyColumn(Modifier.testTag(MULTIPLE_CHOICE_LIST_TEST_TAG), state = scrollState) {
76+
items(list, key = { it.option.id }) { item ->
77+
MultipleChoiceItemView(
78+
item = item,
79+
isLastIndex = list.indexOf(item) == list.lastIndex,
80+
toggleItem = onItemToggled,
81+
otherValueChanged = onOtherValueChanged,
82+
)
83+
}
84+
}
85+
}
86+
}
87+
88+
@Preview(showBackground = true)
89+
@Composable
90+
@ExcludeFromJacocoGeneratedReport
91+
private fun MultipleChoiceTaskContentPreview() {
92+
AppTheme {
93+
Surface {
94+
MultipleChoiceTaskContent(
95+
list =
96+
listOf(
97+
MultipleChoiceItem(
98+
option = Option("option id 1", "code1", "Option 1"),
99+
cardinality = Cardinality.SELECT_ONE,
100+
isSelected = true,
101+
),
102+
MultipleChoiceItem(
103+
option = Option("option id 2", "code2", "Option 2"),
104+
cardinality = Cardinality.SELECT_ONE,
105+
isSelected = false,
106+
),
107+
MultipleChoiceItem(
108+
option = Option("option id 3", "code3", "Other"),
109+
cardinality = Cardinality.SELECT_ONE,
110+
isSelected = false,
111+
isOtherOption = true,
112+
),
113+
),
114+
onItemToggled = {},
115+
onOtherValueChanged = {},
116+
)
117+
}
118+
}
119+
}

0 commit comments

Comments
 (0)