mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-05-10 17:18:31 +00:00
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 <evgeny@poberezkin.com>
This commit is contained in:
committed by
GitHub
parent
a9d2535292
commit
f4be0278b6
+3
-2
@@ -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
|
||||
|
||||
+1
-1
@@ -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))
|
||||
|
||||
+3
@@ -137,6 +137,9 @@ fun AppearanceScope.AppearanceLayout(
|
||||
}
|
||||
}
|
||||
|
||||
SectionDividerSpaced(maxBottomPadding = true)
|
||||
FontScaleSection()
|
||||
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<AnimatedViewState>,
|
||||
@@ -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() }
|
||||
|
||||
+4
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
)
|
||||
|
||||
+6
-6
@@ -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
|
||||
|
||||
+3
-1
@@ -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(
|
||||
|
||||
+3
-1
@@ -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()
|
||||
|
||||
+7
-6
@@ -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),
|
||||
|
||||
+26
-16
@@ -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<AnnotatedString.Builder.() -> Unit, Map<String, InlineTextContent>> {
|
||||
fun messageDraft(draft: ComposeState, sp20: Dp): Pair<AnnotatedString.Builder.() -> Unit, Map<String, InlineTextContent>> {
|
||||
fun attachment(): Pair<ImageResource, String?>? =
|
||||
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)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -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)
|
||||
}
|
||||
|
||||
+9
-9
@@ -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,
|
||||
|
||||
+3
-5
@@ -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
|
||||
) {
|
||||
|
||||
+4
-3
@@ -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,
|
||||
|
||||
+3
-1
@@ -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()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
@@ -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) {
|
||||
|
||||
+4
-1
@@ -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
|
||||
|
||||
+6
-6
@@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+63
-2
@@ -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),
|
||||
|
||||
+5
-2
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1606,6 +1606,8 @@
|
||||
<string name="color_wallpaper_background">Wallpaper background</string>
|
||||
<string name="color_wallpaper_tint">Wallpaper accent</string>
|
||||
<string name="theme_remove_image">Remove image</string>
|
||||
<string name="appearance_font_size">Font size</string>
|
||||
<string name="appearance_zoom">Zoom</string>
|
||||
|
||||
<!-- Wallpapers -->
|
||||
<string name="wallpaper_preview_hello_alice">Good afternoon!</string>
|
||||
|
||||
@@ -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<Boolean>) {
|
||||
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 }
|
||||
|
||||
+61
@@ -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,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user