more color options and better code

This commit is contained in:
Avently
2023-04-27 17:33:15 +07:00
parent 1f441c56c7
commit 1efc7aafd8
8 changed files with 284 additions and 61 deletions
+1
View File
@@ -119,6 +119,7 @@ dependencies {
implementation 'androidx.fragment:fragment:1.4.1'
implementation 'org.jetbrains.kotlinx:kotlinx-datetime:0.3.2'
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2'
implementation 'com.charleskorn.kaml:kaml:0.43.0'
//implementation "androidx.compose.material:material-icons-extended:$compose_version"
implementation "androidx.compose.ui:ui-util:$compose_version"
implementation "androidx.navigation:navigation-compose:2.4.1"
@@ -25,6 +25,8 @@ import chat.simplex.app.views.call.*
import chat.simplex.app.views.newchat.ConnectViaLinkTab
import chat.simplex.app.views.onboarding.OnboardingStage
import chat.simplex.app.views.usersettings.*
import com.charleskorn.kaml.Yaml
import com.charleskorn.kaml.YamlConfiguration
import kotlinx.coroutines.*
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
@@ -2991,6 +2993,11 @@ val json = Json {
explicitNulls = false
}
val yaml = Yaml(configuration = YamlConfiguration(
strictMode = false,
encodeDefaults = false,
))
@Serializable
class APIResponse(val resp: CR, val corr: String? = null) {
companion object {
@@ -10,34 +10,84 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.*
import androidx.compose.ui.unit.dp
import chat.simplex.app.R
import chat.simplex.app.SimplexApp
import chat.simplex.app.views.helpers.generalGetString
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.serialization.Serializable
enum class DefaultTheme {
SYSTEM, LIGHT, DARK, BLUE;
// Call in only with base theme, not SYSTEM
fun hasChangedPrimary(colors: Colors): Boolean {
return when (this) {
// Call it only with base theme, not SYSTEM
fun hasChangedAnyColor(colors: Colors): Boolean {
val palette = when (this) {
SYSTEM -> return false
LIGHT -> colors.primary != LightColorPalette.primary
DARK -> colors.primary != DarkColorPalette.primary
BLUE -> colors.primary != BlueColorPalette.primary
LIGHT -> LightColorPalette
DARK -> DarkColorPalette
BLUE -> BlueColorPalette
}
return with(palette) {
colors.primary != primary ||
colors.primaryVariant != primaryVariant ||
colors.secondary != secondary ||
colors.secondaryVariant != secondaryVariant ||
colors.background != background ||
colors.surface != surface
}
}
}
enum class ThemeColor {
PRIMARY, PRIMARY_VARIANT, SECONDARY, SECONDARY_VARIANT, BACKGROUND, SURFACE;
fun fromColors(colors: Colors): Color {
return when (this) {
PRIMARY -> colors.primary
PRIMARY_VARIANT -> colors.primaryVariant
SECONDARY -> colors.secondary
SECONDARY_VARIANT -> colors.secondaryVariant
BACKGROUND -> colors.background
SURFACE -> colors.surface
}
}
val text: String
get() = when (this) {
PRIMARY -> generalGetString(R.string.color_primary)
PRIMARY_VARIANT -> generalGetString(R.string.color_primary_variant)
SECONDARY -> generalGetString(R.string.color_secondary)
SECONDARY_VARIANT -> generalGetString(R.string.color_secondary_variant)
BACKGROUND -> generalGetString(R.string.color_background)
SURFACE -> generalGetString(R.string.color_surface)
}
}
@Serializable
data class ThemeColors(
val primary: String? = null
val primary: String? = null,
val primaryVariant: String? = null,
val secondary: String? = null,
val secondaryVariant: String? = null,
val background: String? = null,
val surface: String? = null,
) {
fun toColors(base: DefaultTheme): Colors = when (base) {
DefaultTheme.LIGHT -> LightColorPalette.copy(primary = primary?.colorFromReadableHex() ?: LightColorPalette.primary)
DefaultTheme.DARK -> DarkColorPalette.copy(primary = primary?.colorFromReadableHex() ?: DarkColorPalette.primary)
DefaultTheme.BLUE -> BlueColorPalette.copy(primary = primary?.colorFromReadableHex() ?: BlueColorPalette.primary)
// shouldn't be here
DefaultTheme.SYSTEM -> LightColorPalette.copy(primary = primary?.colorFromReadableHex() ?: LightColorPalette.primary)
fun toColors(base: DefaultTheme): Colors {
val baseColors = when (base) {
DefaultTheme.LIGHT -> LightColorPalette
DefaultTheme.DARK -> DarkColorPalette
DefaultTheme.BLUE -> BlueColorPalette
// shouldn't be here
DefaultTheme.SYSTEM -> LightColorPalette
}
return baseColors.copy(
primary = primary?.colorFromReadableHex() ?: baseColors.primary,
primaryVariant = primaryVariant?.colorFromReadableHex() ?: baseColors.primaryVariant,
secondary = secondary?.colorFromReadableHex() ?: baseColors.secondary,
secondaryVariant = secondaryVariant?.colorFromReadableHex() ?: baseColors.secondaryVariant,
background = background?.colorFromReadableHex() ?: baseColors.background,
surface = surface?.colorFromReadableHex() ?: baseColors.surface,
)
}
}
@@ -48,7 +98,18 @@ private fun String.colorFromReadableHex(): Color =
data class ThemeOverrides (
val base: DefaultTheme,
val colors: ThemeColors
)
) {
fun withUpdatedColor(name: ThemeColor, color: String): ThemeOverrides {
return copy(colors = when (name) {
ThemeColor.PRIMARY -> colors.copy(primary = color)
ThemeColor.PRIMARY_VARIANT -> colors.copy(primaryVariant = color)
ThemeColor.SECONDARY -> colors.copy(secondary = color)
ThemeColor.SECONDARY_VARIANT -> colors.copy(secondaryVariant = color)
ThemeColor.BACKGROUND -> colors.copy(background = color)
ThemeColor.SURFACE -> colors.copy(surface = color)
})
}
}
fun Modifier.themedBackground(baseTheme: DefaultTheme = CurrentColors.value.base, shape: Shape = RectangleShape): Modifier {
return if (baseTheme == DefaultTheme.BLUE) {
@@ -26,17 +26,17 @@ object ThemeManager {
val themeName = appPrefs.currentTheme.get()!!
val themeOverrides = appPrefs.themeOverrides.get()
val theme = if (themeName != DefaultTheme.SYSTEM.name) {
themeOverrides[themeName]
val nonSystemThemeName = if (themeName != DefaultTheme.SYSTEM.name) {
themeName
} else {
themeOverrides[if (darkForSystemTheme) appPrefs.systemDarkTheme.get() else DefaultTheme.LIGHT.name]
if (darkForSystemTheme) appPrefs.systemDarkTheme.get()!! else DefaultTheme.LIGHT.name
}
val baseTheme = when (themeName) {
DefaultTheme.SYSTEM.name -> if (darkForSystemTheme) systemDarkThemeColors() else Pair(LightColorPalette, DefaultTheme.LIGHT)
val theme = themeOverrides[nonSystemThemeName]
val baseTheme = when (nonSystemThemeName) {
DefaultTheme.LIGHT.name -> Pair(LightColorPalette, DefaultTheme.LIGHT)
DefaultTheme.DARK.name -> Pair(DarkColorPalette, DefaultTheme.DARK)
DefaultTheme.BLUE.name -> Pair(BlueColorPalette, DefaultTheme.BLUE)
else -> if (theme != null) theme.colors.toColors(theme.base) to theme.base else Pair(LightColorPalette, DefaultTheme.LIGHT)
else -> Pair(LightColorPalette, DefaultTheme.LIGHT)
}
if (theme == null) {
return ActiveTheme(themeName, baseTheme.second, baseTheme.first)
@@ -44,6 +44,17 @@ object ThemeManager {
return ActiveTheme(themeName, baseTheme.second, theme.colors.toColors(theme.base))
}
fun currentThemeOverrides(darkForSystemTheme: Boolean): ThemeOverrides {
val themeName = appPrefs.currentTheme.get()!!
val nonSystemThemeName = if (themeName != DefaultTheme.SYSTEM.name) {
themeName
} else {
if (darkForSystemTheme) appPrefs.systemDarkTheme.get()!! else DefaultTheme.LIGHT.name
}
val overrides = appPrefs.themeOverrides.get().toMutableMap()
return overrides[nonSystemThemeName] ?: ThemeOverrides(base = CurrentColors.value.base, colors = ThemeColors())
}
// colors, default theme enum, localized name of theme
fun allThemes(darkForSystemTheme: Boolean): List<Triple<Colors, DefaultTheme, String>> {
val allThemes = ArrayList<Triple<Colors, DefaultTheme, String>>()
@@ -88,24 +99,50 @@ object ThemeManager {
CurrentColors.value = currentColors(darkForSystemTheme)
}
fun saveAndApplyPrimaryColor(color: Color? = null, darkForSystemTheme: Boolean) {
fun saveAndApplyThemeColor(name: ThemeColor, color: Color? = null, darkForSystemTheme: Boolean) {
val themeName = appPrefs.currentTheme.get()!!
val nonSystemThemeName = if (themeName != DefaultTheme.SYSTEM.name) {
themeName
} else {
if (darkForSystemTheme) appPrefs.systemDarkTheme.get()!! else DefaultTheme.LIGHT.name
}
val color = color ?: when(themeName) {
DefaultTheme.LIGHT.name -> LightColorPalette.primary
DefaultTheme.DARK.name -> DarkColorPalette.primary
DefaultTheme.BLUE.name -> BlueColorPalette.primary
else -> (if (darkForSystemTheme) systemDarkThemeColors().first else LightColorPalette).primary
var colorToSet = color
if (colorToSet == null) {
// Setting default color from a base theme
colorToSet = when(nonSystemThemeName) {
DefaultTheme.LIGHT.name -> name.fromColors(LightColorPalette)
DefaultTheme.DARK.name -> name.fromColors(DarkColorPalette)
DefaultTheme.BLUE.name -> name.fromColors(BlueColorPalette)
// Will not be here
else -> return
}
}
val overrides = appPrefs.themeOverrides.get().toMutableMap()
val prevValue = overrides[nonSystemThemeName]
val current = prevValue?.copy(colors = prevValue.colors.copy(primary = color.toReadableHex()))
?: ThemeOverrides(base = CurrentColors.value.base, colors = ThemeColors(primary = color.toReadableHex()))
overrides[nonSystemThemeName] = current
val prevValue = overrides[nonSystemThemeName] ?: ThemeOverrides(base = CurrentColors.value.base, colors = ThemeColors())
overrides[nonSystemThemeName] = prevValue.withUpdatedColor(name, colorToSet.toReadableHex())
appPrefs.themeOverrides.set(overrides)
CurrentColors.value = currentColors(!CurrentColors.value.colors.isLight)
}
fun saveAndApplyThemeOverrides(theme: ThemeOverrides, darkForSystemTheme: Boolean) {
val overrides = appPrefs.themeOverrides.get().toMutableMap()
val prevValue = overrides[theme.base.name] ?: ThemeOverrides(base = CurrentColors.value.base, colors = ThemeColors())
overrides[theme.base.name] = prevValue.copy(colors = theme.colors)
appPrefs.themeOverrides.set(overrides)
appPrefs.currentTheme.set(theme.base.name)
CurrentColors.value = currentColors(!CurrentColors.value.colors.isLight)
}
fun resetAllThemeColors(darkForSystemTheme: Boolean) {
val themeName = appPrefs.currentTheme.get()!!
val nonSystemThemeName = if (themeName != DefaultTheme.SYSTEM.name) {
themeName
} else {
if (darkForSystemTheme) appPrefs.systemDarkTheme.get()!! else DefaultTheme.LIGHT.name
}
val overrides = appPrefs.themeOverrides.get().toMutableMap()
val prevValue = overrides[nonSystemThemeName] ?: return
overrides[nonSystemThemeName] = prevValue.copy(colors = ThemeColors())
appPrefs.themeOverrides.set(overrides)
CurrentColors.value = currentColors(!CurrentColors.value.colors.isLight)
}
@@ -3,10 +3,12 @@ package chat.simplex.app.views.helpers
import android.content.res.Configuration
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
@@ -42,14 +44,19 @@ fun CloseSheetBar(close: (() -> Unit)?, endButtons: @Composable RowScope.() -> U
@Composable
fun AppBarTitle(title: String, withPadding: Boolean = true) {
val theme = CurrentColors.collectAsState()
val brush = if (theme.value.base == DefaultTheme.BLUE)
Brush.linearGradient(listOf(Color(0xff1068D9), Color(0xff41A9F5)), Offset(0f, Float.POSITIVE_INFINITY), Offset(Float.POSITIVE_INFINITY, 0f))
else // color is not updated when changing themes if I pass null here
Brush.linearGradient(listOf(MaterialTheme.colors.primaryVariant, MaterialTheme.colors.primaryVariant), Offset(0f, Float.POSITIVE_INFINITY), Offset(Float.POSITIVE_INFINITY, 0f))
Text(
title,
Modifier
.fillMaxWidth()
.padding(bottom = DEFAULT_PADDING * 1.5f, start = if (withPadding) DEFAULT_PADDING else 0.dp, end = if (withPadding) DEFAULT_PADDING else 0.dp,),
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.h1,
color = if (CurrentColors.collectAsState().value.base == DefaultTheme.BLUE) MaterialTheme.colors.primaryVariant else MaterialTheme.colors.primary,
style = MaterialTheme.typography.h1.copy(brush = brush),
color = MaterialTheme.colors.primaryVariant,
textAlign = TextAlign.Center
)
}
@@ -37,6 +37,8 @@ import androidx.core.text.HtmlCompat
import chat.simplex.app.*
import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.ThemeOverrides
import com.charleskorn.kaml.decodeFromStream
import kotlinx.coroutines.*
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
@@ -388,6 +390,22 @@ fun getDrawableFromUri(uri: Uri, withAlertOnException: Boolean = true): Drawable
}
}
fun getThemeFromUri(uri: Uri, withAlertOnException: Boolean = true): ThemeOverrides? {
SimplexApp.context.contentResolver.openInputStream(uri).use {
runCatching {
return yaml.decodeFromStream<ThemeOverrides>(it!!)
}.onFailure {
if (withAlertOnException) {
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.import_theme_error),
text = generalGetString(R.string.import_theme_error_desc),
)
}
}
}
return null
}
fun saveImage(context: Context, uri: Uri): String? {
val bitmap = getBitmapFromUri(uri) ?: return null
return saveImage(context, bitmap)
@@ -3,14 +3,22 @@ package chat.simplex.app.views.usersettings
import SectionBottomSpacer
import SectionCustomFooter
import SectionDividerSpaced
import SectionItemView
import SectionItemViewSpaceBetween
import SectionSpacer
import SectionView
import android.app.Activity
import android.content.ComponentName
import android.content.Context
import android.content.pm.PackageManager
import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED
import android.net.Uri
import android.util.Log
import android.widget.Toast
import androidx.activity.compose.ManagedActivityResultLauncher
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyRow
@@ -32,12 +40,13 @@ import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toBitmap
import chat.simplex.app.*
import chat.simplex.app.R
import chat.simplex.app.model.ChatModel
import chat.simplex.app.model.SharedPreference
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import com.godaddy.android.colorpicker.*
import kotlinx.coroutines.delay
import kotlinx.serialization.encodeToString
import java.io.BufferedOutputStream
import java.util.*
import kotlin.collections.ArrayList
@@ -72,9 +81,9 @@ fun AppearanceView(m: ChatModel) {
m.controller.appPrefs.appLanguage,
m.controller.appPrefs.systemDarkTheme,
changeIcon = ::setAppIcon,
editPrimaryColor = { primary ->
editColor = { name, initialColor ->
ModalManager.shared.showModalCloseable { close ->
ColorEditor(primary, close)
ColorEditor(name, initialColor, close)
}
},
)
@@ -85,7 +94,7 @@ fun AppearanceView(m: ChatModel) {
languagePref: SharedPreference<String?>,
systemDarkTheme: SharedPreference<String?>,
changeIcon: (AppIcon) -> Unit,
editPrimaryColor: (Color) -> Unit,
editColor: (ThemeColor, Color) -> Unit,
) {
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
@@ -152,31 +161,78 @@ fun AppearanceView(m: ChatModel) {
ThemeManager.applyTheme(it, darkTheme)
}
if (state.value == DefaultTheme.SYSTEM.name) {
val systemDarkTheme = remember { systemDarkTheme.state }
PreferenceToggle(generalGetString(R.string.simplex_blue_as_dark_theme), systemDarkTheme.value == DefaultTheme.BLUE.name) {
ThemeManager.changeDarkTheme(if (it) DefaultTheme.BLUE.name else DefaultTheme.DARK.name, darkTheme)
}
/*DarkThemeSelector(systemDarkTheme) {
DarkThemeSelector(remember { systemDarkTheme.state }) {
ThemeManager.changeDarkTheme(it, darkTheme)
}*/
}
}
SectionItemViewSpaceBetween({ editPrimaryColor(currentTheme.colors.primary) }) {
SectionItemViewSpaceBetween({ editColor(ThemeColor.PRIMARY, currentTheme.colors.primary) }) {
val title = generalGetString(R.string.color_primary)
Text(title)
Icon(painterResource(R.drawable.ic_circle_filled), title, tint = colors.primary)
}
}
if (currentTheme.base.hasChangedPrimary(currentTheme.colors)) {
SectionCustomFooter(PaddingValues(start = 7.dp, end = 7.dp, top = 5.dp)) {
val isInDarkTheme = isInDarkTheme()
TextButton(
onClick = {
ThemeManager.saveAndApplyPrimaryColor(darkForSystemTheme = isInDarkTheme)
},
) {
Text(generalGetString(R.string.reset_color))
// Not allowed to change title color since it is using gradient brush with custom colors
if (currentTheme.base != DefaultTheme.BLUE) {
SectionItemViewSpaceBetween({ editColor(ThemeColor.PRIMARY_VARIANT, currentTheme.colors.primaryVariant) }) {
val title = generalGetString(R.string.color_primary_variant)
Text(title)
Icon(painterResource(R.drawable.ic_circle_filled), title, tint = colors.primaryVariant)
}
}
SectionItemViewSpaceBetween({ editColor(ThemeColor.SECONDARY, currentTheme.colors.secondary) }) {
val title = generalGetString(R.string.color_secondary)
Text(title)
Icon(painterResource(R.drawable.ic_circle_filled), title, tint = colors.secondary)
}
// Not using it yet
/*SectionItemViewSpaceBetween({ editColor(ThemeColor.SECONDARY_VARIANT, currentTheme.colors.secondaryVariant) }) {
val title = generalGetString(R.string.color_secondary_variant)
Text(title)
Icon(painterResource(R.drawable.ic_circle_filled), title, tint = colors.secondaryVariant)
}*/
SectionItemViewSpaceBetween({ editColor(ThemeColor.BACKGROUND, currentTheme.colors.background) }) {
val title = generalGetString(R.string.color_background)
Text(title)
Icon(painterResource(R.drawable.ic_circle_filled), title, tint = colors.background)
}
SectionItemViewSpaceBetween({ editColor(ThemeColor.SURFACE, currentTheme.colors.surface) }) {
val title = generalGetString(R.string.color_surface)
Text(title)
Icon(painterResource(R.drawable.ic_circle_filled), title, tint = colors.surface)
}
}
val isInDarkTheme = isInDarkTheme()
if (currentTheme.base.hasChangedAnyColor(currentTheme.colors)) {
SectionItemView({ ThemeManager.resetAllThemeColors(darkForSystemTheme = isInDarkTheme) }) {
Text(generalGetString(R.string.reset_color), color = colors.error)
}
}
SectionSpacer()
SectionView {
if (currentTheme.base.hasChangedAnyColor(currentTheme.colors)) {
val context = LocalContext.current
val theme = remember { mutableStateOf(null as String?) }
val exportThemeLauncher = rememberSaveThemeLauncher(context, theme)
SectionItemView({
val overrides = ThemeManager.currentThemeOverrides(isInDarkTheme)
theme.value = yaml.encodeToString<ThemeOverrides>(overrides)
exportThemeLauncher.launch("SimpleX-${overrides.base.name}.yml")
}) {
Text(generalGetString(R.string.export_theme), color = colors.primary)
}
}
val importThemeLauncher = rememberGetContentLauncher { uri: Uri? ->
if (uri != null) {
val theme = getThemeFromUri(uri)
if (theme != null) {
ThemeManager.saveAndApplyThemeOverrides(theme, isInDarkTheme)
}
}
}
// Can not limit to YAML mime type since it's unsupported by Android
SectionItemView({ importThemeLauncher.launch("*/*") }) {
Text(generalGetString(R.string.import_theme), color = colors.error)
}
}
SectionBottomSpacer()
}
@@ -184,6 +240,7 @@ fun AppearanceView(m: ChatModel) {
@Composable
fun ColorEditor(
name: ThemeColor,
initialColor: Color,
close: () -> Unit,
) {
@@ -191,7 +248,7 @@ fun ColorEditor(
Modifier
.fillMaxWidth()
) {
AppBarTitle(stringResource(R.string.color_primary))
AppBarTitle(name.text)
var currentColor by remember { mutableStateOf(initialColor) }
ColorPicker(initialColor) {
currentColor = it
@@ -201,7 +258,7 @@ fun ColorEditor(
val isInDarkTheme = isInDarkTheme()
TextButton(
onClick = {
ThemeManager.saveAndApplyPrimaryColor(currentColor, isInDarkTheme)
ThemeManager.saveAndApplyThemeColor(name, currentColor, isInDarkTheme)
close()
},
Modifier.align(Alignment.CenterHorizontally),
@@ -289,6 +346,33 @@ private fun DarkThemeSelector(state: State<String?>, onSelected: (String) -> Uni
// activity.startActivity(Intent(Settings.ACTION_APP_LOCALE_SETTINGS, Uri.parse("package:" + SimplexApp.context.packageName)))
//}
@Composable
private fun rememberSaveThemeLauncher(cxt: Context, theme: MutableState<String?>): ManagedActivityResultLauncher<String, Uri?> =
rememberLauncherForActivityResult(
contract = ActivityResultContracts.CreateDocument(),
onResult = { destination ->
try {
destination?.let {
val theme = theme.value
if (theme != null) {
val contentResolver = cxt.contentResolver
contentResolver.openOutputStream(destination)?.let { stream ->
BufferedOutputStream(stream).use { outputStream ->
theme.byteInputStream().use { it.copyTo(outputStream) }
}
Toast.makeText(cxt, generalGetString(R.string.file_saved), Toast.LENGTH_SHORT).show()
}
}
}
} catch (e: Error) {
Toast.makeText(cxt, generalGetString(R.string.error_saving_file), Toast.LENGTH_SHORT).show()
Log.e(TAG, "rememberSaveThemeLauncher error saving theme $e")
} finally {
theme.value = null
}
}
)
private fun findEnabledIcon(): AppIcon = AppIcon.values().first { icon ->
SimplexApp.context.packageManager.getComponentEnabledSetting(
ComponentName(BuildConfig.APPLICATION_ID, "chat.simplex.app.MainActivity_${icon.name.lowercase()}")
@@ -304,7 +388,7 @@ fun PreviewAppearanceSettings() {
languagePref = SharedPreference({ null }, {}),
systemDarkTheme = SharedPreference({ null }, {}),
changeIcon = {},
editPrimaryColor = {},
editColor = { _, _ -> },
)
}
}
@@ -1163,11 +1163,19 @@
<!-- Appearance.kt -->
<string name="theme">Theme</string>
<string name="simplex_blue_as_dark_theme">Blue in dark mode</string>
<string name="dark_theme" translatable="false">Dark theme</string>
<string name="dark_theme">Dark theme</string>
<string name="save_color">Save color</string>
<string name="import_theme">Import theme</string>
<string name="import_theme_error">Import theme error</string>
<string name="import_theme_error_desc">Make sure the file has correct YAML syntax. Export theme to have an example of the theme file structure.</string>
<string name="export_theme">Export theme</string>
<string name="reset_color">Reset colors</string>
<string name="color_primary">Accent</string>
<string name="color_primary_variant">Additional accent</string>
<string name="color_secondary">Secondary</string>
<string name="color_secondary_variant">Additional secondary</string>
<string name="color_background">Background</string>
<string name="color_surface">Surface</string>
<!-- Preferences.kt -->
<string name="chat_preferences_you_allow">You allow</string>