Skip to content

Commit 49c723e

Browse files
author
Marco Romano
authored
Poll Creation: Switch focus to newly added option field when clicking "Add option". #1294
Poll Creation: Switch focus to newly added option field when clicking "Add option".
2 parents bdc6cdd + f456eea commit 49c723e

File tree

1 file changed

+56
-37
lines changed
  • features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create

1 file changed

+56
-37
lines changed

features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollView.kt

Lines changed: 56 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,23 @@ package io.element.android.features.poll.impl.create
1818

1919
import androidx.activity.compose.BackHandler
2020
import androidx.compose.foundation.clickable
21+
import androidx.compose.foundation.layout.Column
2122
import androidx.compose.foundation.layout.consumeWindowInsets
2223
import androidx.compose.foundation.layout.fillMaxSize
2324
import androidx.compose.foundation.layout.fillMaxWidth
2425
import androidx.compose.foundation.layout.imePadding
2526
import androidx.compose.foundation.layout.padding
2627
import androidx.compose.foundation.lazy.LazyColumn
2728
import androidx.compose.foundation.lazy.itemsIndexed
29+
import androidx.compose.foundation.lazy.rememberLazyListState
2830
import androidx.compose.foundation.text.KeyboardOptions
2931
import androidx.compose.material.icons.Icons
3032
import androidx.compose.material.icons.filled.Add
3133
import androidx.compose.material3.ExperimentalMaterial3Api
3234
import androidx.compose.runtime.Composable
3335
import androidx.compose.runtime.LaunchedEffect
3436
import androidx.compose.runtime.remember
37+
import androidx.compose.runtime.rememberCoroutineScope
3538
import androidx.compose.ui.Modifier
3639
import androidx.compose.ui.focus.FocusRequester
3740
import androidx.compose.ui.focus.focusRequester
@@ -61,13 +64,17 @@ import io.element.android.libraries.designsystem.theme.components.TopAppBar
6164
import io.element.android.libraries.matrix.api.poll.PollKind
6265
import io.element.android.libraries.theme.ElementTheme
6366
import io.element.android.libraries.ui.strings.CommonStrings
67+
import kotlinx.coroutines.Dispatchers
68+
import kotlinx.coroutines.launch
6469

