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:
Stanislav Dmitrenko
2023-08-05 00:28:09 +03:00
committed by GitHub
parent 353fe4539c
commit 5952fd5290
13 changed files with 106 additions and 12 deletions

View File

@@ -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 {

View File

@@ -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

View File

@@ -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)

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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>)

View File

@@ -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.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -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 {

View File

@@ -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)
)
}

View File

@@ -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 = {

View File

@@ -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