mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-09-09 11:46:06 +00:00
changes
This commit is contained in:
+7
-3
@@ -6,11 +6,11 @@ import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.Configuration
|
||||
import android.text.BidiFormatter
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.*
|
||||
import androidx.compose.ui.text.font.Font
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
@@ -50,7 +50,11 @@ actual fun windowOrientation(): WindowOrientation = when (mainActivity.get()?.re
|
||||
}
|
||||
|
||||
@Composable
|
||||
actual fun windowWidth(): Dp = LocalConfiguration.current.screenWidthDp.dp
|
||||
actual fun windowWidth(): Dp {
|
||||
val direction = LocalLayoutDirection.current
|
||||
val cutout = WindowInsets.displayCutout.only(WindowInsetsSides.Horizontal).asPaddingValues()
|
||||
return LocalConfiguration.current.screenWidthDp.dp - cutout.calculateStartPadding(direction) - cutout.calculateEndPadding(direction)
|
||||
}
|
||||
|
||||
@Composable
|
||||
actual fun windowHeight(): Dp = LocalConfiguration.current.screenHeightDp.dp
|
||||
|
||||
+4
-2
@@ -9,7 +9,9 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import chat.simplex.common.model.ChatController.appPrefs
|
||||
import chat.simplex.common.ui.theme.DEFAULT_PADDING
|
||||
import chat.simplex.common.views.chatlist.NavigationBarBackground
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import kotlinx.coroutines.flow.filter
|
||||
@@ -101,9 +103,9 @@ actual fun ColumnWithScrollBar(
|
||||
}, verticalArrangement, horizontalAlignment
|
||||
) {
|
||||
if (oneHandUI.value) {
|
||||
Spacer(Modifier.windowInsetsTopHeight(WindowInsets.statusBars))
|
||||
Spacer(Modifier.padding(top = DEFAULT_PADDING + 5.dp).windowInsetsTopHeight(WindowInsets.statusBars))
|
||||
content()
|
||||
Spacer(Modifier.padding(bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + AppBarHeight * fontSizeSqrtMultiplier))
|
||||
Spacer(Modifier.navigationBarsPadding().padding(bottom = AppBarHeight * fontSizeSqrtMultiplier))
|
||||
} else {
|
||||
Spacer(Modifier.statusBarsPadding().padding(top = AppBarHeight * fontSizeSqrtMultiplier))
|
||||
content()
|
||||
|
||||
+9
-5
@@ -47,6 +47,7 @@ import chat.simplex.common.model.ChatController.appPrefs
|
||||
import chat.simplex.common.platform.*
|
||||
import chat.simplex.common.ui.theme.*
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import chat.simplex.common.views.onboarding.OnboardingStage
|
||||
import chat.simplex.res.MR
|
||||
import com.google.accompanist.permissions.*
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
@@ -328,11 +329,14 @@ private fun ActiveCallOverlayLayout(
|
||||
flipCamera: () -> Unit
|
||||
) {
|
||||
Column {
|
||||
CloseSheetBar({ chatModel.activeCallViewIsCollapsed.value = true }, true, tintColor = Color(0xFFFFFFD8)) {
|
||||
if (call.hasVideo) {
|
||||
Text(call.contact.chatViewName, Modifier.fillMaxWidth().padding(end = DEFAULT_PADDING), color = Color(0xFFFFFFD8), style = MaterialTheme.typography.h2, overflow = TextOverflow.Ellipsis, maxLines = 1)
|
||||
}
|
||||
}
|
||||
CallAppBar(
|
||||
title = {
|
||||
if (call.hasVideo) {
|
||||
Text(call.contact.chatViewName, Modifier.offset(x = (-4).dp).padding(end = DEFAULT_PADDING), color = Color(0xFFFFFFD8), style = MaterialTheme.typography.h2, overflow = TextOverflow.Ellipsis, maxLines = 1)
|
||||
}
|
||||
},
|
||||
onBack = { chatModel.activeCallViewIsCollapsed.value = true }
|
||||
)
|
||||
Column(Modifier.padding(horizontal = DEFAULT_PADDING)) {
|
||||
@Composable
|
||||
fun SelectSoundDevice(size: Dp) {
|
||||
|
||||
-3
@@ -120,9 +120,6 @@ fun AppearanceScope.AppearanceLayout(
|
||||
SectionDividerSpaced()
|
||||
BarsAlphaSection(MR.strings.appearance_in_app_bars_alpha, appPrefs.inAppBarsAlpha, 0.95f)
|
||||
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
BarsAlphaSection(MR.strings.appearance_nav_bar_alpha, appPrefs.navBarAlpha, 0.6f)
|
||||
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
ProfileImageSection()
|
||||
|
||||
|
||||
+1
-3
@@ -224,7 +224,6 @@ class AppPreferences {
|
||||
val fontScale = mkFloatPreference(SHARED_PREFS_FONT_SCALE, 1f)
|
||||
val densityScale = mkFloatPreference(SHARED_PREFS_DENSITY_SCALE, 1f)
|
||||
val inAppBarsAlpha = mkFloatPreference(SHARED_PREFS_IN_APP_BARS_ALPHA, 0.95f)
|
||||
val navBarAlpha = mkFloatPreference(SHARED_PREFS_NAV_BAR_ALPHA, 0.6f)
|
||||
|
||||
val whatsNewVersion = mkStrPreference(SHARED_PREFS_WHATS_NEW_VERSION, null)
|
||||
val lastMigratedVersionCode = mkIntPreference(SHARED_PREFS_LAST_MIGRATED_VERSION_CODE, 0)
|
||||
@@ -246,7 +245,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, appPlatform.isAndroid)
|
||||
val oneHandUI = mkBoolPreference(SHARED_PREFS_ONE_HAND_UI, true)
|
||||
|
||||
val hintPreferences: List<Pair<SharedPreference<Boolean>, Boolean>> = listOf(
|
||||
laNoticeShown to false,
|
||||
@@ -431,7 +430,6 @@ class AppPreferences {
|
||||
private const val SHARED_PREFS_FONT_SCALE = "FontScale"
|
||||
private const val SHARED_PREFS_DENSITY_SCALE = "DensityScale"
|
||||
private const val SHARED_PREFS_IN_APP_BARS_ALPHA = "InAppBarsAlpha"
|
||||
private const val SHARED_PREFS_NAV_BAR_ALPHA = "NavBarAlpha"
|
||||
private const val SHARED_PREFS_WHATS_NEW_VERSION = "WhatsNewVersion"
|
||||
private const val SHARED_PREFS_LAST_MIGRATED_VERSION_CODE = "LastMigratedVersionCode"
|
||||
private const val SHARED_PREFS_CUSTOM_DISAPPEARING_MESSAGE_TIME = "CustomDisappearingMessageTime"
|
||||
|
||||
+8
-4
@@ -79,6 +79,7 @@ fun TerminalLayout(
|
||||
fun onMessageChange(s: String) {
|
||||
composeState.value = composeState.value.copy(message = s)
|
||||
}
|
||||
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||
Box(Modifier.fillMaxSize()) {
|
||||
val composeViewHeight = remember { mutableStateOf(0.dp) }
|
||||
AdaptingBottomPaddingLayout(Modifier, CONSOLE_COMPOSE_LAYOUT_ID, composeViewHeight) {
|
||||
@@ -88,8 +89,10 @@ fun TerminalLayout(
|
||||
.layoutId(CONSOLE_COMPOSE_LAYOUT_ID)
|
||||
.align(Alignment.BottomCenter)
|
||||
.navigationBarsPadding()
|
||||
.consumeWindowInsets(PaddingValues(bottom = if (oneHandUI.value) AppBarHeight * fontSizeSqrtMultiplier else 0.dp))
|
||||
.imePadding()
|
||||
.background(MaterialTheme.colors.background.copy(remember { appPrefs.inAppBarsAlpha.state }.value))
|
||||
.padding(bottom = if (oneHandUI.value) AppBarHeight * fontSizeSqrtMultiplier else 0.dp)
|
||||
.background(MaterialTheme.colors.background)
|
||||
) {
|
||||
Divider()
|
||||
Box(Modifier.padding(horizontal = 8.dp)) {
|
||||
@@ -119,8 +122,9 @@ fun TerminalLayout(
|
||||
}
|
||||
}
|
||||
}
|
||||
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||
NavigationBarBackground(true, oneHandUI.value)
|
||||
if (!oneHandUI.value) {
|
||||
NavigationBarBackground(true, oneHandUI.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +180,7 @@ fun TerminalLog(floating: Boolean, composeViewHeight: State<Dp>) {
|
||||
} else {
|
||||
ModalManager.start
|
||||
}
|
||||
modalPlace.showModal(endButtons = { ShareButton { clipboard.shareText(item.details) } }) {
|
||||
modalPlace.showModal(endButtons = listOf { ShareButton { clipboard.shareText(item.details) } }) {
|
||||
ColumnWithScrollBar {
|
||||
SelectionContainer {
|
||||
val details = item.details
|
||||
|
||||
+10
-7
@@ -118,13 +118,16 @@ fun CreateFirstProfile(chatModel: ChatModel, close: () -> Unit) {
|
||||
.themedBackground(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
CloseSheetBar(close = {
|
||||
if (chatModel.users.none { !it.user.hidden }) {
|
||||
appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo)
|
||||
} else {
|
||||
close()
|
||||
}
|
||||
})
|
||||
DefaultTopAppBar(
|
||||
navigationButton = { NavigationButtonBack(onButtonClicked = {
|
||||
if (chatModel.users.none { !it.user.hidden }) {
|
||||
appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo)
|
||||
} else {
|
||||
close()
|
||||
}
|
||||
} ) },
|
||||
onTop = true
|
||||
)
|
||||
BackHandler(onBack = {
|
||||
appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo)
|
||||
})
|
||||
|
||||
+27
-14
@@ -463,7 +463,7 @@ fun ChatView(staleChatId: State<String?>, onComposed: suspend (chatId: String) -
|
||||
withBGApi {
|
||||
var initialCiInfo = loadChatItemInfo() ?: return@withBGApi
|
||||
ModalManager.end.closeModals()
|
||||
ModalManager.end.showModalCloseable(endButtons = {
|
||||
ModalManager.end.showModalCloseable(endButtons = listOf {
|
||||
ShareButton {
|
||||
clipboard.shareText(itemInfoShareText(chatModel, cItem, initialCiInfo, chatModel.controller.appPrefs.developerTools.get()))
|
||||
}
|
||||
@@ -548,7 +548,7 @@ fun ChatView(staleChatId: State<String?>, onComposed: suspend (chatId: String) -
|
||||
CompositionLocalProvider(
|
||||
LocalAppBarHandler provides handler
|
||||
) {
|
||||
ModalView(close, showClose = appPlatform.isAndroid, endButtons = { ShareButton { clipboard.shareText(chatInfo.json) } }, content = {
|
||||
ModalView(close, showClose = appPlatform.isAndroid, endButtons = listOf { ShareButton { clipboard.shareText(chatInfo.json) } }, content = {
|
||||
InvalidJSONView(chatInfo.json)
|
||||
})
|
||||
LaunchedEffect(chatInfo.id) {
|
||||
@@ -678,18 +678,24 @@ fun ChatLayout(
|
||||
}
|
||||
}
|
||||
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||
Box(Modifier
|
||||
.layoutId(CHAT_COMPOSE_LAYOUT_ID)
|
||||
.align(Alignment.BottomCenter)
|
||||
.imePadding()
|
||||
.then(if (oneHandUI.value) Modifier.padding(bottom = AppBarHeight * fontSizeSqrtMultiplier) else Modifier.navigationBarsPadding())
|
||||
Box(
|
||||
Modifier
|
||||
.layoutId(CHAT_COMPOSE_LAYOUT_ID)
|
||||
.align(Alignment.BottomCenter)
|
||||
.imePadding()
|
||||
.navigationBarsPadding()
|
||||
.then(if (oneHandUI.value) Modifier.padding(bottom = AppBarHeight * fontSizeSqrtMultiplier) else Modifier)
|
||||
) {
|
||||
composeView()
|
||||
}
|
||||
}
|
||||
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||
NavigationBarBackground(true, oneHandUI.value)
|
||||
Box(if (oneHandUI.value) Modifier.align(Alignment.BottomStart).navigationBarsPadding() else Modifier) {
|
||||
if (oneHandUI.value) {
|
||||
StatusBarBackground()
|
||||
} else {
|
||||
NavigationBarBackground(true, oneHandUI.value)
|
||||
}
|
||||
Box(if (oneHandUI.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)
|
||||
@@ -862,22 +868,29 @@ fun BoxScope.ChatInfoToolbar(
|
||||
title = { ChatInfoToolbarTitle(chatInfo) },
|
||||
onTitleClick = if (chatInfo is ChatInfo.Local) null else info,
|
||||
showSearch = showSearch.value,
|
||||
onTop = oneHandUI.value,
|
||||
onTop = !oneHandUI.value,
|
||||
onSearchValueChanged = onSearchValueChanged,
|
||||
buttons = barButtons
|
||||
)
|
||||
Box(Modifier.fillMaxWidth().wrapContentSize(Alignment.TopEnd)) {
|
||||
val density = LocalDensity.current
|
||||
val width = remember { mutableStateOf(250.dp) }
|
||||
val height = remember { mutableStateOf(0.dp) }
|
||||
DefaultDropdownMenu(
|
||||
showMenu,
|
||||
modifier = Modifier.onSizeChanged { with(density) { width.value = it.width.toDp().coerceAtLeast(250.dp) } },
|
||||
offset = DpOffset(-width.value, AppBarHeight)
|
||||
modifier = Modifier.onSizeChanged { with(density) {
|
||||
width.value = it.width.toDp().coerceAtLeast(250.dp)
|
||||
if (oneHandUI.value) height.value = it.height.toDp()
|
||||
} },
|
||||
offset = DpOffset(-width.value, if (oneHandUI.value) -height.value else AppBarHeight)
|
||||
) {
|
||||
menuItems.forEach { it() }
|
||||
if (oneHandUI.value) {
|
||||
menuItems.asReversed().forEach { it() }
|
||||
} else {
|
||||
menuItems.forEach { it() }
|
||||
}
|
||||
}
|
||||
}
|
||||
Divider(Modifier.background(MaterialTheme.colors.background).align(if (oneHandUI.value) Alignment.TopStart else Alignment.BottomStart))
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
||||
+2
-1
@@ -13,6 +13,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.layout.onSizeChanged
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import dev.icerock.moko.resources.compose.painterResource
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
@@ -897,7 +898,7 @@ fun ComposeView(
|
||||
}
|
||||
}
|
||||
}
|
||||
Column(Modifier.background(MaterialTheme.colors.background.copy(remember { appPrefs.inAppBarsAlpha.state }.value))) {
|
||||
Box(Modifier.background(MaterialTheme.colors.background).onSizeChanged { println("LALAL SIZE0 $it") }) {
|
||||
Divider()
|
||||
Row(Modifier.padding(end = 8.dp), verticalAlignment = Alignment.Bottom) {
|
||||
val isGroupAndProhibitedFiles = chat.chatInfo is ChatInfo.Group && !chat.chatInfo.groupInfo.fullGroupPreferences.files.on(chat.chatInfo.groupInfo.membership)
|
||||
|
||||
+1
-3
@@ -41,11 +41,9 @@ fun BoxScope.SelectedItemsTopToolbar(selectedChatItems: MutableState<Set<Long>?>
|
||||
)
|
||||
},
|
||||
onTitleClick = null,
|
||||
showSearch = false,
|
||||
onTop = oneHandUI.value,
|
||||
onTop = !oneHandUI.value,
|
||||
onSearchValueChanged = {},
|
||||
)
|
||||
Divider(Modifier.align(if (oneHandUI.value) Alignment.TopStart else Alignment.BottomStart))
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
||||
+3
-1
@@ -14,6 +14,7 @@ import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.*
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.layout.onSizeChanged
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.unit.*
|
||||
@@ -60,7 +61,8 @@ fun SendMsgView(
|
||||
) {
|
||||
val showCustomDisappearingMessageDialog = remember { mutableStateOf(false) }
|
||||
|
||||
Box(Modifier.padding(vertical = if (appPlatform.isAndroid) 8.dp else 6.dp)) {
|
||||
val padding = if (appPlatform.isAndroid) PaddingValues(vertical = 8.dp) else PaddingValues(top = 3.dp, bottom = 4.dp)
|
||||
Box(Modifier.padding(padding)) {
|
||||
val cs = composeState.value
|
||||
var progressByTimeout by rememberSaveable { mutableStateOf(false) }
|
||||
LaunchedEffect(composeState.value.inProgress) {
|
||||
|
||||
+6
-1
@@ -285,9 +285,15 @@ fun ModalData.GroupChatInfoLayout(
|
||||
}
|
||||
}
|
||||
Box {
|
||||
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||
LazyColumnWithScrollBar(
|
||||
Modifier
|
||||
.fillMaxWidth(),
|
||||
contentPadding = if (oneHandUI.value) {
|
||||
PaddingValues(top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding() + DEFAULT_PADDING + 5.dp, bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding())
|
||||
} else {
|
||||
PaddingValues()
|
||||
},
|
||||
state = listState
|
||||
) {
|
||||
item {
|
||||
@@ -402,7 +408,6 @@ fun ModalData.GroupChatInfoLayout(
|
||||
Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
|
||||
}
|
||||
}
|
||||
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||
NavigationBarBackground(oneHandUI.value, oneHandUI.value)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ fun CIInvalidJSONView(json: String) {
|
||||
.clickable {
|
||||
ModalManager.center.closeModals()
|
||||
ModalManager.end.closeModals()
|
||||
ModalManager.center.showModal(true, endButtons = { ShareButton { clipboard.shareText(json) } }) { InvalidJSONView(json) }
|
||||
ModalManager.center.showModal(true, endButtons = listOf { ShareButton { clipboard.shareText(json) } }) { InvalidJSONView(json) }
|
||||
}
|
||||
.padding(horizontal = 10.dp, vertical = 6.dp)
|
||||
) {
|
||||
|
||||
+33
-25
@@ -12,8 +12,12 @@ import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.*
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.focus.*
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.*
|
||||
import androidx.compose.ui.layout.onSizeChanged
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.platform.*
|
||||
import androidx.compose.ui.text.TextRange
|
||||
@@ -149,26 +153,27 @@ fun ChatListView(chatModel: ChatModel, userPickerState: MutableStateFlow<Animate
|
||||
}
|
||||
}
|
||||
val searchText = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) }
|
||||
val listState = rememberLazyListState(lazyListState.first, lazyListState.second)
|
||||
Box(Modifier.fillMaxSize()) {
|
||||
if (oneHandUI.value) {
|
||||
ChatListWithLoadingScreen(searchText)
|
||||
ChatListWithLoadingScreen(searchText, listState)
|
||||
Column(Modifier.align(Alignment.BottomCenter)) {
|
||||
Divider()
|
||||
ChatListToolbar(
|
||||
userPickerState,
|
||||
listState,
|
||||
stopped,
|
||||
setPerformLA,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
ChatListWithLoadingScreen(searchText)
|
||||
ChatListWithLoadingScreen(searchText, listState)
|
||||
Column {
|
||||
ChatListToolbar(
|
||||
userPickerState,
|
||||
listState,
|
||||
stopped,
|
||||
setPerformLA,
|
||||
)
|
||||
Divider()
|
||||
}
|
||||
if (searchText.value.text.isEmpty() && !chatModel.desktopNoUserNoRemote && chatModel.chatRunning.value == true) {
|
||||
NewChatSheetFloatingButton(oneHandUI, stopped)
|
||||
@@ -196,9 +201,9 @@ fun ChatListView(chatModel: ChatModel, userPickerState: MutableStateFlow<Animate
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BoxScope.ChatListWithLoadingScreen(searchText: MutableState<TextFieldValue>) {
|
||||
private fun BoxScope.ChatListWithLoadingScreen(searchText: MutableState<TextFieldValue>, listState: LazyListState) {
|
||||
if (!chatModel.desktopNoUserNoRemote) {
|
||||
ChatList(searchText = searchText)
|
||||
ChatList(searchText = searchText, listState)
|
||||
}
|
||||
if (chatModel.chats.value.isEmpty() && !chatModel.switchingUsersAndHosts.value && !chatModel.desktopNoUserNoRemote) {
|
||||
Text(
|
||||
@@ -252,7 +257,7 @@ private fun ConnectButton(text: String, onClick: () -> Unit) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ChatListToolbar(userPickerState: MutableStateFlow<AnimatedViewState>, stopped: Boolean, setPerformLA: (Boolean) -> Unit) {
|
||||
private fun ChatListToolbar(userPickerState: MutableStateFlow<AnimatedViewState>, listState: LazyListState, stopped: Boolean, setPerformLA: (Boolean) -> Unit) {
|
||||
val serversSummary: MutableState<PresentedServersSummary?> = remember { mutableStateOf(null) }
|
||||
val barButtons = arrayListOf<@Composable RowScope.() -> Unit>()
|
||||
val updatingProgress = remember { chatModel.updatingProgress }.value
|
||||
@@ -319,6 +324,8 @@ private fun ChatListToolbar(userPickerState: MutableStateFlow<AnimatedViewState>
|
||||
}
|
||||
}
|
||||
val clipboard = LocalClipboardManager.current
|
||||
val scope = rememberCoroutineScope()
|
||||
val canScrollToZero = remember { derivedStateOf { listState.firstVisibleItemIndex != 0 || listState.firstVisibleItemScrollOffset != 0 } }
|
||||
DefaultTopAppBar(
|
||||
navigationButton = {
|
||||
if (chatModel.users.isEmpty() && !chatModel.desktopNoUserNoRemote) {
|
||||
@@ -347,27 +354,25 @@ private fun ChatListToolbar(userPickerState: MutableStateFlow<AnimatedViewState>
|
||||
SubscriptionStatusIndicator(
|
||||
click = {
|
||||
ModalManager.start.closeModals()
|
||||
val summary = serversSummary.value
|
||||
ModalManager.start.showModalCloseable(
|
||||
endButtons = {
|
||||
val summary = serversSummary.value
|
||||
if (summary != null) {
|
||||
endButtons = if (summary != null) {
|
||||
listOf {
|
||||
ShareButton {
|
||||
val json = Json {
|
||||
prettyPrint = true
|
||||
}
|
||||
|
||||
val text = json.encodeToString(PresentedServersSummary.serializer(), summary)
|
||||
clipboard.shareText(text)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else emptyList()
|
||||
) { ServersSummaryView(chatModel.currentRemoteHost.value, serversSummary) }
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
onTitleClick = null,
|
||||
showSearch = false,
|
||||
onTitleClick = if (canScrollToZero.value) { { scrollToBottom(scope, listState) } } else null,
|
||||
onTop = !oneHandUI.value,
|
||||
onSearchValueChanged = {},
|
||||
buttons = barButtons
|
||||
@@ -489,7 +494,7 @@ fun connectIfOpenedViaUri(rhId: Long?, uri: String, chatModel: ChatModel) {
|
||||
@Composable
|
||||
private fun ChatListSearchBar(listState: LazyListState, searchText: MutableState<TextFieldValue>, searchShowingSimplexLink: MutableState<Boolean>, searchChatFilteredBySimplexLink: MutableState<String?>) {
|
||||
Box {
|
||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth().heightIn(min = AppBarHeight * fontSizeSqrtMultiplier)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth().onSizeChanged { println("LALAL SIZE-1 $it") }) {
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
var focused by remember { mutableStateOf(false) }
|
||||
Icon(
|
||||
@@ -593,19 +598,18 @@ enum class ScrollDirection {
|
||||
@Composable
|
||||
fun BoxScope.StatusBarBackground() {
|
||||
if (appPlatform.isAndroid) {
|
||||
val finalColor = MaterialTheme.colors.background.copy(remember { appPrefs.inAppBarsAlpha.state }.value)
|
||||
val finalColor = MaterialTheme.colors.background.copy(0.88f)
|
||||
Box(Modifier.fillMaxWidth().windowInsetsTopHeight(WindowInsets.statusBars).background(finalColor))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BoxScope.NavigationBarBackground(appBarOnBottom: Boolean = false, mixedColor: Boolean) {
|
||||
val keyboardState = getKeyboardState()
|
||||
if (appPlatform.isAndroid && keyboardState.value == KeyboardState.Closed) {
|
||||
if (appPlatform.isAndroid) {
|
||||
val barPadding = WindowInsets.navigationBars.asPaddingValues()
|
||||
val paddingBottom = barPadding.calculateBottomPadding()
|
||||
val color = if (mixedColor) MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, 0.97f) else MaterialTheme.colors.background
|
||||
val finalColor = color.copy(remember(appBarOnBottom) { if (appBarOnBottom) appPrefs.inAppBarsAlpha.state else appPrefs.navBarAlpha.state }.value)
|
||||
val finalColor = color.copy(if (appBarOnBottom) remember { appPrefs.inAppBarsAlpha.state }.value else 0.6f)
|
||||
Box(Modifier.align(Alignment.BottomStart).height(paddingBottom).fillMaxWidth().background(finalColor))
|
||||
}
|
||||
}
|
||||
@@ -616,14 +620,13 @@ fun BoxScope.NavigationBarBackground(modifier: Modifier, color: Color = Material
|
||||
if (appPlatform.isAndroid && keyboardState.value == KeyboardState.Closed) {
|
||||
val barPadding = WindowInsets.navigationBars.asPaddingValues()
|
||||
val paddingBottom = barPadding.calculateBottomPadding()
|
||||
val finalColor = color.copy(remember { appPrefs.navBarAlpha.state }.value)
|
||||
val finalColor = color.copy(0.6f)
|
||||
Box(modifier.align(Alignment.BottomStart).height(paddingBottom).fillMaxWidth().background(finalColor))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BoxScope.ChatList(searchText: MutableState<TextFieldValue>) {
|
||||
val listState = rememberLazyListState(lazyListState.first, lazyListState.second)
|
||||
private fun BoxScope.ChatList(searchText: MutableState<TextFieldValue>, listState: LazyListState) {
|
||||
var scrollDirection by remember { mutableStateOf(ScrollDirection.Idle) }
|
||||
var previousIndex by remember { mutableStateOf(0) }
|
||||
var previousScrollOffset by remember { mutableStateOf(0) }
|
||||
@@ -698,7 +701,7 @@ private fun BoxScope.ChatList(searchText: MutableState<TextFieldValue>) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (appPlatform.isAndroid && !oneHandUICardShown.value && chats.count() > 1) {
|
||||
if (!oneHandUICardShown.value && chats.size > 1) {
|
||||
item {
|
||||
ToggleChatListCard()
|
||||
}
|
||||
@@ -709,7 +712,7 @@ private fun BoxScope.ChatList(searchText: MutableState<TextFieldValue>) {
|
||||
} }
|
||||
ChatListNavLinkView(chat, nextChatSelected)
|
||||
}
|
||||
if (appPlatform.isAndroid && !oneHandUICardShown.value && chats.count() <= 1) {
|
||||
if (!oneHandUICardShown.value && chats.size <= 1) {
|
||||
item {
|
||||
ToggleChatListCard()
|
||||
}
|
||||
@@ -725,8 +728,9 @@ private fun BoxScope.ChatList(searchText: MutableState<TextFieldValue>) {
|
||||
}
|
||||
if (oneHandUI.value) {
|
||||
StatusBarBackground()
|
||||
} else {
|
||||
NavigationBarBackground(oneHandUI.value, true)
|
||||
}
|
||||
NavigationBarBackground(oneHandUI.value, true)
|
||||
}
|
||||
|
||||
fun filteredChats(
|
||||
@@ -771,3 +775,7 @@ private fun filtered(chat: Chat): Boolean =
|
||||
(chat.chatInfo.chatSettings?.favorite ?: false) ||
|
||||
chat.chatStats.unreadChat ||
|
||||
(chat.chatInfo.ntfsEnabled && chat.chatStats.unreadCount > 0)
|
||||
|
||||
fun scrollToBottom(scope: CoroutineScope, listState: LazyListState) {
|
||||
scope.launch { try { listState.animateScrollToItem(0) } catch (e: Exception) { Log.e(TAG, e.stackTraceToString()) } }
|
||||
}
|
||||
|
||||
+7
-10
@@ -27,16 +27,12 @@ fun ShareListView(chatModel: ChatModel, stopped: Boolean) {
|
||||
contentColor = LocalContentColor.current,
|
||||
topBar = {
|
||||
if (!oneHandUI.value) {
|
||||
Column {
|
||||
ShareListToolbar(chatModel, stopped) { searchInList = it.trim() }
|
||||
Divider()
|
||||
}
|
||||
ShareListToolbar(chatModel, stopped) { searchInList = it.trim() }
|
||||
}
|
||||
},
|
||||
bottomBar = {
|
||||
if (oneHandUI.value) {
|
||||
Column(Modifier.imePadding()) {
|
||||
Divider()
|
||||
Box(Modifier.imePadding()) {
|
||||
ShareListToolbar(chatModel, stopped) { searchInList = it.trim() }
|
||||
}
|
||||
}
|
||||
@@ -83,8 +79,9 @@ fun ShareListView(chatModel: ChatModel, stopped: Boolean) {
|
||||
}
|
||||
if (oneHandUI.value) {
|
||||
StatusBarBackground()
|
||||
} else {
|
||||
NavigationBarBackground(oneHandUI.value, true)
|
||||
}
|
||||
NavigationBarBackground(oneHandUI.value, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -122,9 +119,9 @@ private fun ShareListToolbar(chatModel: ChatModel, stopped: Boolean, onSearchVal
|
||||
val search = rememberSaveable { mutableStateOf("") }
|
||||
ModalView(
|
||||
{ close() },
|
||||
endButtons = {
|
||||
SearchTextField(Modifier.fillMaxWidth(), placeholder = stringResource(MR.strings.search_verb), alwaysVisible = true) { search.value = it }
|
||||
},
|
||||
showSearch = true,
|
||||
searchAlwaysVisible = true,
|
||||
onSearchValueChanged = { search.value = it },
|
||||
content = {
|
||||
ActiveProfilePicker(
|
||||
search = search,
|
||||
|
||||
+4
-2
@@ -277,8 +277,10 @@ fun UserPicker(
|
||||
val profileHidden = rememberSaveable { mutableStateOf(false) }
|
||||
ModalView(
|
||||
{ close() },
|
||||
endButtons = {
|
||||
SearchTextField(Modifier.fillMaxWidth(), placeholder = stringResource(MR.strings.search_verb), alwaysVisible = true) { search.value = it }
|
||||
showSearch = true,
|
||||
searchAlwaysVisible = true,
|
||||
onSearchValueChanged = {
|
||||
search.value = it
|
||||
},
|
||||
content = { UserProfilesView(chatModel, search, profileHidden) })
|
||||
}
|
||||
|
||||
+3
-22
@@ -31,7 +31,7 @@ fun CloseSheetBar(
|
||||
barPaddingValues: PaddingValues = PaddingValues(horizontal = AppBarHorizontalPadding),
|
||||
endButtons: @Composable RowScope.() -> Unit = {}
|
||||
) {
|
||||
val background = MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, 0.97f)
|
||||
/*val background = MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, 0.97f)
|
||||
val prefAlpha = remember { appPrefs.inAppBarsAlpha.state }.value
|
||||
val themeBackgroundMix = background.copy(prefAlpha)
|
||||
val handler = LocalAppBarHandler.current
|
||||
@@ -44,7 +44,7 @@ fun CloseSheetBar(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.then(if (oneHandUI.value) Modifier.navigationBarsPadding() else Modifier)
|
||||
.clickable(interactionSource = interactionSource, indication = null) { /* receive clicks to not allow to click through */ }
|
||||
.clickable(interactionSource = interactionSource, indication = null) { *//* receive clicks to not allow to click through *//* }
|
||||
.heightIn(min = AppBarHeight * fontSizeSqrtMultiplier)
|
||||
.drawWithCache {
|
||||
val backgroundColor = if (connection != null) themeBackgroundMix.copy(alpha = if (oneHandUI.value) prefAlpha else topTitleAlpha(false, connection)) else Color.Transparent
|
||||
@@ -94,22 +94,7 @@ fun CloseSheetBar(
|
||||
}
|
||||
)
|
||||
CloseBarDivider(connection)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BoxScope.CloseBarDivider(connection: CollapsingAppBarNestedScrollConnection?) {
|
||||
if (connection != null) {
|
||||
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||
val prefAlpha = appPrefs.inAppBarsAlpha.get()
|
||||
Divider(
|
||||
Modifier
|
||||
.align(if (oneHandUI.value) Alignment.TopStart else Alignment.BottomStart)
|
||||
.graphicsLayer {
|
||||
alpha = if (oneHandUI.value) prefAlpha else topTitleAlpha(false, connection)
|
||||
}
|
||||
)
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -196,10 +181,6 @@ fun AppBarTitle(title: String, hostDevice: Pair<Long?, String>? = null, withPad
|
||||
}
|
||||
}
|
||||
|
||||
private fun topTitleAlpha(text: Boolean, connection: CollapsingAppBarNestedScrollConnection) =
|
||||
if (connection.appBarOffset.absoluteValue < AppBarHandler.appBarMaxHeightPx / 3) 0f
|
||||
else ((-connection.appBarOffset * 1.5f) / (AppBarHandler.appBarMaxHeightPx)).coerceIn(0f, if (text) 1f else appPrefs.inAppBarsAlpha.get())
|
||||
|
||||
private fun bottomTitleAlpha(connection: CollapsingAppBarNestedScrollConnection?) =
|
||||
if ((connection?.appBarOffset ?: 0f).absoluteValue < AppBarHandler.appBarMaxHeightPx / 3) 1f
|
||||
else ((AppBarHandler.appBarMaxHeightPx) + (connection?.appBarOffset ?: 0f) / 1.5f).coerceAtLeast(0f) / AppBarHandler.appBarMaxHeightPx
|
||||
|
||||
+111
-26
@@ -3,27 +3,34 @@ package chat.simplex.common.views.helpers
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawWithCache
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.*
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import dev.icerock.moko.resources.compose.painterResource
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import chat.simplex.common.model.ChatController.appPrefs
|
||||
import chat.simplex.common.ui.theme.*
|
||||
import chat.simplex.common.views.chatlist.NavigationBarBackground
|
||||
import chat.simplex.res.MR
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
@Composable
|
||||
fun DefaultTopAppBar(
|
||||
navigationButton: (@Composable RowScope.() -> Unit)? = null,
|
||||
title: (@Composable () -> Unit)?,
|
||||
title: (@Composable () -> Unit)? = null,
|
||||
fixedTitleText: String? = null,
|
||||
onTitleClick: (() -> Unit)? = null,
|
||||
showSearch: Boolean,
|
||||
onTop: Boolean,
|
||||
onSearchValueChanged: (String) -> Unit,
|
||||
showSearch: Boolean = false,
|
||||
searchAlwaysVisible: Boolean = false,
|
||||
onSearchValueChanged: (String) -> Unit = {},
|
||||
buttons: List<@Composable RowScope.() -> Unit> = emptyList(),
|
||||
) {
|
||||
// If I just disable clickable modifier when don't need it, it will stop passing clicks to search. Replacing the whole modifier
|
||||
@@ -31,21 +38,83 @@ fun DefaultTopAppBar(
|
||||
Modifier.clickable(enabled = onTitleClick != null, onClick = onTitleClick ?: { })
|
||||
} else Modifier
|
||||
|
||||
val background = MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, 0.97f)
|
||||
val prefAlpha = remember { appPrefs.inAppBarsAlpha.state }.value
|
||||
val themeBackgroundMix = background.copy(prefAlpha)
|
||||
val handler = LocalAppBarHandler.current
|
||||
val connection = LocalAppBarHandler.current?.connection
|
||||
val titleText = remember(handler?.title?.value, fixedTitleText) {
|
||||
if (fixedTitleText != null) {
|
||||
mutableStateOf(fixedTitleText)
|
||||
} else {
|
||||
handler?.title ?: mutableStateOf("")
|
||||
}
|
||||
}
|
||||
Box(modifier) {
|
||||
if (!onTop) {
|
||||
NavigationBarBackground(true, true)
|
||||
}
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.then(if (!onTop) Modifier.navigationBarsPadding() else Modifier)
|
||||
.heightIn(min = AppBarHeight * fontSizeSqrtMultiplier)
|
||||
.drawWithCache {
|
||||
val backgroundColor = if (connection != null && onTop) {
|
||||
themeBackgroundMix.copy(topTitleAlpha(false, connection))
|
||||
} else if (title != null || fixedTitleText != null || connection != null) {
|
||||
themeBackgroundMix.copy(prefAlpha)
|
||||
} else {
|
||||
Color.Transparent
|
||||
}
|
||||
onDrawBehind {
|
||||
drawRect(backgroundColor)
|
||||
}
|
||||
}
|
||||
) {
|
||||
TopAppBar(
|
||||
title = {
|
||||
if (showSearch) {
|
||||
SearchTextField(Modifier.fillMaxWidth(), alwaysVisible = searchAlwaysVisible, onValueChange = onSearchValueChanged)
|
||||
} else if (title != null) {
|
||||
title()
|
||||
} else if (titleText.value.isNotEmpty() && connection != null) {
|
||||
Row(
|
||||
Modifier
|
||||
.graphicsLayer {
|
||||
alpha = if (fixedTitleText != null) prefAlpha else topTitleAlpha(true, connection)
|
||||
}
|
||||
) {
|
||||
Text(
|
||||
titleText.value,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
navigationIcon = navigationButton,
|
||||
buttons = if (!showSearch) buttons else emptyList(),
|
||||
centered = !showSearch && (title != null || !onTop),
|
||||
onTop = onTop,
|
||||
)
|
||||
CloseBarDivider(onTop, connection)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun CallAppBar(
|
||||
title: @Composable () -> Unit,
|
||||
onBack: () -> Unit
|
||||
) {
|
||||
TopAppBar(
|
||||
modifier = modifier,
|
||||
title = {
|
||||
if (!showSearch) {
|
||||
title?.invoke()
|
||||
} else {
|
||||
SearchTextField(Modifier.fillMaxWidth(), alwaysVisible = false, onValueChange = onSearchValueChanged)
|
||||
}
|
||||
},
|
||||
backgroundColor = MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, 0.97f)
|
||||
.copy(remember { appPrefs.inAppBarsAlpha.state }.value),
|
||||
navigationIcon = navigationButton,
|
||||
buttons = if (!showSearch) buttons else emptyList(),
|
||||
centered = !showSearch,
|
||||
onTop = onTop,
|
||||
title,
|
||||
navigationIcon = { NavigationButtonBack(tintColor = Color(0xFFFFFFD8), onButtonClicked = onBack) },
|
||||
centered = false,
|
||||
onTop = true
|
||||
)
|
||||
}
|
||||
|
||||
@@ -87,23 +156,36 @@ fun NavigationButtonMenu(onButtonClicked: () -> Unit) {
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BoxScope.CloseBarDivider(onTop: Boolean, connection: CollapsingAppBarNestedScrollConnection?) {
|
||||
if (connection != null) {
|
||||
val prefAlpha = appPrefs.inAppBarsAlpha.get()
|
||||
Divider(
|
||||
Modifier
|
||||
.align(if (onTop) Alignment.BottomStart else Alignment.TopStart)
|
||||
.graphicsLayer {
|
||||
alpha = if (!onTop) prefAlpha else topTitleAlpha(false, connection)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
Divider(Modifier.align(if (onTop) Alignment.BottomStart else Alignment.TopStart))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TopAppBar(
|
||||
title: @Composable () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
navigationIcon: @Composable (RowScope.() -> Unit)? = null,
|
||||
buttons: List<@Composable RowScope.() -> Unit> = emptyList(),
|
||||
backgroundColor: Color = MaterialTheme.colors.primarySurface,
|
||||
centered: Boolean,
|
||||
onTop: Boolean,
|
||||
) {
|
||||
Box(
|
||||
modifier
|
||||
.fillMaxWidth()
|
||||
.then(if (!onTop) Modifier.navigationBarsPadding() else Modifier)
|
||||
.background(backgroundColor)
|
||||
.then(if (onTop) Modifier.statusBarsPadding() else Modifier)
|
||||
.height(AppBarHeight * fontSizeSqrtMultiplier)
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 4.dp),
|
||||
contentAlignment = Alignment.CenterStart,
|
||||
) {
|
||||
@@ -134,15 +216,18 @@ private fun TopAppBar(
|
||||
start = if (centered) kotlin.math.max(startPadding.value, endPadding.value).dp else startPadding,
|
||||
end = if (centered) kotlin.math.max(startPadding.value, endPadding.value).dp else endPadding
|
||||
),
|
||||
contentAlignment = Alignment.Center
|
||||
contentAlignment = if (centered) Alignment.Center else Alignment.CenterStart
|
||||
) {
|
||||
title()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun topTitleAlpha(text: Boolean, connection: CollapsingAppBarNestedScrollConnection) =
|
||||
if (connection.appBarOffset.absoluteValue < AppBarHandler.appBarMaxHeightPx / 3) 0f
|
||||
else ((-connection.appBarOffset * 1.5f) / (AppBarHandler.appBarMaxHeightPx)).coerceIn(0f, if (text) 1f else appPrefs.inAppBarsAlpha.get())
|
||||
|
||||
val AppBarHeight = 56.dp
|
||||
val AppBarHorizontalPadding = 4.dp
|
||||
val BottomAppBarHeight = 60.dp
|
||||
private val TitleInsetWithoutIcon = DEFAULT_PADDING - AppBarHorizontalPadding
|
||||
val TitleInsetWithIcon = 72.dp
|
||||
val TitleInsetWithIcon = 52.dp
|
||||
|
||||
+19
-7
@@ -8,13 +8,12 @@ import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import chat.simplex.common.model.ChatController.appPrefs
|
||||
import chat.simplex.common.model.ChatModel
|
||||
import chat.simplex.common.platform.*
|
||||
import chat.simplex.common.ui.theme.*
|
||||
import chat.simplex.common.views.chatlist.StatusBarBackground
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import kotlin.math.min
|
||||
@@ -28,7 +27,10 @@ fun ModalView(
|
||||
enableClose: Boolean = true,
|
||||
background: Color = Color.Unspecified,
|
||||
modifier: Modifier = Modifier,
|
||||
endButtons: @Composable RowScope.() -> Unit = {},
|
||||
showSearch: Boolean = false,
|
||||
searchAlwaysVisible: Boolean = false,
|
||||
onSearchValueChanged: (String) -> Unit = {},
|
||||
endButtons: List<@Composable RowScope.() -> Unit> = emptyList(),
|
||||
content: @Composable BoxScope.() -> Unit,
|
||||
) {
|
||||
if (showClose) {
|
||||
@@ -41,8 +43,18 @@ fun ModalView(
|
||||
content()
|
||||
}
|
||||
if (showCloseBar) {
|
||||
Box(Modifier.align(if (oneHandUI.value) Alignment.BottomStart else Alignment.TopStart).then(if (oneHandUI.value) Modifier.imePadding() else Modifier)) {
|
||||
CloseSheetBar(if (enableClose) close else null, showClose, endButtons = endButtons)
|
||||
if (oneHandUI.value) {
|
||||
StatusBarBackground()
|
||||
}
|
||||
Box(Modifier.align(if (oneHandUI.value) Alignment.BottomStart else Alignment.TopStart)) {
|
||||
DefaultTopAppBar(
|
||||
navigationButton = if (showClose) {{ NavigationButtonBack(onButtonClicked = if (enableClose) close else null) }} else null,
|
||||
onTop = !oneHandUI.value,
|
||||
showSearch = showSearch,
|
||||
searchAlwaysVisible = searchAlwaysVisible,
|
||||
onSearchValueChanged = onSearchValueChanged,
|
||||
buttons = endButtons
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,14 +87,14 @@ class ModalManager(private val placement: ModalPlacement? = null) {
|
||||
private var passcodeView: MutableStateFlow<(@Composable (close: () -> Unit) -> Unit)?> = MutableStateFlow(null)
|
||||
private var onTimePasscodeView: MutableStateFlow<(@Composable (close: () -> Unit) -> Unit)?> = MutableStateFlow(null)
|
||||
|
||||
fun showModal(settings: Boolean = false, showClose: Boolean = true, endButtons: @Composable RowScope.() -> Unit = {}, content: @Composable ModalData.() -> Unit) {
|
||||
fun showModal(settings: Boolean = false, showClose: Boolean = true, endButtons: List<@Composable RowScope.() -> Unit> = emptyList(), content: @Composable ModalData.() -> Unit) {
|
||||
val data = ModalData()
|
||||
showCustomModal { close ->
|
||||
ModalView(close, showClose = showClose, endButtons = endButtons, content = { data.content() })
|
||||
}
|
||||
}
|
||||
|
||||
fun showModalCloseable(settings: Boolean = false, showClose: Boolean = true, endButtons: @Composable RowScope.() -> Unit = {}, content: @Composable ModalData.(close: () -> Unit) -> Unit) {
|
||||
fun showModalCloseable(settings: Boolean = false, showClose: Boolean = true, endButtons: List<@Composable RowScope.() -> Unit> = emptyList(), content: @Composable ModalData.(close: () -> Unit) -> Unit) {
|
||||
val data = ModalData()
|
||||
showCustomModal { close ->
|
||||
ModalView(close, showClose = showClose, endButtons = endButtons, content = { data.content(close) })
|
||||
|
||||
+10
-8
@@ -2,7 +2,7 @@ package chat.simplex.common.views.helpers
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.ZeroCornerSize
|
||||
import androidx.compose.foundation.text.*
|
||||
import androidx.compose.material.*
|
||||
@@ -10,6 +10,7 @@ import androidx.compose.material.TextFieldDefaults.indicatorLine
|
||||
import androidx.compose.material.TextFieldDefaults.textFieldWithLabelPadding
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
@@ -81,15 +82,20 @@ fun SearchTextField(
|
||||
)
|
||||
val shape = MaterialTheme.shapes.small.copy(bottomEnd = ZeroCornerSize, bottomStart = ZeroCornerSize)
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
val textStyle = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.onBackground)
|
||||
// sizing is done differently on Android and desktop in order to have the same height of search and compose view on desktop
|
||||
// see PlatformTextField.desktop + SendMsgView
|
||||
val padding = if (appPlatform.isAndroid) PaddingValues() else PaddingValues(top = 3.dp, bottom = 4.dp)
|
||||
BasicTextField(
|
||||
value = searchText.value,
|
||||
modifier = modifier
|
||||
.background(colors.backgroundColor(enabled).value, shape)
|
||||
.indicatorLine(enabled, false, interactionSource, colors)
|
||||
.focusRequester(focusRequester)
|
||||
.padding(padding)
|
||||
.defaultMinSize(
|
||||
minWidth = TextFieldDefaults.MinWidth,
|
||||
minHeight = TextFieldDefaults.MinHeight
|
||||
minHeight = if (appPlatform.isAndroid) TextFieldDefaults.MinHeight else 0.dp
|
||||
),
|
||||
onValueChange = {
|
||||
searchText.value = it
|
||||
@@ -100,18 +106,14 @@ fun SearchTextField(
|
||||
visualTransformation = VisualTransformation.None,
|
||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
|
||||
singleLine = true,
|
||||
textStyle = TextStyle(
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 15.sp
|
||||
),
|
||||
textStyle = textStyle,
|
||||
interactionSource = interactionSource,
|
||||
decorationBox = @Composable { innerTextField ->
|
||||
TextFieldDefaults.TextFieldDecorationBox(
|
||||
value = searchText.value.text,
|
||||
innerTextField = innerTextField,
|
||||
placeholder = {
|
||||
Text(placeholder, maxLines = 1, overflow = TextOverflow.Ellipsis)
|
||||
Text(placeholder, style = textStyle.copy(color = MaterialTheme.colors.secondary), maxLines = 1, overflow = TextOverflow.Ellipsis)
|
||||
},
|
||||
trailingIcon = if (searchText.value.text.isNotEmpty()) {{
|
||||
IconButton({
|
||||
|
||||
+14
-13
@@ -48,10 +48,10 @@ fun ModalData.NewChatSheet(rh: RemoteHostInfo?, close: () -> Unit) {
|
||||
Column(modifier = Modifier.fillMaxSize()) {
|
||||
NewChatSheetLayout(
|
||||
addContact = {
|
||||
ModalManager.start.showModalCloseable(endButtons = { AddContactLearnMoreButton() }) { _ -> NewChatView(chatModel.currentRemoteHost.value, NewChatOption.INVITE, close = closeAll) }
|
||||
ModalManager.start.showModalCloseable(endButtons = listOf { AddContactLearnMoreButton() }) { _ -> NewChatView(chatModel.currentRemoteHost.value, NewChatOption.INVITE, close = closeAll) }
|
||||
},
|
||||
scanPaste = {
|
||||
ModalManager.start.showModalCloseable(endButtons = { AddContactLearnMoreButton() }) { _ -> NewChatView(chatModel.currentRemoteHost.value, NewChatOption.CONNECT, showQRCodeScanner = appPlatform.isAndroid, close = closeAll) }
|
||||
ModalManager.start.showModalCloseable(endButtons = listOf { AddContactLearnMoreButton() }) { _ -> NewChatView(chatModel.currentRemoteHost.value, NewChatOption.CONNECT, showQRCodeScanner = appPlatform.isAndroid, close = closeAll) }
|
||||
},
|
||||
createGroup = {
|
||||
ModalManager.start.showCustomModal { close -> AddGroupView(chatModel, chatModel.currentRemoteHost.value, close, closeAll) }
|
||||
@@ -62,10 +62,10 @@ fun ModalData.NewChatSheet(rh: RemoteHostInfo?, close: () -> Unit) {
|
||||
}
|
||||
if (oneHandUI.value) {
|
||||
Column(Modifier.align(Alignment.BottomCenter)) {
|
||||
CloseSheetBarBottom(
|
||||
close = close,
|
||||
showClose = true,
|
||||
closeBarTitle = generalGetString(MR.strings.new_message)
|
||||
DefaultTopAppBar(
|
||||
navigationButton = { NavigationButtonBack(onButtonClicked = close) },
|
||||
fixedTitleText = generalGetString(MR.strings.new_message),
|
||||
onTop = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -289,7 +289,7 @@ private fun ModalData.NewChatSheetLayout(
|
||||
)
|
||||
) {
|
||||
Divider()
|
||||
Column(Modifier.consumeWindowInsets(WindowInsets.navigationBars).consumeWindowInsets(PaddingValues(bottom = AppBarHeight))) {
|
||||
Column(Modifier.consumeWindowInsets(WindowInsets.navigationBars).consumeWindowInsets(PaddingValues(bottom = AppBarHeight * fontSizeSqrtMultiplier))) {
|
||||
ContactsSearchBar(
|
||||
listState = listState,
|
||||
searchText = searchText,
|
||||
@@ -420,8 +420,8 @@ private fun ModalData.NewChatSheetLayout(
|
||||
StatusBarBackground()
|
||||
} else {
|
||||
NonOneHandLazyColumn()
|
||||
NavigationBarBackground(oneHandUI.value, true)
|
||||
}
|
||||
NavigationBarBackground(oneHandUI.value, true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -719,15 +719,16 @@ private fun ModalData.DeletedContactsView(rh: RemoteHostInfo?, closeDeletedChats
|
||||
}
|
||||
if (oneHandUI.value) {
|
||||
StatusBarBackground()
|
||||
} else {
|
||||
NavigationBarBackground(oneHandUI.value, true)
|
||||
}
|
||||
NavigationBarBackground(oneHandUI.value, true)
|
||||
}
|
||||
if (oneHandUI.value) {
|
||||
Column(Modifier.align(Alignment.BottomCenter)) {
|
||||
CloseSheetBarBottom(
|
||||
close = closeDeletedChats,
|
||||
showClose = true,
|
||||
closeBarTitle = generalGetString(MR.strings.deleted_chats),
|
||||
DefaultTopAppBar(
|
||||
navigationButton = { NavigationButtonBack(onButtonClicked = closeDeletedChats) },
|
||||
fixedTitleText = generalGetString(MR.strings.deleted_chats),
|
||||
onTop = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -480,9 +480,9 @@ private fun InviteView(rhId: Long?, connReqInvitation: String, contactConnection
|
||||
val search = rememberSaveable { mutableStateOf("") }
|
||||
ModalView(
|
||||
{ close() },
|
||||
endButtons = {
|
||||
SearchTextField(Modifier.fillMaxWidth(), placeholder = stringResource(MR.strings.search_verb), alwaysVisible = true) { search.value = it }
|
||||
},
|
||||
showSearch = true,
|
||||
searchAlwaysVisible = true,
|
||||
onSearchValueChanged = { search.value = it },
|
||||
content = {
|
||||
ActiveProfilePicker(
|
||||
search = search,
|
||||
|
||||
+4
-3
@@ -60,9 +60,10 @@ private fun LinkAMobileLayout(
|
||||
updateDeviceName: (String) -> Unit,
|
||||
) {
|
||||
Column(Modifier.themedBackground()) {
|
||||
CloseSheetBar(close = {
|
||||
appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo)
|
||||
})
|
||||
DefaultTopAppBar(
|
||||
navigationButton = { NavigationButtonBack(onButtonClicked = { appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo) } ) },
|
||||
onTop = true
|
||||
)
|
||||
BackHandler(onBack = {
|
||||
appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo)
|
||||
})
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ import dev.icerock.moko.resources.StringResource
|
||||
@Composable
|
||||
fun SimpleXInfo(chatModel: ChatModel, onboarding: Boolean = true) {
|
||||
if (onboarding) {
|
||||
ModalView({}, showClose = false, endButtons = {
|
||||
ModalView({}, showClose = false, endButtons = listOf {
|
||||
IconButton({ ModalManager.fullscreen.showModal { HowItWorks(chatModel.currentUser.value, null) }}) {
|
||||
Icon(painterResource(MR.images.ic_info), null, Modifier.size(28.dp), tint = MaterialTheme.colors.primary)
|
||||
}
|
||||
|
||||
+9
-9
@@ -116,7 +116,7 @@ object AppearanceScope {
|
||||
val localFontScale = remember { mutableStateOf(appPrefs.fontScale.get()) }
|
||||
SectionView(stringResource(MR.strings.appearance_font_size).uppercase(), contentPadding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
Row(Modifier.padding(top = 10.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Box(Modifier.size(60.dp)
|
||||
Box(Modifier.size(50.dp)
|
||||
.background(MaterialTheme.colors.surface, RoundedCornerShape(percent = 22))
|
||||
.clip(RoundedCornerShape(percent = 22))
|
||||
.clickable {
|
||||
@@ -130,7 +130,7 @@ object AppearanceScope {
|
||||
Text("Aa", color = if (localFontScale.value == 1f) MaterialTheme.colors.primary else MaterialTheme.colors.onBackground)
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.width(10.dp))
|
||||
Spacer(Modifier.width(15.dp))
|
||||
// Text("${(localFontScale.value * 100).roundToInt()}%", Modifier.width(70.dp), textAlign = TextAlign.Center, fontSize = 12.sp)
|
||||
if (appPlatform.isAndroid) {
|
||||
Slider(
|
||||
@@ -176,27 +176,27 @@ object AppearanceScope {
|
||||
val prefValue = remember { pref.state }.value
|
||||
SectionView(stringResource(sectionTitle).uppercase(), contentPadding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
Row(Modifier.padding(top = 10.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Box(Modifier.size(60.dp)
|
||||
Box(Modifier.size(50.dp)
|
||||
.background(MaterialTheme.colors.surface, RoundedCornerShape(percent = 22))
|
||||
.clip(RoundedCornerShape(percent = 22))
|
||||
.clickable {
|
||||
pref.set(defaultValue)
|
||||
},
|
||||
contentAlignment = Alignment.Center) {
|
||||
Text(String.format(Locale.US, "%.2f", prefValue),
|
||||
Text(String.format(Locale.US, "%.2f", 1 - prefValue),
|
||||
color = if (prefValue == defaultValue) MaterialTheme.colors.primary else MaterialTheme.colors.onBackground,
|
||||
fontSize = 12.sp,
|
||||
maxLines = 1
|
||||
)
|
||||
}
|
||||
Spacer(Modifier.width(10.dp))
|
||||
Spacer(Modifier.width(15.dp))
|
||||
Slider(
|
||||
prefValue,
|
||||
1 - prefValue,
|
||||
valueRange = 0f..1f,
|
||||
steps = 101,
|
||||
steps = 21,
|
||||
onValueChange = {
|
||||
val diff = it % 0.01f
|
||||
pref.set(String.format(Locale.US, "%.2f", it + (if (diff >= 0.005f) -diff + 0.01f else -diff)).toFloatOrNull() ?: 1f)
|
||||
val diff = it % 0.05f
|
||||
pref.set(1f - (String.format(Locale.US, "%.2f", it + (if (diff >= 0.025f) -diff + 0.05f else -diff)).toFloatOrNull() ?: 1f))
|
||||
},
|
||||
colors = SliderDefaults.colors(
|
||||
activeTickColor = Color.Transparent,
|
||||
|
||||
+3
-3
@@ -52,9 +52,9 @@ fun SettingsView(chatModel: ChatModel, setPerformLA: (Boolean) -> Unit, close: (
|
||||
val search = rememberSaveable { mutableStateOf("") }
|
||||
ModalView(
|
||||
{ close() },
|
||||
endButtons = {
|
||||
SearchTextField(Modifier.fillMaxWidth(), placeholder = stringResource(MR.strings.search_verb), alwaysVisible = true) { search.value = it }
|
||||
},
|
||||
showSearch = true,
|
||||
searchAlwaysVisible = true,
|
||||
onSearchValueChanged = { search.value = it },
|
||||
content = { modalView(chatModel, search) })
|
||||
}
|
||||
},
|
||||
|
||||
+19
-21
@@ -1,10 +1,12 @@
|
||||
package chat.simplex.common.platform
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.material.TextFieldDefaults.textFieldWithLabelPadding
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -113,7 +115,9 @@ actual fun PlatformTextField(
|
||||
autoCorrectEnabled = true
|
||||
),
|
||||
modifier = Modifier
|
||||
.padding(vertical = 4.dp)
|
||||
.padding(start = startPadding, end = endPadding)
|
||||
.offset(y = (-5).dp)
|
||||
.fillMaxWidth()
|
||||
.focusRequester(focusRequester)
|
||||
.onPreviewKeyEvent {
|
||||
if ((it.key == Key.Enter || it.key == Key.NumPadEnter) && it.type == KeyEventType.KeyDown) {
|
||||
@@ -177,30 +181,24 @@ actual fun PlatformTextField(
|
||||
},
|
||||
cursorBrush = SolidColor(MaterialTheme.colors.secondary),
|
||||
decorationBox = { innerTextField ->
|
||||
Row(verticalAlignment = Alignment.Bottom) {
|
||||
CompositionLocalProvider(
|
||||
LocalLayoutDirection provides if (isRtlByCharacters) LayoutDirection.Rtl else LocalLayoutDirection.current
|
||||
) {
|
||||
Column(Modifier.weight(1f).padding(start = startPadding, end = endPadding)) {
|
||||
Spacer(Modifier.height(8.dp))
|
||||
TextFieldDefaults.TextFieldDecorationBox(
|
||||
value = textFieldValue.text,
|
||||
innerTextField = innerTextField,
|
||||
placeholder = { Text(placeholder, style = textStyle.value.copy(color = MaterialTheme.colors.secondary)) },
|
||||
singleLine = false,
|
||||
enabled = true,
|
||||
isError = false,
|
||||
trailingIcon = null,
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
contentPadding = PaddingValues(),
|
||||
visualTransformation = VisualTransformation.None,
|
||||
colors = TextFieldDefaults.textFieldColors(backgroundColor = Color.Unspecified)
|
||||
)
|
||||
Spacer(Modifier.height(10.dp))
|
||||
}
|
||||
TextFieldDefaults.TextFieldDecorationBox(
|
||||
value = textFieldValue.text,
|
||||
innerTextField = innerTextField,
|
||||
placeholder = { Text(placeholder, style = textStyle.value.copy(color = MaterialTheme.colors.secondary)) },
|
||||
singleLine = false,
|
||||
enabled = true,
|
||||
isError = false,
|
||||
trailingIcon = null,
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
contentPadding = textFieldWithLabelPadding(start = 0.dp, end = 0.dp),
|
||||
visualTransformation = VisualTransformation.None,
|
||||
colors = TextFieldDefaults.textFieldColors(backgroundColor = Color.Unspecified)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
showDeleteTextButton.value = cs.message.split("\n").size >= 4 && !cs.inProgress
|
||||
if (composeState.value.preview is ComposePreview.VoicePreview) {
|
||||
|
||||
+4
-2
@@ -18,6 +18,8 @@ import androidx.compose.ui.input.pointer.*
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import chat.simplex.common.model.ChatController.appPrefs
|
||||
import chat.simplex.common.ui.theme.DEFAULT_PADDING
|
||||
import chat.simplex.common.ui.theme.DEFAULT_PADDING_HALF
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.filter
|
||||
@@ -166,8 +168,8 @@ actual fun ColumnWithScrollBar(
|
||||
modifier.verticalScroll(state).then(scrollModifier)
|
||||
},
|
||||
verticalArrangement, horizontalAlignment) {
|
||||
if (connection != null && !oneHandUI.value) {
|
||||
Spacer(Modifier.padding(padding))
|
||||
if (connection != null) {
|
||||
Spacer(if (oneHandUI.value) Modifier.padding(top = DEFAULT_PADDING + 5.dp) else Modifier.padding(padding))
|
||||
}
|
||||
content()
|
||||
if (connection != null && oneHandUI.value) {
|
||||
|
||||
+2
-2
@@ -88,7 +88,7 @@ fun DensityScaleSection() {
|
||||
val localDensityScale = remember { mutableStateOf(appPrefs.densityScale.get()) }
|
||||
SectionView(stringResource(MR.strings.appearance_zoom).uppercase(), contentPadding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
Row(Modifier.padding(top = 10.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Box(Modifier.size(60.dp)
|
||||
Box(Modifier.size(50.dp)
|
||||
.background(MaterialTheme.colors.surface, RoundedCornerShape(percent = 22))
|
||||
.clip(RoundedCornerShape(percent = 22))
|
||||
.clickable {
|
||||
@@ -106,7 +106,7 @@ fun DensityScaleSection() {
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.width(10.dp))
|
||||
Spacer(Modifier.width(15.dp))
|
||||
Slider(
|
||||
localDensityScale.value,
|
||||
valueRange = 1f..2f,
|
||||
|
||||
Reference in New Issue
Block a user