6570
@OptIn(ExperimentalMaterial3Api::class)
6671
@Composable
6772
fun CreatePollView(
6873
state: CreatePollState,
6974
modifier: Modifier = Modifier,
7075
) {
76+
val coroutineScope = rememberCoroutineScope()
77+
7178
val navBack = { state.eventSink(CreatePollEvents.ConfirmNavBack) }
7279
BackHandler(onBack = navBack)
7380
if (state.showConfirmation) ConfirmationDialog(
@@ -76,6 +83,7 @@ fun CreatePollView(
7683
onDismiss = { state.eventSink(CreatePollEvents.HideConfirmation) }
7784
)
7885
val questionFocusRequester = remember { FocusRequester() }
86+
val answerFocusRequester = remember { FocusRequester() }
7987
LaunchedEffect(Unit) {
8088
questionFocusRequester.requestFocus()
8189
}
@@ -102,48 +110,53 @@ fun CreatePollView(
102110
)
103111
},
104112
) { paddingValues ->
113+
val lazyListState = rememberLazyListState()
105114
LazyColumn(
106115
modifier = Modifier
107116
.padding(paddingValues)
108117
.consumeWindowInsets(paddingValues)
109118
.imePadding()
110119
.fillMaxSize(),
120+
state = lazyListState,
111121
) {
112122
item {
113-
Text(
114-
text = stringResource(id = R.string.screen_create_poll_question_desc),
115-
modifier = Modifier.padding(start = 32.dp),
116-
style = ElementTheme.typography.fontBodyMdRegular,
117-
)
118-
}
119-
item {
120-
ListItem(
121-
headlineContent = {
122-
OutlinedTextField(
123-
value = state.question,
124-
onValueChange = {
125-
state.eventSink(CreatePollEvents.SetQuestion(it))
126-
},
127-
modifier = Modifier
128-
.focusRequester(questionFocusRequester)
129-
.fillMaxWidth(),
130-
placeholder = {
131-
Text(text = stringResource(id = R.string.screen_create_poll_question_hint))
132-
},
133-
keyboardOptions = keyboardOptions,
134-
)
135-
}
136-
)
123+
Column {
124+
Text(
125+
text = stringResource(id = R.string.screen_create_poll_question_desc),
126+
modifier = Modifier.padding(start = 32.dp),
127+
style = ElementTheme.typography.fontBodyMdRegular,
128+
)
129+
ListItem(
130+
headlineContent = {
131+
OutlinedTextField(
132+
value = state.question,
133+
onValueChange = {
134+
state.eventSink(CreatePollEvents.SetQuestion(it))
135+
},
136+
modifier = Modifier
137+
.focusRequester(questionFocusRequester)
138+
.fillMaxWidth(),
139+
placeholder = {
140+
Text(text = stringResource(id = R.string.screen_create_poll_question_hint))
141+
},
142+
keyboardOptions = keyboardOptions,
143+
)
144+
}
145+
)
146+
}
137147
}
138148
itemsIndexed(state.answers) { index, answer ->
149+
val isLastItem = index == state.answers.size - 1
139150
ListItem(
140151
headlineContent = {
141152
OutlinedTextField(
142153
value = answer.text,
143154
onValueChange = {
144155
state.eventSink(CreatePollEvents.SetAnswer(index, it))
145156
},
146-
modifier = Modifier.fillMaxWidth(),
157+
modifier = Modifier
158+
.then(if (isLastItem) Modifier.focusRequester(answerFocusRequester) else Modifier)
159+
.fillMaxWidth(),
147160
placeholder = {
148161
Text(text = stringResource(id = R.string.screen_create_poll_answer_hint, index + 1))
149162
},
@@ -170,22 +183,28 @@ fun CreatePollView(
170183
iconSource = IconSource.Vector(Icons.Default.Add),
171184
),
172185
style = ListItemStyle.Primary,
173-
onClick = { state.eventSink(CreatePollEvents.AddAnswer) },
186+
onClick = {
187+
state.eventSink(CreatePollEvents.AddAnswer)
188+
coroutineScope.launch(Dispatchers.Main) {
189+
lazyListState.animateScrollToItem(state.answers.size + 1)
190+
answerFocusRequester.requestFocus()
191+
}
192+
},
174193
)
175194
}
176195
}
177196
item {
178-
HorizontalDivider()
179-
}
180-
item {
181-
ListItem(
182-
headlineContent = { Text(text = stringResource(id = R.string.screen_create_poll_anonymous_headline)) },
183-
supportingContent = { Text(text = stringResource(id = R.string.screen_create_poll_anonymous_desc)) },
184-
trailingContent = ListItemContent.Switch(
185-
checked = state.pollKind == PollKind.Undisclosed,
186-
onChange = { state.eventSink(CreatePollEvents.SetPollKind(if (it) PollKind.Undisclosed else PollKind.Disclosed)) },
187-
),
188-
)
197+
Column {
198+
HorizontalDivider()
199+
ListItem(
200+
headlineContent = { Text(text = stringResource(id = R.string.screen_create_poll_anonymous_headline)) },
201+
supportingContent = { Text(text = stringResource(id = R.string.screen_create_poll_anonymous_desc)) },
202+
trailingContent = ListItemContent.Switch(
203+
checked = state.pollKind == PollKind.Undisclosed,
204+
onChange = { state.eventSink(CreatePollEvents.SetPollKind(if (it) PollKind.Undisclosed else PollKind.Disclosed)) },
205+
),
206+
)
207+
}
189208
}
190209
}
191210
}

0 commit comments

Comments
 (0)