From f4be0278b6c5bfa1dbc33393e27fa89f6cf7f83c Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Wed, 10 Jul 2024 00:41:23 +0700 Subject: [PATCH] desktop: zoom and font size (#4421) * desktop: font scale * new line * moved to slider * default value highlighting * clickable * more places with adapted scale * attachment and edit icons * verified * icons in chat view * zoom * new chat button size * preview icons * android support * preview * text scale in chat view's text field * paddings --------- Co-authored-by: Evgeny Poberezkin --- .../platform/PlatformTextField.android.kt | 5 +- .../common/views/call/CallView.android.kt | 2 +- .../views/usersettings/Appearance.android.kt | 3 + .../kotlin/chat/simplex/common/App.kt | 14 ++-- .../chat/simplex/common/model/SimpleXAPI.kt | 4 ++ .../chat/simplex/common/ui/theme/Theme.kt | 4 ++ .../simplex/common/views/chat/ChatView.kt | 12 ++-- .../simplex/common/views/chat/ComposeView.kt | 4 +- .../simplex/common/views/chat/SendMsgView.kt | 4 +- .../common/views/chatlist/ChatListView.kt | 13 ++-- .../common/views/chatlist/ChatPreviewView.kt | 42 +++++++----- .../views/chatlist/ServersSummaryView.kt | 4 +- .../common/views/chatlist/UserPicker.kt | 18 ++--- .../common/views/helpers/CloseSheetBar.kt | 8 +-- .../common/views/helpers/DefaultTopAppBar.kt | 7 +- .../simplex/common/views/helpers/ModalView.kt | 4 +- .../simplex/common/views/helpers/Utils.kt | 10 +++ .../views/migration/MigrateFromDevice.kt | 5 +- .../common/views/newchat/NewChatSheet.kt | 12 ++-- .../common/views/usersettings/Appearance.kt | 65 ++++++++++++++++++- .../common/views/usersettings/SettingsView.kt | 7 +- .../commonMain/resources/MR/base/strings.xml | 2 + .../kotlin/chat/simplex/common/DesktopApp.kt | 5 +- .../views/usersettings/Appearance.desktop.kt | 61 +++++++++++++++++ 24 files changed, 245 insertions(+), 70 deletions(-) diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/PlatformTextField.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/PlatformTextField.android.kt index 9e28c4f2bc..f49196c64a 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/PlatformTextField.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/PlatformTextField.android.kt @@ -29,6 +29,7 @@ import androidx.core.widget.doAfterTextChanged import androidx.core.widget.doOnTextChanged import chat.simplex.common.R import chat.simplex.common.helpers.toURI +import chat.simplex.common.model.ChatController.appPrefs import chat.simplex.common.model.ChatModel import chat.simplex.common.ui.theme.CurrentColors import chat.simplex.common.views.chat.* @@ -107,7 +108,7 @@ actual fun PlatformTextField( editText.maxLines = 16 editText.inputType = InputType.TYPE_TEXT_FLAG_CAP_SENTENCES or editText.inputType editText.setTextColor(textColor.toArgb()) - editText.textSize = textStyle.value.fontSize.value + editText.textSize = textStyle.value.fontSize.value * appPrefs.fontScale.get() val drawable = androidAppContext.getDrawable(R.drawable.send_msg_view_background)!! DrawableCompat.setTint(drawable, tintColor.toArgb()) editText.background = drawable @@ -135,7 +136,7 @@ actual fun PlatformTextField( editText }) { it.setTextColor(textColor.toArgb()) - it.textSize = textStyle.value.fontSize.value + it.textSize = textStyle.value.fontSize.value * appPrefs.fontScale.get() DrawableCompat.setTint(it.background, tintColor.toArgb()) it.isFocusable = composeState.value.preview !is ComposePreview.VoicePreview it.isFocusableInTouchMode = it.isFocusable diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/call/CallView.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/call/CallView.android.kt index d6af35432d..8d4ab3206a 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/call/CallView.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/call/CallView.android.kt @@ -554,7 +554,7 @@ fun CallPermissionsView(pipActive: Boolean, hasVideo: Boolean, cancel: () -> Uni } } else { ColumnWithScrollBar(Modifier.fillMaxSize()) { - Spacer(Modifier.height(AppBarHeight)) + Spacer(Modifier.height(AppBarHeight * fontSizeSqrtMultiplier)) AppBarTitle(stringResource(MR.strings.permissions_required)) Spacer(Modifier.weight(1f)) diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/usersettings/Appearance.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/usersettings/Appearance.android.kt index 7cb5c77f6e..9601152773 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/usersettings/Appearance.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/usersettings/Appearance.android.kt @@ -137,6 +137,9 @@ fun AppearanceScope.AppearanceLayout( } } + SectionDividerSpaced(maxBottomPadding = true) + FontScaleSection() + SectionBottomSpacer() } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt index b215b2b6cd..bd35594ac0 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt @@ -18,6 +18,7 @@ import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.unit.dp import chat.simplex.common.views.usersettings.SetDeliveryReceiptsView import chat.simplex.common.model.* +import chat.simplex.common.model.ChatController.appPrefs import chat.simplex.common.platform.* import chat.simplex.common.ui.theme.* import chat.simplex.common.views.CreateFirstProfile @@ -36,6 +37,7 @@ import dev.icerock.moko.resources.compose.painterResource import dev.icerock.moko.resources.compose.stringResource import kotlinx.coroutines.* import kotlinx.coroutines.flow.* +import kotlin.math.sqrt data class SettingsViewState( val userPickerState: MutableStateFlow, @@ -333,21 +335,21 @@ fun EndPartOfScreen() { fun DesktopScreen(settingsState: SettingsViewState) { Box { // 56.dp is a size of unused space of settings drawer - Box(Modifier.width(DEFAULT_START_MODAL_WIDTH + 56.dp)) { + Box(Modifier.width(DEFAULT_START_MODAL_WIDTH * fontSizeSqrtMultiplier + 56.dp)) { StartPartOfScreen(settingsState) } - Box(Modifier.widthIn(max = DEFAULT_START_MODAL_WIDTH)) { + Box(Modifier.widthIn(max = DEFAULT_START_MODAL_WIDTH * fontSizeSqrtMultiplier)) { ModalManager.start.showInView() SwitchingUsersView() } - Row(Modifier.padding(start = DEFAULT_START_MODAL_WIDTH).clipToBounds()) { + Row(Modifier.padding(start = DEFAULT_START_MODAL_WIDTH * fontSizeSqrtMultiplier).clipToBounds()) { Box(Modifier.widthIn(min = DEFAULT_MIN_CENTER_MODAL_WIDTH).weight(1f)) { CenterPartOfScreen() } if (ModalManager.end.hasModalsOpen()) { VerticalDivider() } - Box(Modifier.widthIn(max = DEFAULT_END_MODAL_WIDTH).clipToBounds()) { + Box(Modifier.widthIn(max = DEFAULT_END_MODAL_WIDTH * fontSizeSqrtMultiplier).clipToBounds()) { EndPartOfScreen() } } @@ -357,14 +359,14 @@ fun DesktopScreen(settingsState: SettingsViewState) { Box( Modifier .fillMaxSize() - .padding(start = DEFAULT_START_MODAL_WIDTH) + .padding(start = DEFAULT_START_MODAL_WIDTH * fontSizeSqrtMultiplier) .clickable(interactionSource = remember { MutableInteractionSource() }, indication = null, onClick = { ModalManager.start.closeModals() scope.launch { settingsState.scaffoldState.drawerState.close() } }) ) } - VerticalDivider(Modifier.padding(start = DEFAULT_START_MODAL_WIDTH)) + VerticalDivider(Modifier.padding(start = DEFAULT_START_MODAL_WIDTH * fontSizeSqrtMultiplier)) tryOrShowError("UserPicker", error = {}) { UserPicker(chatModel, userPickerState) { scope.launch { if (scaffoldState.drawerState.isOpen) scaffoldState.drawerState.close() else scaffoldState.drawerState.open() } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt index 0a42541c75..7633b0c808 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt @@ -198,6 +198,8 @@ class AppPreferences { }, settingsThemes) val themeOverrides = mkThemeOverridesPreference() val profileImageCornerRadius = mkFloatPreference(SHARED_PREFS_PROFILE_IMAGE_CORNER_RADIUS, 22.5f) + val fontScale = mkFloatPreference(SHARED_PREFS_FONT_SCALE, 1f) + val densityScale = mkFloatPreference(SHARED_PREFS_DENSITY_SCALE, 1f) val whatsNewVersion = mkStrPreference(SHARED_PREFS_WHATS_NEW_VERSION, null) val lastMigratedVersionCode = mkIntPreference(SHARED_PREFS_LAST_MIGRATED_VERSION_CODE, 0) @@ -380,6 +382,8 @@ class AppPreferences { 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_FONT_SCALE = "FontScale" + private const val SHARED_PREFS_DENSITY_SCALE = "DensityScale" 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" diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt index f6e113ea13..fb922fe52b 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt @@ -6,6 +6,8 @@ import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.* +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.dp import chat.simplex.common.model.ChatController import chat.simplex.common.model.ChatController.appPrefs @@ -777,6 +779,7 @@ fun SimpleXTheme(darkTheme: Boolean? = null, content: @Composable () -> Unit) { typography = Typography, shapes = Shapes, content = { + val density = Density(LocalDensity.current.density * desktopDensityScaleMultiplier, LocalDensity.current.fontScale * fontSizeMultiplier) val rememberedAppColors = remember { // Explicitly creating a new object here so we don't mutate the initial [appColors] // provided, and overwrite the values set in it. @@ -791,6 +794,7 @@ fun SimpleXTheme(darkTheme: Boolean? = null, content: @Composable () -> Unit) { LocalContentColor provides MaterialTheme.colors.onBackground, LocalAppColors provides rememberedAppColors, LocalAppWallpaper provides rememberedWallpaper, + LocalDensity provides density, content = content) } ) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt index af9d77b1d0..ec34a73d31 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt @@ -821,9 +821,9 @@ fun ChatInfoToolbar( buttons = barButtons ) - Divider(Modifier.padding(top = AppBarHeight)) + Divider(Modifier.padding(top = AppBarHeight * fontSizeSqrtMultiplier)) - Box(Modifier.fillMaxWidth().wrapContentSize(Alignment.TopEnd).offset(y = AppBarHeight)) { + Box(Modifier.fillMaxWidth().wrapContentSize(Alignment.TopEnd).offset(y = AppBarHeight * fontSizeSqrtMultiplier)) { DefaultDropdownMenu(showMenu) { menuItems.forEach { it() } } @@ -837,9 +837,9 @@ fun ChatInfoToolbarTitle(cInfo: ChatInfo, imageSize: Dp = 40.dp, iconColor: Colo verticalAlignment = Alignment.CenterVertically ) { if (cInfo.incognito) { - IncognitoImage(size = 36.dp, Indigo) + IncognitoImage(size = 36.dp * fontSizeSqrtMultiplier, Indigo) } - ChatInfoImage(cInfo, size = imageSize, iconColor) + ChatInfoImage(cInfo, size = imageSize * fontSizeSqrtMultiplier, iconColor) Column( Modifier.padding(start = 8.dp), horizontalAlignment = Alignment.CenterHorizontally @@ -865,7 +865,7 @@ fun ChatInfoToolbarTitle(cInfo: ChatInfo, imageSize: Dp = 40.dp, iconColor: Colo @Composable private fun ContactVerifiedShield() { - Icon(painterResource(MR.images.ic_verified_user), null, Modifier.size(18.dp).padding(end = 3.dp, top = 1.dp), tint = MaterialTheme.colors.secondary) + Icon(painterResource(MR.images.ic_verified_user), null, Modifier.size(18.dp * fontSizeSqrtMultiplier).padding(end = 3.dp, top = 1.dp), tint = MaterialTheme.colors.secondary) } data class CIListState(val scrolled: Boolean, val itemCount: Int, val keyboardState: KeyboardState) @@ -1283,7 +1283,7 @@ val MEMBER_IMAGE_SIZE: Dp = 38.dp @Composable fun MemberImage(member: GroupMember) { - ProfileImage(MEMBER_IMAGE_SIZE, member.memberProfile.image, backgroundColor = MaterialTheme.colors.background) + ProfileImage(MEMBER_IMAGE_SIZE * fontSizeSqrtMultiplier, member.memberProfile.image, backgroundColor = MaterialTheme.colors.background) } @Composable diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt index 24533247ba..a0e1bf8107 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt @@ -13,10 +13,12 @@ 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.platform.LocalDensity import androidx.compose.ui.text.font.FontStyle import dev.icerock.moko.resources.compose.painterResource import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import chat.simplex.common.model.* import chat.simplex.common.model.ChatModel.controller import chat.simplex.common.model.ChatModel.filesToDelete @@ -884,7 +886,7 @@ fun ComposeView( && !nextSendGrpInv.value IconButton( attachmentClicked, - Modifier.padding(bottom = if (appPlatform.isAndroid) 0.dp else 7.dp), + Modifier.padding(bottom = if (appPlatform.isAndroid) 0.dp else with(LocalDensity.current) { 7.sp.toDp() }), enabled = attachmentEnabled ) { Icon( diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SendMsgView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SendMsgView.kt index 779371a07c..192f1b005f 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SendMsgView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SendMsgView.kt @@ -15,10 +15,12 @@ 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.platform.LocalDensity import androidx.compose.ui.semantics.Role import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.* import chat.simplex.common.model.* +import chat.simplex.common.model.ChatController.appPrefs import chat.simplex.common.ui.theme.* import chat.simplex.common.views.chat.item.ItemAction import chat.simplex.common.views.helpers.* @@ -99,7 +101,7 @@ fun SendMsgView( if (showDeleteTextButton.value) { DeleteTextButton(composeState) } - Box(Modifier.align(Alignment.BottomEnd).padding(bottom = if (appPlatform.isAndroid) 0.dp else 5.dp)) { + Box(Modifier.align(Alignment.BottomEnd).padding(bottom = if (appPlatform.isAndroid) 0.dp else with(LocalDensity.current) { 5.sp.toDp() } * fontSizeSqrtMultiplier)) { val sendButtonSize = remember { Animatable(36f) } val sendButtonAlpha = remember { Animatable(1f) } val scope = rememberCoroutineScope() diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt index 3417333370..13e88c3b2f 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt @@ -91,7 +91,7 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf if (newChatSheetState.value.isVisible()) hideNewChatSheet(true) else showNewChatSheet() } }, - Modifier.padding(end = DEFAULT_PADDING - 16.dp + endPadding, bottom = DEFAULT_PADDING - 16.dp), + Modifier.padding(end = DEFAULT_PADDING - 16.dp + endPadding, bottom = DEFAULT_PADDING - 16.dp).size(AppBarHeight * fontSizeSqrtMultiplier), elevation = FloatingActionButtonDefaults.elevation( defaultElevation = 0.dp, pressedElevation = 0.dp, @@ -101,7 +101,7 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf backgroundColor = if (!stopped) MaterialTheme.colors.primary else MaterialTheme.colors.secondary, contentColor = Color.White ) { - Icon(if (!newChatSheetState.collectAsState().value.isVisible()) painterResource(MR.images.ic_edit_filled) else painterResource(MR.images.ic_close), stringResource(MR.strings.add_contact_or_create_group)) + Icon(if (!newChatSheetState.collectAsState().value.isVisible()) painterResource(MR.images.ic_edit_filled) else painterResource(MR.images.ic_close), stringResource(MR.strings.add_contact_or_create_group), Modifier.size(24.dp * fontSizeSqrtMultiplier)) } } } @@ -259,7 +259,7 @@ private fun ChatListToolbar(drawerState: DrawerState, userPickerState: MutableSt onSearchValueChanged = {}, buttons = barButtons ) - Divider(Modifier.padding(top = AppBarHeight)) + Divider(Modifier.padding(top = AppBarHeight * fontSizeSqrtMultiplier)) } @Composable @@ -316,7 +316,7 @@ fun UserProfileButton(image: String?, allRead: Boolean, onButtonClicked: () -> U Box { ProfileImage( image = image, - size = 37.dp, + size = 37.dp * fontSizeSqrtMultiplier, color = MaterialTheme.colors.secondaryVariant.mixWith(MaterialTheme.colors.onBackground, 0.97f) ) if (!allRead) { @@ -355,6 +355,7 @@ private fun BoxScope.unreadBadge(text: String? = "") { private fun ToggleFilterEnabledButton() { val pref = remember { ChatController.appPrefs.showUnreadAndFavorites } IconButton(onClick = { pref.set(!pref.get()) }) { + val sp16 = with(LocalDensity.current) { 16.sp.toDp() } Icon( painterResource(MR.images.ic_filter_list), null, @@ -364,7 +365,7 @@ private fun ToggleFilterEnabledButton() { .background(color = if (pref.state.value) MaterialTheme.colors.primary else Color.Unspecified, shape = RoundedCornerShape(50)) .border(width = 1.dp, color = if (pref.state.value) MaterialTheme.colors.primary else Color.Unspecified, shape = RoundedCornerShape(50)) .padding(3.dp) - .size(16.dp) + .size(sp16) ) } } @@ -388,7 +389,7 @@ private fun ChatListSearchBar(listState: LazyListState, searchText: MutableState Row(verticalAlignment = Alignment.CenterVertically) { val focusRequester = remember { FocusRequester() } var focused by remember { mutableStateOf(false) } - Icon(painterResource(MR.images.ic_search), null, Modifier.padding(horizontal = DEFAULT_PADDING_HALF), tint = MaterialTheme.colors.secondary) + Icon(painterResource(MR.images.ic_search), null, Modifier.padding(horizontal = DEFAULT_PADDING_HALF).size(24.dp * fontSizeSqrtMultiplier), tint = MaterialTheme.colors.secondary) SearchTextField( Modifier.weight(1f).onFocusChanged { focused = it.hasFocus }.focusRequester(focusRequester), placeholder = stringResource(MR.strings.search_or_paste_simplex_link), diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt index 336d104d2d..0e215724f7 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt @@ -47,10 +47,11 @@ fun ChatPreviewView( @Composable fun inactiveIcon() { + val sp18 = with(LocalDensity.current) { 18.sp.toDp() } Icon( painterResource(MR.images.ic_cancel_filled), stringResource(MR.strings.icon_descr_group_inactive), - Modifier.size(18.dp).background(MaterialTheme.colors.background, CircleShape), + Modifier.size(sp18).background(MaterialTheme.colors.background, CircleShape), tint = MaterialTheme.colors.secondary ) } @@ -87,10 +88,11 @@ fun ChatPreviewView( @Composable fun VerifiedIcon() { - Icon(painterResource(MR.images.ic_verified_user), null, Modifier.size(19.dp).padding(end = 3.dp, top = 1.dp), tint = MaterialTheme.colors.secondary) + val sp19 = with(LocalDensity.current) { 19.sp.toDp() } + Icon(painterResource(MR.images.ic_verified_user), null, Modifier.size(sp19).padding(end = 3.dp, top = 1.dp), tint = MaterialTheme.colors.secondary) } - fun messageDraft(draft: ComposeState): Pair Unit, Map> { + fun messageDraft(draft: ComposeState, sp20: Dp): Pair Unit, Map> { fun attachment(): Pair? = when (draft.preview) { is ComposePreview.FilePreview -> MR.images.ic_draft_filled to draft.preview.fileName @@ -115,12 +117,12 @@ fun ChatPreviewView( "editIcon" to InlineTextContent( Placeholder(20.sp, 20.sp, PlaceholderVerticalAlign.TextCenter) ) { - Icon(painterResource(MR.images.ic_edit_note), null, tint = MaterialTheme.colors.primary) + Icon(painterResource(MR.images.ic_edit_note), null, Modifier.size(sp20), tint = MaterialTheme.colors.primary) }, "attachmentIcon" to InlineTextContent( Placeholder(20.sp, 20.sp, PlaceholderVerticalAlign.TextCenter) ) { - Icon(if (attachment?.first != null) painterResource(attachment.first) else painterResource(MR.images.ic_edit_note), null, tint = MaterialTheme.colors.secondary) + Icon(if (attachment?.first != null) painterResource(attachment.first) else painterResource(MR.images.ic_edit_note), null, Modifier.size(sp20), tint = MaterialTheme.colors.secondary) } ) return inlineContentBuilder to inlineContent @@ -167,8 +169,9 @@ fun ChatPreviewView( val ci = chat.chatItems.lastOrNull() if (ci != null) { if (showChatPreviews || (chatModelDraftChatId == chat.id && chatModelDraft != null)) { + val sp20 = with(LocalDensity.current) { 20.sp.toDp() } val (text: CharSequence, inlineTextContent) = when { - chatModelDraftChatId == chat.id && chatModelDraft != null -> remember(chatModelDraft) { chatModelDraft.message to messageDraft(chatModelDraft) } + chatModelDraftChatId == chat.id && chatModelDraft != null -> remember(chatModelDraft) { chatModelDraft.message to messageDraft(chatModelDraft, sp20) } ci.meta.itemDeleted == null -> ci.text to null else -> markedDeletedText(ci.meta) to null } @@ -220,10 +223,11 @@ fun ChatPreviewView( @Composable fun progressView() { + val sp15 = with(LocalDensity.current) { 15.sp.toDp() } CircularProgressIndicator( Modifier .padding(horizontal = 2.dp) - .size(15.dp), + .size(sp15), color = MaterialTheme.colors.secondary, strokeWidth = 1.5.dp ) @@ -231,6 +235,7 @@ fun ChatPreviewView( @Composable fun chatStatusImage() { + val sp19 = with(LocalDensity.current) { 19.sp.toDp() } if (cInfo is ChatInfo.Direct) { if (cInfo.contact.active && cInfo.contact.activeConn != null) { val descr = contactNetworkStatus?.statusString @@ -244,7 +249,7 @@ fun ChatPreviewView( contentDescription = descr, tint = MaterialTheme.colors.secondary, modifier = Modifier - .size(19.dp) + .size(sp19) ) else -> @@ -266,7 +271,7 @@ fun ChatPreviewView( Row { Box(contentAlignment = Alignment.BottomEnd) { - ChatInfoImage(cInfo, size = 72.dp) + ChatInfoImage(cInfo, size = 72.dp * fontSizeSqrtMultiplier) Box(Modifier.padding(end = 6.dp, bottom = 6.dp)) { chatPreviewImageOverlayIcon() } @@ -295,9 +300,13 @@ fun ChatPreviewView( ) val n = chat.chatStats.unreadCount val showNtfsIcon = !chat.chatInfo.ntfsEnabled && (chat.chatInfo is ChatInfo.Direct || chat.chatInfo is ChatInfo.Group) + val sp17 = with(LocalDensity.current) { 17.sp.toDp() } + val sp21 = with(LocalDensity.current) { 21.sp.toDp() } + val sp23 = with(LocalDensity.current) { 23.sp.toDp() } + val sp46 = with(LocalDensity.current) { 46.sp.toDp() } if (n > 0 || chat.chatStats.unreadChat) { Box( - Modifier.padding(top = 24.dp), + Modifier.padding(top = sp23, end = with(LocalDensity.current) { 3.sp.toDp() }), contentAlignment = Alignment.Center ) { Text( @@ -313,7 +322,7 @@ fun ChatPreviewView( } } else if (showNtfsIcon) { Box( - Modifier.padding(top = 24.dp), + Modifier.padding(top = sp21), contentAlignment = Alignment.Center ) { Icon( @@ -323,12 +332,12 @@ fun ChatPreviewView( modifier = Modifier .padding(horizontal = 3.dp) .padding(vertical = 1.dp) - .size(17.dp) + .size(sp17) ) } } else if (chat.chatInfo.chatSettings?.favorite == true) { Box( - Modifier.padding(top = 24.dp), + Modifier.padding(top = sp21), contentAlignment = Alignment.Center ) { Icon( @@ -338,12 +347,12 @@ fun ChatPreviewView( modifier = Modifier .padding(horizontal = 3.dp) .padding(vertical = 1.dp) - .size(17.dp) + .size(sp17) ) } } Box( - Modifier.padding(top = 50.dp), + Modifier.padding(top = sp46), contentAlignment = Alignment.Center ) { chatStatusImage() @@ -355,12 +364,13 @@ fun ChatPreviewView( @Composable fun IncognitoIcon(incognito: Boolean) { if (incognito) { + val sp21 = with(LocalDensity.current) { 21.sp.toDp() } Icon( painterResource(MR.images.ic_theater_comedy), contentDescription = null, tint = MaterialTheme.colors.secondary, modifier = Modifier - .size(21.dp) + .size(sp21) ) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ServersSummaryView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ServersSummaryView.kt index 22478c18f9..5a3f09919e 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ServersSummaryView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ServersSummaryView.kt @@ -26,6 +26,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp @@ -126,6 +127,7 @@ fun SubscriptionStatusIndicatorView(subs: SMPServerSubs, sess: ServerSessions, l horizontalArrangement = Arrangement.spacedBy(DEFAULT_SPACE_AFTER_ICON) ) { if (pref.state.value && leadingPercentage) SubscriptionStatusIndicatorPercentage(percentageText) + val sp16 = with(LocalDensity.current) { 16.sp.toDp() } SubscriptionStatusIcon( color = when(statusColorAndPercentage.color) { SubscriptionColorType.ACTIVE -> MaterialTheme.colors.primary @@ -133,7 +135,7 @@ fun SubscriptionStatusIndicatorView(subs: SMPServerSubs, sess: ServerSessions, l SubscriptionColorType.ACTIVE_DISCONNECTED -> WarningOrange SubscriptionColorType.DISCONNECTED -> MaterialTheme.colors.secondary }, - modifier = Modifier.size(16.dp), + modifier = Modifier.size(sp16), variableValue = statusColorAndPercentage.variableValue) if (pref.state.value && !leadingPercentage) SubscriptionStatusIndicatorPercentage(percentageText) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/UserPicker.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/UserPicker.kt index 23272fcc0c..8199a3f2d6 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/UserPicker.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/UserPicker.kt @@ -309,7 +309,7 @@ fun UserProfileRow(u: User, enabled: Boolean = chatModel.chatRunning.value == tr ) { ProfileImage( image = u.image, - size = 54.dp + size = 54.dp * fontSizeSqrtMultiplier ) Text( u.displayName, @@ -354,7 +354,7 @@ fun RemoteHostRow(h: RemoteHostInfo) { .padding(start = 17.dp), verticalAlignment = Alignment.CenterVertically ) { - Icon(painterResource(MR.images.ic_smartphone_300), h.hostDeviceName, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground) + Icon(painterResource(MR.images.ic_smartphone_300), h.hostDeviceName, Modifier.size(20.dp * fontSizeSqrtMultiplier), tint = MaterialTheme.colors.onBackground) Text( h.hostDeviceName, modifier = Modifier.padding(start = 26.dp, end = 8.dp), @@ -395,7 +395,7 @@ fun LocalDeviceRow(active: Boolean) { .padding(start = 17.dp, end = DEFAULT_PADDING), verticalAlignment = Alignment.CenterVertically ) { - Icon(painterResource(MR.images.ic_desktop), stringResource(MR.strings.this_device), Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground) + Icon(painterResource(MR.images.ic_desktop), stringResource(MR.strings.this_device), Modifier.size(20.dp * fontSizeSqrtMultiplier), tint = MaterialTheme.colors.onBackground) Text( stringResource(MR.strings.this_device), modifier = Modifier.padding(start = 26.dp, end = 8.dp), @@ -409,7 +409,7 @@ fun LocalDeviceRow(active: Boolean) { private fun UseFromDesktopPickerItem(onClick: () -> Unit) { SectionItemView(onClick, padding = PaddingValues(start = DEFAULT_PADDING + 7.dp, end = DEFAULT_PADDING), minHeight = 68.dp) { val text = generalGetString(MR.strings.settings_section_title_use_from_desktop).lowercase().capitalize(Locale.current) - Icon(painterResource(MR.images.ic_desktop), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground) + Icon(painterResource(MR.images.ic_desktop), text, Modifier.size(20.dp * fontSizeSqrtMultiplier), tint = MaterialTheme.colors.onBackground) Spacer(Modifier.width(DEFAULT_PADDING + 6.dp)) Text(text, color = MenuTextColor) } @@ -419,7 +419,7 @@ private fun UseFromDesktopPickerItem(onClick: () -> Unit) { private fun LinkAMobilePickerItem(onClick: () -> Unit) { SectionItemView(onClick, padding = PaddingValues(start = DEFAULT_PADDING + 7.dp, end = DEFAULT_PADDING), minHeight = 68.dp) { val text = generalGetString(MR.strings.link_a_mobile) - Icon(painterResource(MR.images.ic_smartphone_300), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground) + Icon(painterResource(MR.images.ic_smartphone_300), text, Modifier.size(20.dp * fontSizeSqrtMultiplier), tint = MaterialTheme.colors.onBackground) Spacer(Modifier.width(DEFAULT_PADDING + 6.dp)) Text(text, color = MenuTextColor) } @@ -429,7 +429,7 @@ private fun LinkAMobilePickerItem(onClick: () -> Unit) { private fun CreateInitialProfile(onClick: () -> Unit) { SectionItemView(onClick, padding = PaddingValues(start = DEFAULT_PADDING + 7.dp, end = DEFAULT_PADDING), minHeight = 68.dp) { val text = generalGetString(MR.strings.create_chat_profile) - Icon(painterResource(MR.images.ic_manage_accounts), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground) + Icon(painterResource(MR.images.ic_manage_accounts), text, Modifier.size(20.dp * fontSizeSqrtMultiplier), tint = MaterialTheme.colors.onBackground) Spacer(Modifier.width(DEFAULT_PADDING + 6.dp)) Text(text, color = MenuTextColor) } @@ -439,7 +439,7 @@ private fun CreateInitialProfile(onClick: () -> Unit) { private fun SettingsPickerItem(onClick: () -> Unit) { SectionItemView(onClick, padding = PaddingValues(start = DEFAULT_PADDING + 7.dp, end = DEFAULT_PADDING), minHeight = 68.dp) { val text = generalGetString(MR.strings.settings_section_title_settings).lowercase().capitalize(Locale.current) - Icon(painterResource(MR.images.ic_settings), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground) + Icon(painterResource(MR.images.ic_settings), text, Modifier.size(20.dp * fontSizeSqrtMultiplier), tint = MaterialTheme.colors.onBackground) Spacer(Modifier.width(DEFAULT_PADDING + 6.dp)) Text(text, color = MenuTextColor) } @@ -449,7 +449,7 @@ private fun SettingsPickerItem(onClick: () -> Unit) { private fun CancelPickerItem(onClick: () -> Unit) { SectionItemView(onClick, padding = PaddingValues(start = DEFAULT_PADDING + 7.dp, end = DEFAULT_PADDING), minHeight = 68.dp) { val text = generalGetString(MR.strings.cancel_verb) - Icon(painterResource(MR.images.ic_close), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground) + Icon(painterResource(MR.images.ic_close), text, Modifier.size(20.dp * fontSizeSqrtMultiplier), tint = MaterialTheme.colors.onBackground) Spacer(Modifier.width(DEFAULT_PADDING + 6.dp)) Text(text, color = MenuTextColor) } @@ -459,7 +459,7 @@ private fun CancelPickerItem(onClick: () -> Unit) { fun HostDisconnectButton(onClick: (() -> Unit)?) { val interactionSource = remember { MutableInteractionSource() } val hovered = interactionSource.collectIsHoveredAsState().value - IconButton(onClick ?: {}, Modifier.requiredSize(20.dp), enabled = onClick != null) { + IconButton(onClick ?: {}, Modifier.requiredSize(20.dp * fontSizeSqrtMultiplier), enabled = onClick != null) { Icon( painterResource(if (onClick == null) MR.images.ic_desktop else if (hovered) MR.images.ic_wifi_off else MR.images.ic_wifi), null, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CloseSheetBar.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CloseSheetBar.kt index b26a047b0e..d92dccddc2 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CloseSheetBar.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CloseSheetBar.kt @@ -22,15 +22,13 @@ fun CloseSheetBar(close: (() -> Unit)?, showClose: Boolean = true, tintColor: Co Column( Modifier .fillMaxWidth() - .heightIn(min = AppBarHeight) - .padding(horizontal = AppBarHorizontalPadding), + .heightIn(min = AppBarHeight * fontSizeSqrtMultiplier) + .padding(horizontal = AppBarHorizontalPadding) ) { Row( - Modifier - .padding(top = 4.dp), // Like in DefaultAppBar content = { Row( - Modifier.fillMaxWidth().height(TextFieldDefaults.MinHeight), + Modifier.fillMaxWidth().height(AppBarHeight * fontSizeSqrtMultiplier), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultTopAppBar.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultTopAppBar.kt index 577411c7e3..3d6d242832 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultTopAppBar.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultTopAppBar.kt @@ -7,6 +7,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.* +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 @@ -44,10 +45,10 @@ fun DefaultTopAppBar( } @Composable -fun NavigationButtonBack(onButtonClicked: (() -> Unit)?, tintColor: Color = if (onButtonClicked != null) MaterialTheme.colors.primary else MaterialTheme.colors.secondary) { +fun NavigationButtonBack(onButtonClicked: (() -> Unit)?, tintColor: Color = if (onButtonClicked != null) MaterialTheme.colors.primary else MaterialTheme.colors.secondary, height: Dp = 24.dp) { IconButton(onButtonClicked ?: {}, enabled = onButtonClicked != null) { Icon( - painterResource(MR.images.ic_arrow_back_ios_new), stringResource(MR.strings.back), tint = tintColor + painterResource(MR.images.ic_arrow_back_ios_new), stringResource(MR.strings.back), Modifier.height(height), tint = tintColor ) } } @@ -84,7 +85,7 @@ private fun TopAppBar( Box( modifier .fillMaxWidth() - .height(AppBarHeight) + .height(AppBarHeight * fontSizeSqrtMultiplier) .background(backgroundColor) .padding(horizontal = 4.dp), contentAlignment = Alignment.CenterStart, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt index d7116d11b6..4acb18561a 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt @@ -8,12 +8,14 @@ import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +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 kotlinx.coroutines.flow.MutableStateFlow import java.util.concurrent.atomic.AtomicBoolean import kotlin.math.min +import kotlin.math.sqrt @Composable fun ModalView( @@ -89,7 +91,7 @@ class ModalManager(private val placement: ModalPlacement? = null) { if (placement == ModalPlacement.CENTER) { ChatModel.chatId.value = null } else if (placement == ModalPlacement.END) { - desktopExpandWindowToWidth(DEFAULT_START_MODAL_WIDTH + DEFAULT_MIN_CENTER_MODAL_WIDTH + DEFAULT_END_MODAL_WIDTH) + desktopExpandWindowToWidth(DEFAULT_START_MODAL_WIDTH * sqrt(appPrefs.fontScale.get()) + DEFAULT_MIN_CENTER_MODAL_WIDTH + DEFAULT_END_MODAL_WIDTH * sqrt(appPrefs.fontScale.get())) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Utils.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Utils.kt index 884551f600..ccef86c343 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Utils.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Utils.kt @@ -8,6 +8,7 @@ import androidx.compose.ui.platform.* import androidx.compose.ui.text.* import androidx.compose.ui.unit.* import chat.simplex.common.model.* +import chat.simplex.common.model.ChatController.appPrefs import chat.simplex.common.platform.* import chat.simplex.common.ui.theme.ThemeOverrides import chat.simplex.common.views.chatlist.connectIfOpenedViaUri @@ -519,6 +520,15 @@ fun includeMoreFailedComposables() { lastExecutedComposables.clear() } +val fontSizeMultiplier: Float + @Composable get() = remember { appPrefs.fontScale.state }.value + +val fontSizeSqrtMultiplier: Float + @Composable get() = sqrt(remember { appPrefs.fontScale.state }.value) + +val desktopDensityScaleMultiplier: Float + @Composable get() = if (appPlatform.isDesktop) remember { appPrefs.densityScale.state }.value else 1f + @Composable fun DisposableEffectOnGone(always: () -> Unit = {}, whenDispose: () -> Unit = {}, whenGone: () -> Unit) { DisposableEffect(Unit) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateFromDevice.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateFromDevice.kt index f8e3d48625..3cc5468bbb 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateFromDevice.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateFromDevice.kt @@ -17,6 +17,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.common.model.* +import chat.simplex.common.model.ChatController.appPrefs import chat.simplex.common.model.ChatController.getNetCfg import chat.simplex.common.model.ChatController.startChat import chat.simplex.common.model.ChatController.startChatWithTemporaryDatabase @@ -38,6 +39,7 @@ import kotlinx.serialization.* import java.io.File import java.net.URLEncoder import kotlin.math.max +import kotlin.math.sqrt @Serializable data class MigrationFileLinkData( @@ -426,7 +428,8 @@ fun LargeProgressView(value: Float, title: String, description: String) { Box(Modifier.padding(DEFAULT_PADDING).fillMaxSize(), contentAlignment = Alignment.Center) { CircularProgressIndicator( progress = value, - (if (appPlatform.isDesktop) Modifier.size(DEFAULT_START_MODAL_WIDTH) else Modifier.size(windowWidth() - DEFAULT_PADDING * 2)) + (if (appPlatform.isDesktop) Modifier.size(DEFAULT_START_MODAL_WIDTH * fontSizeSqrtMultiplier) else Modifier.size(windowWidth() - DEFAULT_PADDING * + 2)) .rotate(-90f), color = MaterialTheme.colors.primary, strokeWidth = 25.dp diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt index 9f47a5cdf9..9faee4532a 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt @@ -125,11 +125,11 @@ private fun NewChatSheetLayout( Box(contentAlignment = Alignment.CenterEnd) { Button( actions[index], - shape = RoundedCornerShape(21.dp), + shape = RoundedCornerShape(21.dp * fontSizeSqrtMultiplier), colors = ButtonDefaults.textButtonColors(backgroundColor = backgroundColor), elevation = null, contentPadding = PaddingValues(horizontal = DEFAULT_PADDING_HALF, vertical = DEFAULT_PADDING_HALF), - modifier = Modifier.height(42.dp) + modifier = Modifier.height(42.dp * fontSizeSqrtMultiplier) ) { Text( stringResource(titles[index]), @@ -140,7 +140,7 @@ private fun NewChatSheetLayout( Icon( painterResource(icons[index]), stringResource(titles[index]), - Modifier.size(42.dp), + Modifier.size(42.dp * fontSizeSqrtMultiplier), tint = if (isInDarkTheme()) MaterialTheme.colors.primary else MaterialTheme.colors.primary ) } @@ -152,7 +152,7 @@ private fun NewChatSheetLayout( } FloatingActionButton( onClick = { if (!stopped) closeNewChatSheet(true) }, - Modifier.padding(end = DEFAULT_PADDING, bottom = DEFAULT_PADDING), + Modifier.padding(end = DEFAULT_PADDING, bottom = DEFAULT_PADDING).size(AppBarHeight * fontSizeSqrtMultiplier), elevation = FloatingActionButtonDefaults.elevation( defaultElevation = 0.dp, pressedElevation = 0.dp, @@ -164,11 +164,11 @@ private fun NewChatSheetLayout( ) { Icon( painterResource(MR.images.ic_edit_filled), stringResource(MR.strings.add_contact_or_create_group), - Modifier.graphicsLayer { alpha = 1 - animatedFloat.value } + Modifier.graphicsLayer { alpha = 1 - animatedFloat.value }.size(24.dp * fontSizeSqrtMultiplier) ) Icon( painterResource(MR.images.ic_close), stringResource(MR.strings.add_contact_or_create_group), - Modifier.graphicsLayer { alpha = animatedFloat.value } + Modifier.graphicsLayer { alpha = animatedFloat.value }.size(24.dp * fontSizeSqrtMultiplier) ) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Appearance.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Appearance.kt index 84fe333ba8..5fda4b7d1d 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Appearance.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Appearance.kt @@ -19,6 +19,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.* import androidx.compose.ui.graphics.* import androidx.compose.ui.platform.LocalClipboardManager +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.unit.* import dev.icerock.moko.resources.compose.painterResource @@ -82,6 +83,66 @@ object AppearanceScope { } } + @Composable + fun FontScaleSection() { + val localFontScale = remember { mutableStateOf(appPrefs.fontScale.get()) } + SectionView(stringResource(MR.strings.appearance_font_size).uppercase(), padding = PaddingValues(horizontal = DEFAULT_PADDING)) { + Row(Modifier.padding(top = 10.dp), verticalAlignment = Alignment.CenterVertically) { + Box(Modifier.size(60.dp) + .background(MaterialTheme.colors.surface, RoundedCornerShape(percent = 22)) + .clip(RoundedCornerShape(percent = 22)) + .clickable { + localFontScale.value = 1f + appPrefs.fontScale.set(localFontScale.value) + }, + contentAlignment = Alignment.Center) { + CompositionLocalProvider( + LocalDensity provides Density(LocalDensity.current.density, localFontScale.value) + ) { + Text("Aa", color = if (localFontScale.value == 1f) MaterialTheme.colors.primary else MaterialTheme.colors.onBackground) + } + } + Spacer(Modifier.width(10.dp)) + // Text("${(localFontScale.value * 100).roundToInt()}%", Modifier.width(70.dp), textAlign = TextAlign.Center, fontSize = 12.sp) + if (appPlatform.isAndroid) { + Slider( + localFontScale.value, + valueRange = 0.75f..1.25f, + steps = 11, + onValueChange = { + val diff = it % 0.05f + localFontScale.value = String.format(Locale.US, "%.2f", it + (if (diff >= 0.025f) -diff + 0.05f else -diff)).toFloatOrNull() ?: 1f + }, + onValueChangeFinished = { + appPrefs.fontScale.set(localFontScale.value) + }, + colors = SliderDefaults.colors( + activeTickColor = Color.Transparent, + inactiveTickColor = Color.Transparent, + ) + ) + } else { + Slider( + localFontScale.value, + valueRange = 0.7f..1.5f, + steps = 9, + onValueChange = { + val diff = it % 0.1f + localFontScale.value = String.format(Locale.US, "%.1f", it + (if (diff >= 0.05f) -diff + 0.1f else -diff)).toFloatOrNull() ?: 1f + }, + onValueChangeFinished = { + appPrefs.fontScale.set(localFontScale.value) + }, + colors = SliderDefaults.colors( + activeTickColor = Color.Transparent, + inactiveTickColor = Color.Transparent, + ) + ) + } + } + } + } + @Composable fun ChatThemePreview( theme: DefaultTheme, @@ -225,8 +286,8 @@ object AppearanceScope { } if (appPlatform.isDesktop) { - val itemWidth = (DEFAULT_START_MODAL_WIDTH - DEFAULT_PADDING * 2 - DEFAULT_PADDING_HALF * 3) / 4 - val itemHeight = (DEFAULT_START_MODAL_WIDTH - DEFAULT_PADDING * 2) / 4 + val itemWidth = (DEFAULT_START_MODAL_WIDTH * fontSizeSqrtMultiplier - DEFAULT_PADDING * 2 - DEFAULT_PADDING_HALF * 3) / 4 + val itemHeight = (DEFAULT_START_MODAL_WIDTH * fontSizeSqrtMultiplier - DEFAULT_PADDING * 2) / 4 val rows = ceil((PresetWallpaper.entries.size + 2) / 4f).roundToInt() LazyVerticalGrid( columns = GridCells.Fixed(4), diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt index 0b5033aca3..cef457de2e 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt @@ -174,11 +174,14 @@ fun SettingsLayout( Box( Modifier .fillMaxWidth() + .height(AppBarHeight * fontSizeSqrtMultiplier) .background(MaterialTheme.colors.background) .background(if (isInDarkTheme()) ToolbarDark else ToolbarLight) - .padding(start = 4.dp, top = 8.dp) + .padding(start = 4.dp, top = 8.dp), + contentAlignment = Alignment.CenterStart ) { - NavigationButtonBack(closeSettings) + val sp24 = with(LocalDensity.current) { 24.sp.toDp() } + NavigationButtonBack(closeSettings, height = sp24) } } } diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml index 24c94a5ddc..3452e6ff60 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -1606,6 +1606,8 @@ Wallpaper background Wallpaper accent Remove image + Font size + Zoom Good afternoon! diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/DesktopApp.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/DesktopApp.kt index 4128982f78..df8887c4e1 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/DesktopApp.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/DesktopApp.kt @@ -14,6 +14,7 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.dp import androidx.compose.ui.window.* import chat.simplex.common.model.* +import chat.simplex.common.model.ChatController.appPrefs import chat.simplex.common.platform.* import chat.simplex.common.ui.theme.DEFAULT_START_MODAL_WIDTH import chat.simplex.common.ui.theme.SimpleXTheme @@ -26,6 +27,7 @@ import kotlinx.coroutines.* import java.awt.event.WindowEvent import java.awt.event.WindowFocusListener import java.io.File +import kotlin.math.sqrt import kotlin.system.exitProcess val simplexWindowState = SimplexWindowState() @@ -195,7 +197,8 @@ private fun ApplicationScope.AppWindow(closedByError: MutableState) { if (remember { ChatController.appPrefs.developerTools.state }.value && remember { ChatController.appPrefs.terminalAlwaysVisible.state }.value && remember { ChatController.appPrefs.appLanguage.state }.value != "") { var hiddenUntilRestart by remember { mutableStateOf(false) } if (!hiddenUntilRestart) { - val cWindowState = rememberWindowState(placement = WindowPlacement.Floating, width = DEFAULT_START_MODAL_WIDTH, height = 768.dp) + val cWindowState = rememberWindowState(placement = WindowPlacement.Floating, width = DEFAULT_START_MODAL_WIDTH * fontSizeSqrtMultiplier, height = + 768.dp) Window(state = cWindowState, onCloseRequest = { hiddenUntilRestart = true }, title = stringResource(MR.strings.chat_console)) { SimpleXTheme { TerminalView(ChatModel) { hiddenUntilRestart = true } diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/usersettings/Appearance.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/usersettings/Appearance.desktop.kt index 669dd1949d..9f7f613835 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/usersettings/Appearance.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/usersettings/Appearance.desktop.kt @@ -3,18 +3,29 @@ package chat.simplex.common.views.usersettings import SectionBottomSpacer import SectionDividerSpaced import SectionView +import androidx.compose.foundation.* import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.* +import chat.simplex.common.model.ChatController.appPrefs import chat.simplex.common.model.ChatModel import chat.simplex.common.model.SharedPreference import chat.simplex.common.platform.* +import chat.simplex.common.ui.theme.DEFAULT_PADDING import chat.simplex.common.views.helpers.* import chat.simplex.res.MR import dev.icerock.moko.resources.compose.stringResource import kotlinx.coroutines.delay import java.util.Locale +import kotlin.math.roundToInt @Composable actual fun AppearanceView(m: ChatModel) { @@ -55,6 +66,56 @@ fun AppearanceScope.AppearanceLayout( SectionDividerSpaced(maxTopPadding = true) ProfileImageSection() + SectionDividerSpaced(maxBottomPadding = true) + FontScaleSection() + + SectionDividerSpaced(maxBottomPadding = true) + DensityScaleSection() + SectionBottomSpacer() } } + +@Composable +fun DensityScaleSection() { + val localDensityScale = remember { mutableStateOf(appPrefs.densityScale.get()) } + SectionView(stringResource(MR.strings.appearance_zoom).uppercase(), padding = PaddingValues(horizontal = DEFAULT_PADDING)) { + Row(Modifier.padding(top = 10.dp), verticalAlignment = Alignment.CenterVertically) { + Box(Modifier.size(60.dp) + .background(MaterialTheme.colors.surface, RoundedCornerShape(percent = 22)) + .clip(RoundedCornerShape(percent = 22)) + .clickable { + localDensityScale.value = 1f + appPrefs.densityScale.set(localDensityScale.value) + }, + contentAlignment = Alignment.Center) { + CompositionLocalProvider( + LocalDensity provides Density(LocalDensity.current.density * localDensityScale.value, LocalDensity.current.fontScale) + ) { + Text("${localDensityScale.value}", + color = if (localDensityScale.value == 1f) MaterialTheme.colors.primary else MaterialTheme.colors.onBackground, + fontSize = 12.sp, + maxLines = 1 + ) + } + } + Spacer(Modifier.width(10.dp)) + Slider( + localDensityScale.value, + valueRange = 1f..2f, + steps = 11, + onValueChange = { + val diff = it % 0.1f + localDensityScale.value = String.format(Locale.US, "%.1f", it + (if (diff >= 0.05f) -diff + 0.1f else -diff)).toFloatOrNull() ?: 1f + }, + onValueChangeFinished = { + appPrefs.densityScale.set(localDensityScale.value) + }, + colors = SliderDefaults.colors( + activeTickColor = Color.Transparent, + inactiveTickColor = Color.Transparent, + ) + ) + } + } +}