From 55f51a01a089aec7cd3a7210a36b456af5646466 Mon Sep 17 00:00:00 2001 From: Marco Romano Date: Wed, 13 Sep 2023 10:25:30 +0200 Subject: [PATCH 1/3] Improve ListItem logical item grouping --- .../poll/impl/create/CreatePollView.kt | 71 ++++++++++--------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollView.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollView.kt index 8e3de07574..e69d23fd32 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollView.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollView.kt @@ -18,6 +18,7 @@ package io.element.android.features.poll.impl.create import androidx.activity.compose.BackHandler import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -110,30 +111,30 @@ fun CreatePollView( .fillMaxSize(), ) { item { - Text( - text = stringResource(id = R.string.screen_create_poll_question_desc), - modifier = Modifier.padding(start = 32.dp), - style = ElementTheme.typography.fontBodyMdRegular, - ) - } - item { - ListItem( - headlineContent = { - OutlinedTextField( - value = state.question, - onValueChange = { - state.eventSink(CreatePollEvents.SetQuestion(it)) - }, - modifier = Modifier - .focusRequester(questionFocusRequester) - .fillMaxWidth(), - placeholder = { - Text(text = stringResource(id = R.string.screen_create_poll_question_hint)) - }, - keyboardOptions = keyboardOptions, - ) - } - ) + Column { + Text( + text = stringResource(id = R.string.screen_create_poll_question_desc), + modifier = Modifier.padding(start = 32.dp), + style = ElementTheme.typography.fontBodyMdRegular, + ) + ListItem( + headlineContent = { + OutlinedTextField( + value = state.question, + onValueChange = { + state.eventSink(CreatePollEvents.SetQuestion(it)) + }, + modifier = Modifier + .focusRequester(questionFocusRequester) + .fillMaxWidth(), + placeholder = { + Text(text = stringResource(id = R.string.screen_create_poll_question_hint)) + }, + keyboardOptions = keyboardOptions, + ) + } + ) + } } itemsIndexed(state.answers) { index, answer -> ListItem( @@ -175,17 +176,17 @@ fun CreatePollView( } } item { - HorizontalDivider() - } - item { - ListItem( - headlineContent = { Text(text = stringResource(id = R.string.screen_create_poll_anonymous_headline)) }, - supportingContent = { Text(text = stringResource(id = R.string.screen_create_poll_anonymous_desc)) }, - trailingContent = ListItemContent.Switch( - checked = state.pollKind == PollKind.Undisclosed, - onChange = { state.eventSink(CreatePollEvents.SetPollKind(if (it) PollKind.Undisclosed else PollKind.Disclosed)) }, - ), - ) + Column { + HorizontalDivider() + ListItem( + headlineContent = { Text(text = stringResource(id = R.string.screen_create_poll_anonymous_headline)) }, + supportingContent = { Text(text = stringResource(id = R.string.screen_create_poll_anonymous_desc)) }, + trailingContent = ListItemContent.Switch( + checked = state.pollKind == PollKind.Undisclosed, + onChange = { state.eventSink(CreatePollEvents.SetPollKind(if (it) PollKind.Undisclosed else PollKind.Disclosed)) }, + ), + ) + } } } } From 1144cee572455626a4cf883983403084d4bc77f5 Mon Sep 17 00:00:00 2001 From: Marco Romano Date: Wed, 13 Sep 2023 11:02:25 +0200 Subject: [PATCH 2/3] Poll Creation: Switch focus to newly added option field when clicking "Add option". - Also scrolls the list to make the "Add option" button visible for further additions. --- .../features/poll/impl/create/CreatePollView.kt | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollView.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollView.kt index e69d23fd32..462ff4e48a 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollView.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollView.kt @@ -26,6 +26,7 @@ import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add @@ -77,6 +78,7 @@ fun CreatePollView( onDismiss = { state.eventSink(CreatePollEvents.HideConfirmation) } ) val questionFocusRequester = remember { FocusRequester() } + val answerFocusRequester = remember { FocusRequester() } LaunchedEffect(Unit) { questionFocusRequester.requestFocus() } @@ -103,12 +105,14 @@ fun CreatePollView( ) }, ) { paddingValues -> + val lazyListState = rememberLazyListState() LazyColumn( modifier = Modifier .padding(paddingValues) .consumeWindowInsets(paddingValues) .imePadding() .fillMaxSize(), + state = lazyListState, ) { item { Column { @@ -137,6 +141,8 @@ fun CreatePollView( } } itemsIndexed(state.answers) { index, answer -> + val isLastItem = index == state.answers.size - 1 + val hasAdditionalOptions = state.answers.size > 2 ListItem( headlineContent = { OutlinedTextField( @@ -144,7 +150,9 @@ fun CreatePollView( onValueChange = { state.eventSink(CreatePollEvents.SetAnswer(index, it)) }, - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .then(if (isLastItem) Modifier.focusRequester(answerFocusRequester) else Modifier) + .fillMaxWidth(), placeholder = { Text(text = stringResource(id = R.string.screen_create_poll_answer_hint, index + 1)) }, @@ -162,6 +170,10 @@ fun CreatePollView( }, style = if (answer.canDelete) ListItemStyle.Destructive else ListItemStyle.Default, ) + LaunchedEffect(isLastItem, hasAdditionalOptions) { + lazyListState.animateScrollToItem(state.answers.size + 1) + if (isLastItem && hasAdditionalOptions) answerFocusRequester.requestFocus() + } } if (state.canAddAnswer) { item { From dfdd8e59f7c1205982011e4eb2675b3f9cff605f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADn?= Date: Wed, 13 Sep 2023 16:35:32 +0200 Subject: [PATCH 3/3] Request focus after adding an answer --- .../poll/impl/create/CreatePollView.kt | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollView.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollView.kt index 462ff4e48a..0355b34375 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollView.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollView.kt @@ -34,6 +34,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester @@ -63,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.theme.ElementTheme import io.element.android.libraries.ui.strings.CommonStrings +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -70,6 +73,8 @@ fun CreatePollView( state: CreatePollState, modifier: Modifier = Modifier, ) { + val coroutineScope = rememberCoroutineScope() + val navBack = { state.eventSink(CreatePollEvents.ConfirmNavBack) } BackHandler(onBack = navBack) if (state.showConfirmation) ConfirmationDialog( @@ -142,7 +147,6 @@ fun CreatePollView( } itemsIndexed(state.answers) { index, answer -> val isLastItem = index == state.answers.size - 1 - val hasAdditionalOptions = state.answers.size > 2 ListItem( headlineContent = { OutlinedTextField( @@ -170,10 +174,6 @@ fun CreatePollView( }, style = if (answer.canDelete) ListItemStyle.Destructive else ListItemStyle.Default, ) - LaunchedEffect(isLastItem, hasAdditionalOptions) { - lazyListState.animateScrollToItem(state.answers.size + 1) - if (isLastItem && hasAdditionalOptions) answerFocusRequester.requestFocus() - } } if (state.canAddAnswer) { item { @@ -183,7 +183,13 @@ fun CreatePollView( iconSource = IconSource.Vector(Icons.Default.Add), ), 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() + } + }, ) } }