desktop: font for emoji (#2853)
* desktop: font for emoji * heart emoji for Mac * limit font size * alignment * padding * emoji item layout * padding on desktop --------- Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
353fe4539c
commit
5952fd5290
@@ -114,6 +114,15 @@ android {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
val isAndroid = gradle.startParameter.taskNames.find {
|
||||
val lower = it.toLowerCase()
|
||||
lower.contains("release") || lower.startsWith("assemble") || lower.startsWith("install")
|
||||
} != null
|
||||
if (isAndroid) {
|
||||
// This is not needed on Android but can't be moved to desktopMain because MR lib don't support this.
|
||||
// No other ways to exclude a file work but it's large and should be excluded
|
||||
kotlin.sourceSets["commonMain"].resources.exclude("/MR/fonts/NotoColorEmoji-Regular.ttf")
|
||||
}
|
||||
}
|
||||
|
||||
multiplatformResources {
|
||||
|
||||
@@ -11,3 +11,5 @@ actual val Inter: FontFamily = FontFamily(
|
||||
Font(MR.fonts.Inter.medium.fontResourceId, FontWeight.Medium),
|
||||
Font(MR.fonts.Inter.light.fontResourceId, FontWeight.Light)
|
||||
)
|
||||
|
||||
actual val EmojiFont: FontFamily = FontFamily.Default
|
||||
|
||||
@@ -2,18 +2,27 @@ package chat.simplex.common.views.chat.item
|
||||
|
||||
import android.Manifest
|
||||
import android.os.Build
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.ui.unit.TextUnit
|
||||
import androidx.compose.ui.unit.sp
|
||||
import chat.simplex.common.model.ChatItem
|
||||
import chat.simplex.common.model.MsgContent
|
||||
import chat.simplex.common.platform.FileChooserLauncher
|
||||
import chat.simplex.common.platform.saveImage
|
||||
import chat.simplex.common.views.helpers.SharedContent
|
||||
import chat.simplex.common.views.helpers.withApi
|
||||
import chat.simplex.res.MR
|
||||
import com.google.accompanist.permissions.rememberPermissionState
|
||||
import dev.icerock.moko.resources.compose.painterResource
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
|
||||
@Composable
|
||||
actual fun ReactionIcon(text: String, fontSize: TextUnit) {
|
||||
Text(text, fontSize = fontSize)
|
||||
}
|
||||
|
||||
@Composable
|
||||
actual fun SaveContentItemAction(cItem: ChatItem, saveFileLauncher: FileChooserLauncher, showMenu: MutableState<Boolean>) {
|
||||
val writePermissionState = rememberPermissionState(permission = Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package chat.simplex.common.views.chat.item
|
||||
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
@Composable
|
||||
actual fun EmojiText(text: String) {
|
||||
val s = text.trim()
|
||||
Text(s, style = if (s.codePoints().count() < 4) largeEmojiFont else mediumEmojiFont)
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import chat.simplex.common.views.helpers.generalGetString
|
||||
// https://github.com/rsms/inter
|
||||
// I place it here because IDEA shows an error (but still works anyway) when this declaration inside Type.kt
|
||||
expect val Inter: FontFamily
|
||||
expect val EmojiFont: FontFamily
|
||||
|
||||
object ThemeManager {
|
||||
private val appPrefs: AppPreferences = ChatController.appPrefs
|
||||
|
||||
@@ -17,8 +17,7 @@ import androidx.compose.ui.text.AnnotatedString
|
||||
import dev.icerock.moko.resources.compose.painterResource
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.unit.*
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.platform.*
|
||||
import chat.simplex.common.ui.theme.*
|
||||
@@ -84,7 +83,7 @@ fun ChatItemView(
|
||||
|
||||
@Composable
|
||||
fun ChatItemReactions() {
|
||||
Row {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
cItem.reactions.forEach { r ->
|
||||
var modifier = Modifier.padding(horizontal = 5.dp, vertical = 2.dp).clip(RoundedCornerShape(8.dp))
|
||||
if (cInfo.featureEnabled(ChatFeature.Reactions) && (cItem.allowAddReaction || r.userReacted)) {
|
||||
@@ -93,13 +92,14 @@ fun ChatItemView(
|
||||
}
|
||||
}
|
||||
Row(modifier.padding(2.dp)) {
|
||||
Text(r.reaction.text, fontSize = 12.sp)
|
||||
ReactionIcon(r.reaction.text, fontSize = 12.sp)
|
||||
if (r.totalReacted > 1) {
|
||||
Spacer(Modifier.width(4.dp))
|
||||
Text("${r.totalReacted}",
|
||||
fontSize = 11.5.sp,
|
||||
fontWeight = if (r.userReacted) FontWeight.Bold else FontWeight.Normal,
|
||||
color = if (r.userReacted) MaterialTheme.colors.primary else MaterialTheme.colors.secondary,
|
||||
modifier = if (appPlatform.isAndroid) Modifier else Modifier.padding(top = 4.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -145,7 +145,7 @@ fun ChatItemView(
|
||||
}
|
||||
}
|
||||
if (rs.isNotEmpty()) {
|
||||
Row(modifier = Modifier.padding(horizontal = DEFAULT_PADDING).horizontalScroll(rememberScrollState())) {
|
||||
Row(modifier = Modifier.padding(horizontal = DEFAULT_PADDING).horizontalScroll(rememberScrollState()), verticalAlignment = Alignment.CenterVertically) {
|
||||
rs.forEach() { r ->
|
||||
Box(
|
||||
Modifier.size(36.dp).clickable {
|
||||
@@ -154,7 +154,7 @@ fun ChatItemView(
|
||||
},
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(r.text)
|
||||
ReactionIcon(r.text, 12.sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -324,6 +324,9 @@ fun ChatItemView(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
expect fun ReactionIcon(text: String, fontSize: TextUnit = TextUnit.Unspecified)
|
||||
|
||||
@Composable
|
||||
expect fun SaveContentItemAction(cItem: ChatItem, saveFileLauncher: FileChooserLauncher, showMenu: MutableState<Boolean>)
|
||||
|
||||
|
||||
@@ -10,9 +10,11 @@ import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import chat.simplex.common.model.ChatItem
|
||||
import chat.simplex.common.model.MREmojiChar
|
||||
import chat.simplex.common.ui.theme.EmojiFont
|
||||
|
||||
val largeEmojiFont: TextStyle = TextStyle(fontSize = 48.sp)
|
||||
val mediumEmojiFont: TextStyle = TextStyle(fontSize = 36.sp)
|
||||
val largeEmojiFont: TextStyle = TextStyle(fontSize = 48.sp, fontFamily = EmojiFont)
|
||||
val mediumEmojiFont: TextStyle = TextStyle(fontSize = 36.sp, fontFamily = EmojiFont)
|
||||
|
||||
@Composable
|
||||
fun EmojiItemView(chatItem: ChatItem, timedMessagesTTL: Int?) {
|
||||
@@ -26,10 +28,7 @@ fun EmojiItemView(chatItem: ChatItem, timedMessagesTTL: Int?) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun EmojiText(text: String) {
|
||||
val s = text.trim()
|
||||
Text(s, style = if (s.codePoints().count() < 4) largeEmojiFont else mediumEmojiFont)
|
||||
}
|
||||
expect fun EmojiText(text: String)
|
||||
|
||||
// https://stackoverflow.com/a/46279500
|
||||
private const val emojiStr = "^(" +
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
@@ -16,6 +16,7 @@ enum class DesktopPlatform(val libPath: String, val libExtension: String, val co
|
||||
MAC_AARCH64("/libs/mac-aarch64", "dylib", unixConfigPath, unixDataPath);
|
||||
|
||||
fun isLinux() = this == LINUX_X86_64 || this == LINUX_AARCH64
|
||||
fun isMac() = this == MAC_X86_64 || this == MAC_AARCH64
|
||||
}
|
||||
|
||||
private fun detectDesktopPlatform(): DesktopPlatform {
|
||||
|
||||
@@ -2,6 +2,7 @@ package chat.simplex.common.ui.theme
|
||||
|
||||
import androidx.compose.ui.text.font.*
|
||||
import androidx.compose.ui.text.platform.Font
|
||||
import chat.simplex.common.platform.desktopPlatform
|
||||
import chat.simplex.res.MR
|
||||
|
||||
actual val Inter: FontFamily = FontFamily(
|
||||
@@ -12,3 +13,16 @@ actual val Inter: FontFamily = FontFamily(
|
||||
Font(MR.fonts.Inter.medium.file, FontWeight.Medium),
|
||||
Font(MR.fonts.Inter.light.file, FontWeight.Light)
|
||||
)
|
||||
|
||||
actual val EmojiFont: FontFamily = if (desktopPlatform.isMac()) {
|
||||
FontFamily.Default
|
||||
} else {
|
||||
FontFamily(
|
||||
Font(MR.fonts.NotoColorEmoji.regular.file),
|
||||
Font(MR.fonts.NotoColorEmoji.regular.file, style = FontStyle.Italic),
|
||||
Font(MR.fonts.NotoColorEmoji.regular.file, FontWeight.Bold),
|
||||
Font(MR.fonts.NotoColorEmoji.regular.file, FontWeight.SemiBold),
|
||||
Font(MR.fonts.NotoColorEmoji.regular.file, FontWeight.Medium),
|
||||
Font(MR.fonts.NotoColorEmoji.regular.file, FontWeight.Light)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,15 +1,34 @@
|
||||
package chat.simplex.common.views.chat.item
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.*
|
||||
import chat.simplex.common.model.ChatItem
|
||||
import chat.simplex.common.model.MsgContent
|
||||
import chat.simplex.common.platform.FileChooserLauncher
|
||||
import chat.simplex.common.platform.desktopPlatform
|
||||
import chat.simplex.common.ui.theme.EmojiFont
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import chat.simplex.res.MR
|
||||
import dev.icerock.moko.resources.compose.painterResource
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
|
||||
@Composable
|
||||
actual fun ReactionIcon(text: String, fontSize: TextUnit) {
|
||||
if (desktopPlatform.isMac() && isHeartEmoji(text)) {
|
||||
val sp = with(LocalDensity.current) { (fontSize.value + 8).sp.toDp() }
|
||||
Image(painterResource(MR.images.ic_heart), null, Modifier.size(sp).padding(top = 4.dp, bottom = 2.dp))
|
||||
} else {
|
||||
Text(text, fontSize = fontSize, fontFamily = EmojiFont)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
actual fun SaveContentItemAction(cItem: ChatItem, saveFileLauncher: FileChooserLauncher, showMenu: MutableState<Boolean>) {
|
||||
ItemAction(stringResource(MR.strings.save_verb), painterResource(MR.images.ic_download), onClick = {
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package chat.simplex.common.views.chat.item
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import chat.simplex.common.model.MREmojiChar
|
||||
import chat.simplex.common.platform.desktopPlatform
|
||||
import chat.simplex.res.MR
|
||||
import dev.icerock.moko.resources.compose.painterResource
|
||||
|
||||
@Composable
|
||||
actual fun EmojiText(text: String) {
|
||||
val s = text.trim()
|
||||
if (desktopPlatform.isMac() && isHeartEmoji(s)) {
|
||||
Image(painterResource(MR.images.ic_heart), null, Modifier.height(62.dp).width(54.dp).padding(vertical = 8.dp))
|
||||
} else {
|
||||
Text(s, style = if (s.codePoints().count() < 4) largeEmojiFont else mediumEmojiFont)
|
||||
}
|
||||
}
|
||||
|
||||
/** [MREmojiChar.Heart.value] */
|
||||
fun isHeartEmoji(s: String): Boolean =
|
||||
(s.codePoints().count() == 2L && s.codePointAt(0) == 10084 && s.codePointAt(1) == 65039) ||
|
||||
s.codePoints().count() == 1L && s.codePointAt(0) == 10084
|
||||
Reference in New Issue
Block a user