From c99d685ae5dcd63378c9578f67f6cb07af9973b2 Mon Sep 17 00:00:00 2001 From: "Evgeny @ SimpleX Chat" <259188159+evgeny-simplex@users.noreply.github.com> Date: Mon, 20 Apr 2026 22:09:38 +0000 Subject: [PATCH] ui: oklch colors --- apps/ios/Shared/Theme/Theme.swift | 21 +++- apps/ios/SimpleXChat/Theme/Color.swift | 98 ++++++++++++++----- apps/ios/SimpleXChat/Theme/ThemeTypes.swift | 68 ++++++------- .../android/src/main/AndroidManifest.xml | 1 + .../chat/simplex/common/ui/theme/Color.kt | 43 ++++++-- .../chat/simplex/common/ui/theme/Theme.kt | 86 ++++++++-------- .../simplex/common/ui/theme/ThemeManager.kt | 3 + 7 files changed, 212 insertions(+), 108 deletions(-) diff --git a/apps/ios/Shared/Theme/Theme.swift b/apps/ios/Shared/Theme/Theme.swift index 1f98b23a1d..e3d8cf88e1 100644 --- a/apps/ios/Shared/Theme/Theme.swift +++ b/apps/ios/Shared/Theme/Theme.swift @@ -146,13 +146,12 @@ extension ThemeModeOverride { let w: ThemeWallpaper switch wallpaperType { case let WallpaperType.preset(filename, scale): - let p = PresetWallpaper.from(filename) w = ThemeWallpaper( preset: filename, scale: scale ?? wallpaper?.scale, scaleType: nil, - background: p?.background[base]?.toReadableHex(), - tint: p?.tint[base]?.toReadableHex(), + background: nil, + tint: nil, image: nil, imageFile: nil ) @@ -174,8 +173,20 @@ extension ThemeModeOverride { preset: wallpaper.preset, scale: wallpaper.scale != w.scale ? wallpaper.scale : nil, scaleType: wallpaper.scaleType != w.scaleType ? wallpaper.scaleType : nil, - background: wallpaper.background != w.background ? wallpaper.background : nil, - tint: wallpaper.tint != w.tint ? wallpaper.tint : nil, + background: { + if case let WallpaperType.preset(filename, _) = wallpaperType, + let p = PresetWallpaper.from(filename) { + return wallpaper.background?.colorFromReadableHex().toReadableHex() != p.background[base]?.toReadableHex() ? wallpaper.background : nil + } + return wallpaper.background != w.background ? wallpaper.background : nil + }(), + tint: { + if case let WallpaperType.preset(filename, _) = wallpaperType, + let p = PresetWallpaper.from(filename) { + return wallpaper.tint?.colorFromReadableHex().toReadableHex() != p.tint[base]?.toReadableHex() ? wallpaper.tint : nil + } + return wallpaper.tint != w.tint ? wallpaper.tint : nil + }(), image: wallpaper.image, imageFile: wallpaper.imageFile ) diff --git a/apps/ios/SimpleXChat/Theme/Color.swift b/apps/ios/SimpleXChat/Theme/Color.swift index f307eaa5aa..67626052a4 100644 --- a/apps/ios/SimpleXChat/Theme/Color.swift +++ b/apps/ios/SimpleXChat/Theme/Color.swift @@ -33,63 +33,116 @@ let HighOrLowlight = Color(139, 135, 134, a: 255) //let FileLight = Color(183, 190, 199, a: 255) //let FileDark = Color(101, 101, 106, a: 255) +private let displayP3ColorSpace = CGColorSpace(name: CGColorSpace.displayP3)! +private let sRGBColorSpace = CGColorSpace(name: CGColorSpace.sRGB)! + +private func srgbToP3(red r: Double, green g: Double, blue b: Double, opacity a: Double) -> Color { + let srgb = UIColor(red: r, green: g, blue: b, alpha: a) + if let p3 = srgb.cgColor.converted(to: displayP3ColorSpace, intent: .defaultIntent, options: nil) { + return Color(p3) + } + return Color(.sRGB, red: r, green: g, blue: b, opacity: a) +} + +/// Create a Display P3 Color from oklch components. H in degrees. +func oklch(_ L: Double, _ C: Double, _ H: Double, alpha: Double = 1.0) -> Color { + let hRad = H * .pi / 180.0 + let a = C * cos(hRad) + let b = C * sin(hRad) + // oklab → LMS (Ottosson 2021) + let l_ = L + 0.3963377774 * a + 0.2158037573 * b + let m_ = L - 0.1055613458 * a - 0.0638541728 * b + let s_ = L - 0.0894841775 * a - 1.2914855480 * b + let l = l_ * l_ * l_ + let m = m_ * m_ * m_ + let s = s_ * s_ * s_ + // LMS → linear Display P3 (direct, no sRGB clamping) + let lr = 3.1281105148 * l - 2.2570749853 * m + 0.1293047593 * s + let lg = -1.0911282009 * l + 2.4132668169 * m - 0.3221681599 * s + let lb = -0.0260136845 * l - 0.5080276339 * m + 1.5333166364 * s + // linear P3 → gamma-encoded P3 (same transfer function as sRGB) + func gammaEncode(_ x: Double) -> Double { x >= 0.0031308 ? 1.055 * pow(x, 1.0 / 2.4) - 0.055 : 12.92 * x } + return Color(.displayP3, + red: gammaEncode(min(max(lr, 0), 1)), + green: gammaEncode(min(max(lg, 0), 1)), + blue: gammaEncode(min(max(lb, 0), 1)), + opacity: alpha + ) +} + extension Color { public init(_ argb: Int64) { let a = Double((argb & 0xFF000000) >> 24) / 255.0 let r = Double((argb & 0xFF0000) >> 16) / 255.0 let g = Double((argb & 0xFF00) >> 8) / 255.0 let b = Double((argb & 0xFF)) / 255.0 - self.init(.sRGB, red: r, green: g, blue: b, opacity: a) + self = srgbToP3(red: r, green: g, blue: b, opacity: a) } public init(_ r: Int, _ g: Int, _ b: Int, a: Int) { - self.init(.sRGB, red: Double(r) / 255.0, green: Double(g) / 255.0, blue: Double(b) / 255.0, opacity: Double(a) / 255.0) + self = srgbToP3(red: Double(r) / 255.0, green: Double(g) / 255.0, blue: Double(b) / 255.0, opacity: Double(a) / 255.0) } public func toReadableHex() -> String { let uiColor: UIColor = .init(self) + // Convert to sRGB explicitly since internal colors may be P3 + if let srgbCG = uiColor.cgColor.converted(to: sRGBColorSpace, intent: .defaultIntent, options: nil), + let comps = srgbCG.components, comps.count >= 3 { + let r = min(1, max(0, comps[0])) + let g = min(1, max(0, comps[1])) + let b = min(1, max(0, comps[2])) + let a = comps.count >= 4 ? min(1, max(0, comps[3])) : 1.0 + return String(format: "#%02x%02x%02x%02x", + Int((a * 255).rounded()), + Int((r * 255).rounded()), + Int((g * 255).rounded()), + Int((b * 255).rounded())) + } + // Fallback var (r, g, b, a): (CGFloat, CGFloat, CGFloat, CGFloat) = (0, 0, 0, 0) uiColor.getRed(&r, green: &g, blue: &b, alpha: &a) - // Can be negative values and more than 1. Extended color range, making it normal - r = min(1, max(0, r)) - g = min(1, max(0, g)) - b = min(1, max(0, b)) - a = min(1, max(0, a)) + r = min(1, max(0, r)); g = min(1, max(0, g)); b = min(1, max(0, b)); a = min(1, max(0, a)) return String(format: "#%02x%02x%02x%02x", Int((a * 255).rounded()), Int((r * 255).rounded()), Int((g * 255).rounded()), - Int((b * 255).rounded()) - ) + Int((b * 255).rounded())) } public func toHTMLHex() -> String { let uiColor: UIColor = .init(self) + if let srgbCG = uiColor.cgColor.converted(to: sRGBColorSpace, intent: .defaultIntent, options: nil), + let comps = srgbCG.components, comps.count >= 3 { + let r = min(1, max(0, comps[0])) + let g = min(1, max(0, comps[1])) + let b = min(1, max(0, comps[2])) + let a = comps.count >= 4 ? min(1, max(0, comps[3])) : 1.0 + return String(format: "#%02x%02x%02x%02x", + Int((r * 255).rounded()), + Int((g * 255).rounded()), + Int((b * 255).rounded()), + Int((a * 255).rounded())) + } var (r, g, b, a): (CGFloat, CGFloat, CGFloat, CGFloat) = (0, 0, 0, 0) uiColor.getRed(&r, green: &g, blue: &b, alpha: &a) - // Can be negative values and more than 1. Extended color range, making it normal - r = min(1, max(0, r)) - g = min(1, max(0, g)) - b = min(1, max(0, b)) - a = min(1, max(0, a)) + r = min(1, max(0, r)); g = min(1, max(0, g)); b = min(1, max(0, b)); a = min(1, max(0, a)) return String(format: "#%02x%02x%02x%02x", Int((r * 255).rounded()), Int((g * 255).rounded()), Int((b * 255).rounded()), - Int((a * 255).rounded()) - ) + Int((a * 255).rounded())) } public func darker(_ factor: CGFloat = 0.1) -> Color { var (r, g, b, a): (CGFloat, CGFloat, CGFloat, CGFloat) = (0, 0, 0, 0) UIColor(self).getRed(&r, green: &g, blue: &b, alpha: &a) - return Color(.sRGB, red: max(r * (1 - factor), 0), green: max(g * (1 - factor), 0), blue: max(b * (1 - factor), 0), opacity: a) + return Color(.displayP3, red: max(r * (1 - factor), 0), green: max(g * (1 - factor), 0), blue: max(b * (1 - factor), 0), opacity: a) } public func lighter(_ factor: CGFloat = 0.1) -> Color { var (r, g, b, a): (CGFloat, CGFloat, CGFloat, CGFloat) = (0, 0, 0, 0) UIColor(self).getRed(&r, green: &g, blue: &b, alpha: &a) - return Color(.sRGB, red: min(r * (1 + factor), 1), green: min(g * (1 + factor), 1), blue: min(b * (1 + factor), 1), opacity: a) + return Color(.displayP3, red: min(r * (1 + factor), 1), green: min(g * (1 + factor), 1), blue: min(b * (1 + factor), 1), opacity: a) } public func asGroupedBackground(_ mode: DefaultThemeMode) -> Color { @@ -97,8 +150,8 @@ extension Color { var (r, g, b, a): (CGFloat, CGFloat, CGFloat, CGFloat) = (0, 0, 0, 0) uiColor.getRed(&r, green: &g, blue: &b, alpha: &a) return mode == DefaultThemeMode.light - ? Color(.sRGB, red: max(0, r - 0.052), green: max(0, g - 0.051), blue: max(0, b - 0.032), opacity: a) - : Color(.sRGB, red: min(1, r + 0.11), green: min(1, g + 0.11), blue: min(1, b + 0.115), opacity: a) + ? Color(.displayP3, red: max(0, r - 0.052), green: max(0, g - 0.051), blue: max(0, b - 0.032), opacity: a) + : Color(.displayP3, red: min(1, r + 0.11), green: min(1, g + 0.11), blue: min(1, b + 0.115), opacity: a) } } @@ -120,11 +173,10 @@ extension String { (a, r, g, b) = (1, 1, 1, 0) } - return Color( - .sRGB, + return srgbToP3( red: Double(r) / 255, green: Double(g) / 255, - blue: Double(b) / 255, + blue: Double(b) / 255, opacity: Double(a) / 255 ) } diff --git a/apps/ios/SimpleXChat/Theme/ThemeTypes.swift b/apps/ios/SimpleXChat/Theme/ThemeTypes.swift index a4e8050c6e..c9c570ae91 100644 --- a/apps/ios/SimpleXChat/Theme/ThemeTypes.swift +++ b/apps/ios/SimpleXChat/Theme/ThemeTypes.swift @@ -632,19 +632,19 @@ public let DarkColorPalette = Colors( secondary: HighOrLowlight, secondaryVariant: DarkGray, background: Color.black, - surface: Color(0xFF222222), + surface: oklch(0.2519647, 0, 0), error: Color.red, - onBackground: Color.white, - onSurface: Color.white, + onBackground: oklch(0.9908696, 0.00447983, 34.30938), + onSurface: oklch(0.9908696, 0.00447983, 34.30938), isLight: false ) public let DarkColorPaletteApp = AppColors( title: .white, - primaryVariant2: Color(0xFF18262E), - sentMessage: Color(0xFF18262E), - sentQuote: Color(0xFF1D3847), - receivedMessage: Color(0xff262627), - receivedQuote: Color(0xff373739) + primaryVariant2: oklch(0.2596116, 0.02435695, 234.0127), + sentMessage: oklch(0.2596116, 0.02435695, 234.0127), + sentQuote: oklch(0.3262685, 0.04242656, 234.4608), + receivedMessage: oklch(0.2690091, 0.001828474, 286.2761), + receivedQuote: oklch(0.3375424, 0.003458181, 286.2129) ) public let LightColorPalette = Colors ( @@ -661,20 +661,20 @@ public let LightColorPalette = Colors ( ) public let LightColorPaletteApp = AppColors( title: .black, - primaryVariant2: Color(0xFFE9F7FF), - sentMessage: Color(0xFFE9F7FF), - sentQuote: Color(0xFFD6F0FF), - receivedMessage: Color(0xfff5f5f6), - receivedQuote: Color(0xffececee) + primaryVariant2: oklch(0.9680794, 0.0183117, 232.503), + sentMessage: oklch(0.9680794, 0.0183117, 232.503), + sentQuote: oklch(0.9407676, 0.03409827, 233.0377), + receivedMessage: oklch(0.9704316, 0.001324867, 286.3749), + receivedQuote: oklch(0.943656, 0.002669381, 286.3484) ) public let SimplexColorPalette = Colors( - primary: Color(0xFF70F0F9), - primaryVariant: Color(0xFF1298A5), + primary: oklch(0.8862563, 0.113699, 201.5703), + primaryVariant: oklch(0.6217762, 0.1034518, 205.799), secondary: HighOrLowlight, - secondaryVariant: Color(0xFF2C464D), - background: Color(0xFF111528), - surface: Color(0xFF121C37), + secondaryVariant: oklch(0.3761328, 0.03384425, 216.5493), + background: oklch(0.2024453, 0.03849037, 273.4875), + surface: oklch(0.2331016, 0.05415408, 266.8904), error: Color.red, onBackground: Color.white, onSurface: Color.white, @@ -682,32 +682,32 @@ public let SimplexColorPalette = Colors( ) public let SimplexColorPaletteApp = AppColors( title: .white, - primaryVariant2: Color(0xFF172941), - sentMessage: Color(0xFF172941), - sentQuote: Color(0xFF1C3A57), - receivedMessage: Color(0xff25283a), - receivedQuote: Color(0xff36394a) + primaryVariant2: oklch(0.2782386, 0.05068946, 256.0234), + sentMessage: oklch(0.2782386, 0.05068946, 256.0234), + sentQuote: oklch(0.3401385, 0.06268949, 249.4274), + receivedMessage: oklch(0.2823021, 0.03341238, 276.7299), + receivedQuote: oklch(0.3488846, 0.02991734, 276.9226) ) public let BlackColorPalette = Colors( - primary: Color(0xff0077e0), - primaryVariant: Color(0xff0077e0), + primary: oklch(0.5737125, 0.1826329, 254.0001), + primaryVariant: oklch(0.5737125, 0.1826329, 254.0001), secondary: HighOrLowlight, secondaryVariant: DarkGray, - background: Color(0xff070707), - surface: Color(0xff161617), + background: oklch(0.1285578, 0, 0), + surface: oklch(0.200616, 0.001969079, 286.2208), error: Color.red, - onBackground: Color.white, - onSurface: Color.white, + onBackground: oklch(0.9908696, 0.00447983, 34.30938), + onSurface: oklch(0.9908696, 0.00447983, 34.30938), isLight: false ) public let BlackColorPaletteApp = AppColors( title: .white, - primaryVariant2: Color(0xff243747), - sentMessage: Color(0xFF18262E), - sentQuote: Color(0xFF1D3847), - receivedMessage: Color(0xff1b1b1b), - receivedQuote: Color(0xff29292b) + primaryVariant2: oklch(0.327876, 0.03765742, 244.7111), + sentMessage: oklch(0.2596116, 0.02435695, 234.0127), + sentQuote: oklch(0.3262685, 0.04242656, 234.4608), + receivedMessage: oklch(0.2221287, 0, 0), + receivedQuote: oklch(0.2817215, 0.003620283, 286.165) ) extension Colors { diff --git a/apps/multiplatform/android/src/main/AndroidManifest.xml b/apps/multiplatform/android/src/main/AndroidManifest.xml index d6059896a5..9e059afa14 100644 --- a/apps/multiplatform/android/src/main/AndroidManifest.xml +++ b/apps/multiplatform/android/src/main/AndroidManifest.xml @@ -51,6 +51,7 @@ = 0.0031308f) 1.055f * x.pow(1f / 2.4f) - 0.055f else 12.92f * x + return Color( + red = gammaEncode(r.coerceIn(0f, 1f)), + green = gammaEncode(g.coerceIn(0f, 1f)), + blue = gammaEncode(bl.coerceIn(0f, 1f)), + alpha = alpha, + colorSpace = ColorSpaces.DisplayP3 + ) +} val Purple200 = Color(0xFFBB86FC) val Purple500 = Color(0xFF6200EE) @@ -14,12 +45,12 @@ val Purple700 = Color(0xFF3700B3) val Teal200 = Color(0xFF03DAC5) val Gray = Color(0x22222222) val Indigo = Color(0xFF9966FF) -val SimplexBlue = Color(0, 136, 255, 255) // If this value changes also need to update #0088ff in string resource files -val SimplexGreen = Color(77, 218, 103, 255) -val SecretColor = Color(0x40808080) -val LightGray = Color(241, 242, 246, 255) -val DarkGray = Color(43, 44, 46, 255) -val HighOrLowlight = Color(139, 135, 134, 255) +val SimplexBlue = oklch(0.6320536f, 0.2017874f, 254.0879f) // If this value changes also need to update #0088ff in string resource files +val SimplexGreen = oklch(0.7871495f, 0.1979258f, 146.6814f) +val SecretColor = oklch(0.5998708f, 0f, 0f, 0.2509804f) +val LightGray = oklch(0.9615242f, 0.005440391f, 274.9652f) +val DarkGray = oklch(0.2928853f, 0.003884885f, 264.5058f) +val HighOrLowlight = oklch(0.6265517f, 0.005036114f, 34.30441f) val MessagePreviewDark = Color(179, 175, 174, 255) val MessagePreviewLight = Color(49, 45, 44, 255) val ToolbarLight = Color(220, 220, 220, 12) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt index 1b5a81a819..ee97ae8c9f 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt @@ -537,8 +537,8 @@ data class ThemeModeOverride ( preset = wallpaperType.filename, scale = p?.scale ?: wallpaper?.scale, scaleType = null, - background = p?.background?.get(base)?.toReadableHex(), - tint = p?.tint?.get(base)?.toReadableHex(), + background = null, + tint = null, image = null, imageFile = null, ) @@ -578,8 +578,14 @@ data class ThemeModeOverride ( preset = wallpaper.preset, scale = if (wallpaper.scale != w.scale) wallpaper.scale else null, scaleType = if (wallpaper.scaleType != w.scaleType) wallpaper.scaleType else null, - background = if (wallpaper.background != w.background) wallpaper.background else null, - tint = if (wallpaper.tint != w.tint) wallpaper.tint else null, + background = if (WallpaperType.from(wallpaper) is WallpaperType.Preset) { + val p = PresetWallpaper.from((WallpaperType.from(wallpaper) as WallpaperType.Preset).filename) + if (wallpaper.background?.colorFromReadableHex()?.toArgb() != p?.background?.get(base)?.toArgb()) wallpaper.background else null + } else if (wallpaper.background != w.background) wallpaper.background else null, + tint = if (WallpaperType.from(wallpaper) is WallpaperType.Preset) { + val p = PresetWallpaper.from((WallpaperType.from(wallpaper) as WallpaperType.Preset).filename) + if (wallpaper.tint?.colorFromReadableHex()?.toArgb() != p?.tint?.get(base)?.toArgb()) wallpaper.tint else null + } else if (wallpaper.tint != w.tint) wallpaper.tint else null, image = wallpaper.image, imageFile = wallpaper.imageFile, ) @@ -637,20 +643,20 @@ val DarkColorPalette = darkColors( secondary = HighOrLowlight, secondaryVariant = DarkGray, // background = Color.Black, - surface = Color(0xFF222222), + surface = oklch(0.2519647f, 0f, 0f), // background = Color(0xFF121212), error = Color.Red, - onBackground = Color(0xFFFFFBFA), - onSurface = Color(0xFFFFFBFA), + onBackground = oklch(0.9908696f, 0.00447983f, 34.30938f), + onSurface = oklch(0.9908696f, 0.00447983f, 34.30938f), // onError: Color = Color.Black, ) val DarkColorPaletteApp = AppColors( title = SimplexBlue, - primaryVariant2 = Color(0xFF18262E), - sentMessage = Color(0xFF18262E), - sentQuote = Color(0xFF1D3847), - receivedMessage = Color(0xff262627), - receivedQuote = Color(0xff373739), + primaryVariant2 = oklch(0.2596116f, 0.02435695f, 234.0127f), + sentMessage = oklch(0.2596116f, 0.02435695f, 234.0127f), + sentQuote = oklch(0.3262685f, 0.04242656f, 234.4608f), + receivedMessage = oklch(0.2690091f, 0.001828474f, 286.2761f), + receivedQuote = oklch(0.3375424f, 0.003458181f, 286.2129f), ) val LightColorPalette = lightColors( @@ -668,57 +674,57 @@ val LightColorPalette = lightColors( ) val LightColorPaletteApp = AppColors( title = SimplexBlue, - primaryVariant2 = Color(0xFFE9F7FF), - sentMessage = Color(0xFFE9F7FF), - sentQuote = Color(0xFFD6F0FF), - receivedMessage = Color(0xfff5f5f6), - receivedQuote = Color(0xffececee), + primaryVariant2 = oklch(0.9680794f, 0.0183117f, 232.503f), + sentMessage = oklch(0.9680794f, 0.0183117f, 232.503f), + sentQuote = oklch(0.9407676f, 0.03409827f, 233.0377f), + receivedMessage = oklch(0.9704316f, 0.001324867f, 286.3749f), + receivedQuote = oklch(0.943656f, 0.002669381f, 286.3484f), ) val SimplexColorPalette = darkColors( - primary = Color(0xFF70F0F9), // If this value changes also need to update #0088ff in string resource files - primaryVariant = Color(0xFF1298A5), + primary = oklch(0.8862563f, 0.113699f, 201.5703f), // If this value changes also need to update #0088ff in string resource files + primaryVariant = oklch(0.6217762f, 0.1034518f, 205.799f), secondary = HighOrLowlight, - secondaryVariant = Color(0xFF2C464D), - background = Color(0xFF111528), + secondaryVariant = oklch(0.3761328f, 0.03384425f, 216.5493f), + background = oklch(0.2024453f, 0.03849037f, 273.4875f), // surface = Color.Black, // background = Color(0xFF121212), - surface = Color(0xFF121C37), + surface = oklch(0.2331016f, 0.05415408f, 266.8904f), error = Color.Red, // onBackground = Color(0xFFFFFBFA), // onSurface = Color(0xFFFFFBFA), // onError: Color = Color.Black, ) val SimplexColorPaletteApp = AppColors( - title = Color(0xFF267BE5), - primaryVariant2 = Color(0xFF172941), - sentMessage = Color(0xFF172941), - sentQuote = Color(0xFF1C3A57), - receivedMessage = Color(0xff25283a), - receivedQuote = Color(0xff36394a), + title = oklch(0.5909158f, 0.1793687f, 256.4473f), + primaryVariant2 = oklch(0.2782386f, 0.05068946f, 256.0234f), + sentMessage = oklch(0.2782386f, 0.05068946f, 256.0234f), + sentQuote = oklch(0.3401385f, 0.06268949f, 249.4274f), + receivedMessage = oklch(0.2823021f, 0.03341238f, 276.7299f), + receivedQuote = oklch(0.3488846f, 0.02991734f, 276.9226f), ) val BlackColorPalette = darkColors( - primary = Color(0xff0077e0), // If this value changes also need to update #0088ff in string resource files - primaryVariant = Color(0xff0077e0), + primary = oklch(0.5737125f, 0.1826329f, 254.0001f), // If this value changes also need to update #0088ff in string resource files + primaryVariant = oklch(0.5737125f, 0.1826329f, 254.0001f), secondary = HighOrLowlight, secondaryVariant = DarkGray, - background = Color(0xff070707), - surface = Color(0xff161617), + background = oklch(0.1285578f, 0f, 0f), + surface = oklch(0.200616f, 0.001969079f, 286.2208f), // background = Color(0xFF121212), // surface = Color(0xFF121212), error = Color.Red, - onBackground = Color(0xFFFFFBFA), - onSurface = Color(0xFFFFFBFA), + onBackground = oklch(0.9908696f, 0.00447983f, 34.30938f), + onSurface = oklch(0.9908696f, 0.00447983f, 34.30938f), // onError: Color = Color.Black, ) val BlackColorPaletteApp = AppColors( - title = Color(0xff0077e0), - primaryVariant2 = Color(0xff243747), - sentMessage = Color(0xFF18262E), - sentQuote = Color(0xFF1D3847), - receivedMessage = Color(0xff1b1b1b), - receivedQuote = Color(0xff29292b), + title = oklch(0.5737125f, 0.1826329f, 254.0001f), + primaryVariant2 = oklch(0.327876f, 0.03765742f, 244.7111f), + sentMessage = oklch(0.2596116f, 0.02435695f, 234.0127f), + sentQuote = oklch(0.3262685f, 0.04242656f, 234.4608f), + receivedMessage = oklch(0.2221287f, 0f, 0f), + receivedQuote = oklch(0.2817215f, 0.003620283f, 286.165f), ) var systemInDarkThemeCurrently: Boolean = isInNightMode() diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/ThemeManager.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/ThemeManager.kt index 7d8c79b4a8..ba7c7d1b13 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/ThemeManager.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/ThemeManager.kt @@ -3,6 +3,8 @@ package chat.simplex.common.ui.theme import androidx.compose.material.Colors import androidx.compose.runtime.MutableState import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.colorspace.ColorSpaces +import androidx.compose.ui.graphics.convert import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.text.font.FontFamily import chat.simplex.common.model.* @@ -223,6 +225,7 @@ object ThemeManager { fun String.colorFromReadableHex(): Color = Color(this.replace("#", "").toLongOrNull(16) ?: Color.White.toArgb().toLong()) + .convert(ColorSpaces.DisplayP3) fun Color.toReadableHex(): String { val s = Integer.toHexString(toArgb())