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 ccb85c3982..5a60e1d1b0 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 @@ -12,10 +12,12 @@ import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.MaterialTheme.colors import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.* import androidx.compose.ui.layout.ContentScale @@ -34,11 +36,13 @@ import chat.simplex.common.helpers.APPLICATION_ID import chat.simplex.common.helpers.saveAppLocale import chat.simplex.common.views.usersettings.AppearanceScope.ColorEditor import chat.simplex.res.MR +import dev.icerock.moko.resources.ImageResource +import dev.icerock.moko.resources.compose.painterResource import kotlinx.coroutines.delay -enum class AppIcon(val resId: Int) { - DEFAULT(R.drawable.icon_round_common), - DARK_BLUE(R.drawable.icon_dark_blue_round_common), +enum class AppIcon(val image: ImageResource) { + DEFAULT(MR.images.ic_simplex_light), + DARK_BLUE(MR.images.ic_simplex_dark), } @Composable @@ -122,9 +126,8 @@ fun AppearanceScope.AppearanceLayout( LazyRow { items(AppIcon.values().size, { index -> AppIcon.values()[index] }) { index -> val item = AppIcon.values()[index] - val mipmap = ContextCompat.getDrawable(LocalContext.current, item.resId)!! Image( - bitmap = mipmap.toBitmap().asImageBitmap(), + painterResource(item.image), contentDescription = "", contentScale = ContentScale.Fit, modifier = Modifier @@ -132,6 +135,7 @@ fun AppearanceScope.AppearanceLayout( .size(70.dp) .clickable { changeIcon(item) } .padding(10.dp) + .clip(CircleShape) ) if (index + 1 != AppIcon.values().size) { @@ -141,6 +145,9 @@ fun AppearanceScope.AppearanceLayout( } } + SectionDividerSpaced(maxTopPadding = true) + ProfileImageSection() + SectionDividerSpaced(maxTopPadding = true) ThemesSection(systemDarkTheme, showSettingsModal, editColor) SectionBottomSpacer() diff --git a/apps/multiplatform/common/src/androidMain/res/drawable/icon_dark_blue_round_common.png b/apps/multiplatform/common/src/androidMain/res/drawable/icon_dark_blue_round_common.png deleted file mode 100644 index e413ad857d..0000000000 Binary files a/apps/multiplatform/common/src/androidMain/res/drawable/icon_dark_blue_round_common.png and /dev/null differ diff --git a/apps/multiplatform/common/src/androidMain/res/drawable/icon_round_common.png b/apps/multiplatform/common/src/androidMain/res/drawable/icon_round_common.png deleted file mode 100644 index 755904ee8e..0000000000 Binary files a/apps/multiplatform/common/src/androidMain/res/drawable/icon_round_common.png and /dev/null differ 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 0bf3f23d2c..494f400fbc 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 @@ -171,6 +171,7 @@ class AppPreferences { }, decode = { json.decodeFromString(MapSerializer(String.serializer(), ThemeOverrides.serializer()), it) }, settingsThemes) + val profileImageCornerRadius = mkFloatPreference(SHARED_PREFS_PROFILE_IMAGE_CORNER_RADIUS, 22.5f) val whatsNewVersion = mkStrPreference(SHARED_PREFS_WHATS_NEW_VERSION, null) val lastMigratedVersionCode = mkIntPreference(SHARED_PREFS_LAST_MIGRATED_VERSION_CODE, 0) @@ -201,6 +202,12 @@ class AppPreferences { set = fun(value) = settings.putLong(prefName, value) ) + private fun mkFloatPreference(prefName: String, default: Float) = + SharedPreference( + get = fun() = settings.getFloat(prefName, default), + set = fun(value) = settings.putFloat(prefName, value) + ) + private fun mkTimeoutPreference(prefName: String, default: Long, proxyDefault: Long): SharedPreference { val d = if (networkUseSocksProxy.get()) proxyDefault else default return SharedPreference( @@ -331,6 +338,7 @@ class AppPreferences { private const val SHARED_PREFS_CURRENT_THEME = "CurrentTheme" private const val SHARED_PREFS_SYSTEM_DARK_THEME = "SystemDarkTheme" private const val SHARED_PREFS_THEMES = "Themes" + private const val SHARED_PREFS_PROFILE_IMAGE_CORNER_RADIUS = "ProfileImageCornerRadius" 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/views/chat/ChatView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt index 21a9cfa7b4..ff5364adc2 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 @@ -1010,13 +1010,7 @@ fun BoxWithConstraintsScope.ChatItemsList( swipeableModifier, horizontalArrangement = Arrangement.spacedBy(4.dp) ) { - Box( - Modifier - .clip(CircleShape) - .clickable { - showMemberInfo(chat.chatInfo.groupInfo, member) - } - ) { + Box(Modifier.clickable { showMemberInfo(chat.chatInfo.groupInfo, member) }) { MemberImage(member) } ChatItemViewShortHand(cItem, range) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ChatInfoImage.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ChatInfoImage.kt index 6813bec550..72764f215e 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ChatInfoImage.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ChatInfoImage.kt @@ -3,22 +3,24 @@ package chat.simplex.common.views.helpers import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.Image import androidx.compose.foundation.layout.* -import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.* import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.* import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.InspectableValue +import androidx.compose.ui.unit.* 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.dp import chat.simplex.common.model.ChatInfo +import chat.simplex.common.platform.appPreferences import chat.simplex.common.platform.base64ToBitmap -import chat.simplex.common.ui.theme.NoteFolderIconColor -import chat.simplex.common.ui.theme.SimpleXTheme +import chat.simplex.common.ui.theme.* import chat.simplex.res.MR import dev.icerock.moko.resources.ImageResource @@ -79,12 +81,32 @@ fun ProfileImage( imageBitmap, stringResource(MR.strings.image_descr_profile_image), contentScale = ContentScale.Crop, - modifier = Modifier.size(size).padding(size / 12).clip(CircleShape) + modifier = Modifier.size(size).padding(size / 12).clip(ProfileIconShape()) ) } } } +@Composable +fun ProfileImage(size: Dp, image: ImageResource) { + Image( + painterResource(image), + stringResource(MR.strings.image_descr_profile_image), + contentScale = ContentScale.Crop, + modifier = Modifier.size(size).padding(size / 12).clip(ProfileIconShape()) + ) +} + +@Composable +fun ProfileIconShape(): Shape { + val percent = remember { appPreferences.profileImageCornerRadius.state } + return when { + percent.value <= 0 -> RectangleShape + percent.value >= 50 -> CircleShape + else -> RoundedCornerShape(PercentCornerSize(percent.value)) + } +} + /** [AccountCircleFilled] has its inner padding which leads to visible border if there is background underneath. * This is workaround * */ @@ -109,11 +131,30 @@ fun ProfileImageForActiveCall( imageBitmap, stringResource(MR.strings.image_descr_profile_image), contentScale = ContentScale.Crop, - modifier = Modifier.size(size).clip(CircleShape) + modifier = Modifier.size(size).clip(ProfileIconShape()) ) } } +/** (c) [androidx.compose.foundation.shape.CornerSize] */ +private data class PercentCornerSize( + private val percent: Float +) : CornerSize, InspectableValue { + init { + if (percent < 0 || percent > 100) { + throw IllegalArgumentException("The percent should be in the range of [0, 100]") + } + } + + override fun toPx(shapeSize: Size, density: Density) = + shapeSize.minDimension * (percent / 100f) + + override fun toString(): String = "CornerSize(size = $percent%)" + + override val valueOverride: String + get() = "$percent%" +} + @Preview @Composable diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/WhatsNewView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/WhatsNewView.kt index 0ea2d25c4f..43c492a732 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/WhatsNewView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/WhatsNewView.kt @@ -539,6 +539,11 @@ private val versionDescriptions: List = listOf( titleId = MR.strings.v5_7_call_sounds, descrId = MR.strings.v5_7_call_sounds_descr ), + FeatureDescription( + icon = MR.images.ic_account_box, + titleId = MR.strings.v5_7_shape_profile_images, + descrId = MR.strings.v5_7_shape_profile_images_descr + ), FeatureDescription( icon = MR.images.ic_wifi_tethering, titleId = MR.strings.v5_7_network, 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 c55888d8a3..78e24e5e7e 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 @@ -5,14 +5,16 @@ import SectionItemView import SectionItemViewSpaceBetween import SectionSpacer import SectionView -import androidx.compose.foundation.* +import androidx.compose.foundation.Image import androidx.compose.foundation.layout.* import androidx.compose.material.* import androidx.compose.material.MaterialTheme.colors import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.* +import androidx.compose.ui.layout.ContentScale import dev.icerock.moko.resources.compose.painterResource import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.dp @@ -24,7 +26,6 @@ import chat.simplex.common.platform.* import chat.simplex.res.MR import com.godaddy.android.colorpicker.* import kotlinx.serialization.encodeToString -import java.io.File import java.net.URI import java.util.* import kotlin.collections.ArrayList @@ -33,6 +34,37 @@ import kotlin.collections.ArrayList expect fun AppearanceView(m: ChatModel, showSettingsModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit)) object AppearanceScope { + @Composable + fun ProfileImageSection() { + SectionView(stringResource(MR.strings.settings_section_title_profile_images).uppercase(), padding = PaddingValues(horizontal = DEFAULT_PADDING)) { + val image = remember { chatModel.currentUser }.value?.image + Row(Modifier.padding(top = 10.dp), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically) { + val size = 60 + Box(Modifier.offset(x = -(size / 12).dp)) { + if (!image.isNullOrEmpty()) { + ProfileImage(size.dp, image, MR.images.ic_simplex_light, color = Color.Unspecified) + } else { + ProfileImage(size.dp, if (isInDarkTheme()) MR.images.ic_simplex_light else MR.images.ic_simplex_dark) + } + } + Spacer(Modifier.width(DEFAULT_PADDING_HALF - (size / 12).dp)) + Slider( + remember { appPreferences.profileImageCornerRadius.state }.value, + valueRange = 0f..50f, + steps = 20, + onValueChange = { + val diff = it % 2.5f + appPreferences.profileImageCornerRadius.set(it + (if (diff >= 1.25f) -diff + 2.5f else -diff)) + }, + colors = SliderDefaults.colors( + activeTickColor = Color.Transparent, + inactiveTickColor = Color.Transparent, + ) + ) + } + } + } + @Composable fun ThemesSection( systemDarkTheme: SharedPreference, @@ -41,7 +73,7 @@ object AppearanceScope { ) { val currentTheme by CurrentColors.collectAsState() SectionView(stringResource(MR.strings.settings_section_title_themes)) { - val darkTheme = chat.simplex.common.ui.theme.isSystemInDarkTheme() + val darkTheme = isSystemInDarkTheme() val state = remember { derivedStateOf { currentTheme.name } } ThemeSelector(state) { ThemeManager.applyTheme(it, darkTheme) 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 f3a5c138d5..6ca14aace2 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -1033,6 +1033,7 @@ LANGUAGE APP ICON THEMES + Profile images MESSAGES AND FILES CALLS Network connection @@ -1770,6 +1771,8 @@ Message source remains private. In-call sounds When connecting audio and video calls. + Shape profile images + Square, circle, or anything in between. Network management More reliable network connection. Lithuanian UI diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_account_box.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_account_box.svg new file mode 100644 index 0000000000..9680161c4f --- /dev/null +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_account_box.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_simplex_dark@4x.png b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_simplex_dark@4x.png new file mode 100644 index 0000000000..45fc44af43 Binary files /dev/null and b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_simplex_dark@4x.png differ diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_simplex_light@4x.png b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_simplex_light@4x.png new file mode 100644 index 0000000000..c372e25b76 Binary files /dev/null and b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_simplex_light@4x.png differ diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml index adb0d077cf..a71638eae0 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml @@ -1848,5 +1848,7 @@ Литовский интерфейс Источник сообщения остаётся конфиденциальным. Во время соединения аудио и видео звонков. + Форма картинок профилей + Квадрат, круг и все, что между ними. Будет включено в прямых разговорах! \ No newline at end of file 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 5ffc68be79..4e4846bc9f 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 @@ -62,6 +62,9 @@ fun AppearanceScope.AppearanceLayout( } } } + SectionDividerSpaced(maxTopPadding = true) + ProfileImageSection() + SectionDividerSpaced(maxTopPadding = true) ThemesSection(systemDarkTheme, showSettingsModal, editColor) SectionBottomSpacer()