From 601b081cabc991b76a62a96ac0fd506ee50ba551 Mon Sep 17 00:00:00 2001 From: Diogo Date: Tue, 6 Aug 2024 18:27:57 +0100 Subject: [PATCH] android: one hand UI fixes and improvements (#4597) * fix bottom toolbar in share one hand ui * rename one hand ui label to reachable chat toolbar * one hand ui to be android default * dumb if remove * make one hand ui always false when outside android * override set of one hand ui for imports on desktop * no need to override current * always default one hand to true * one hand ui without using mirrors * remove unused vars * added space on multiplication * clean subscription to prop and param spread --------- Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> --- .../chatlist/ChatListNavLinkView.android.kt | 6 - .../chat/simplex/common/model/SimpleXAPI.kt | 6 +- .../views/chatlist/ChatListNavLinkView.kt | 12 +- .../common/views/chatlist/ChatListView.kt | 86 ++++++-------- .../views/chatlist/ShareListNavLinkView.kt | 20 +--- .../common/views/chatlist/ShareListView.kt | 52 ++++----- .../views/contacts/ContactListNavView.kt | 7 +- .../common/views/newchat/NewChatSheet.kt | 110 ++++++++++-------- .../commonMain/resources/MR/base/strings.xml | 2 +- .../chatlist/ChatListNavLinkView.desktop.kt | 1 - 10 files changed, 134 insertions(+), 168 deletions(-) diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.android.kt index 1b9e80b8a0..9a3d9e5e4f 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.android.kt @@ -6,7 +6,6 @@ import androidx.compose.material.Divider import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.scale import androidx.compose.ui.unit.dp import chat.simplex.common.platform.onRightClick import chat.simplex.common.views.helpers.* @@ -20,14 +19,9 @@ actual fun ChatListNavLinkLayout( disabled: Boolean, selectedChat: State, nextChatSelected: State, - oneHandUI: State ) { var modifier = Modifier.fillMaxWidth() - if (oneHandUI != null && oneHandUI.value) { - modifier = modifier.scale(scaleX = 1f, scaleY = -1f) - } - if (!disabled) modifier = modifier .combinedClickable(onClick = click, onLongClick = { showMenu.value = true }) .onRightClick { showMenu.value = true } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt index 3d66fea485..4f193bebd2 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt @@ -225,7 +225,7 @@ class AppPreferences { val iosCallKitEnabled = mkBoolPreference(SHARED_PREFS_IOS_CALL_KIT_ENABLED, true) val iosCallKitCallsInRecents = mkBoolPreference(SHARED_PREFS_IOS_CALL_KIT_CALLS_IN_RECENTS, false) - val oneHandUI = mkBoolPreference(SHARED_PREFS_ONE_HAND_UI, false) + val oneHandUI = mkBoolPreference(SHARED_PREFS_ONE_HAND_UI, appPlatform.isAndroid) private fun mkIntPreference(prefName: String, default: Int) = SharedPreference( @@ -6221,7 +6221,7 @@ data class AppSettings( uiDarkColorScheme?.let { def.systemDarkTheme.set(it) } uiCurrentThemeIds?.let { def.currentThemeIds.set(it) } uiThemes?.let { def.themeOverrides.set(it.skipDuplicates()) } - oneHandUI?.let { def.oneHandUI.set(it) } + oneHandUI?.let { def.oneHandUI.set(if (appPlatform.isAndroid) it else false) } } companion object { @@ -6253,7 +6253,7 @@ data class AppSettings( uiDarkColorScheme = DefaultTheme.SIMPLEX.themeName, uiCurrentThemeIds = null, uiThemes = null, - oneHandUI = false + oneHandUI = true ) val current: AppSettings diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt index 39c8866747..e39adcca3b 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt @@ -35,7 +35,7 @@ import kotlinx.coroutines.* import kotlinx.datetime.Clock @Composable -fun ChatListNavLinkView(chat: Chat, nextChatSelected: State, oneHandUI: State) { +fun ChatListNavLinkView(chat: Chat, nextChatSelected: State) { val showMenu = remember { mutableStateOf(false) } val showMarkRead = remember(chat.chatStats.unreadCount, chat.chatStats.unreadChat) { chat.chatStats.unreadCount > 0 || chat.chatStats.unreadChat @@ -81,7 +81,6 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State, oneHandUI: disabled, selectedChat, nextChatSelected, - oneHandUI ) } is ChatInfo.Group -> @@ -101,7 +100,6 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State, oneHandUI: disabled, selectedChat, nextChatSelected, - oneHandUI ) is ChatInfo.Local -> { ChatListNavLinkLayout( @@ -120,7 +118,6 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State, oneHandUI: disabled, selectedChat, nextChatSelected, - oneHandUI ) } is ChatInfo.ContactRequest -> @@ -140,7 +137,6 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State, oneHandUI: disabled, selectedChat, nextChatSelected, - oneHandUI ) is ChatInfo.ContactConnection -> ChatListNavLinkLayout( @@ -161,7 +157,6 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State, oneHandUI: disabled, selectedChat, nextChatSelected, - oneHandUI ) is ChatInfo.InvalidJSON -> ChatListNavLinkLayout( @@ -178,7 +173,6 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State, oneHandUI: disabled, selectedChat, nextChatSelected, - oneHandUI ) } } @@ -879,7 +873,6 @@ expect fun ChatListNavLinkLayout( disabled: Boolean, selectedChat: State, nextChatSelected: State, - oneHandUI: State ) @Preview/*( @@ -923,7 +916,6 @@ fun PreviewChatListNavLinkDirect() { disabled = false, selectedChat = remember { mutableStateOf(false) }, nextChatSelected = remember { mutableStateOf(false) }, - oneHandUI = remember { mutableStateOf(false) } ) } } @@ -969,7 +961,6 @@ fun PreviewChatListNavLinkGroup() { disabled = false, selectedChat = remember { mutableStateOf(false) }, nextChatSelected = remember { mutableStateOf(false) }, - oneHandUI = remember { mutableStateOf(false) } ) } } @@ -992,7 +983,6 @@ fun PreviewChatListNavLinkContactRequest() { disabled = false, selectedChat = remember { mutableStateOf(false) }, nextChatSelected = remember { mutableStateOf(false) }, - oneHandUI = remember { mutableStateOf(false) } ) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt index 1a6ce3ce00..207f8a4b26 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt @@ -12,7 +12,6 @@ import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.scale import androidx.compose.ui.focus.* import androidx.compose.ui.graphics.* import androidx.compose.ui.text.font.FontStyle @@ -25,6 +24,7 @@ import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.unit.* import chat.simplex.common.SettingsViewState import chat.simplex.common.model.* +import chat.simplex.common.model.ChatController.appPrefs import chat.simplex.common.model.ChatController.stopRemoteHostAndReloadHosts import chat.simplex.common.ui.theme.* import chat.simplex.common.views.helpers.* @@ -72,7 +72,7 @@ private fun showNewChatSheet(oneHandUI: State) { @Composable fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerformLA: (Boolean) -> Unit, stopped: Boolean) { - val oneHandUI = remember { chatModel.controller.appPrefs.oneHandUI } + val oneHandUI = remember { appPrefs.oneHandUI.state } LaunchedEffect(Unit) { if (shouldShowWhatsNew(chatModel)) { @@ -96,27 +96,25 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf val (userPickerState, scaffoldState ) = settingsState Scaffold( topBar = { - if (!oneHandUI.state.value) { + if (!oneHandUI.value) { Column(Modifier.padding(end = endPadding)) { ChatListToolbar( scaffoldState.drawerState, userPickerState, stopped, - oneHandUI ) Divider() } } }, bottomBar = { - if (oneHandUI.state.value) { + if (oneHandUI.value) { Column(Modifier.padding(end = endPadding)) { Divider() ChatListToolbar( scaffoldState.drawerState, userPickerState, stopped, - oneHandUI ) } } @@ -132,11 +130,11 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf drawerScrimColor = MaterialTheme.colors.onSurface.copy(alpha = if (isInDarkTheme()) 0.16f else 0.32f), drawerGesturesEnabled = appPlatform.isAndroid, floatingActionButton = { - if (!oneHandUI.state.value && searchText.value.text.isEmpty() && !chatModel.desktopNoUserNoRemote && chatModel.chatRunning.value == true) { + if (!oneHandUI.value && searchText.value.text.isEmpty() && !chatModel.desktopNoUserNoRemote && chatModel.chatRunning.value == true) { FloatingActionButton( onClick = { if (!stopped) { - showNewChatSheet(oneHandUI.state) + showNewChatSheet(oneHandUI) } }, Modifier @@ -156,28 +154,17 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf } } ) { - var modifier = Modifier.padding(it).padding(end = endPadding) - if (oneHandUI.state.value) { - modifier = modifier.scale(scaleX = 1f, scaleY = -1f) - } - - Box(modifier) { + Box(Modifier.padding(it).padding(end = endPadding)) { Box( modifier = Modifier .fillMaxSize() ) { if (!chatModel.desktopNoUserNoRemote) { - ChatList(chatModel, searchText = searchText, oneHandUI = oneHandUI) + ChatList(chatModel, searchText = searchText) } if (chatModel.chats.value.isEmpty() && !chatModel.switchingUsersAndHosts.value && !chatModel.desktopNoUserNoRemote) { - var textModifier = Modifier.align(Alignment.Center) - - if (oneHandUI.state.value) { - textModifier = textModifier.scale(scaleX = 1f, scaleY = -1f) - } - Text(stringResource( - if (chatModel.chatRunning.value == null) MR.strings.loading_chats else MR.strings.you_have_no_chats), textModifier, color = MaterialTheme.colors.secondary) + if (chatModel.chatRunning.value == null) MR.strings.loading_chats else MR.strings.you_have_no_chats), Modifier.align(Alignment.Center), color = MaterialTheme.colors.secondary) } } } @@ -195,7 +182,7 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf UserPicker( chatModel = chatModel, userPickerState = userPickerState, - contentAlignment = if (oneHandUI.state.value) Alignment.BottomStart else Alignment.TopStart + contentAlignment = if (oneHandUI.value) Alignment.BottomStart else Alignment.TopStart ) { scope.launch { if (scaffoldState.drawerState.isOpen) scaffoldState.drawerState.close() else scaffoldState.drawerState.open() } userPickerState.value = AnimatedViewState.GONE @@ -221,19 +208,20 @@ private fun ConnectButton(text: String, onClick: () -> Unit) { } @Composable -private fun ChatListToolbar(drawerState: DrawerState, userPickerState: MutableStateFlow, stopped: Boolean, oneHandUI: SharedPreference) { +private fun ChatListToolbar(drawerState: DrawerState, userPickerState: MutableStateFlow, stopped: Boolean) { val serversSummary: MutableState = remember { mutableStateOf(null) } val barButtons = arrayListOf<@Composable RowScope.() -> Unit>() val updatingProgress = remember { chatModel.updatingProgress }.value + val oneHandUI = remember { appPrefs.oneHandUI.state } - if (oneHandUI.state.value) { + if (oneHandUI.value) { val sp16 = with(LocalDensity.current) { 16.sp.toDp() } if (!stopped) { barButtons.add { IconButton( onClick = { - showNewChatSheet(oneHandUI.state) + showNewChatSheet(oneHandUI) }, ) { Box( @@ -452,14 +440,8 @@ fun connectIfOpenedViaUri(rhId: Long?, uri: URI, chatModel: ChatModel) { } @Composable -private fun ChatListSearchBar(listState: LazyListState, searchText: MutableState, searchShowingSimplexLink: MutableState, searchChatFilteredBySimplexLink: MutableState, oneHandUI: SharedPreference) { - var modifier = Modifier.fillMaxWidth(); - - if (oneHandUI.state.value) { - modifier = modifier.scale(scaleX = 1f, scaleY = -1f) - } - - Row(verticalAlignment = Alignment.CenterVertically, modifier = modifier) { +private fun ChatListSearchBar(listState: LazyListState, searchText: MutableState, searchShowingSimplexLink: MutableState, searchChatFilteredBySimplexLink: MutableState) { + Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) { val focusRequester = remember { FocusRequester() } var focused by remember { mutableStateOf(false) } Icon( @@ -558,12 +540,13 @@ enum class ScrollDirection { } @Composable -private fun ChatList(chatModel: ChatModel, searchText: MutableState, oneHandUI: SharedPreference) { +private fun ChatList(chatModel: ChatModel, searchText: MutableState) { val listState = rememberLazyListState(lazyListState.first, lazyListState.second) var scrollDirection by remember { mutableStateOf(ScrollDirection.Idle) } var previousIndex by remember { mutableStateOf(0) } var previousScrollOffset by remember { mutableStateOf(0) } val keyboardState by getKeyboardState() + val oneHandUI = remember { appPrefs.oneHandUI.state } LaunchedEffect(listState.firstVisibleItemIndex, listState.firstVisibleItemScrollOffset) { val currentIndex = listState.firstVisibleItemIndex @@ -595,46 +578,47 @@ private fun ChatList(chatModel: ChatModel, searchText: MutableState(null) } val chats = filteredChats(showUnreadAndFavorites, searchShowingSimplexLink, searchChatFilteredBySimplexLink, searchText.value.text, allChats.value.toList()) LazyColumnWithScrollBar( - Modifier.fillMaxWidth(), - listState + Modifier.fillMaxSize(), + listState, + reverseLayout = oneHandUI.value ) { stickyHeader { Column( Modifier .offset { val y = if (searchText.value.text.isEmpty()) { + val offsetMultiplier = if (oneHandUI.value) 1 else -1 if ( - (oneHandUI.state.value && scrollDirection == ScrollDirection.Up) || + (oneHandUI.value && scrollDirection == ScrollDirection.Up) || (appPlatform.isAndroid && keyboardState == KeyboardState.Opened) ) { 0 - } else if (listState.firstVisibleItemIndex == 0) -listState.firstVisibleItemScrollOffset else -1000 + } else if (listState.firstVisibleItemIndex == 0) offsetMultiplier * listState.firstVisibleItemScrollOffset else offsetMultiplier * 1000 } else { 0 } IntOffset(0, y) } - .background(MaterialTheme.colors.background) - ) { - ChatListSearchBar(listState, searchText, searchShowingSimplexLink, searchChatFilteredBySimplexLink, oneHandUI) - Divider() + .background(MaterialTheme.colors.background), + ) { + if (oneHandUI.value) { + Divider() + } + ChatListSearchBar(listState, searchText, searchShowingSimplexLink, searchChatFilteredBySimplexLink) + if (!oneHandUI.value) { + Divider() + } } } itemsIndexed(chats, key = { _, chat -> chat.remoteHostId to chat.id }) { index, chat -> val nextChatSelected = remember(chat.id, chats) { derivedStateOf { chatModel.chatId.value != null && chats.getOrNull(index + 1)?.id == chatModel.chatId.value } } - ChatListNavLinkView(chat, nextChatSelected, oneHandUI.state) + ChatListNavLinkView(chat, nextChatSelected) } } if (chats.isEmpty() && chatModel.chats.value.isNotEmpty()) { - var modifier = Modifier.fillMaxSize(); - - if (oneHandUI.state.value) { - modifier = modifier.scale(scaleX = 1f, scaleY = -1f) - } - - Box(modifier, contentAlignment = Alignment.Center) { + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Text(generalGetString(MR.strings.no_filtered_chats), color = MaterialTheme.colors.secondary) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ShareListNavLinkView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ShareListNavLinkView.kt index 8035cddc6d..8b2e008ad3 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ShareListNavLinkView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ShareListNavLinkView.kt @@ -6,7 +6,6 @@ import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -22,8 +21,7 @@ fun ShareListNavLinkView( chatModel: ChatModel, isMediaOrFileAttachment: Boolean, isVoice: Boolean, - hasSimplexLink: Boolean, - oneHandUI: State + hasSimplexLink: Boolean ) { val stopped = chatModel.chatRunning.value == false val scope = rememberCoroutineScope() @@ -31,7 +29,7 @@ fun ShareListNavLinkView( is ChatInfo.Direct -> { val voiceProhibited = isVoice && !chat.chatInfo.featureEnabled(ChatFeature.Voice) ShareListNavLinkLayout( - chatLinkPreview = { SharePreviewView(chat, disabled = voiceProhibited, oneHandUI = oneHandUI) }, + chatLinkPreview = { SharePreviewView(chat, disabled = voiceProhibited) }, click = { if (voiceProhibited) { showForwardProhibitedByPrefAlert() @@ -48,7 +46,7 @@ fun ShareListNavLinkView( val voiceProhibited = isVoice && !chat.chatInfo.featureEnabled(ChatFeature.Voice) val prohibitedByPref = simplexLinkProhibited || fileProhibited || voiceProhibited ShareListNavLinkLayout( - chatLinkPreview = { SharePreviewView(chat, disabled = prohibitedByPref, oneHandUI = oneHandUI) }, + chatLinkPreview = { SharePreviewView(chat, disabled = prohibitedByPref) }, click = { if (prohibitedByPref) { showForwardProhibitedByPrefAlert() @@ -61,7 +59,7 @@ fun ShareListNavLinkView( } is ChatInfo.Local -> ShareListNavLinkLayout( - chatLinkPreview = { SharePreviewView(chat, disabled = false, oneHandUI = oneHandUI) }, + chatLinkPreview = { SharePreviewView(chat, disabled = false) }, click = { scope.launch { noteFolderChatAction(chat.remoteHostId, chat.chatInfo.noteFolder) } }, stopped ) @@ -89,15 +87,9 @@ private fun ShareListNavLinkLayout( } @Composable -private fun SharePreviewView(chat: Chat, disabled: Boolean, oneHandUI: State) { - var modifier = Modifier.fillMaxSize() - - if (oneHandUI.value) { - modifier = modifier.scale(scaleX = 1f, scaleY = -1f) - } - +private fun SharePreviewView(chat: Chat, disabled: Boolean) { Row( - modifier, + Modifier.fillMaxSize(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ShareListView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ShareListView.kt index b86bc16dbc..6dfac75126 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ShareListView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ShareListView.kt @@ -7,7 +7,6 @@ import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.Color import dev.icerock.moko.resources.compose.painterResource import dev.icerock.moko.resources.compose.stringResource @@ -15,6 +14,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import chat.simplex.common.SettingsViewState import chat.simplex.common.model.* +import chat.simplex.common.model.ChatController.appPrefs import chat.simplex.common.views.helpers.* import chat.simplex.common.platform.* import chat.simplex.res.MR @@ -25,16 +25,30 @@ fun ShareListView(chatModel: ChatModel, settingsState: SettingsViewState, stoppe var searchInList by rememberSaveable { mutableStateOf("") } val (userPickerState, scaffoldState) = settingsState val endPadding = if (appPlatform.isDesktop) 56.dp else 0.dp - val oneHandUI = remember { chatModel.controller.appPrefs.oneHandUI } + val oneHandUI = remember { appPrefs.oneHandUI.state } Scaffold( Modifier.padding(end = endPadding), contentColor = LocalContentColor.current, drawerContentColor = LocalContentColor.current, scaffoldState = scaffoldState, - topBar = { if (!oneHandUI.state.value) Column { ShareListToolbar(chatModel, userPickerState, stopped) { searchInList = it.trim() } } }, - bottomBar = { if (oneHandUI.state.value) Column { ShareListToolbar(chatModel, userPickerState, stopped) { searchInList = it.trim() } } }, - ) { + topBar = { + if (!oneHandUI.value) { + Column { + ShareListToolbar(chatModel, userPickerState, stopped) { searchInList = it.trim() } + Divider() + } + } + }, + bottomBar = { + if (oneHandUI.value) { + Column { + Divider() + ShareListToolbar(chatModel, userPickerState, stopped) { searchInList = it.trim() } + } + } + } + ) { val sharedContent = chatModel.sharedContent.value var isMediaOrFileAttachment = false var isVoice = false @@ -60,15 +74,9 @@ fun ShareListView(chatModel: ChatModel, settingsState: SettingsViewState, stoppe } null -> {} } - var modifier = Modifier.fillMaxSize() - - if (oneHandUI.state.value) { - modifier = modifier.scale(scaleX = 1f, scaleY = -1f) - } - Box(Modifier.padding(it)) { Column( - modifier = modifier + modifier = Modifier.fillMaxSize() ) { if (chatModel.chats.value.isNotEmpty()) { ShareList( @@ -77,10 +85,9 @@ fun ShareListView(chatModel: ChatModel, settingsState: SettingsViewState, stoppe isMediaOrFileAttachment = isMediaOrFileAttachment, isVoice = isVoice, hasSimplexLink = hasSimplexLink, - oneHandUI = oneHandUI.state ) } else { - EmptyList(oneHandUI = oneHandUI.state) + EmptyList() } } } @@ -101,14 +108,8 @@ private fun hasSimplexLink(msg: String): Boolean { } @Composable -private fun EmptyList(oneHandUI: State) { - var modifier = Modifier.fillMaxSize() - - if (oneHandUI.value) { - modifier = modifier.scale(scaleX = 1f, scaleY = -1f) - } - - Box(modifier, contentAlignment = Alignment.Center) { +private fun EmptyList() { + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Text(stringResource(MR.strings.you_have_no_chats), color = MaterialTheme.colors.secondary) } } @@ -189,7 +190,6 @@ private fun ShareListToolbar(chatModel: ChatModel, userPickerState: MutableState onSearchValueChanged = onSearchValueChanged, buttons = barButtons ) - Divider() } @Composable @@ -199,8 +199,8 @@ private fun ShareList( isMediaOrFileAttachment: Boolean, isVoice: Boolean, hasSimplexLink: Boolean, - oneHandUI: State ) { + val oneHandUI = remember { appPrefs.oneHandUI.state } val chats by remember(search) { derivedStateOf { val sorted = chatModel.chats.value.toList().sortedByDescending { it.chatInfo is ChatInfo.Local } @@ -212,7 +212,8 @@ private fun ShareList( } } LazyColumnWithScrollBar( - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxSize(), + reverseLayout = oneHandUI.value ) { items(chats) { chat -> ShareListNavLinkView( @@ -221,7 +222,6 @@ private fun ShareList( isMediaOrFileAttachment = isMediaOrFileAttachment, isVoice = isVoice, hasSimplexLink = hasSimplexLink, - oneHandUI = oneHandUI ) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/contacts/ContactListNavView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/contacts/ContactListNavView.kt index b1f53061a1..05e693b7c2 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/contacts/ContactListNavView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/contacts/ContactListNavView.kt @@ -5,7 +5,6 @@ import androidx.compose.ui.graphics.Color import dev.icerock.moko.resources.compose.painterResource import dev.icerock.moko.resources.compose.stringResource import chat.simplex.common.model.* -import chat.simplex.common.model.ChatController.appPrefs import chat.simplex.common.model.ChatModel.withChats import chat.simplex.common.platform.* import chat.simplex.common.views.chat.* @@ -29,7 +28,6 @@ fun onRequestAccepted(chat: Chat) { @Composable fun ContactListNavLinkView(chat: Chat, nextChatSelected: State, showDeletedChatIcon: Boolean) { - val oneHandUI = remember { appPrefs.oneHandUI.state } val showMenu = remember { mutableStateOf(false) } val rhId = chat.remoteHostId val disabled = chatModel.chatRunning.value == false || chatModel.deletedChats.value.contains(rhId to chat.chatInfo.id) @@ -90,7 +88,6 @@ fun ContactListNavLinkView(chat: Chat, nextChatSelected: State, showDel disabled, selectedChat, nextChatSelected, - oneHandUI ) } is ChatInfo.ContactRequest -> { @@ -123,9 +120,7 @@ fun ContactListNavLinkView(chat: Chat, nextChatSelected: State, showDel showMenu, disabled, selectedChat, - nextChatSelected, - oneHandUI - ) + nextChatSelected) } else -> {} } 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 d84ef62658..a1eaf97fe7 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 @@ -14,7 +14,6 @@ import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.scale import androidx.compose.ui.focus.* import androidx.compose.ui.graphics.* import androidx.compose.ui.graphics.painter.Painter @@ -66,7 +65,7 @@ fun NewChatSheet(rh: RemoteHostInfo?, close: () -> Unit) { ) { val closeAll = { ModalManager.start.closeModals() } - Column(modifier = Modifier.fillMaxSize().then(if (oneHandUI.value) Modifier.scale(scaleX = 1f, scaleY = -1f) else Modifier)) { + Column(modifier = Modifier.fillMaxSize()) { NewChatSheetLayout( addContact = { ModalManager.start.showModalCloseable { _ -> NewChatView(chatModel.currentRemoteHost.value, NewChatOption.INVITE, close = closeAll ) } @@ -164,10 +163,12 @@ private fun NewChatSheetLayout( contactChats = allChats ) - val sectionModifier = if (oneHandUI.value) Modifier.fillMaxWidth().scale(scaleX = 1f, scaleY = -1f) else Modifier.fillMaxWidth() + val sectionModifier = Modifier.fillMaxWidth() + LazyColumnWithScrollBar( - Modifier.fillMaxWidth(), - listState + Modifier.fillMaxSize(), + listState, + reverseLayout = oneHandUI.value ) { if (!oneHandUI.value) { item { @@ -186,12 +187,14 @@ private fun NewChatSheetLayout( Modifier .offset { val y = if (searchText.value.text.isEmpty()) { + val offsetMultiplier = if (oneHandUI.value) 1 else -1 + if ( (oneHandUI.value && scrollDirection == ScrollDirection.Up) || (appPlatform.isAndroid && keyboardState == KeyboardState.Opened) ) { 0 - } else if (listState.firstVisibleItemIndex == 0) -listState.firstVisibleItemScrollOffset else -1000 + } else if (listState.firstVisibleItemIndex == 0) offsetMultiplier * listState.firstVisibleItemScrollOffset else offsetMultiplier * 1000 } else { 0 } @@ -199,9 +202,7 @@ private fun NewChatSheetLayout( } .background(MaterialTheme.colors.background) ) { - if (!oneHandUI.value) { - Divider() - } + Divider() ContactsSearchBar( listState = listState, searchText = searchText, @@ -209,33 +210,49 @@ private fun NewChatSheetLayout( searchChatFilteredBySimplexLink = searchChatFilteredBySimplexLink, close = close, ) - Divider() + if (!oneHandUI.value) { + Divider() + } } } item { Spacer(Modifier.padding(bottom = 27.dp)) + val actionButtonsOriginal = listOf( + Triple( + painterResource(MR.images.ic_add_link), + stringResource(MR.strings.add_contact_tab), + addContact, + ), + Triple( + painterResource(MR.images.ic_qr_code), + if (appPlatform.isAndroid) stringResource(MR.strings.scan_paste_link) else stringResource(MR.strings.paste_link), + scanPaste, + ), + Triple( + painterResource(MR.images.ic_group), + stringResource(MR.strings.create_group_button), + createGroup, + ) + ) + + val actionButtons by remember(oneHandUI.value) { + derivedStateOf { + if (oneHandUI.value) actionButtonsOriginal.asReversed() else actionButtonsOriginal + } + } + if (searchText.value.text.isEmpty()) { Row { SectionView { - NewChatButton( - icon = painterResource(MR.images.ic_add_link), - text = stringResource(MR.strings.add_contact_tab), - click = addContact, - extraPadding = true, - ) - NewChatButton( - icon = painterResource(MR.images.ic_qr_code), - text = if (appPlatform.isAndroid) stringResource(MR.strings.scan_paste_link) else stringResource(MR.strings.paste_link), - click = scanPaste, - extraPadding = true, - ) - NewChatButton( - icon = painterResource(MR.images.ic_group), - text = stringResource(MR.strings.create_group_button), - click = createGroup, - extraPadding = true, - ) + actionButtons.map { + NewChatButton( + icon = it.first, + text = it.second, + click = it.third, + extraPadding = true, + ) + } } } SectionDividerSpaced(maxBottomPadding = false) @@ -317,10 +334,8 @@ private fun NewChatButton( disabled: Boolean = false, extraPadding: Boolean = false, ) { - val oneHandUI = remember { appPrefs.oneHandUI.state } - SectionItemView(click, disabled = disabled) { - Row(modifier = if (oneHandUI.value) Modifier.scale(scaleX = 1f, scaleY = -1f) else Modifier) { + Row { Icon(icon, text, tint = if (disabled) MaterialTheme.colors.secondary else iconColor) TextIconSpaced(extraPadding) Text(text, color = if (disabled) MaterialTheme.colors.secondary else textColor) @@ -336,12 +351,9 @@ private fun ContactsSearchBar( searchChatFilteredBySimplexLink: MutableState, close: () -> Unit, ) { - val oneHandUI = remember { appPrefs.oneHandUI.state } - - val modifier = if (oneHandUI.value) Modifier.fillMaxWidth().scale(scaleX = 1f, scaleY = -1f) else Modifier.fillMaxWidth() var focused by remember { mutableStateOf(false) } - Row(verticalAlignment = Alignment.CenterVertically, modifier = modifier) { + Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) { val focusRequester = remember { FocusRequester() } Icon( painterResource(MR.images.ic_search), @@ -525,15 +537,17 @@ private fun DeletedContactsView(rh: RemoteHostInfo?, closeDeletedChats: () -> Un Scaffold( bottomBar = { if (showToolbarInOneHandUI.value) { - CloseSheetBar( - close = closeDeletedChats, - showClose = true, - endButtons = { Spacer(Modifier.minimumInteractiveComponentSize()) }, - arrangement = Arrangement.Bottom, - closeBarTitle = generalGetString(MR.strings.deleted_chats), - barPaddingValues = PaddingValues(horizontal = 0.dp) - ) - Divider() + Column { + Divider() + CloseSheetBar( + close = closeDeletedChats, + showClose = true, + endButtons = { Spacer(Modifier.minimumInteractiveComponentSize()) }, + arrangement = Arrangement.Bottom, + closeBarTitle = generalGetString(MR.strings.deleted_chats), + barPaddingValues = PaddingValues(horizontal = 0.dp) + ) + } } } ) { @@ -541,7 +555,6 @@ private fun DeletedContactsView(rh: RemoteHostInfo?, closeDeletedChats: () -> Un Modifier .fillMaxSize() .padding(it) - .then(if (oneHandUI.value) Modifier.scale(scaleX = 1f, scaleY = -1f) else Modifier), ) { if (!oneHandUI.value) { Box(contentAlignment = Alignment.Center) { @@ -571,9 +584,9 @@ private fun DeletedContactsView(rh: RemoteHostInfo?, closeDeletedChats: () -> Un ) LazyColumnWithScrollBar( - Modifier.fillMaxWidth(), - listState - ) { + Modifier.fillMaxSize(), + reverseLayout = oneHandUI.value, + ) { item { if (!oneHandUI.value) { Divider() @@ -605,7 +618,6 @@ private fun DeletedContactsView(rh: RemoteHostInfo?, closeDeletedChats: () -> Un Text( generalGetString(MR.strings.no_filtered_contacts), color = MaterialTheme.colors.secondary, - modifier = if (oneHandUI.value) Modifier.scale(scaleX = 1f, scaleY = -1f) else Modifier ) } } diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml index 8c7b772089..28b65cae04 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -1293,7 +1293,7 @@ Database downgrade Incompatible database version Confirm database upgrades - One-hand UI + Reachable chat toolbar Show console in new window Show chat list in new window Invalid migration confirmation diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.desktop.kt index 57069a8caa..189f1842dd 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.desktop.kt @@ -35,7 +35,6 @@ actual fun ChatListNavLinkLayout( disabled: Boolean, selectedChat: State, nextChatSelected: State, - oneHandUI: State, ) { var modifier = Modifier.fillMaxWidth() if (!disabled) modifier = modifier