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:
Stanislav Dmitrenko
2024-12-04 23:49:45 +07:00
committed by GitHub
parent 219381f941
commit ee146cdc7b
18 changed files with 83 additions and 47 deletions
@@ -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
}
}
+4 -1
View File
@@ -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
)
}
}
+3 -1
View File
@@ -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
])
}
@@ -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()
@@ -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()
@@ -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()
)
}
}
@@ -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
)
@@ -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,
@@ -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 {
@@ -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
) {
@@ -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,
@@ -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(
@@ -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(
@@ -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>
@@ -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)
@@ -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)
+11 -5
View File
@@ -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