diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt index 2444c7d0ba..dda04dd574 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt @@ -677,18 +677,19 @@ fun ChatLayout( ) } } + val oneHandUI = remember { appPrefs.oneHandUI.state } Box(Modifier .layoutId(CHAT_COMPOSE_LAYOUT_ID) .align(Alignment.BottomCenter) .imePadding() - .navigationBarsPadding() + .then(if (oneHandUI.value) Modifier.padding(bottom = AppBarHeight * fontSizeSqrtMultiplier) else Modifier.navigationBarsPadding()) ) { composeView() } } val oneHandUI = remember { appPrefs.oneHandUI.state } NavigationBarBackground(true, oneHandUI.value) - Column { + Box(if (oneHandUI.value) Modifier.align(Alignment.BottomStart).navigationBarsPadding() else Modifier) { if (selectedChatItems.value == null) { if (chatInfo != null) { ChatInfoToolbar(chatInfo, back, info, startCall, endCall, addMembers, openGroupLink, changeNtfsState, onSearchValueChanged, showSearch) @@ -703,7 +704,7 @@ fun ChatLayout( } @Composable -fun ColumnScope.ChatInfoToolbar( +fun BoxScope.ChatInfoToolbar( chatInfo: ChatInfo, back: () -> Unit, info: () -> Unit, @@ -855,13 +856,13 @@ fun ColumnScope.ChatInfoToolbar( } } } - + val oneHandUI = remember { appPrefs.oneHandUI.state } DefaultTopAppBar( navigationButton = { if (appPlatform.isAndroid || showSearch.value) { NavigationButtonBack(onBackClicked) } }, title = { ChatInfoToolbarTitle(chatInfo) }, onTitleClick = if (chatInfo is ChatInfo.Local) null else info, showSearch = showSearch.value, - onTop = true, + onTop = oneHandUI.value, onSearchValueChanged = onSearchValueChanged, buttons = barButtons ) @@ -871,12 +872,12 @@ fun ColumnScope.ChatInfoToolbar( DefaultDropdownMenu( showMenu, modifier = Modifier.onSizeChanged { with(density) { width.value = it.width.toDp().coerceAtLeast(250.dp) } }, - offset = DpOffset(-width.value, 0.dp) + offset = DpOffset(-width.value, AppBarHeight) ) { menuItems.forEach { it() } } } - Divider(Modifier.background(MaterialTheme.colors.background)) + Divider(Modifier.background(MaterialTheme.colors.background).align(if (oneHandUI.value) Alignment.TopStart else Alignment.BottomStart)) } @Composable @@ -1479,7 +1480,14 @@ private fun TopEndFloatingButton( } @Composable -fun topPaddingToContent(): Dp = AppBarHeight * fontSizeSqrtMultiplier + WindowInsets.statusBars.asPaddingValues().calculateTopPadding() +fun topPaddingToContent(): Dp { + val oneHandUI = remember { appPrefs.oneHandUI.state } + return if (oneHandUI.value) { + WindowInsets.statusBars.asPaddingValues().calculateTopPadding() + } else { + AppBarHeight * fontSizeSqrtMultiplier + WindowInsets.statusBars.asPaddingValues().calculateTopPadding() + } +} @Composable private fun FloatingDate( diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SelectableChatItemToolbars.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SelectableChatItemToolbars.kt index 501def5fc1..6c421e7e04 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SelectableChatItemToolbars.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SelectableChatItemToolbars.kt @@ -12,6 +12,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import chat.simplex.common.model.* +import chat.simplex.common.model.ChatController.appPrefs import chat.simplex.common.platform.BackHandler import chat.simplex.common.platform.chatModel import chat.simplex.common.views.helpers.* @@ -20,10 +21,11 @@ import chat.simplex.res.MR import dev.icerock.moko.resources.compose.painterResource @Composable -fun ColumnScope.SelectedItemsTopToolbar(selectedChatItems: MutableState?>) { +fun BoxScope.SelectedItemsTopToolbar(selectedChatItems: MutableState?>) { val onBackClicked = { selectedChatItems.value = null } BackHandler(onBack = onBackClicked) val count = selectedChatItems.value?.size ?: 0 + val oneHandUI = remember { appPrefs.oneHandUI.state } DefaultTopAppBar( navigationButton = { NavigationButtonClose(onButtonClicked = onBackClicked) }, title = { @@ -40,10 +42,10 @@ fun ColumnScope.SelectedItemsTopToolbar(selectedChatItems: MutableState, searchShowingSimplexLink: MutableState, searchChatFilteredBySimplexLink: MutableState) { - Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) { - val focusRequester = remember { FocusRequester() } - var focused by remember { mutableStateOf(false) } - Icon( - painterResource(MR.images.ic_search), - contentDescription = null, - Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING_HALF).size(22.dp * fontSizeSqrtMultiplier), - tint = MaterialTheme.colors.secondary - ) - SearchTextField( - Modifier.weight(1f).onFocusChanged { focused = it.hasFocus }.focusRequester(focusRequester), - placeholder = stringResource(MR.strings.search_or_paste_simplex_link), - alwaysVisible = true, - searchText = searchText, - enabled = !remember { searchShowingSimplexLink }.value, - trailingContent = null, - ) { - searchText.value = searchText.value.copy(it) - } - val hasText = remember { derivedStateOf { searchText.value.text.isNotEmpty() } } - if (hasText.value) { - val hideSearchOnBack: () -> Unit = { searchText.value = TextFieldValue() } - BackHandler(onBack = hideSearchOnBack) - KeyChangeEffect(chatModel.currentRemoteHost.value) { - hideSearchOnBack() + Box { + Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth().heightIn(min = AppBarHeight * fontSizeSqrtMultiplier)) { + val focusRequester = remember { FocusRequester() } + var focused by remember { mutableStateOf(false) } + Icon( + painterResource(MR.images.ic_search), + contentDescription = null, + Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING_HALF).size(22.dp * fontSizeSqrtMultiplier), + tint = MaterialTheme.colors.secondary + ) + SearchTextField( + Modifier.weight(1f).onFocusChanged { focused = it.hasFocus }.focusRequester(focusRequester), + placeholder = stringResource(MR.strings.search_or_paste_simplex_link), + alwaysVisible = true, + searchText = searchText, + enabled = !remember { searchShowingSimplexLink }.value, + trailingContent = null, + ) { + searchText.value = searchText.value.copy(it) } - } else { - val padding = if (appPlatform.isDesktop) 0.dp else 7.dp - if (chatModel.chats.value.isNotEmpty()) { - ToggleFilterEnabledButton() - } - Spacer(Modifier.width(padding)) - } - val focusManager = LocalFocusManager.current - val keyboardState = getKeyboardState() - LaunchedEffect(keyboardState.value) { - if (keyboardState.value == KeyboardState.Closed && focused) { - focusManager.clearFocus() - } - } - val view = LocalMultiplatformView() - LaunchedEffect(Unit) { - snapshotFlow { searchText.value.text } - .distinctUntilChanged() - .collect { - val link = strHasSingleSimplexLink(it.trim()) - if (link != null) { - // if SimpleX link is pasted, show connection dialogue - hideKeyboard(view) - if (link.format is Format.SimplexLink) { - val linkText = link.simplexLinkText(link.format.linkType, link.format.smpHosts) - searchText.value = searchText.value.copy(linkText, selection = TextRange.Zero) - } - searchShowingSimplexLink.value = true - searchChatFilteredBySimplexLink.value = null - connect(link.text, searchChatFilteredBySimplexLink) { searchText.value = TextFieldValue() } - } else if (!searchShowingSimplexLink.value || it.isEmpty()) { - if (it.isNotEmpty()) { - // if some other text is pasted, enter search mode - focusRequester.requestFocus() - } else if (listState.layoutInfo.totalItemsCount > 0) { - listState.scrollToItem(0) - } - searchShowingSimplexLink.value = false - searchChatFilteredBySimplexLink.value = null - } + val hasText = remember { derivedStateOf { searchText.value.text.isNotEmpty() } } + if (hasText.value) { + val hideSearchOnBack: () -> Unit = { searchText.value = TextFieldValue() } + BackHandler(onBack = hideSearchOnBack) + KeyChangeEffect(chatModel.currentRemoteHost.value) { + hideSearchOnBack() } + } else { + val padding = if (appPlatform.isDesktop) 0.dp else 7.dp + if (chatModel.chats.value.isNotEmpty()) { + ToggleFilterEnabledButton() + } + Spacer(Modifier.width(padding)) + } + val focusManager = LocalFocusManager.current + val keyboardState = getKeyboardState() + LaunchedEffect(keyboardState.value) { + if (keyboardState.value == KeyboardState.Closed && focused) { + focusManager.clearFocus() + } + } + val view = LocalMultiplatformView() + LaunchedEffect(Unit) { + snapshotFlow { searchText.value.text } + .distinctUntilChanged() + .collect { + val link = strHasSingleSimplexLink(it.trim()) + if (link != null) { + // if SimpleX link is pasted, show connection dialogue + hideKeyboard(view) + if (link.format is Format.SimplexLink) { + val linkText = link.simplexLinkText(link.format.linkType, link.format.smpHosts) + searchText.value = searchText.value.copy(linkText, selection = TextRange.Zero) + } + searchShowingSimplexLink.value = true + searchChatFilteredBySimplexLink.value = null + connect(link.text, searchChatFilteredBySimplexLink) { searchText.value = TextFieldValue() } + } else if (!searchShowingSimplexLink.value || it.isEmpty()) { + if (it.isNotEmpty()) { + // if some other text is pasted, enter search mode + focusRequester.requestFocus() + } else if (listState.layoutInfo.totalItemsCount > 0) { + listState.scrollToItem(0) + } + searchShowingSimplexLink.value = false + searchChatFilteredBySimplexLink.value = null + } + } + } } + val oneHandUI = remember { appPrefs.oneHandUI.state } + Divider(Modifier.align(if (oneHandUI.value) Alignment.TopStart else Alignment.BottomStart)) } } @@ -685,14 +689,12 @@ private fun BoxScope.ChatList(searchText: MutableState) { .background(MaterialTheme.colors.background) ) { if (oneHandUI.value) { - Divider() Column(Modifier.consumeWindowInsets(WindowInsets.navigationBars).consumeWindowInsets(PaddingValues(bottom = AppBarHeight))) { ChatListSearchBar(listState, searchText, searchShowingSimplexLink, searchChatFilteredBySimplexLink) Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime)) } } else { ChatListSearchBar(listState, searchText, searchShowingSimplexLink, searchChatFilteredBySimplexLink) - Divider() } } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CloseSheetBar.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CloseSheetBar.kt index 1dbc543f97..92d2d7dd8e 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CloseSheetBar.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CloseSheetBar.kt @@ -40,7 +40,7 @@ fun CloseSheetBar( val interactionSource = remember { MutableInteractionSource() } val oneHandUI = remember { appPrefs.oneHandUI.state } - Column( + Box( modifier = Modifier .fillMaxWidth() .then(if (oneHandUI.value) Modifier.navigationBarsPadding() else Modifier) @@ -53,9 +53,6 @@ fun CloseSheetBar( } } ) { - if (oneHandUI.value && title.value.isNotEmpty()) { - CloseBarDivider(connection) - } Row( modifier = Modifier.padding(barPaddingValues), content = { @@ -96,19 +93,18 @@ fun CloseSheetBar( } } ) - if (!oneHandUI.value && title.value.isNotEmpty()) { - CloseBarDivider(connection) - } + CloseBarDivider(connection) } } @Composable -private fun CloseBarDivider(connection: CollapsingAppBarNestedScrollConnection?) { +private fun BoxScope.CloseBarDivider(connection: CollapsingAppBarNestedScrollConnection?) { if (connection != null) { val oneHandUI = remember { appPrefs.oneHandUI.state } val prefAlpha = appPrefs.inAppBarsAlpha.get() Divider( Modifier + .align(if (oneHandUI.value) Alignment.TopStart else Alignment.BottomStart) .graphicsLayer { alpha = if (oneHandUI.value) prefAlpha else topTitleAlpha(false, connection) } @@ -127,42 +123,39 @@ fun CloseSheetBarBottom( val background = MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, 0.97f) val themeBackgroundMix = background.copy(remember { appPrefs.inAppBarsAlpha.state }.value) val interactionSource = remember { MutableInteractionSource() } - Column( + Box( modifier = Modifier .fillMaxWidth() .navigationBarsPadding() .clickable(interactionSource = interactionSource, indication = null) { /* receive clicks to not allow to click through */ } - .heightIn(min = AppBarHeight * fontSizeSqrtMultiplier) .background(themeBackgroundMix) ) { Row( - content = { - Row( - Modifier - .fillMaxWidth() - .height(AppBarHeight * fontSizeSqrtMultiplier), - verticalAlignment = Alignment.CenterVertically - ) { - if (showClose) { - NavigationButtonBack(tintColor = tintColor, onButtonClicked = close) - } - Row( - Modifier.weight(1f), - horizontalArrangement = Arrangement.Center, - verticalAlignment = Alignment.CenterVertically - ) { - Text( - closeBarTitle, - fontWeight = FontWeight.SemiBold, - maxLines = 1 - ) - } - Row { - endButtons() - } - } + Modifier + .fillMaxWidth() + .height(AppBarHeight * fontSizeSqrtMultiplier), + verticalAlignment = Alignment.CenterVertically + ) { + if (showClose) { + NavigationButtonBack(tintColor = tintColor, onButtonClicked = close) } - ) + Row( + Modifier.weight(1f), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + closeBarTitle, + fontWeight = FontWeight.SemiBold, + maxLines = 1 + ) + } + Row { + endButtons() + } + } + val oneHandUI = remember { appPrefs.oneHandUI.state } + Divider(Modifier.align(if (oneHandUI.value) Alignment.TopStart else Alignment.BottomStart)) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt index 98127cf2a7..546f089ed0 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt @@ -62,11 +62,9 @@ fun ModalData.NewChatSheet(rh: RemoteHostInfo?, close: () -> Unit) { } if (oneHandUI.value) { Column(Modifier.align(Alignment.BottomCenter)) { - Divider() CloseSheetBarBottom( close = close, showClose = true, - endButtons = { Spacer(Modifier.minimumInteractiveComponentSize()) }, closeBarTitle = generalGetString(MR.strings.new_message) ) } @@ -726,11 +724,9 @@ private fun ModalData.DeletedContactsView(rh: RemoteHostInfo?, closeDeletedChats } if (oneHandUI.value) { Column(Modifier.align(Alignment.BottomCenter)) { - Divider() CloseSheetBarBottom( close = closeDeletedChats, showClose = true, - endButtons = { Spacer(Modifier.minimumInteractiveComponentSize()) }, closeBarTitle = generalGetString(MR.strings.deleted_chats), ) } diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/ScrollableColumn.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/ScrollableColumn.desktop.kt index 890a82b42e..71e4adaaa8 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/ScrollableColumn.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/ScrollableColumn.desktop.kt @@ -101,12 +101,13 @@ private fun ScrollBar( scrollBarDraggingState: MutableState, additionalBarHeight: State? ) { + val oneHandUI = remember { appPrefs.oneHandUI.state } val padding = if (additionalBarHeight != null) { - PaddingValues(top = AppBarHeight * fontSizeSqrtMultiplier, bottom = additionalBarHeight.value) + PaddingValues(top = if (oneHandUI.value) 0.dp else AppBarHeight * fontSizeSqrtMultiplier, bottom = additionalBarHeight.value) } else if (reverseLayout) { PaddingValues(bottom = AppBarHeight * fontSizeSqrtMultiplier) } else { - PaddingValues(top = AppBarHeight * fontSizeSqrtMultiplier) + PaddingValues(top = if (oneHandUI.value) 0.dp else AppBarHeight * fontSizeSqrtMultiplier) } Box(Modifier.fillMaxSize().padding(padding), contentAlignment = Alignment.CenterEnd) { DesktopScrollBar(rememberScrollbarAdapter(state), Modifier.fillMaxHeight(), scrollBarAlpha, scrollJob, reverseLayout, scrollBarDraggingState)