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".
This commit is contained in:
commit
1fdcdff4b8
1 changed files with 56 additions and 37 deletions
|
|
@ -18,6 +18,7 @@ package io.element.android.features.poll.impl.create
|
||||||
|
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
|
@ -25,6 +26,7 @@ import androidx.compose.foundation.layout.imePadding
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
|
|
@ -32,6 +34,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
|
|
@ -61,6 +64,8 @@ import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||||
import io.element.android.libraries.matrix.api.poll.PollKind
|
import io.element.android.libraries.matrix.api.poll.PollKind
|
||||||
import io.element.android.libraries.theme.ElementTheme
|
import io.element.android.libraries.theme.ElementTheme
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -68,6 +73,8 @@ fun CreatePollView(
|
||||||
state: CreatePollState,
|
state: CreatePollState,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
val navBack = { state.eventSink(CreatePollEvents.ConfirmNavBack) }
|
val navBack = { state.eventSink(CreatePollEvents.ConfirmNavBack) }
|
||||||
BackHandler(onBack = navBack)
|
BackHandler(onBack = navBack)
|
||||||
if (state.showConfirmation) ConfirmationDialog(
|
if (state.showConfirmation) ConfirmationDialog(
|
||||||
|
|
@ -76,6 +83,7 @@ fun CreatePollView(
|
||||||
onDismiss = { state.eventSink(CreatePollEvents.HideConfirmation) }
|
onDismiss = { state.eventSink(CreatePollEvents.HideConfirmation) }
|
||||||
)
|
)
|
||||||
val questionFocusRequester = remember { FocusRequester() }
|
val questionFocusRequester = remember { FocusRequester() }
|
||||||
|
val answerFocusRequester = remember { FocusRequester() }
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
questionFocusRequester.requestFocus()
|
questionFocusRequester.requestFocus()
|
||||||
}
|
}
|
||||||
|
|
@ -102,40 +110,43 @@ fun CreatePollView(
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
|
val lazyListState = rememberLazyListState()
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(paddingValues)
|
.padding(paddingValues)
|
||||||
.consumeWindowInsets(paddingValues)
|
.consumeWindowInsets(paddingValues)
|
||||||
.imePadding()
|
.imePadding()
|
||||||
.fillMaxSize(),
|
.fillMaxSize(),
|
||||||
|
state = lazyListState,
|
||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
Text(
|
Column {
|
||||||
text = stringResource(id = R.string.screen_create_poll_question_desc),
|
Text(
|
||||||
modifier = Modifier.padding(start = 32.dp),
|
text = stringResource(id = R.string.screen_create_poll_question_desc),
|
||||||
style = ElementTheme.typography.fontBodyMdRegular,
|
modifier = Modifier.padding(start = 32.dp),
|
||||||
)
|
style = ElementTheme.typography.fontBodyMdRegular,
|
||||||
}
|
)
|
||||||
item {
|
ListItem(
|
||||||
ListItem(
|
headlineContent = {
|
||||||
headlineContent = {
|
OutlinedTextField(
|
||||||
OutlinedTextField(
|
value = state.question,
|
||||||
value = state.question,
|
onValueChange = {
|
||||||
onValueChange = {
|
state.eventSink(CreatePollEvents.SetQuestion(it))
|
||||||
state.eventSink(CreatePollEvents.SetQuestion(it))
|
},
|
||||||
},
|
modifier = Modifier
|
||||||
modifier = Modifier
|
.focusRequester(questionFocusRequester)
|
||||||
.focusRequester(questionFocusRequester)
|
.fillMaxWidth(),
|
||||||
.fillMaxWidth(),
|
placeholder = {
|
||||||
placeholder = {
|
Text(text = stringResource(id = R.string.screen_create_poll_question_hint))
|
||||||
Text(text = stringResource(id = R.string.screen_create_poll_question_hint))
|
},
|
||||||
},
|
keyboardOptions = keyboardOptions,
|
||||||
keyboardOptions = keyboardOptions,
|
)
|
||||||
)
|
}
|
||||||
}
|
)
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
itemsIndexed(state.answers) { index, answer ->
|
itemsIndexed(state.answers) { index, answer ->
|
||||||
|
val isLastItem = index == state.answers.size - 1
|
||||||
ListItem(
|
ListItem(
|
||||||
headlineContent = {
|
headlineContent = {
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
|
@ -143,7 +154,9 @@ fun CreatePollView(
|
||||||
onValueChange = {
|
onValueChange = {
|
||||||
state.eventSink(CreatePollEvents.SetAnswer(index, it))
|
state.eventSink(CreatePollEvents.SetAnswer(index, it))
|
||||||
},
|
},
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier
|
||||||
|
.then(if (isLastItem) Modifier.focusRequester(answerFocusRequester) else Modifier)
|
||||||
|
.fillMaxWidth(),
|
||||||
placeholder = {
|
placeholder = {
|
||||||
Text(text = stringResource(id = R.string.screen_create_poll_answer_hint, index + 1))
|
Text(text = stringResource(id = R.string.screen_create_poll_answer_hint, index + 1))
|
||||||
},
|
},
|
||||||
|
|
@ -170,22 +183,28 @@ fun CreatePollView(
|
||||||
iconSource = IconSource.Vector(Icons.Default.Add),
|
iconSource = IconSource.Vector(Icons.Default.Add),
|
||||||
),
|
),
|
||||||
style = ListItemStyle.Primary,
|
style = ListItemStyle.Primary,
|
||||||
onClick = { state.eventSink(CreatePollEvents.AddAnswer) },
|
onClick = {
|
||||||
|
state.eventSink(CreatePollEvents.AddAnswer)
|
||||||
|
coroutineScope.launch(Dispatchers.Main) {
|
||||||
|
lazyListState.animateScrollToItem(state.answers.size + 1)
|
||||||
|
answerFocusRequester.requestFocus()
|
||||||
|
}
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
HorizontalDivider()
|
Column {
|
||||||
}
|
HorizontalDivider()
|
||||||
item {
|
ListItem(
|
||||||
ListItem(
|
headlineContent = { Text(text = stringResource(id = R.string.screen_create_poll_anonymous_headline)) },
|
||||||
headlineContent = { Text(text = stringResource(id = R.string.screen_create_poll_anonymous_headline)) },
|
supportingContent = { Text(text = stringResource(id = R.string.screen_create_poll_anonymous_desc)) },
|
||||||
supportingContent = { Text(text = stringResource(id = R.string.screen_create_poll_anonymous_desc)) },
|
trailingContent = ListItemContent.Switch(
|
||||||
trailingContent = ListItemContent.Switch(
|
checked = state.pollKind == PollKind.Undisclosed,
|
||||||
checked = state.pollKind == PollKind.Undisclosed,
|
onChange = { state.eventSink(CreatePollEvents.SetPollKind(if (it) PollKind.Undisclosed else PollKind.Disclosed)) },
|
||||||
onChange = { state.eventSink(CreatePollEvents.SetPollKind(if (it) PollKind.Undisclosed else PollKind.Disclosed)) },
|
),
|
||||||
),
|
)
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue