mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-05-25 18:34:24 +00:00
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>
This commit is contained in:
-6
@@ -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<Boolean>,
|
||||
nextChatSelected: State<Boolean>,
|
||||
oneHandUI: State<Boolean>
|
||||
) {
|
||||
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 }
|
||||
|
||||
+3
-3
@@ -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
|
||||
|
||||
+1
-11
@@ -35,7 +35,7 @@ import kotlinx.coroutines.*
|
||||
import kotlinx.datetime.Clock
|
||||
|
||||
@Composable
|
||||
fun ChatListNavLinkView(chat: Chat, nextChatSelected: State<Boolean>, oneHandUI: State<Boolean>) {
|
||||
fun ChatListNavLinkView(chat: Chat, nextChatSelected: State<Boolean>) {
|
||||
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<Boolean>, oneHandUI:
|
||||
disabled,
|
||||
selectedChat,
|
||||
nextChatSelected,
|
||||
oneHandUI
|
||||
)
|
||||
}
|
||||
is ChatInfo.Group ->
|
||||
@@ -101,7 +100,6 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State<Boolean>, oneHandUI:
|
||||
disabled,
|
||||
selectedChat,
|
||||
nextChatSelected,
|
||||
oneHandUI
|
||||
)
|
||||
is ChatInfo.Local -> {
|
||||
ChatListNavLinkLayout(
|
||||
@@ -120,7 +118,6 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State<Boolean>, oneHandUI:
|
||||
disabled,
|
||||
selectedChat,
|
||||
nextChatSelected,
|
||||
oneHandUI
|
||||
)
|
||||
}
|
||||
is ChatInfo.ContactRequest ->
|
||||
@@ -140,7 +137,6 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State<Boolean>, oneHandUI:
|
||||
disabled,
|
||||
selectedChat,
|
||||
nextChatSelected,
|
||||
oneHandUI
|
||||
)
|
||||
is ChatInfo.ContactConnection ->
|
||||
ChatListNavLinkLayout(
|
||||
@@ -161,7 +157,6 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State<Boolean>, oneHandUI:
|
||||
disabled,
|
||||
selectedChat,
|
||||
nextChatSelected,
|
||||
oneHandUI
|
||||
)
|
||||
is ChatInfo.InvalidJSON ->
|
||||
ChatListNavLinkLayout(
|
||||
@@ -178,7 +173,6 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State<Boolean>, oneHandUI:
|
||||
disabled,
|
||||
selectedChat,
|
||||
nextChatSelected,
|
||||
oneHandUI
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -879,7 +873,6 @@ expect fun ChatListNavLinkLayout(
|
||||
disabled: Boolean,
|
||||
selectedChat: State<Boolean>,
|
||||
nextChatSelected: State<Boolean>,
|
||||
oneHandUI: State<Boolean>
|
||||
)
|
||||
|
||||
@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) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+35
-51
@@ -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<Boolean>) {
|
||||
|
||||
@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<AnimatedViewState>, stopped: Boolean, oneHandUI: SharedPreference<Boolean>) {
|
||||
private fun ChatListToolbar(drawerState: DrawerState, userPickerState: MutableStateFlow<AnimatedViewState>, stopped: Boolean) {
|
||||
val serversSummary: MutableState<PresentedServersSummary?> = 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<TextFieldValue>, searchShowingSimplexLink: MutableState<Boolean>, searchChatFilteredBySimplexLink: MutableState<String?>, oneHandUI: SharedPreference<Boolean>) {
|
||||
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<TextFieldValue>, searchShowingSimplexLink: MutableState<Boolean>, searchChatFilteredBySimplexLink: MutableState<String?>) {
|
||||
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<TextFieldValue>, oneHandUI: SharedPreference<Boolean>) {
|
||||
private fun ChatList(chatModel: ChatModel, searchText: MutableState<TextFieldValue>) {
|
||||
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<TextFieldVal
|
||||
val searchChatFilteredBySimplexLink = remember { mutableStateOf<String?>(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)
|
||||
}
|
||||
}
|
||||
|
||||
+6
-14
@@ -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<Boolean>
|
||||
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<Boolean>) {
|
||||
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
|
||||
) {
|
||||
|
||||
+26
-26
@@ -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<Boolean>) {
|
||||
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<Boolean>
|
||||
) {
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-6
@@ -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<Boolean>, 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<Boolean>, showDel
|
||||
disabled,
|
||||
selectedChat,
|
||||
nextChatSelected,
|
||||
oneHandUI
|
||||
)
|
||||
}
|
||||
is ChatInfo.ContactRequest -> {
|
||||
@@ -123,9 +120,7 @@ fun ContactListNavLinkView(chat: Chat, nextChatSelected: State<Boolean>, showDel
|
||||
showMenu,
|
||||
disabled,
|
||||
selectedChat,
|
||||
nextChatSelected,
|
||||
oneHandUI
|
||||
)
|
||||
nextChatSelected)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
+61
-49
@@ -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<String?>,
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1293,7 +1293,7 @@
|
||||
<string name="database_downgrade">Database downgrade</string>
|
||||
<string name="incompatible_database_version">Incompatible database version</string>
|
||||
<string name="confirm_database_upgrades">Confirm database upgrades</string>
|
||||
<string name="one_hand_ui">One-hand UI</string>
|
||||
<string name="one_hand_ui">Reachable chat toolbar</string>
|
||||
<string name="terminal_always_visible">Show console in new window</string>
|
||||
<string name="chat_list_always_visible">Show chat list in new window</string>
|
||||
<string name="invalid_migration_confirmation">Invalid migration confirmation</string>
|
||||
|
||||
-1
@@ -35,7 +35,6 @@ actual fun ChatListNavLinkLayout(
|
||||
disabled: Boolean,
|
||||
selectedChat: State<Boolean>,
|
||||
nextChatSelected: State<Boolean>,
|
||||
oneHandUI: State<Boolean>,
|
||||
) {
|
||||
var modifier = Modifier.fillMaxWidth()
|
||||
if (!disabled) modifier = modifier
|
||||
|
||||
Reference in New Issue
Block a user