mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-04-26 21:45:52 +00:00
android, desktop, core: option to show toolbar in chat at the top in reachable UI (#5316)
* android, desktop: ability to show toolbar in chat at the top in reachable UI * rename * core AppSettings * ios AppSettings * rename * strings, enable reachable chat toolbar when enabled reachable app toolbars --------- Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
This commit is contained in:
committed by
GitHub
parent
219381f941
commit
ee146cdc7b
@@ -65,6 +65,7 @@ extension AppSettings {
|
||||
if let val = uiCurrentThemeIds { currentThemeIdsDefault.set(val) }
|
||||
if let val = uiThemes { themeOverridesDefault.set(val.skipDuplicates()) }
|
||||
if let val = oneHandUI { groupDefaults.setValue(val, forKey: GROUP_DEFAULT_ONE_HAND_UI) }
|
||||
if let val = chatBottomBar { groupDefaults.setValue(val, forKey: GROUP_DEFAULT_CHAT_BOTTOM_BAR) }
|
||||
}
|
||||
|
||||
public static var current: AppSettings {
|
||||
@@ -100,6 +101,7 @@ extension AppSettings {
|
||||
c.uiCurrentThemeIds = currentThemeIdsDefault.get()
|
||||
c.uiThemes = themeOverridesDefault.get()
|
||||
c.oneHandUI = groupDefaults.bool(forKey: GROUP_DEFAULT_ONE_HAND_UI)
|
||||
c.chatBottomBar = groupDefaults.bool(forKey: GROUP_DEFAULT_CHAT_BOTTOM_BAR)
|
||||
return c
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2655,6 +2655,7 @@ public struct AppSettings: Codable, Equatable {
|
||||
public var uiCurrentThemeIds: [String: String]? = nil
|
||||
public var uiThemes: [ThemeOverrides]? = nil
|
||||
public var oneHandUI: Bool? = nil
|
||||
public var chatBottomBar: Bool? = nil
|
||||
|
||||
public func prepareForExport() -> AppSettings {
|
||||
var empty = AppSettings()
|
||||
@@ -2689,6 +2690,7 @@ public struct AppSettings: Codable, Equatable {
|
||||
if uiCurrentThemeIds != def.uiCurrentThemeIds { empty.uiCurrentThemeIds = uiCurrentThemeIds }
|
||||
if uiThemes != def.uiThemes { empty.uiThemes = uiThemes }
|
||||
if oneHandUI != def.oneHandUI { empty.oneHandUI = oneHandUI }
|
||||
if chatBottomBar != def.chatBottomBar { empty.chatBottomBar = chatBottomBar }
|
||||
return empty
|
||||
}
|
||||
|
||||
@@ -2723,7 +2725,8 @@ public struct AppSettings: Codable, Equatable {
|
||||
uiDarkColorScheme: DefaultTheme.SIMPLEX.themeName,
|
||||
uiCurrentThemeIds: nil as [String: String]?,
|
||||
uiThemes: nil as [ThemeOverrides]?,
|
||||
oneHandUI: false
|
||||
oneHandUI: false,
|
||||
chatBottomBar: true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ public let GROUP_DEFAULT_CONFIRM_DB_UPGRADES = "confirmDBUpgrades"
|
||||
public let GROUP_DEFAULT_CALL_KIT_ENABLED = "callKitEnabled"
|
||||
public let GROUP_DEFAULT_PQ_EXPERIMENTAL_ENABLED = "pqExperimentalEnabled" // no longer used
|
||||
public let GROUP_DEFAULT_ONE_HAND_UI = "oneHandUI"
|
||||
public let GROUP_DEFAULT_CHAT_BOTTOM_BAR = "chatBottomBar"
|
||||
|
||||
public let APP_GROUP_NAME = "group.chat.simplex.app"
|
||||
|
||||
@@ -94,7 +95,8 @@ public func registerGroupDefaults() {
|
||||
GROUP_DEFAULT_CONFIRM_DB_UPGRADES: false,
|
||||
GROUP_DEFAULT_CALL_KIT_ENABLED: true,
|
||||
GROUP_DEFAULT_PQ_EXPERIMENTAL_ENABLED: false,
|
||||
GROUP_DEFAULT_ONE_HAND_UI: true
|
||||
GROUP_DEFAULT_ONE_HAND_UI: true,
|
||||
GROUP_DEFAULT_CHAT_BOTTOM_BAR: true
|
||||
])
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -29,6 +29,7 @@ actual fun LazyColumnWithScrollBar(
|
||||
flingBehavior: FlingBehavior,
|
||||
userScrollEnabled: Boolean,
|
||||
additionalBarOffset: State<Dp>?,
|
||||
chatBottomBar: State<Boolean>,
|
||||
fillMaxSize: Boolean,
|
||||
content: LazyListScope.() -> Unit
|
||||
) {
|
||||
@@ -91,6 +92,7 @@ actual fun LazyColumnWithScrollBarNoAppBar(
|
||||
flingBehavior: FlingBehavior,
|
||||
userScrollEnabled: Boolean,
|
||||
additionalBarOffset: State<Dp>?,
|
||||
chatBottomBar: State<Boolean>,
|
||||
content: LazyListScope.() -> Unit
|
||||
) {
|
||||
val state = state ?: rememberLazyListState()
|
||||
|
||||
+6
-1
@@ -106,7 +106,12 @@ fun AppearanceScope.AppearanceLayout(
|
||||
}
|
||||
// }
|
||||
|
||||
SettingsPreferenceItem(icon = null, stringResource(MR.strings.one_hand_ui), ChatModel.controller.appPrefs.oneHandUI)
|
||||
SettingsPreferenceItem(icon = null, stringResource(MR.strings.one_hand_ui), ChatModel.controller.appPrefs.oneHandUI) { enabled ->
|
||||
if (enabled) appPrefs.chatBottomBar.set(true)
|
||||
}
|
||||
if (remember { appPrefs.oneHandUI.state }.value) {
|
||||
SettingsPreferenceItem(icon = null, stringResource(MR.strings.chat_bottom_bar), ChatModel.controller.appPrefs.chatBottomBar)
|
||||
}
|
||||
}
|
||||
|
||||
SectionDividerSpaced()
|
||||
|
||||
+10
-4
@@ -257,6 +257,7 @@ class AppPreferences {
|
||||
val iosCallKitCallsInRecents = mkBoolPreference(SHARED_PREFS_IOS_CALL_KIT_CALLS_IN_RECENTS, false)
|
||||
|
||||
val oneHandUI = mkBoolPreference(SHARED_PREFS_ONE_HAND_UI, true)
|
||||
val chatBottomBar = mkBoolPreference(SHARED_PREFS_CHAT_BOTTOM_BAR, true)
|
||||
|
||||
val hintPreferences: List<Pair<SharedPreference<Boolean>, Boolean>> = listOf(
|
||||
laNoticeShown to false,
|
||||
@@ -431,6 +432,7 @@ class AppPreferences {
|
||||
private const val SHARED_PREFS_SHOULD_IMPORT_APP_SETTINGS = "ShouldImportAppSettings"
|
||||
private const val SHARED_PREFS_CONFIRM_DB_UPGRADES = "ConfirmDBUpgrades"
|
||||
private const val SHARED_PREFS_ONE_HAND_UI = "OneHandUI"
|
||||
private const val SHARED_PREFS_CHAT_BOTTOM_BAR = "ChatBottomBar"
|
||||
private const val SHARED_PREFS_SELF_DESTRUCT = "LocalAuthenticationSelfDestruct"
|
||||
private const val SHARED_PREFS_SELF_DESTRUCT_DISPLAY_NAME = "LocalAuthenticationSelfDestructDisplayName"
|
||||
private const val SHARED_PREFS_PQ_EXPERIMENTAL_ENABLED = "PQExperimentalEnabled" // no longer used
|
||||
@@ -438,7 +440,6 @@ class AppPreferences {
|
||||
private const val SHARED_PREFS_CURRENT_THEME_IDs = "CurrentThemeIds"
|
||||
private const val SHARED_PREFS_SYSTEM_DARK_THEME = "SystemDarkTheme"
|
||||
private const val SHARED_PREFS_THEMES_OLD = "Themes"
|
||||
private const val SHARED_PREFS_THEME_OVERRIDES = "ThemeOverrides"
|
||||
private const val SHARED_PREFS_PROFILE_IMAGE_CORNER_RADIUS = "ProfileImageCornerRadius"
|
||||
private const val SHARED_PREFS_CHAT_ITEM_ROUNDNESS = "ChatItemRoundness"
|
||||
private const val SHARED_PREFS_CHAT_ITEM_TAIL = "ChatItemTail"
|
||||
@@ -6882,7 +6883,8 @@ data class AppSettings(
|
||||
var uiDarkColorScheme: String? = null,
|
||||
var uiCurrentThemeIds: Map<String, String>? = null,
|
||||
var uiThemes: List<ThemeOverrides>? = null,
|
||||
var oneHandUI: Boolean? = null
|
||||
var oneHandUI: Boolean? = null,
|
||||
var chatBottomBar: Boolean? = null
|
||||
) {
|
||||
fun prepareForExport(): AppSettings {
|
||||
val empty = AppSettings()
|
||||
@@ -6917,6 +6919,7 @@ data class AppSettings(
|
||||
if (uiCurrentThemeIds != def.uiCurrentThemeIds) { empty.uiCurrentThemeIds = uiCurrentThemeIds }
|
||||
if (uiThemes != def.uiThemes) { empty.uiThemes = uiThemes }
|
||||
if (oneHandUI != def.oneHandUI) { empty.oneHandUI = oneHandUI }
|
||||
if (chatBottomBar != def.chatBottomBar) { empty.chatBottomBar = chatBottomBar }
|
||||
return empty
|
||||
}
|
||||
|
||||
@@ -6962,6 +6965,7 @@ data class AppSettings(
|
||||
uiCurrentThemeIds?.let { def.currentThemeIds.set(it) }
|
||||
uiThemes?.let { def.themeOverrides.set(it.skipDuplicates()) }
|
||||
oneHandUI?.let { def.oneHandUI.set(it) }
|
||||
chatBottomBar?.let { if (appPlatform.isAndroid) def.chatBottomBar.set(it) else def.chatBottomBar.set(true) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -6996,7 +7000,8 @@ data class AppSettings(
|
||||
uiDarkColorScheme = DefaultTheme.SIMPLEX.themeName,
|
||||
uiCurrentThemeIds = null,
|
||||
uiThemes = null,
|
||||
oneHandUI = true
|
||||
oneHandUI = true,
|
||||
chatBottomBar = true,
|
||||
)
|
||||
|
||||
val current: AppSettings
|
||||
@@ -7032,7 +7037,8 @@ data class AppSettings(
|
||||
uiDarkColorScheme = def.systemDarkTheme.get() ?: DefaultTheme.SIMPLEX.themeName,
|
||||
uiCurrentThemeIds = def.currentThemeIds.get(),
|
||||
uiThemes = def.themeOverrides.get(),
|
||||
oneHandUI = def.oneHandUI.get()
|
||||
oneHandUI = def.oneHandUI.get(),
|
||||
chatBottomBar = def.chatBottomBar.get()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -23,6 +23,7 @@ expect fun LazyColumnWithScrollBar(
|
||||
flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(),
|
||||
userScrollEnabled: Boolean = true,
|
||||
additionalBarOffset: State<Dp>? = null,
|
||||
chatBottomBar: State<Boolean> = remember { mutableStateOf(true) },
|
||||
// by default, this function will include .fillMaxSize() without you doing anything. If you don't need it, pass `false` here
|
||||
// maxSize (at least maxHeight) is needed for blur on appBars to work correctly
|
||||
fillMaxSize: Boolean = true,
|
||||
@@ -41,6 +42,7 @@ expect fun LazyColumnWithScrollBarNoAppBar(
|
||||
flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(),
|
||||
userScrollEnabled: Boolean = true,
|
||||
additionalBarOffset: State<Dp>? = null,
|
||||
chatBottomBar: State<Boolean> = remember { mutableStateOf(true) },
|
||||
content: LazyListScope.() -> Unit
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -156,7 +156,7 @@ fun TerminalLog(floating: Boolean, composeViewHeight: State<Dp>) {
|
||||
LazyColumnWithScrollBar (
|
||||
reverseLayout = true,
|
||||
contentPadding = PaddingValues(
|
||||
top = topPaddingToContent(),
|
||||
top = topPaddingToContent(false),
|
||||
bottom = composeViewHeight.value
|
||||
),
|
||||
state = listState,
|
||||
|
||||
+23
-22
@@ -658,6 +658,8 @@ fun ChatLayout(
|
||||
Box(Modifier.fillMaxSize().chatViewBackgroundModifier(MaterialTheme.colors, MaterialTheme.wallpaper, LocalAppBarHandler.current?.backgroundGraphicsLayerSize, LocalAppBarHandler.current?.backgroundGraphicsLayer)) {
|
||||
val remoteHostId = remember { remoteHostId }.value
|
||||
val chatInfo = remember { chatInfo }.value
|
||||
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||
val chatBottomBar = remember { appPrefs.chatBottomBar.state }
|
||||
AdaptingBottomPaddingLayout(Modifier, CHAT_COMPOSE_LAYOUT_ID, composeViewHeight) {
|
||||
if (chatInfo != null) {
|
||||
Box(Modifier.fillMaxSize()) {
|
||||
@@ -670,25 +672,23 @@ 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)
|
||||
.then(if (oneHandUI.value && chatBottomBar.value) Modifier.padding(bottom = AppBarHeight * fontSizeSqrtMultiplier) else Modifier)
|
||||
) {
|
||||
composeView()
|
||||
}
|
||||
}
|
||||
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||
if (oneHandUI.value) {
|
||||
if (oneHandUI.value && chatBottomBar.value) {
|
||||
StatusBarBackground()
|
||||
} else {
|
||||
NavigationBarBackground(true, oneHandUI.value, noAlpha = true)
|
||||
}
|
||||
Box(if (oneHandUI.value) Modifier.align(Alignment.BottomStart).imePadding() else Modifier) {
|
||||
Box(if (oneHandUI.value && chatBottomBar.value) Modifier.align(Alignment.BottomStart).imePadding() else Modifier) {
|
||||
if (selectedChatItems.value == null) {
|
||||
if (chatInfo != null) {
|
||||
ChatInfoToolbar(chatInfo, back, info, startCall, endCall, addMembers, openGroupLink, changeNtfsState, onSearchValueChanged, showSearch)
|
||||
@@ -856,12 +856,13 @@ fun BoxScope.ChatInfoToolbar(
|
||||
}
|
||||
}
|
||||
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||
val chatBottomBar = remember { appPrefs.chatBottomBar.state }
|
||||
DefaultAppBar(
|
||||
navigationButton = { if (appPlatform.isAndroid || showSearch.value) { NavigationButtonBack(onBackClicked) } },
|
||||
title = { ChatInfoToolbarTitle(chatInfo) },
|
||||
onTitleClick = if (chatInfo is ChatInfo.Local) null else info,
|
||||
showSearch = showSearch.value,
|
||||
onTop = !oneHandUI.value,
|
||||
onTop = !oneHandUI.value || !chatBottomBar.value,
|
||||
onSearchValueChanged = onSearchValueChanged,
|
||||
buttons = { barButtons.forEach { it() } }
|
||||
)
|
||||
@@ -873,11 +874,11 @@ fun BoxScope.ChatInfoToolbar(
|
||||
showMenu,
|
||||
modifier = Modifier.onSizeChanged { with(density) {
|
||||
width.value = it.width.toDp().coerceAtLeast(250.dp)
|
||||
if (oneHandUI.value && (appPlatform.isDesktop || (platform.androidApiLevel ?: 0) >= 30)) height.value = it.height.toDp()
|
||||
if (oneHandUI.value && chatBottomBar.value && (appPlatform.isDesktop || (platform.androidApiLevel ?: 0) >= 30)) height.value = it.height.toDp()
|
||||
} },
|
||||
offset = DpOffset(-width.value, if (oneHandUI.value) -height.value else AppBarHeight)
|
||||
offset = DpOffset(-width.value, if (oneHandUI.value && chatBottomBar.value) -height.value else AppBarHeight)
|
||||
) {
|
||||
if (oneHandUI.value) {
|
||||
if (oneHandUI.value && chatBottomBar.value) {
|
||||
menuItems.asReversed().forEach { it() }
|
||||
} else {
|
||||
menuItems.forEach { it() }
|
||||
@@ -964,7 +965,7 @@ fun BoxScope.ChatItemsList(
|
||||
val reversedChatItems = remember { derivedStateOf { chatModel.chatItems.asReversed() } }
|
||||
val revealedItems = rememberSaveable(stateSaver = serializableSaver()) { mutableStateOf(setOf<Long>()) }
|
||||
val mergedItems = remember { derivedStateOf { MergedItems.create(reversedChatItems.value, unreadCount, revealedItems.value, chatModel.chatState) } }
|
||||
val topPaddingToContentPx = rememberUpdatedState(with(LocalDensity.current) { topPaddingToContent().roundToPx() })
|
||||
val topPaddingToContentPx = rememberUpdatedState(with(LocalDensity.current) { topPaddingToContent(true).roundToPx() })
|
||||
/** determines height based on window info and static height of two AppBars. It's needed because in the first graphic frame height of
|
||||
* [composeViewHeight] is unknown, but we need to set scroll position for unread messages already so it will be correct before the first frame appears
|
||||
* */
|
||||
@@ -1264,10 +1265,11 @@ fun BoxScope.ChatItemsList(
|
||||
state = listState.value,
|
||||
reverseLayout = true,
|
||||
contentPadding = PaddingValues(
|
||||
top = topPaddingToContent(),
|
||||
top = topPaddingToContent(true),
|
||||
bottom = composeViewHeight.value
|
||||
),
|
||||
additionalBarOffset = composeViewHeight
|
||||
additionalBarOffset = composeViewHeight,
|
||||
chatBottomBar = remember { appPrefs.chatBottomBar.state }
|
||||
) {
|
||||
val mergedItemsValue = mergedItems.value
|
||||
itemsIndexed(mergedItemsValue.items, key = { _, merged -> keyForItem(merged.newest().item) }) { index, merged ->
|
||||
@@ -1310,8 +1312,8 @@ fun BoxScope.ChatItemsList(
|
||||
}
|
||||
}
|
||||
}
|
||||
FloatingButtons(loadingMoreItems, mergedItems, unreadCount, maxHeight, composeViewHeight, remoteHostId, chatInfo, searchValue, markChatRead, listState)
|
||||
FloatingDate(Modifier.padding(top = 10.dp + topPaddingToContent()).align(Alignment.TopCenter), mergedItems, listState)
|
||||
FloatingButtons(loadingMoreItems, mergedItems, unreadCount, maxHeight, composeViewHeight, searchValue, markChatRead, listState)
|
||||
FloatingDate(Modifier.padding(top = 10.dp + topPaddingToContent(true)).align(Alignment.TopCenter), mergedItems, listState)
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
snapshotFlow { listState.value.isScrollInProgress }
|
||||
@@ -1400,14 +1402,12 @@ fun BoxScope.FloatingButtons(
|
||||
unreadCount: State<Int>,
|
||||
maxHeight: State<Int>,
|
||||
composeViewHeight: State<Dp>,
|
||||
remoteHostId: Long?,
|
||||
chatInfo: ChatInfo,
|
||||
searchValue: State<String>,
|
||||
markChatRead: () -> Unit,
|
||||
listState: State<LazyListState>
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
val topPaddingToContentPx = rememberUpdatedState(with(LocalDensity.current) { topPaddingToContent().roundToPx() })
|
||||
val topPaddingToContentPx = rememberUpdatedState(with(LocalDensity.current) { topPaddingToContent(true).roundToPx() })
|
||||
val bottomUnreadCount = remember {
|
||||
derivedStateOf {
|
||||
if (unreadCount.value == 0) return@derivedStateOf 0
|
||||
@@ -1447,7 +1447,7 @@ fun BoxScope.FloatingButtons(
|
||||
val showDropDown = remember { mutableStateOf(false) }
|
||||
|
||||
TopEndFloatingButton(
|
||||
Modifier.padding(end = DEFAULT_PADDING, top = 24.dp + topPaddingToContent()).align(Alignment.TopEnd),
|
||||
Modifier.padding(end = DEFAULT_PADDING, top = 24.dp + topPaddingToContent(true)).align(Alignment.TopEnd),
|
||||
topUnreadCount,
|
||||
onClick = {
|
||||
val index = mergedItems.value.items.indexOfLast { it.hasUnread() }
|
||||
@@ -1465,7 +1465,7 @@ fun BoxScope.FloatingButtons(
|
||||
DefaultDropdownMenu(
|
||||
showDropDown,
|
||||
modifier = Modifier.onSizeChanged { with(density) { width.value = it.width.toDp().coerceAtLeast(250.dp) } },
|
||||
offset = DpOffset(-DEFAULT_PADDING - width.value, 24.dp + fabSize + topPaddingToContent())
|
||||
offset = DpOffset(-DEFAULT_PADDING - width.value, 24.dp + fabSize + topPaddingToContent(true))
|
||||
) {
|
||||
ItemAction(
|
||||
generalGetString(MR.strings.mark_read),
|
||||
@@ -1615,9 +1615,10 @@ private fun TopEndFloatingButton(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun topPaddingToContent(): Dp {
|
||||
fun topPaddingToContent(chatView: Boolean): Dp {
|
||||
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||
return if (oneHandUI.value) {
|
||||
val chatBottomBar = remember { appPrefs.chatBottomBar.state }
|
||||
return if (oneHandUI.value && (!chatView || chatBottomBar.value)) {
|
||||
WindowInsets.statusBars.asPaddingValues().calculateTopPadding()
|
||||
} else {
|
||||
AppBarHeight * fontSizeSqrtMultiplier + WindowInsets.statusBars.asPaddingValues().calculateTopPadding()
|
||||
@@ -1634,7 +1635,7 @@ private fun FloatingDate(
|
||||
val nearBottomIndex = remember(chatModel.chatId) { mutableStateOf(if (isNearBottom.value) -1 else 0) }
|
||||
val showDate = remember(chatModel.chatId) { mutableStateOf(false) }
|
||||
val density = LocalDensity.current.density
|
||||
val topPaddingToContentPx = rememberUpdatedState(with(LocalDensity.current) { topPaddingToContent().roundToPx() })
|
||||
val topPaddingToContentPx = rememberUpdatedState(with(LocalDensity.current) { topPaddingToContent(true).roundToPx() })
|
||||
val fontSizeSqrtMultiplier = fontSizeSqrtMultiplier
|
||||
val lastVisibleItemDate = remember {
|
||||
derivedStateOf {
|
||||
|
||||
+1
-1
@@ -306,7 +306,7 @@ fun ModalData.GroupChatInfoLayout(
|
||||
contentPadding = if (oneHandUI.value) {
|
||||
PaddingValues(top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding() + DEFAULT_PADDING + 5.dp, bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding())
|
||||
} else {
|
||||
PaddingValues(top = topPaddingToContent())
|
||||
PaddingValues(top = topPaddingToContent(false))
|
||||
},
|
||||
state = listState
|
||||
) {
|
||||
|
||||
+1
-1
@@ -761,7 +761,7 @@ private fun BoxScope.ChatList(searchText: MutableState<TextFieldValue>, listStat
|
||||
val searchShowingSimplexLink = remember { mutableStateOf(false) }
|
||||
val searchChatFilteredBySimplexLink = remember { mutableStateOf<String?>(null) }
|
||||
val chats = filteredChats(showUnreadAndFavorites, searchShowingSimplexLink, searchChatFilteredBySimplexLink, searchText.value.text, allChats.value.toList())
|
||||
val topPaddingToContent = topPaddingToContent()
|
||||
val topPaddingToContent = topPaddingToContent(false)
|
||||
val blankSpaceSize = if (oneHandUI.value) WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + AppBarHeight * fontSizeSqrtMultiplier else topPaddingToContent
|
||||
LazyColumnWithScrollBar(
|
||||
if (!oneHandUI.value) Modifier.imePadding() else Modifier,
|
||||
|
||||
+1
-1
@@ -194,7 +194,7 @@ private fun ShareList(
|
||||
filteredChats(false, mutableStateOf(false), mutableStateOf(null), search, sorted)
|
||||
}
|
||||
}
|
||||
val topPaddingToContent = topPaddingToContent()
|
||||
val topPaddingToContent = topPaddingToContent(false)
|
||||
LazyColumnWithScrollBar(
|
||||
modifier = Modifier.then(if (oneHandUI.value) Modifier.consumeWindowInsets(WindowInsets.navigationBars.only(WindowInsetsSides.Vertical)) else Modifier).imePadding(),
|
||||
contentPadding = PaddingValues(
|
||||
|
||||
+2
-2
@@ -334,7 +334,7 @@ private fun ModalData.NewChatSheetLayout(
|
||||
|
||||
@Composable
|
||||
fun NonOneHandLazyColumn() {
|
||||
val blankSpaceSize = topPaddingToContent()
|
||||
val blankSpaceSize = topPaddingToContent(false)
|
||||
LazyColumnWithScrollBar(
|
||||
Modifier.imePadding(),
|
||||
state = listState,
|
||||
@@ -646,7 +646,7 @@ private fun ModalData.DeletedContactsView(rh: RemoteHostInfo?, closeDeletedChats
|
||||
)
|
||||
|
||||
Box {
|
||||
val topPaddingToContent = topPaddingToContent()
|
||||
val topPaddingToContent = topPaddingToContent(false)
|
||||
LazyColumnWithScrollBar(
|
||||
if (!oneHandUI.value) Modifier.imePadding() else Modifier,
|
||||
contentPadding = PaddingValues(
|
||||
|
||||
+1
-1
@@ -400,7 +400,7 @@ fun ActiveProfilePicker(
|
||||
.fillMaxSize()
|
||||
.alpha(if (progressByTimeout) 0.6f else 1f)
|
||||
) {
|
||||
LazyColumnWithScrollBar(Modifier.padding(top = topPaddingToContent()), userScrollEnabled = !switchingProfile.value) {
|
||||
LazyColumnWithScrollBar(Modifier.padding(top = topPaddingToContent(false)), userScrollEnabled = !switchingProfile.value) {
|
||||
item {
|
||||
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||
if (oneHandUI.value) {
|
||||
|
||||
@@ -1396,7 +1396,8 @@
|
||||
<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">Reachable chat toolbar</string>
|
||||
<string name="one_hand_ui">Reachable app toolbars</string>
|
||||
<string name="chat_bottom_bar">Reachable chat toolbar</string>
|
||||
<string name="one_hand_ui_card_title">Toggle chat list:</string>
|
||||
<string name="one_hand_ui_change_instruction">You can change it in Appearance settings.</string>
|
||||
<string name="terminal_always_visible">Show console in new window</string>
|
||||
|
||||
+8
-5
@@ -36,6 +36,7 @@ actual fun LazyColumnWithScrollBar(
|
||||
flingBehavior: FlingBehavior,
|
||||
userScrollEnabled: Boolean,
|
||||
additionalBarOffset: State<Dp>?,
|
||||
chatBottomBar: State<Boolean>,
|
||||
fillMaxSize: Boolean,
|
||||
content: LazyListScope.() -> Unit
|
||||
) {
|
||||
@@ -92,7 +93,7 @@ actual fun LazyColumnWithScrollBar(
|
||||
val modifier = if (fillMaxSize) Modifier.fillMaxSize().then(modifier) else modifier
|
||||
Box(Modifier.copyViewToAppBar(remember { appPrefs.appearanceBarsBlurRadius.state }.value, LocalAppBarHandler.current?.graphicsLayer).nestedScroll(connection)) {
|
||||
LazyColumn(modifier.then(scrollModifier), state, contentPadding, reverseLayout, verticalArrangement, horizontalAlignment, flingBehavior, userScrollEnabled, content)
|
||||
ScrollBar(reverseLayout, state, scrollBarAlpha, scrollJob, scrollBarDraggingState, additionalBarOffset)
|
||||
ScrollBar(reverseLayout, state, scrollBarAlpha, scrollJob, scrollBarDraggingState, additionalBarOffset, chatBottomBar)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,6 +108,7 @@ actual fun LazyColumnWithScrollBarNoAppBar(
|
||||
flingBehavior: FlingBehavior,
|
||||
userScrollEnabled: Boolean,
|
||||
additionalBarOffset: State<Dp>?,
|
||||
chatBottomBar: State<Boolean>,
|
||||
content: LazyListScope.() -> Unit
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
@@ -133,7 +135,7 @@ actual fun LazyColumnWithScrollBarNoAppBar(
|
||||
val scrollBarDraggingState = remember { mutableStateOf(false) }
|
||||
Box {
|
||||
LazyColumn(modifier.then(scrollModifier), state, contentPadding, reverseLayout, verticalArrangement, horizontalAlignment, flingBehavior, userScrollEnabled, content)
|
||||
ScrollBar(reverseLayout, state, scrollBarAlpha, scrollJob, scrollBarDraggingState, additionalBarOffset)
|
||||
ScrollBar(reverseLayout, state, scrollBarAlpha, scrollJob, scrollBarDraggingState, additionalBarOffset, chatBottomBar)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,15 +146,16 @@ private fun ScrollBar(
|
||||
scrollBarAlpha: Animatable<Float, AnimationVector1D>,
|
||||
scrollJob: MutableState<Job>,
|
||||
scrollBarDraggingState: MutableState<Boolean>,
|
||||
additionalBarHeight: State<Dp>?
|
||||
additionalBarHeight: State<Dp>?,
|
||||
chatBottomBar: State<Boolean>,
|
||||
) {
|
||||
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||
val padding = if (additionalBarHeight != null) {
|
||||
PaddingValues(top = if (oneHandUI.value) 0.dp else AppBarHeight * fontSizeSqrtMultiplier, bottom = additionalBarHeight.value)
|
||||
PaddingValues(top = if (oneHandUI.value && chatBottomBar.value) 0.dp else AppBarHeight * fontSizeSqrtMultiplier, bottom = additionalBarHeight.value)
|
||||
} else if (reverseLayout) {
|
||||
PaddingValues(bottom = AppBarHeight * fontSizeSqrtMultiplier)
|
||||
} else {
|
||||
PaddingValues(top = if (oneHandUI.value) 0.dp else AppBarHeight * fontSizeSqrtMultiplier)
|
||||
PaddingValues(top = if (oneHandUI.value && chatBottomBar.value) 0.dp else AppBarHeight * fontSizeSqrtMultiplier)
|
||||
}
|
||||
Box(Modifier.fillMaxSize().padding(padding), contentAlignment = Alignment.CenterEnd) {
|
||||
DesktopScrollBar(rememberScrollbarAdapter(state), Modifier.fillMaxHeight(), scrollBarAlpha, scrollJob, reverseLayout, scrollBarDraggingState)
|
||||
|
||||
+3
@@ -58,6 +58,9 @@ fun AppearanceScope.AppearanceLayout(
|
||||
}
|
||||
}
|
||||
SettingsPreferenceItem(icon = null, stringResource(MR.strings.one_hand_ui), ChatModel.controller.appPrefs.oneHandUI)
|
||||
if (remember { appPrefs.oneHandUI.state }.value && !remember { appPrefs.chatBottomBar.state }.value) {
|
||||
SettingsPreferenceItem(icon = null, stringResource(MR.strings.chat_bottom_bar), ChatModel.controller.appPrefs.chatBottomBar)
|
||||
}
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
ThemesSection(systemDarkTheme)
|
||||
|
||||
@@ -56,7 +56,8 @@ data AppSettings = AppSettings
|
||||
uiDarkColorScheme :: Maybe DarkColorScheme,
|
||||
uiCurrentThemeIds :: Maybe (Map ThemeColorScheme Text),
|
||||
uiThemes :: Maybe [UITheme],
|
||||
oneHandUI :: Maybe Bool
|
||||
oneHandUI :: Maybe Bool,
|
||||
chatBottomBar :: Maybe Bool
|
||||
}
|
||||
deriving (Show)
|
||||
|
||||
@@ -105,7 +106,8 @@ defaultAppSettings =
|
||||
uiDarkColorScheme = Just DCSSimplex,
|
||||
uiCurrentThemeIds = Nothing,
|
||||
uiThemes = Nothing,
|
||||
oneHandUI = Just True
|
||||
oneHandUI = Just True,
|
||||
chatBottomBar = Just True
|
||||
}
|
||||
|
||||
defaultParseAppSettings :: AppSettings
|
||||
@@ -141,7 +143,8 @@ defaultParseAppSettings =
|
||||
uiDarkColorScheme = Nothing,
|
||||
uiCurrentThemeIds = Nothing,
|
||||
uiThemes = Nothing,
|
||||
oneHandUI = Nothing
|
||||
oneHandUI = Nothing,
|
||||
chatBottomBar = Nothing
|
||||
}
|
||||
|
||||
combineAppSettings :: AppSettings -> AppSettings -> AppSettings
|
||||
@@ -177,7 +180,8 @@ combineAppSettings platformDefaults storedSettings =
|
||||
uiDarkColorScheme = p uiDarkColorScheme,
|
||||
uiCurrentThemeIds = p uiCurrentThemeIds,
|
||||
uiThemes = p uiThemes,
|
||||
oneHandUI = p oneHandUI
|
||||
oneHandUI = p oneHandUI,
|
||||
chatBottomBar = p chatBottomBar
|
||||
}
|
||||
where
|
||||
p :: (AppSettings -> Maybe a) -> Maybe a
|
||||
@@ -230,6 +234,7 @@ instance FromJSON AppSettings where
|
||||
uiCurrentThemeIds <- p "uiCurrentThemeIds"
|
||||
uiThemes <- p "uiThemes"
|
||||
oneHandUI <- p "oneHandUI"
|
||||
chatBottomBar <- p "chatBottomBar"
|
||||
pure
|
||||
AppSettings
|
||||
{ appPlatform,
|
||||
@@ -262,7 +267,8 @@ instance FromJSON AppSettings where
|
||||
uiDarkColorScheme,
|
||||
uiCurrentThemeIds,
|
||||
uiThemes,
|
||||
oneHandUI
|
||||
oneHandUI,
|
||||
chatBottomBar
|
||||
}
|
||||
where
|
||||
p key = v .:? key <|> pure Nothing
|
||||
|
||||
Reference in New Issue
Block a user