mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-05-26 05:24:43 +00:00
divided types per target
This commit is contained in:
committed by
Evgeny Poberezkin
parent
2023464a13
commit
fb4927ca87
@@ -425,7 +425,7 @@ final class ChatModel: ObservableObject {
|
||||
func updateCurrentUserUiThemes(uiThemes: ThemeModeOverrides?) {
|
||||
guard var current = currentUser else { return }
|
||||
current.uiThemes = uiThemes
|
||||
let i = users.index(where: { $0.user.userId == current.userId })
|
||||
let i = users.firstIndex(where: { $0.user.userId == current.userId })
|
||||
if let i {
|
||||
users[i].user = current
|
||||
}
|
||||
|
||||
@@ -825,15 +825,15 @@ func apiSetConnectionAlias(connId: Int64, localAlias: String) async throws -> Pe
|
||||
throw r
|
||||
}
|
||||
|
||||
func apiSetUserUIThemes(userId: Int64, themes: ThemeModeOverrides?) -> Bool {
|
||||
func apiSetUserUIThemes(userId: Int64, themes: ThemeModeOverrides?) async -> Bool {
|
||||
let r = await chatSendCmd(.apiSetUserUIThemes(userId: userId, themes: themes))
|
||||
if case .cmdOk = r { return true }
|
||||
logger.error("apiSetUserUIThemes bad response: \(String(describing: r))")
|
||||
return false
|
||||
}
|
||||
|
||||
func apiSetChatUIThemes(chatId: ChatId, themes: ThemeModeOverrides?) -> Bool {
|
||||
let r = chatSendCmd(.apiSetChatUIThemes(chatId: chatId, themes: themes))
|
||||
func apiSetChatUIThemes(chatId: ChatId, themes: ThemeModeOverrides?) async -> Bool {
|
||||
let r = await chatSendCmd(.apiSetChatUIThemes(chatId: chatId, themes: themes))
|
||||
if case .cmdOk = r { return true }
|
||||
logger.error("apiSetChatUIThemes bad response: \(String(describing: r))")
|
||||
return false
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
//
|
||||
// ThemeShared.swift
|
||||
// SimpleX (iOS)
|
||||
//
|
||||
// Created by Avently on 14.06.2024.
|
||||
// Copyright © 2024 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import SimpleXChat
|
||||
|
||||
var CurrentColors: ThemeManager.ActiveTheme = ThemeManager.currentColors(nil, nil, ChatModel.shared.currentUser?.uiThemes, themeOverridesDefault.get()) {
|
||||
didSet {
|
||||
AppTheme.shared.name = CurrentColors.name
|
||||
AppTheme.shared.base = CurrentColors.base
|
||||
AppTheme.shared.colors.updateColorsFrom(CurrentColors.colors)
|
||||
AppTheme.shared.appColors.updateColorsFrom(CurrentColors.appColors)
|
||||
AppTheme.shared.wallpaper.updateWallpaperFrom(CurrentColors.wallpaper)
|
||||
AppTheme.shared.objectWillChange.send()
|
||||
}
|
||||
}
|
||||
|
||||
var MenuTextColor: Color { if isInDarkTheme() { AppTheme.shared.colors.onBackground.opacity(0.8) } else { Color.black } }
|
||||
var NoteFolderIconColor: Color { AppTheme.shared.appColors.primaryVariant2 }
|
||||
|
||||
func isInDarkTheme() -> Bool { !CurrentColors.colors.isLight }
|
||||
|
||||
class AppTheme: ObservableObject {
|
||||
static let shared = AppTheme(name: CurrentColors.name, base: CurrentColors.base, colors: CurrentColors.colors, appColors: CurrentColors.appColors, wallpaper: CurrentColors.wallpaper)
|
||||
|
||||
var name: String
|
||||
var base: DefaultTheme
|
||||
@ObservedObject var colors: Colors
|
||||
@ObservedObject var appColors: AppColors
|
||||
@ObservedObject var wallpaper: AppWallpaper
|
||||
|
||||
init(name: String, base: DefaultTheme, colors: Colors, appColors: AppColors, wallpaper: AppWallpaper) {
|
||||
self.name = name
|
||||
self.base = base
|
||||
self.colors = colors
|
||||
self.appColors = appColors
|
||||
self.wallpaper = wallpaper
|
||||
}
|
||||
}
|
||||
|
||||
struct ThemedBackground: ViewModifier {
|
||||
@EnvironmentObject var theme: AppTheme
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
.background(
|
||||
theme.base == DefaultTheme.SIMPLEX
|
||||
? LinearGradient(
|
||||
colors: [
|
||||
theme.colors.background.lighter(0.4),
|
||||
theme.colors.background.darker(0.4)
|
||||
],
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
: LinearGradient(
|
||||
colors: [],
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
)
|
||||
.background(
|
||||
theme.base == DefaultTheme.SIMPLEX
|
||||
? Color.clear
|
||||
: theme.colors.background
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func reactOnDarkThemeChanges(_ isDark: Bool) {
|
||||
systemInDarkThemeCurrently = isDark
|
||||
//sceneDelegate.window?.overrideUserInterfaceStyle == .unspecified
|
||||
if currentThemeDefault.get() == DefaultTheme.SYSTEM_THEME_NAME && CurrentColors.colors.isLight == isDark {
|
||||
// Change active colors from light to dark and back based on system theme
|
||||
ThemeManager.applyTheme(DefaultTheme.SYSTEM_THEME_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
extension ThemeWallpaper {
|
||||
public func importFromString() -> ThemeWallpaper {
|
||||
if preset == nil, let image {
|
||||
// Need to save image from string and to save its path
|
||||
if let data = Data(base64Encoded: dropImagePrefix(image)),
|
||||
let parsed = UIImage(data: data),
|
||||
let filename = saveWallpaperFile(image: parsed) {
|
||||
var copy = self
|
||||
copy.image = nil
|
||||
copy.imageFile = filename
|
||||
return copy
|
||||
} else {
|
||||
return ThemeWallpaper()
|
||||
}
|
||||
} else {
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
||||
func withFilledWallpaperBase64() -> ThemeWallpaper {
|
||||
let aw = toAppWallpaper()
|
||||
let type = aw.type
|
||||
let preset: String? = if case let WallpaperType.Preset(filename, _) = type { filename } else { nil }
|
||||
let scale: Float? = if case let WallpaperType.Preset(_, scale) = type { scale } else { if case let WallpaperType.Image(_, scale, _) = type { scale } else { 1.0 } }
|
||||
let scaleType: WallpaperScaleType? = if case let WallpaperType.Image(_, _, scaleType) = type { scaleType } else { nil }
|
||||
let image: String? = if case WallpaperType.Image = type, let image = type.uiImage { resizeImageToStrSize(image, maxDataSize: 5_000_000) } else { nil }
|
||||
return ThemeWallpaper (
|
||||
preset: preset,
|
||||
scale: scale,
|
||||
scaleType: scaleType,
|
||||
background: aw.background?.toReadableHex(),
|
||||
tint: aw.tint?.toReadableHex(),
|
||||
image: image,
|
||||
imageFile: nil
|
||||
)
|
||||
}
|
||||
}
|
||||
+9
-79
@@ -10,8 +10,8 @@ import Foundation
|
||||
import SwiftUI
|
||||
import SimpleXChat
|
||||
|
||||
public class ThemeManager {
|
||||
public struct ActiveTheme {
|
||||
class ThemeManager {
|
||||
struct ActiveTheme {
|
||||
let name: String
|
||||
let base: DefaultTheme
|
||||
let colors: Colors
|
||||
@@ -49,7 +49,7 @@ public class ThemeManager {
|
||||
return perUserTheme
|
||||
}
|
||||
let defaultTheme = defaultActiveTheme(appSettingsTheme)
|
||||
return ThemeModeOverride(colors: defaultTheme?.colors ?? ThemeColors(), wallpaper: defaultTheme?.wallpaper)
|
||||
return ThemeModeOverride(mode: CurrentColors.base.mode, colors: defaultTheme?.colors ?? ThemeColors(), wallpaper: defaultTheme?.wallpaper)
|
||||
}
|
||||
|
||||
static func currentColors(_ themeOverridesForType: WallpaperType?, _ perChatTheme: ThemeModeOverride?, _ perUserTheme: ThemeModeOverrides?, _ appSettingsTheme: [ThemeOverrides]) -> ActiveTheme {
|
||||
@@ -95,7 +95,7 @@ public class ThemeManager {
|
||||
let wType = current.wallpaper.type
|
||||
let wBackground = current.wallpaper.background
|
||||
let wTint = current.wallpaper.tint
|
||||
let w: ThemeWallpaper? = if case WallpaperType.Empty = wType {
|
||||
let w: ThemeWallpaper? = if case WallpaperType.Empty = wType {
|
||||
nil
|
||||
} else {
|
||||
ThemeWallpaper.from(wType, wBackground?.toReadableHex(), wTint?.toReadableHex()).withFilledWallpaperBase64()
|
||||
@@ -176,19 +176,17 @@ public class ThemeManager {
|
||||
var w: ThemeWallpaper = ThemeWallpaper.from(type, nil, nil)
|
||||
w.scale = nil
|
||||
w.scaleType = nil
|
||||
pref.wrappedValue = ThemeModeOverride(wallpaper: w)
|
||||
pref.wrappedValue = ThemeModeOverride(mode: CurrentColors.base.mode, wallpaper: w)
|
||||
} else {
|
||||
// Make an empty wallpaper to override any top level ones
|
||||
pref.wrappedValue = ThemeModeOverride(wallpaper: ThemeWallpaper())
|
||||
pref.wrappedValue = ThemeModeOverride(mode: CurrentColors.base.mode, wallpaper: ThemeWallpaper())
|
||||
}
|
||||
return true
|
||||
}
|
||||
var type = sameWallpaper.toAppWallpaper().type
|
||||
if case let WallpaperType.Image(filename, scale, scaleType) = type, sameWallpaper.imageFile == filename {
|
||||
// same image file. Needs to be copied first in order to be able to remove the file once it's not needed anymore without affecting main theme override
|
||||
// LALAL
|
||||
let filename: String? = "LALAL"//saveWallpaperFile(File(getWallpaperFilePath(filename)).toURI())
|
||||
if let filename {
|
||||
if let filename = saveWallpaperFile(url: getWallpaperFilePath(filename)) {
|
||||
type = WallpaperType.Image(filename, scale, scaleType)
|
||||
} else {
|
||||
logger.error("Error while copying wallpaper from global overrides to chat overrides")
|
||||
@@ -221,9 +219,8 @@ public class ThemeManager {
|
||||
let pref: CodableDefault<[ThemeOverrides]> = pref ?? themeOverridesDefault
|
||||
let overrides = pref.get()
|
||||
var prevValue = overrides.getTheme(nil, wallpaper?.toAppWallpaper().type, theme.base) ?? ThemeOverrides(base: theme.base)
|
||||
if prevValue.wallpaper?.imageFile != nil {
|
||||
// LALAL
|
||||
//File(getWallpaperFilePath(prevValue.wallpaper.imageFile)).delete()
|
||||
if let imageFile = prevValue.wallpaper?.imageFile {
|
||||
try? FileManager.default.removeItem(at: getWallpaperFilePath(imageFile))
|
||||
}
|
||||
prevValue.base = theme.base
|
||||
prevValue.colors = theme.colors
|
||||
@@ -264,70 +261,3 @@ public class ThemeManager {
|
||||
themeOverridesDefault.set(themes)
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
func colorFromReadableHex() -> Color {
|
||||
// https://stackoverflow.com/a/56874327
|
||||
let hex = self.trimmingCharacters(in: ["#", " "])
|
||||
var int: UInt64 = 0
|
||||
Scanner(string: hex).scanHexInt64(&int)
|
||||
let a, r, g, b: UInt64
|
||||
switch hex.count {
|
||||
case 3: // RGB (12-bit)
|
||||
(a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
|
||||
case 6: // RGB (24-bit)
|
||||
(a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
|
||||
case 8: // ARGB (32-bit)
|
||||
(a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
|
||||
default:
|
||||
(a, r, g, b) = (1, 1, 1, 0)
|
||||
}
|
||||
|
||||
return Color(
|
||||
.sRGB,
|
||||
red: Double(r) / 255,
|
||||
green: Double(g) / 255,
|
||||
blue: Double(b) / 255,
|
||||
opacity: Double(a) / 255
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension Color {
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
func toReadableHex() -> String {
|
||||
let uiColor: UIColor = .init(self)
|
||||
var (r, g, b, a): (CGFloat, CGFloat, CGFloat, CGFloat) = (0, 0, 0, 0)
|
||||
uiColor.getRed(&r, green: &g, blue: &b, alpha: &a)
|
||||
return String(format: "#%02x%02x%02x%02x",
|
||||
Int(a * 255),
|
||||
Int(r * 255),
|
||||
Int(g * 255),
|
||||
Int(b * 255)
|
||||
)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
//
|
||||
// Color.swift
|
||||
// SimpleX (iOS)
|
||||
//
|
||||
// Created by Avently on 05.06.2024.
|
||||
// Copyright © 2024 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
let Purple200 = Color(0xFFBB86FC)
|
||||
let Purple500 = Color(0xFF6200EE)
|
||||
let Purple700 = Color(0xFF3700B3)
|
||||
let Teal200 = Color(0xFF03DAC5)
|
||||
let Gray = Color(0x22222222)
|
||||
let Indigo = Color(0xFF9966FF)
|
||||
let SimplexBlue = Color(0, 136, 255, a: 255)
|
||||
let SimplexGreen = Color(77, 218, 103, a: 255)
|
||||
let SecretColor = Color(0x40808080)
|
||||
let LightGray = Color(241, 242, 246, a: 255)
|
||||
let DarkGray = Color(43, 44, 46, a: 255)
|
||||
let HighOrLowlight = Color(139, 135, 134, a: 255)
|
||||
let MessagePreviewDark = Color(179, 175, 174, a: 255)
|
||||
let MessagePreviewLight = Color(49, 45, 44, a: 255)
|
||||
let ToolbarLight = Color(220, 220, 220, a: 12)
|
||||
let ToolbarDark = Color(80, 80, 80, a: 12)
|
||||
let SettingsSecondaryLight = Color(200, 196, 195, a: 90)
|
||||
let GroupDark = Color(80, 80, 80, a: 60)
|
||||
let IncomingCallLight = Color(239, 237, 236, a: 255)
|
||||
let WarningOrange = Color(255, 127, 0, a: 255)
|
||||
let WarningYellow = Color(255, 192, 0, a: 255)
|
||||
let FileLight = Color(183, 190, 199, a: 255)
|
||||
let FileDark = Color(101, 101, 106, a: 255)
|
||||
|
||||
var MenuTextColor: Color { if isInDarkTheme() { AppTheme.shared.colors.onBackground.opacity(0.8) } else { Color.black } }
|
||||
var NoteFolderIconColor: Color { AppTheme.shared.appColors.primaryVariant2 }
|
||||
@@ -2,7 +2,7 @@
|
||||
// ChatWallpaper.swift
|
||||
// SimpleX (iOS)
|
||||
//
|
||||
// Created by Avently on 06.06.2024.
|
||||
// Created by Avently on 14.06.2024.
|
||||
// Copyright © 2024 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
@@ -10,385 +10,6 @@ import Foundation
|
||||
import SwiftUI
|
||||
import SimpleXChat
|
||||
|
||||
public enum PresetWallpaper {
|
||||
case cats
|
||||
case flowers
|
||||
case hearts
|
||||
case kids
|
||||
case school
|
||||
case travel
|
||||
|
||||
var res: UIImage {
|
||||
UIImage(named: "wallpaper_\(filename)")!
|
||||
}
|
||||
|
||||
var filename: String {
|
||||
switch self {
|
||||
case .cats: "cats"
|
||||
case .flowers: "flowers"
|
||||
case .hearts: "hearts"
|
||||
case .kids: "kids"
|
||||
case .school: "school"
|
||||
case .travel: "travel"
|
||||
}
|
||||
}
|
||||
|
||||
var scale: Float {
|
||||
switch self {
|
||||
case .cats: 0.63
|
||||
case .flowers: 0.53
|
||||
case .hearts: 0.59
|
||||
case .kids: 0.53
|
||||
case .school: 0.53
|
||||
case .travel: 0.68
|
||||
}
|
||||
}
|
||||
|
||||
var background: [DefaultTheme: Color] {
|
||||
switch self {
|
||||
case .cats: wallpaperBackgrounds(light: "#ffF8F6EA")
|
||||
case .flowers: wallpaperBackgrounds(light: "#ffE2FFE4")
|
||||
case .hearts: wallpaperBackgrounds(light: "#ffFDECEC")
|
||||
case .kids: wallpaperBackgrounds(light: "#ffdbfdfb")
|
||||
case .school: wallpaperBackgrounds(light: "#ffE7F5FF")
|
||||
case .travel: wallpaperBackgrounds(light: "#fff9eeff")
|
||||
}
|
||||
}
|
||||
|
||||
var tint: [DefaultTheme: Color] {
|
||||
switch self {
|
||||
case .cats: [
|
||||
DefaultTheme.LIGHT: "#ffefdca6".colorFromReadableHex(),
|
||||
DefaultTheme.DARK: "#ff4b3b0e".colorFromReadableHex(),
|
||||
DefaultTheme.SIMPLEX: "#ff51400f".colorFromReadableHex(),
|
||||
DefaultTheme.BLACK: "#ff4b3b0e".colorFromReadableHex()
|
||||
]
|
||||
case .flowers: [
|
||||
DefaultTheme.LIGHT: "#ff9CEA59".colorFromReadableHex(),
|
||||
DefaultTheme.DARK: "#ff31560D".colorFromReadableHex(),
|
||||
DefaultTheme.SIMPLEX: "#ff36600f".colorFromReadableHex(),
|
||||
DefaultTheme.BLACK: "#ff31560D".colorFromReadableHex()
|
||||
]
|
||||
case .hearts: [
|
||||
DefaultTheme.LIGHT: "#fffde0e0".colorFromReadableHex(),
|
||||
DefaultTheme.DARK: "#ff3c0f0f".colorFromReadableHex(),
|
||||
DefaultTheme.SIMPLEX: "#ff411010".colorFromReadableHex(),
|
||||
DefaultTheme.BLACK: "#ff3C0F0F".colorFromReadableHex()
|
||||
]
|
||||
case .kids: [
|
||||
DefaultTheme.LIGHT: "#ffadeffc".colorFromReadableHex(),
|
||||
DefaultTheme.DARK: "#ff16404B".colorFromReadableHex(),
|
||||
DefaultTheme.SIMPLEX: "#ff184753".colorFromReadableHex(),
|
||||
DefaultTheme.BLACK: "#ff16404B".colorFromReadableHex()
|
||||
]
|
||||
case .school: [
|
||||
DefaultTheme.LIGHT: "#ffCEEBFF".colorFromReadableHex(),
|
||||
DefaultTheme.DARK: "#ff0F293B".colorFromReadableHex(),
|
||||
DefaultTheme.SIMPLEX: "#ff112f43".colorFromReadableHex(),
|
||||
DefaultTheme.BLACK: "#ff0F293B".colorFromReadableHex()
|
||||
]
|
||||
case .travel: [
|
||||
DefaultTheme.LIGHT: "#ffeedbfe".colorFromReadableHex(),
|
||||
DefaultTheme.DARK: "#ff311E48".colorFromReadableHex(),
|
||||
DefaultTheme.SIMPLEX: "#ff35204e".colorFromReadableHex(),
|
||||
DefaultTheme.BLACK: "#ff311E48".colorFromReadableHex()
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
var colors: [DefaultTheme: ThemeColors] {
|
||||
switch self {
|
||||
case .cats: [
|
||||
DefaultTheme.LIGHT: ThemeColors.from(
|
||||
sentMessage: "#fffffaed",
|
||||
sentQuote: "#fffaf0d6",
|
||||
receivedMessage: "#ffF8F7F4",
|
||||
receivedQuote: "#ffefede9"
|
||||
),
|
||||
DefaultTheme.DARK: ThemeColors.from(
|
||||
sentMessage: "#ff2f2919",
|
||||
sentQuote: "#ff473a1d",
|
||||
receivedMessage: "#ff272624",
|
||||
receivedQuote: "#ff373633"
|
||||
),
|
||||
DefaultTheme.SIMPLEX: ThemeColors.from(
|
||||
sentMessage: "#ff41371b",
|
||||
sentQuote: "#ff654f1c",
|
||||
receivedMessage: "#ff272624",
|
||||
receivedQuote: "#ff373633"
|
||||
),
|
||||
DefaultTheme.BLACK: ThemeColors.from(
|
||||
sentMessage: "#ff41371b",
|
||||
sentQuote: "#ff654f1c",
|
||||
receivedMessage: "#ff1f1e1b",
|
||||
receivedQuote: "#ff2f2d27"
|
||||
)
|
||||
]
|
||||
case .flowers: [
|
||||
DefaultTheme.LIGHT: ThemeColors.from(
|
||||
sentMessage: "#fff1ffe5",
|
||||
sentQuote: "#ffdcf9c4",
|
||||
receivedMessage: "#ffF4F8F2",
|
||||
receivedQuote: "#ffe7ece7"
|
||||
),
|
||||
DefaultTheme.DARK: ThemeColors.from(
|
||||
sentMessage: "#ff163521",
|
||||
sentQuote: "#ff1B5330",
|
||||
receivedMessage: "#ff242523",
|
||||
receivedQuote: "#ff353733"
|
||||
),
|
||||
DefaultTheme.SIMPLEX: ThemeColors.from(
|
||||
sentMessage: "#ff184739",
|
||||
sentQuote: "#ff1F6F4B",
|
||||
receivedMessage: "#ff242523",
|
||||
receivedQuote: "#ff353733"
|
||||
),
|
||||
DefaultTheme.BLACK: ThemeColors.from(
|
||||
sentMessage: "#ff184739",
|
||||
sentQuote: "#ff1F6F4B",
|
||||
receivedMessage: "#ff1c1f1a",
|
||||
receivedQuote: "#ff282b25"
|
||||
)
|
||||
]
|
||||
case .hearts: [
|
||||
DefaultTheme.LIGHT: ThemeColors.from(
|
||||
sentMessage: "#fffff4f4",
|
||||
sentQuote: "#ffffdfdf",
|
||||
receivedMessage: "#fff8f6f6",
|
||||
receivedQuote: "#ffefebeb"
|
||||
),
|
||||
DefaultTheme.DARK: ThemeColors.from(
|
||||
sentMessage: "#ff301515",
|
||||
sentQuote: "#ff4C1818",
|
||||
receivedMessage: "#ff242121",
|
||||
receivedQuote: "#ff3b3535"
|
||||
),
|
||||
DefaultTheme.SIMPLEX: ThemeColors.from(
|
||||
sentMessage: "#ff491A28",
|
||||
sentQuote: "#ff761F29",
|
||||
receivedMessage: "#ff242121",
|
||||
receivedQuote: "#ff3b3535"
|
||||
),
|
||||
DefaultTheme.BLACK: ThemeColors.from(
|
||||
sentMessage: "#ff491A28",
|
||||
sentQuote: "#ff761F29",
|
||||
receivedMessage: "#ff1f1b1b",
|
||||
receivedQuote: "#ff2e2626"
|
||||
)
|
||||
]
|
||||
case .kids: [
|
||||
DefaultTheme.LIGHT: ThemeColors.from(
|
||||
sentMessage: "#ffeafeff",
|
||||
sentQuote: "#ffcbf4f7",
|
||||
receivedMessage: "#fff3fafa",
|
||||
receivedQuote: "#ffe4efef"
|
||||
),
|
||||
DefaultTheme.DARK: ThemeColors.from(
|
||||
sentMessage: "#ff16302F",
|
||||
sentQuote: "#ff1a4a49",
|
||||
receivedMessage: "#ff252626",
|
||||
receivedQuote: "#ff373A39"
|
||||
),
|
||||
DefaultTheme.SIMPLEX: ThemeColors.from(
|
||||
sentMessage: "#ff1a4745",
|
||||
sentQuote: "#ff1d6b69",
|
||||
receivedMessage: "#ff252626",
|
||||
receivedQuote: "#ff373a39"
|
||||
),
|
||||
DefaultTheme.BLACK: ThemeColors.from(
|
||||
sentMessage: "#ff1a4745",
|
||||
sentQuote: "#ff1d6b69",
|
||||
receivedMessage: "#ff1e1f1f",
|
||||
receivedQuote: "#ff262b29"
|
||||
)
|
||||
]
|
||||
case .school: [
|
||||
DefaultTheme.LIGHT: ThemeColors.from(
|
||||
sentMessage: "#ffeef9ff",
|
||||
sentQuote: "#ffD6EDFA",
|
||||
receivedMessage: "#ffF3F5F9",
|
||||
receivedQuote: "#ffe4e8ee"
|
||||
),
|
||||
DefaultTheme.DARK: ThemeColors.from(
|
||||
sentMessage: "#ff172833",
|
||||
sentQuote: "#ff1C3E4F",
|
||||
receivedMessage: "#ff26282c",
|
||||
receivedQuote: "#ff393c40"
|
||||
),
|
||||
DefaultTheme.SIMPLEX: ThemeColors.from(
|
||||
sentMessage: "#ff1A3C5D",
|
||||
sentQuote: "#ff235b80",
|
||||
receivedMessage: "#ff26282c",
|
||||
receivedQuote: "#ff393c40"
|
||||
),
|
||||
DefaultTheme.BLACK: ThemeColors.from(
|
||||
sentMessage: "#ff1A3C5D",
|
||||
sentQuote: "#ff235b80",
|
||||
receivedMessage: "#ff1d1e22",
|
||||
receivedQuote: "#ff292b2f"
|
||||
)
|
||||
]
|
||||
case .travel: [
|
||||
DefaultTheme.LIGHT: ThemeColors.from(
|
||||
sentMessage: "#fffcf6ff",
|
||||
sentQuote: "#fff2e0fc",
|
||||
receivedMessage: "#ffF6F4F7",
|
||||
receivedQuote: "#ffede9ee"
|
||||
),
|
||||
DefaultTheme.DARK: ThemeColors.from(
|
||||
sentMessage: "#ff33263B",
|
||||
sentQuote: "#ff53385E",
|
||||
receivedMessage: "#ff272528",
|
||||
receivedQuote: "#ff3B373E"
|
||||
),
|
||||
DefaultTheme.SIMPLEX: ThemeColors.from(
|
||||
sentMessage: "#ff3C255D",
|
||||
sentQuote: "#ff623485",
|
||||
receivedMessage: "#ff26273B",
|
||||
receivedQuote: "#ff3A394F"
|
||||
),
|
||||
DefaultTheme.BLACK: ThemeColors.from(
|
||||
sentMessage: "#ff3C255D",
|
||||
sentQuote: "#ff623485",
|
||||
receivedMessage: "#ff231f23",
|
||||
receivedQuote: "#ff2c2931"
|
||||
)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
func toType(_ base: DefaultTheme, _ scale: Float? = nil) -> WallpaperType {
|
||||
WallpaperType.Preset(
|
||||
filename,
|
||||
scale ?? themeOverridesDefault.get().first { $0.wallpaper != nil && $0.wallpaper!.preset == filename && $0.base == base }?.wallpaper?.scale ?? 1
|
||||
)
|
||||
}
|
||||
|
||||
static func from(_ filename: String) -> PresetWallpaper? {
|
||||
switch filename {
|
||||
case PresetWallpaper.cats.filename: PresetWallpaper.cats
|
||||
case PresetWallpaper.flowers.filename: PresetWallpaper.flowers
|
||||
case PresetWallpaper.hearts.filename: PresetWallpaper.hearts
|
||||
case PresetWallpaper.kids.filename: PresetWallpaper.kids
|
||||
case PresetWallpaper.school.filename: PresetWallpaper.school
|
||||
case PresetWallpaper.travel.filename: PresetWallpaper.travel
|
||||
default: nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func wallpaperBackgrounds(light: String) -> [DefaultTheme : Color] {
|
||||
[
|
||||
DefaultTheme.LIGHT: light.colorFromReadableHex(),
|
||||
DefaultTheme.DARK: "#ff121212".colorFromReadableHex(),
|
||||
DefaultTheme.SIMPLEX: "#ff111528".colorFromReadableHex(),
|
||||
DefaultTheme.BLACK: "#ff070707".colorFromReadableHex()
|
||||
]
|
||||
}
|
||||
|
||||
public enum WallpaperScaleType/*(val contentScale: ContentScale)*/: Codable {
|
||||
case fill/* (ContentScale.Crop)*/
|
||||
case fit/* (ContentScale.Fit)*/
|
||||
case `repeat`/* (ContentScale.Fit)*/
|
||||
|
||||
var text: String {
|
||||
switch self {
|
||||
case .fill: "Fill"
|
||||
case .fit: "Fit"
|
||||
case .repeat: "Repeat"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum WallpaperType {
|
||||
var image: SwiftUI.Image? {
|
||||
if let uiImage {
|
||||
return SwiftUI.Image(uiImage: uiImage)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var uiImage: UIImage? {
|
||||
let filename: String
|
||||
switch self {
|
||||
case let .Preset(f, _): filename = f
|
||||
case let .Image(f, _, _): filename = f
|
||||
default: return nil
|
||||
}
|
||||
if filename == "" { return nil }
|
||||
if let image = WallpaperType.cachedImages[filename] {
|
||||
return image
|
||||
} else {
|
||||
let res: UIImage?
|
||||
if case let .Preset(filename, _) = self {
|
||||
res = (PresetWallpaper.from(filename) ?? PresetWallpaper.cats).res
|
||||
} else {
|
||||
do {
|
||||
// LALAL REMOVE
|
||||
res = nil
|
||||
// In case of unintentional image deletion don't crash the app
|
||||
//File(getWallpaperFilePath(filename)).inputStream().use { loadImageBitmap(it) }
|
||||
} catch let e {
|
||||
logger.error("Error while loading wallpaper file: \(e)")
|
||||
res = nil
|
||||
}
|
||||
}
|
||||
if let res {
|
||||
WallpaperType.cachedImages[filename] = res
|
||||
}
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
func sameType(_ other: WallpaperType?) -> Bool {
|
||||
if case let .Preset(filename, _) = self, case let .Preset(otherFilename, _) = other { filename == otherFilename }
|
||||
else if case .Image = self, case .Image = other { true }
|
||||
else if case .Empty = self, case .Empty = other { true }
|
||||
else { false }
|
||||
}
|
||||
|
||||
func samePreset(other: PresetWallpaper?) -> Bool { if case let .Preset(filename, _) = self, filename == other?.filename { true } else { false } }
|
||||
|
||||
case Preset(_ filename: String, _ scale: Float?)
|
||||
|
||||
case Image(_ filename: String, _ scale: Float?, _ scaleType: WallpaperScaleType?)
|
||||
|
||||
case Empty
|
||||
|
||||
func defaultBackgroundColor(_ theme: DefaultTheme, _ themeBackground: Color) -> Color {
|
||||
if case let .Preset(filename, _) = self {
|
||||
(PresetWallpaper.from(filename) ?? PresetWallpaper.cats).background[theme]!
|
||||
} else {
|
||||
themeBackground
|
||||
}
|
||||
}
|
||||
|
||||
func defaultTintColor(_ theme: DefaultTheme) -> Color {
|
||||
if case let .Preset(filename, _) = self {
|
||||
(PresetWallpaper.from(filename) ?? PresetWallpaper.cats).tint[theme]!
|
||||
} else if case let .Image(_, _, scaleType) = self, scaleType == WallpaperScaleType.repeat {
|
||||
Color.clear
|
||||
} else {
|
||||
Color.clear
|
||||
}
|
||||
}
|
||||
|
||||
static var cachedImages: [String: UIImage] = [:]
|
||||
|
||||
static func from(_ wallpaper: ThemeWallpaper?) -> WallpaperType? {
|
||||
if wallpaper == nil {
|
||||
return nil
|
||||
} else if let preset = wallpaper?.preset {
|
||||
return WallpaperType.Preset(preset, wallpaper?.scale)
|
||||
} else if let imageFile = wallpaper?.imageFile {
|
||||
return WallpaperType.Image(imageFile, wallpaper?.scale, wallpaper?.scaleType)
|
||||
} else {
|
||||
return WallpaperType.Empty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct ChatViewBackground: ViewModifier {
|
||||
@EnvironmentObject var theme: AppTheme
|
||||
var image: Image
|
||||
@@ -420,37 +41,37 @@ struct ChatViewBackground: ViewModifier {
|
||||
case WallpaperScaleType.repeat: repeatDraw(CGFloat(scale ?? 1))
|
||||
case WallpaperScaleType.fill: fallthrough
|
||||
case WallpaperScaleType.fit:
|
||||
// let scale = scaleType.contentScale.computeScaleFactor(Size(image.width.toFloat(), image.height.toFloat()), Size(size.width, size.height))
|
||||
// let scaledWidth = (image.width * scale.scaleX).roundToInt()
|
||||
// let scaledHeight = (image.height * scale.scaleY).roundToInt()
|
||||
// drawImage(image, dstOffset = IntOffset(x = ((size.width - scaledWidth) / 2).roundToInt(), y = ((size.height - scaledHeight) / 2).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality)
|
||||
// if (scaleType == WallpaperScaleType.FIT) {
|
||||
// if (scaledWidth < size.width) {
|
||||
// // has black lines at left and right sides
|
||||
// var x = (size.width - scaledWidth) / 2
|
||||
// while (x > 0) {
|
||||
// drawImage(image, dstOffset = IntOffset(x = (x - scaledWidth).roundToInt(), y = ((size.height - scaledHeight) / 2).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality)
|
||||
// x -= scaledWidth
|
||||
// }
|
||||
// x = size.width - (size.width - scaledWidth) / 2
|
||||
// while (x < size.width) {
|
||||
// drawImage(image, dstOffset = IntOffset(x = x.roundToInt(), y = ((size.height - scaledHeight) / 2).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality)
|
||||
// x += scaledWidth
|
||||
// }
|
||||
// } else {
|
||||
// // has black lines at top and bottom sides
|
||||
// var y = (size.height - scaledHeight) / 2
|
||||
// while (y > 0) {
|
||||
// drawImage(image, dstOffset = IntOffset(x = ((size.width - scaledWidth) / 2).roundToInt(), y = (y - scaledHeight).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality)
|
||||
// y -= scaledHeight
|
||||
// }
|
||||
// y = size.height - (size.height - scaledHeight) / 2
|
||||
// while (y < size.height) {
|
||||
// drawImage(image, dstOffset = IntOffset(x = ((size.width - scaledWidth) / 2).roundToInt(), y = y.roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality)
|
||||
// y += scaledHeight
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// let scale = scaleType.contentScale.computeScaleFactor(Size(image.width.toFloat(), image.height.toFloat()), Size(size.width, size.height))
|
||||
// let scaledWidth = (image.width * scale.scaleX).roundToInt()
|
||||
// let scaledHeight = (image.height * scale.scaleY).roundToInt()
|
||||
// drawImage(image, dstOffset = IntOffset(x = ((size.width - scaledWidth) / 2).roundToInt(), y = ((size.height - scaledHeight) / 2).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality)
|
||||
// if (scaleType == WallpaperScaleType.FIT) {
|
||||
// if (scaledWidth < size.width) {
|
||||
// // has black lines at left and right sides
|
||||
// var x = (size.width - scaledWidth) / 2
|
||||
// while (x > 0) {
|
||||
// drawImage(image, dstOffset = IntOffset(x = (x - scaledWidth).roundToInt(), y = ((size.height - scaledHeight) / 2).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality)
|
||||
// x -= scaledWidth
|
||||
// }
|
||||
// x = size.width - (size.width - scaledWidth) / 2
|
||||
// while (x < size.width) {
|
||||
// drawImage(image, dstOffset = IntOffset(x = x.roundToInt(), y = ((size.height - scaledHeight) / 2).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality)
|
||||
// x += scaledWidth
|
||||
// }
|
||||
// } else {
|
||||
// // has black lines at top and bottom sides
|
||||
// var y = (size.height - scaledHeight) / 2
|
||||
// while (y > 0) {
|
||||
// drawImage(image, dstOffset = IntOffset(x = ((size.width - scaledWidth) / 2).roundToInt(), y = (y - scaledHeight).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality)
|
||||
// y -= scaledHeight
|
||||
// }
|
||||
// y = size.height - (size.height - scaledHeight) / 2
|
||||
// while (y < size.height) {
|
||||
// drawImage(image, dstOffset = IntOffset(x = ((size.width - scaledWidth) / 2).roundToInt(), y = y.roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality)
|
||||
// y += scaledHeight
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
context.fill(Path(rect), with: .color(tint))
|
||||
}
|
||||
case WallpaperType.Empty: ()
|
||||
@@ -460,3 +81,11 @@ struct ChatViewBackground: ViewModifier {
|
||||
}
|
||||
}
|
||||
|
||||
extension PresetWallpaper {
|
||||
public func toType(_ base: DefaultTheme, _ scale: Float? = nil) -> WallpaperType {
|
||||
WallpaperType.Preset(
|
||||
filename,
|
||||
scale ?? themeOverridesDefault.get().first { $0.wallpaper != nil && $0.wallpaper!.preset == filename && $0.base == base }?.wallpaper?.scale ?? 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ extension AppSettings {
|
||||
if let val = uiColorScheme { def.setValue(val, forKey: DEFAULT_CURRENT_THEME) }
|
||||
if let val = uiDarkColorScheme { def.setValue(val, forKey: DEFAULT_SYSTEM_DARK_THEME) }
|
||||
if let val = uiCurrentThemeIds { def.setValue(val, forKey: DEFAULT_CURRENT_THEME_IDS) }
|
||||
if let val = uiThemes { def.setValue(val, forKey: DEFAULT_THEME_OVERRIDES) }
|
||||
if let val = uiThemes { def.setValue(val.skipDuplicates(), forKey: DEFAULT_THEME_OVERRIDES) }
|
||||
}
|
||||
|
||||
public static var current: AppSettings {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SimpleXChat
|
||||
|
||||
let defaultAccentColor = CGColor.init(red: 0, green: 0.533, blue: 1, alpha: 1)
|
||||
|
||||
|
||||
@@ -439,8 +439,7 @@ func doStartChat() -> DBMigrationResult? {
|
||||
logger.debug("NotificationService active user \(String(describing: user))")
|
||||
do {
|
||||
try setNetworkConfig(networkConfig)
|
||||
try apiSetTempFolder(tempFolder: getTempFilesDirectory().path)
|
||||
try apiSetFilesFolder(filesFolder: getAppFilesDirectory().path)
|
||||
try apiSetAppFilePaths(filesFolder: getAppFilesDirectory().path, tempFolder: getTempFilesDirectory().path, assetsFolder: getWallpaperDirectory().deletingLastPathComponent().path)
|
||||
try apiSetEncryptLocalFiles(privacyEncryptLocalFilesGroupDefault.get())
|
||||
// prevent suspension while starting chat
|
||||
suspendLock.wait()
|
||||
@@ -660,14 +659,8 @@ func apiSuspendChat(timeoutMicroseconds: Int) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func apiSetTempFolder(tempFolder: String) throws {
|
||||
let r = sendSimpleXCmd(.setTempFolder(tempFolder: tempFolder))
|
||||
if case .cmdOk = r { return }
|
||||
throw r
|
||||
}
|
||||
|
||||
func apiSetFilesFolder(filesFolder: String) throws {
|
||||
let r = sendSimpleXCmd(.setFilesFolder(filesFolder: filesFolder))
|
||||
func apiSetAppFilePaths(filesFolder: String, tempFolder: String, assetsFolder: String) throws {
|
||||
let r = sendSimpleXCmd(.apiSetAppFilePaths(filesFolder: filesFolder, tempFolder: tempFolder, assetsFolder: assetsFolder))
|
||||
if case .cmdOk = r { return }
|
||||
throw r
|
||||
}
|
||||
|
||||
@@ -186,14 +186,16 @@
|
||||
64F1CC3B28B39D8600CD1FB1 /* IncognitoHelp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F1CC3A28B39D8600CD1FB1 /* IncognitoHelp.swift */; };
|
||||
8C05382E2B39887E006436DC /* VideoUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C05382D2B39887E006436DC /* VideoUtils.swift */; };
|
||||
8C69FE7D2B8C7D2700267E38 /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C69FE7C2B8C7D2700267E38 /* AppSettings.swift */; };
|
||||
8C74C3E52C1B900600039E77 /* ThemeTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C7E3CE32C0DEAC400BFF63A /* ThemeTypes.swift */; };
|
||||
8C74C3E72C1B901900039E77 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C852B072C1086D100BA61E8 /* Color.swift */; };
|
||||
8C74C3E82C1B905B00039E77 /* ChatWallpaperTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C804B1D2C11F966007A63C8 /* ChatWallpaperTypes.swift */; };
|
||||
8C74C3EA2C1B90AF00039E77 /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C86EBE42C0DAE4F00E12243 /* ThemeManager.swift */; };
|
||||
8C74C3EC2C1B92A900039E77 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C74C3EB2C1B92A900039E77 /* Theme.swift */; };
|
||||
8C74C3EE2C1B942300039E77 /* ChatWallpaper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C74C3ED2C1B942300039E77 /* ChatWallpaper.swift */; };
|
||||
8C7D949A2B88952700B7B9E1 /* MigrateToDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C7D94992B88952700B7B9E1 /* MigrateToDevice.swift */; };
|
||||
8C7DF3202B7CDB0A00C886D0 /* MigrateFromDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C7DF31F2B7CDB0A00C886D0 /* MigrateFromDevice.swift */; };
|
||||
8C7E3CE42C0DEAC400BFF63A /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C7E3CE32C0DEAC400BFF63A /* Theme.swift */; };
|
||||
8C7F8F0E2C19C0C100D16888 /* ViewModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C7F8F0D2C19C0C100D16888 /* ViewModifiers.swift */; };
|
||||
8C804B1E2C11F966007A63C8 /* ChatWallpaper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C804B1D2C11F966007A63C8 /* ChatWallpaper.swift */; };
|
||||
8C81482C2BD91CD4002CBEC3 /* AudioDevicePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C81482B2BD91CD4002CBEC3 /* AudioDevicePicker.swift */; };
|
||||
8C852B082C1086D100BA61E8 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C852B072C1086D100BA61E8 /* Color.swift */; };
|
||||
8C86EBE52C0DAE4F00E12243 /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C86EBE42C0DAE4F00E12243 /* ThemeManager.swift */; };
|
||||
8CC4ED902BD7B8530078AEE8 /* CallAudioDeviceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CC4ED8F2BD7B8530078AEE8 /* CallAudioDeviceManager.swift */; };
|
||||
8CC956EE2BC0041000412A11 /* NetworkObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CC956ED2BC0041000412A11 /* NetworkObserver.swift */; };
|
||||
D7197A1829AE89660055C05A /* WebRTC in Frameworks */ = {isa = PBXBuildFile; productRef = D7197A1729AE89660055C05A /* WebRTC */; };
|
||||
@@ -488,11 +490,13 @@
|
||||
64F1CC3A28B39D8600CD1FB1 /* IncognitoHelp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncognitoHelp.swift; sourceTree = "<group>"; };
|
||||
8C05382D2B39887E006436DC /* VideoUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoUtils.swift; sourceTree = "<group>"; };
|
||||
8C69FE7C2B8C7D2700267E38 /* AppSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettings.swift; sourceTree = "<group>"; };
|
||||
8C74C3EB2C1B92A900039E77 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
|
||||
8C74C3ED2C1B942300039E77 /* ChatWallpaper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatWallpaper.swift; sourceTree = "<group>"; };
|
||||
8C7D94992B88952700B7B9E1 /* MigrateToDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateToDevice.swift; sourceTree = "<group>"; };
|
||||
8C7DF31F2B7CDB0A00C886D0 /* MigrateFromDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateFromDevice.swift; sourceTree = "<group>"; };
|
||||
8C7E3CE32C0DEAC400BFF63A /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
|
||||
8C7E3CE32C0DEAC400BFF63A /* ThemeTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeTypes.swift; sourceTree = "<group>"; };
|
||||
8C7F8F0D2C19C0C100D16888 /* ViewModifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModifiers.swift; sourceTree = "<group>"; };
|
||||
8C804B1D2C11F966007A63C8 /* ChatWallpaper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatWallpaper.swift; sourceTree = "<group>"; };
|
||||
8C804B1D2C11F966007A63C8 /* ChatWallpaperTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatWallpaperTypes.swift; sourceTree = "<group>"; };
|
||||
8C81482B2BD91CD4002CBEC3 /* AudioDevicePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioDevicePicker.swift; sourceTree = "<group>"; };
|
||||
8C852B072C1086D100BA61E8 /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = "<group>"; };
|
||||
8C86EBE42C0DAE4F00E12243 /* ThemeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeManager.swift; sourceTree = "<group>"; };
|
||||
@@ -670,8 +674,8 @@
|
||||
64C3B0202A0D359700E19930 /* CustomTimePicker.swift */,
|
||||
5CEBD7452A5C0A8F00665FE2 /* KeyboardPadding.swift */,
|
||||
8C05382D2B39887E006436DC /* VideoUtils.swift */,
|
||||
8C804B1D2C11F966007A63C8 /* ChatWallpaper.swift */,
|
||||
8C7F8F0D2C19C0C100D16888 /* ViewModifiers.swift */,
|
||||
8C74C3ED2C1B942300039E77 /* ChatWallpaper.swift */,
|
||||
);
|
||||
path = Helpers;
|
||||
sourceTree = "<group>";
|
||||
@@ -696,7 +700,7 @@
|
||||
5CA059C2279559F40002BEB4 /* Shared */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8C86EBE22C0DAE0A00E12243 /* UI */,
|
||||
8C74C3E92C1B909200039E77 /* Theme */,
|
||||
5CA059C3279559F40002BEB4 /* SimpleXApp.swift */,
|
||||
5C36027227F47AD5009F19D9 /* AppDelegate.swift */,
|
||||
5CA059C4279559F40002BEB4 /* ContentView.swift */,
|
||||
@@ -833,6 +837,7 @@
|
||||
5CE2BA692845308900EC33A6 /* SimpleXChat */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8C86EBE32C0DAE3700E12243 /* Theme */,
|
||||
5CDCAD5228186F9500503DA2 /* AppGroup.swift */,
|
||||
5CDCAD7228188CFF00503DA2 /* ChatTypes.swift */,
|
||||
5CDCAD7428188D2900503DA2 /* APITypes.swift */,
|
||||
@@ -926,6 +931,15 @@
|
||||
path = Group;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8C74C3E92C1B909200039E77 /* Theme */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8C86EBE42C0DAE4F00E12243 /* ThemeManager.swift */,
|
||||
8C74C3EB2C1B92A900039E77 /* Theme.swift */,
|
||||
);
|
||||
path = Theme;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8C7D94982B8894D300B7B9E1 /* Migration */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -935,20 +949,12 @@
|
||||
path = Migration;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8C86EBE22C0DAE0A00E12243 /* UI */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8C86EBE32C0DAE3700E12243 /* Theme */,
|
||||
);
|
||||
path = UI;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8C86EBE32C0DAE3700E12243 /* Theme */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8C86EBE42C0DAE4F00E12243 /* ThemeManager.swift */,
|
||||
8C7E3CE32C0DEAC400BFF63A /* Theme.swift */,
|
||||
8C7E3CE32C0DEAC400BFF63A /* ThemeTypes.swift */,
|
||||
8C852B072C1086D100BA61E8 /* Color.swift */,
|
||||
8C804B1D2C11F966007A63C8 /* ChatWallpaperTypes.swift */,
|
||||
);
|
||||
path = Theme;
|
||||
sourceTree = "<group>";
|
||||
@@ -1183,6 +1189,7 @@
|
||||
5C93293129239BED0090FFF9 /* ProtocolServerView.swift in Sources */,
|
||||
5C9CC7AD28C55D7800BEF955 /* DatabaseEncryptionView.swift in Sources */,
|
||||
5CBD285A295711D700EC2CF4 /* ImageUtils.swift in Sources */,
|
||||
8C74C3EC2C1B92A900039E77 /* Theme.swift in Sources */,
|
||||
6419EC562AB8BC8B004A607A /* ContextInvitingContactMemberView.swift in Sources */,
|
||||
5CE4407927ADB701007B033A /* EmojiItemView.swift in Sources */,
|
||||
8C7D949A2B88952700B7B9E1 /* MigrateToDevice.swift in Sources */,
|
||||
@@ -1190,7 +1197,6 @@
|
||||
5C029EAA283942EA004A9677 /* CallController.swift in Sources */,
|
||||
5CBE6C142944CC12002D9531 /* ScanCodeView.swift in Sources */,
|
||||
5CC036E029C488D500C0EF20 /* HiddenProfileView.swift in Sources */,
|
||||
8C7E3CE42C0DEAC400BFF63A /* Theme.swift in Sources */,
|
||||
5C5346A827B59A6A004DF848 /* ChatHelp.swift in Sources */,
|
||||
5CB634A829E437960066AD6B /* PasscodeEntry.swift in Sources */,
|
||||
5CFA59C42860BC6200863A68 /* MigrateToAppGroupView.swift in Sources */,
|
||||
@@ -1229,7 +1235,6 @@
|
||||
64E972072881BB22008DBC02 /* CIGroupInvitationView.swift in Sources */,
|
||||
5CC1C99227A6C7F5000D9FF6 /* QRCode.swift in Sources */,
|
||||
5C116CDC27AABE0400E66D01 /* ContactRequestView.swift in Sources */,
|
||||
8C86EBE52C0DAE4F00E12243 /* ThemeManager.swift in Sources */,
|
||||
5CB9250D27A9432000ACCCDD /* ChatListNavLink.swift in Sources */,
|
||||
649BCDA0280460FD00C3A862 /* ComposeImageView.swift in Sources */,
|
||||
5CA059ED279559F40002BEB4 /* ContentView.swift in Sources */,
|
||||
@@ -1242,6 +1247,7 @@
|
||||
5CB346E72868D76D001FD2EF /* NotificationsView.swift in Sources */,
|
||||
647F090E288EA27B00644C40 /* GroupMemberInfoView.swift in Sources */,
|
||||
646BB38E283FDB6D001CE359 /* LocalAuthenticationUtils.swift in Sources */,
|
||||
8C74C3EA2C1B90AF00039E77 /* ThemeManager.swift in Sources */,
|
||||
5C7505A227B65FDB00BE3227 /* CIMetaView.swift in Sources */,
|
||||
5CEBD7462A5C0A8F00665FE2 /* KeyboardPadding.swift in Sources */,
|
||||
5C35CFC827B2782E00FB6C6D /* BGManager.swift in Sources */,
|
||||
@@ -1259,8 +1265,8 @@
|
||||
6454036F2822A9750090DDFF /* ComposeFileView.swift in Sources */,
|
||||
5C5DB70E289ABDD200730FFF /* AppearanceSettings.swift in Sources */,
|
||||
5C5F2B6D27EBC3FE006A9D5F /* ImagePicker.swift in Sources */,
|
||||
8C74C3EE2C1B942300039E77 /* ChatWallpaper.swift in Sources */,
|
||||
5C3CCFCC2AE6BD3100C3F0C3 /* ConnectDesktopView.swift in Sources */,
|
||||
8C804B1E2C11F966007A63C8 /* ChatWallpaper.swift in Sources */,
|
||||
5C9C2DA92899DA6F00CC63B1 /* NetworkAndServers.swift in Sources */,
|
||||
5C6BA667289BD954009B8ECC /* DismissSheets.swift in Sources */,
|
||||
5C577F7D27C83AA10006112D /* MarkdownHelp.swift in Sources */,
|
||||
@@ -1287,7 +1293,6 @@
|
||||
5C5E5D3B2824468B00B0488A /* ActiveCallView.swift in Sources */,
|
||||
5C2E260727A2941F00F70299 /* SimpleXAPI.swift in Sources */,
|
||||
6440CA00288857A10062C672 /* CIEventView.swift in Sources */,
|
||||
8C852B082C1086D100BA61E8 /* Color.swift in Sources */,
|
||||
5CB0BA92282713FD00B3292C /* CreateProfile.swift in Sources */,
|
||||
5C5F2B7027EBC704006A9D5F /* ProfileImage.swift in Sources */,
|
||||
5C9329412929248A0090FFF9 /* ScanProtocolServer.swift in Sources */,
|
||||
@@ -1345,6 +1350,7 @@
|
||||
5C00168128C4FE760094D739 /* KeyChain.swift in Sources */,
|
||||
5CE2BA97284537A800EC33A6 /* dummy.m in Sources */,
|
||||
5CE2BA922845340900EC33A6 /* FileUtils.swift in Sources */,
|
||||
8C74C3E72C1B901900039E77 /* Color.swift in Sources */,
|
||||
5CD67B902B0E858A00C510B1 /* hs_init.c in Sources */,
|
||||
5CE2BA91284533A300EC33A6 /* Notifications.swift in Sources */,
|
||||
5CE2BA79284530CC00EC33A6 /* SimpleXChat.docc in Sources */,
|
||||
@@ -1353,7 +1359,9 @@
|
||||
5CE2BA8F284533A300EC33A6 /* APITypes.swift in Sources */,
|
||||
5C9D811A2AA8727A001D49FD /* CryptoFile.swift in Sources */,
|
||||
5CE2BA8C284533A300EC33A6 /* AppGroup.swift in Sources */,
|
||||
8C74C3E52C1B900600039E77 /* ThemeTypes.swift in Sources */,
|
||||
5CE2BA8D284533A300EC33A6 /* CallTypes.swift in Sources */,
|
||||
8C74C3E82C1B905B00039E77 /* ChatWallpaperTypes.swift in Sources */,
|
||||
5CE2BA8E284533A300EC33A6 /* API.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
||||
@@ -170,7 +170,7 @@ public enum ChatCommand {
|
||||
case .apiStopChat: return "/_stop"
|
||||
case let .apiActivateChat(restore): return "/_app activate restore=\(onOff(restore))"
|
||||
case let .apiSuspendChat(timeoutMicroseconds): return "/_app suspend \(timeoutMicroseconds)"
|
||||
case let .apiSetAppFilePaths(filesFolder, tempFolder, assetsFolder): return "/set file paths \(encodeJSON(AppFilePaths(filesFolder: filesFolder, tempFolder: tempFolder, assetsFolder: assetsFolder)))"
|
||||
case let .apiSetAppFilePaths(filesFolder, tempFolder, assetsFolder): return "/set file paths \(encodeJSON(AppFilePaths(appFilesFolder: filesFolder, appTempFolder: tempFolder, appAssetsFolder: assetsFolder)))"
|
||||
case let .apiSetEncryptLocalFiles(enable): return "/_files_encrypt \(onOff(enable))"
|
||||
case let .apiExportArchive(cfg): return "/_db export \(encodeJSON(cfg))"
|
||||
case let .apiImportArchive(cfg): return "/_db import \(encodeJSON(cfg))"
|
||||
@@ -2244,7 +2244,7 @@ public enum MsgType: String, Codable {
|
||||
}
|
||||
|
||||
public struct AppFilePaths: Encodable {
|
||||
public let filesFolder: String
|
||||
public let tempFolder: String
|
||||
public let assetsFolder: String
|
||||
public let appFilesFolder: String
|
||||
public let appTempFolder: String
|
||||
public let appAssetsFolder: String
|
||||
}
|
||||
|
||||
@@ -0,0 +1,374 @@
|
||||
//
|
||||
// ChatWallpaper.swift
|
||||
// SimpleX (iOS)
|
||||
//
|
||||
// Created by Avently on 06.06.2024.
|
||||
// Copyright © 2024 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
public enum PresetWallpaper {
|
||||
case cats
|
||||
case flowers
|
||||
case hearts
|
||||
case kids
|
||||
case school
|
||||
case travel
|
||||
|
||||
var res: UIImage {
|
||||
UIImage(named: "wallpaper_\(filename)")!
|
||||
}
|
||||
|
||||
public var filename: String {
|
||||
switch self {
|
||||
case .cats: "cats"
|
||||
case .flowers: "flowers"
|
||||
case .hearts: "hearts"
|
||||
case .kids: "kids"
|
||||
case .school: "school"
|
||||
case .travel: "travel"
|
||||
}
|
||||
}
|
||||
|
||||
public var scale: Float {
|
||||
switch self {
|
||||
case .cats: 0.63
|
||||
case .flowers: 0.53
|
||||
case .hearts: 0.59
|
||||
case .kids: 0.53
|
||||
case .school: 0.53
|
||||
case .travel: 0.68
|
||||
}
|
||||
}
|
||||
|
||||
public var background: [DefaultTheme: Color] {
|
||||
switch self {
|
||||
case .cats: wallpaperBackgrounds(light: "#ffF8F6EA")
|
||||
case .flowers: wallpaperBackgrounds(light: "#ffE2FFE4")
|
||||
case .hearts: wallpaperBackgrounds(light: "#ffFDECEC")
|
||||
case .kids: wallpaperBackgrounds(light: "#ffdbfdfb")
|
||||
case .school: wallpaperBackgrounds(light: "#ffE7F5FF")
|
||||
case .travel: wallpaperBackgrounds(light: "#fff9eeff")
|
||||
}
|
||||
}
|
||||
|
||||
public var tint: [DefaultTheme: Color] {
|
||||
switch self {
|
||||
case .cats: [
|
||||
DefaultTheme.LIGHT: "#ffefdca6".colorFromReadableHex(),
|
||||
DefaultTheme.DARK: "#ff4b3b0e".colorFromReadableHex(),
|
||||
DefaultTheme.SIMPLEX: "#ff51400f".colorFromReadableHex(),
|
||||
DefaultTheme.BLACK: "#ff4b3b0e".colorFromReadableHex()
|
||||
]
|
||||
case .flowers: [
|
||||
DefaultTheme.LIGHT: "#ff9CEA59".colorFromReadableHex(),
|
||||
DefaultTheme.DARK: "#ff31560D".colorFromReadableHex(),
|
||||
DefaultTheme.SIMPLEX: "#ff36600f".colorFromReadableHex(),
|
||||
DefaultTheme.BLACK: "#ff31560D".colorFromReadableHex()
|
||||
]
|
||||
case .hearts: [
|
||||
DefaultTheme.LIGHT: "#fffde0e0".colorFromReadableHex(),
|
||||
DefaultTheme.DARK: "#ff3c0f0f".colorFromReadableHex(),
|
||||
DefaultTheme.SIMPLEX: "#ff411010".colorFromReadableHex(),
|
||||
DefaultTheme.BLACK: "#ff3C0F0F".colorFromReadableHex()
|
||||
]
|
||||
case .kids: [
|
||||
DefaultTheme.LIGHT: "#ffadeffc".colorFromReadableHex(),
|
||||
DefaultTheme.DARK: "#ff16404B".colorFromReadableHex(),
|
||||
DefaultTheme.SIMPLEX: "#ff184753".colorFromReadableHex(),
|
||||
DefaultTheme.BLACK: "#ff16404B".colorFromReadableHex()
|
||||
]
|
||||
case .school: [
|
||||
DefaultTheme.LIGHT: "#ffCEEBFF".colorFromReadableHex(),
|
||||
DefaultTheme.DARK: "#ff0F293B".colorFromReadableHex(),
|
||||
DefaultTheme.SIMPLEX: "#ff112f43".colorFromReadableHex(),
|
||||
DefaultTheme.BLACK: "#ff0F293B".colorFromReadableHex()
|
||||
]
|
||||
case .travel: [
|
||||
DefaultTheme.LIGHT: "#ffeedbfe".colorFromReadableHex(),
|
||||
DefaultTheme.DARK: "#ff311E48".colorFromReadableHex(),
|
||||
DefaultTheme.SIMPLEX: "#ff35204e".colorFromReadableHex(),
|
||||
DefaultTheme.BLACK: "#ff311E48".colorFromReadableHex()
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
public var colors: [DefaultTheme: ThemeColors] {
|
||||
switch self {
|
||||
case .cats: [
|
||||
DefaultTheme.LIGHT: ThemeColors.from(
|
||||
sentMessage: "#fffffaed",
|
||||
sentQuote: "#fffaf0d6",
|
||||
receivedMessage: "#ffF8F7F4",
|
||||
receivedQuote: "#ffefede9"
|
||||
),
|
||||
DefaultTheme.DARK: ThemeColors.from(
|
||||
sentMessage: "#ff2f2919",
|
||||
sentQuote: "#ff473a1d",
|
||||
receivedMessage: "#ff272624",
|
||||
receivedQuote: "#ff373633"
|
||||
),
|
||||
DefaultTheme.SIMPLEX: ThemeColors.from(
|
||||
sentMessage: "#ff41371b",
|
||||
sentQuote: "#ff654f1c",
|
||||
receivedMessage: "#ff272624",
|
||||
receivedQuote: "#ff373633"
|
||||
),
|
||||
DefaultTheme.BLACK: ThemeColors.from(
|
||||
sentMessage: "#ff41371b",
|
||||
sentQuote: "#ff654f1c",
|
||||
receivedMessage: "#ff1f1e1b",
|
||||
receivedQuote: "#ff2f2d27"
|
||||
)
|
||||
]
|
||||
case .flowers: [
|
||||
DefaultTheme.LIGHT: ThemeColors.from(
|
||||
sentMessage: "#fff1ffe5",
|
||||
sentQuote: "#ffdcf9c4",
|
||||
receivedMessage: "#ffF4F8F2",
|
||||
receivedQuote: "#ffe7ece7"
|
||||
),
|
||||
DefaultTheme.DARK: ThemeColors.from(
|
||||
sentMessage: "#ff163521",
|
||||
sentQuote: "#ff1B5330",
|
||||
receivedMessage: "#ff242523",
|
||||
receivedQuote: "#ff353733"
|
||||
),
|
||||
DefaultTheme.SIMPLEX: ThemeColors.from(
|
||||
sentMessage: "#ff184739",
|
||||
sentQuote: "#ff1F6F4B",
|
||||
receivedMessage: "#ff242523",
|
||||
receivedQuote: "#ff353733"
|
||||
),
|
||||
DefaultTheme.BLACK: ThemeColors.from(
|
||||
sentMessage: "#ff184739",
|
||||
sentQuote: "#ff1F6F4B",
|
||||
receivedMessage: "#ff1c1f1a",
|
||||
receivedQuote: "#ff282b25"
|
||||
)
|
||||
]
|
||||
case .hearts: [
|
||||
DefaultTheme.LIGHT: ThemeColors.from(
|
||||
sentMessage: "#fffff4f4",
|
||||
sentQuote: "#ffffdfdf",
|
||||
receivedMessage: "#fff8f6f6",
|
||||
receivedQuote: "#ffefebeb"
|
||||
),
|
||||
DefaultTheme.DARK: ThemeColors.from(
|
||||
sentMessage: "#ff301515",
|
||||
sentQuote: "#ff4C1818",
|
||||
receivedMessage: "#ff242121",
|
||||
receivedQuote: "#ff3b3535"
|
||||
),
|
||||
DefaultTheme.SIMPLEX: ThemeColors.from(
|
||||
sentMessage: "#ff491A28",
|
||||
sentQuote: "#ff761F29",
|
||||
receivedMessage: "#ff242121",
|
||||
receivedQuote: "#ff3b3535"
|
||||
),
|
||||
DefaultTheme.BLACK: ThemeColors.from(
|
||||
sentMessage: "#ff491A28",
|
||||
sentQuote: "#ff761F29",
|
||||
receivedMessage: "#ff1f1b1b",
|
||||
receivedQuote: "#ff2e2626"
|
||||
)
|
||||
]
|
||||
case .kids: [
|
||||
DefaultTheme.LIGHT: ThemeColors.from(
|
||||
sentMessage: "#ffeafeff",
|
||||
sentQuote: "#ffcbf4f7",
|
||||
receivedMessage: "#fff3fafa",
|
||||
receivedQuote: "#ffe4efef"
|
||||
),
|
||||
DefaultTheme.DARK: ThemeColors.from(
|
||||
sentMessage: "#ff16302F",
|
||||
sentQuote: "#ff1a4a49",
|
||||
receivedMessage: "#ff252626",
|
||||
receivedQuote: "#ff373A39"
|
||||
),
|
||||
DefaultTheme.SIMPLEX: ThemeColors.from(
|
||||
sentMessage: "#ff1a4745",
|
||||
sentQuote: "#ff1d6b69",
|
||||
receivedMessage: "#ff252626",
|
||||
receivedQuote: "#ff373a39"
|
||||
),
|
||||
DefaultTheme.BLACK: ThemeColors.from(
|
||||
sentMessage: "#ff1a4745",
|
||||
sentQuote: "#ff1d6b69",
|
||||
receivedMessage: "#ff1e1f1f",
|
||||
receivedQuote: "#ff262b29"
|
||||
)
|
||||
]
|
||||
case .school: [
|
||||
DefaultTheme.LIGHT: ThemeColors.from(
|
||||
sentMessage: "#ffeef9ff",
|
||||
sentQuote: "#ffD6EDFA",
|
||||
receivedMessage: "#ffF3F5F9",
|
||||
receivedQuote: "#ffe4e8ee"
|
||||
),
|
||||
DefaultTheme.DARK: ThemeColors.from(
|
||||
sentMessage: "#ff172833",
|
||||
sentQuote: "#ff1C3E4F",
|
||||
receivedMessage: "#ff26282c",
|
||||
receivedQuote: "#ff393c40"
|
||||
),
|
||||
DefaultTheme.SIMPLEX: ThemeColors.from(
|
||||
sentMessage: "#ff1A3C5D",
|
||||
sentQuote: "#ff235b80",
|
||||
receivedMessage: "#ff26282c",
|
||||
receivedQuote: "#ff393c40"
|
||||
),
|
||||
DefaultTheme.BLACK: ThemeColors.from(
|
||||
sentMessage: "#ff1A3C5D",
|
||||
sentQuote: "#ff235b80",
|
||||
receivedMessage: "#ff1d1e22",
|
||||
receivedQuote: "#ff292b2f"
|
||||
)
|
||||
]
|
||||
case .travel: [
|
||||
DefaultTheme.LIGHT: ThemeColors.from(
|
||||
sentMessage: "#fffcf6ff",
|
||||
sentQuote: "#fff2e0fc",
|
||||
receivedMessage: "#ffF6F4F7",
|
||||
receivedQuote: "#ffede9ee"
|
||||
),
|
||||
DefaultTheme.DARK: ThemeColors.from(
|
||||
sentMessage: "#ff33263B",
|
||||
sentQuote: "#ff53385E",
|
||||
receivedMessage: "#ff272528",
|
||||
receivedQuote: "#ff3B373E"
|
||||
),
|
||||
DefaultTheme.SIMPLEX: ThemeColors.from(
|
||||
sentMessage: "#ff3C255D",
|
||||
sentQuote: "#ff623485",
|
||||
receivedMessage: "#ff26273B",
|
||||
receivedQuote: "#ff3A394F"
|
||||
),
|
||||
DefaultTheme.BLACK: ThemeColors.from(
|
||||
sentMessage: "#ff3C255D",
|
||||
sentQuote: "#ff623485",
|
||||
receivedMessage: "#ff231f23",
|
||||
receivedQuote: "#ff2c2931"
|
||||
)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
public static func from(_ filename: String) -> PresetWallpaper? {
|
||||
switch filename {
|
||||
case PresetWallpaper.cats.filename: PresetWallpaper.cats
|
||||
case PresetWallpaper.flowers.filename: PresetWallpaper.flowers
|
||||
case PresetWallpaper.hearts.filename: PresetWallpaper.hearts
|
||||
case PresetWallpaper.kids.filename: PresetWallpaper.kids
|
||||
case PresetWallpaper.school.filename: PresetWallpaper.school
|
||||
case PresetWallpaper.travel.filename: PresetWallpaper.travel
|
||||
default: nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func wallpaperBackgrounds(light: String) -> [DefaultTheme : Color] {
|
||||
[
|
||||
DefaultTheme.LIGHT: light.colorFromReadableHex(),
|
||||
DefaultTheme.DARK: "#ff121212".colorFromReadableHex(),
|
||||
DefaultTheme.SIMPLEX: "#ff111528".colorFromReadableHex(),
|
||||
DefaultTheme.BLACK: "#ff070707".colorFromReadableHex()
|
||||
]
|
||||
}
|
||||
|
||||
public enum WallpaperScaleType/*(val contentScale: ContentScale)*/: Codable {
|
||||
case fill/* (ContentScale.Crop)*/
|
||||
case fit/* (ContentScale.Fit)*/
|
||||
case `repeat`/* (ContentScale.Fit)*/
|
||||
|
||||
public var text: String {
|
||||
switch self {
|
||||
case .fill: "Fill"
|
||||
case .fit: "Fit"
|
||||
case .repeat: "Repeat"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum WallpaperType {
|
||||
public var image: SwiftUI.Image? {
|
||||
if let uiImage {
|
||||
return SwiftUI.Image(uiImage: uiImage)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
public var uiImage: UIImage? {
|
||||
let filename: String
|
||||
switch self {
|
||||
case let .Preset(f, _): filename = f
|
||||
case let .Image(f, _, _): filename = f
|
||||
default: return nil
|
||||
}
|
||||
if filename == "" { return nil }
|
||||
if let image = WallpaperType.cachedImages[filename] {
|
||||
return image
|
||||
} else {
|
||||
let res: UIImage?
|
||||
if case let .Preset(filename, _) = self {
|
||||
res = (PresetWallpaper.from(filename) ?? PresetWallpaper.cats).res
|
||||
} else {
|
||||
// In case of unintentional image deletion don't crash the app
|
||||
res = UIImage(contentsOfFile: getWallpaperFilePath(filename).path)
|
||||
}
|
||||
if let res {
|
||||
WallpaperType.cachedImages[filename] = res
|
||||
}
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
public func sameType(_ other: WallpaperType?) -> Bool {
|
||||
if case let .Preset(filename, _) = self, case let .Preset(otherFilename, _) = other { filename == otherFilename }
|
||||
else if case .Image = self, case .Image = other { true }
|
||||
else if case .Empty = self, case .Empty = other { true }
|
||||
else { false }
|
||||
}
|
||||
|
||||
public func samePreset(other: PresetWallpaper?) -> Bool { if case let .Preset(filename, _) = self, filename == other?.filename { true } else { false } }
|
||||
|
||||
case Preset(_ filename: String, _ scale: Float?)
|
||||
|
||||
case Image(_ filename: String, _ scale: Float?, _ scaleType: WallpaperScaleType?)
|
||||
|
||||
case Empty
|
||||
|
||||
public func defaultBackgroundColor(_ theme: DefaultTheme, _ themeBackground: Color) -> Color {
|
||||
if case let .Preset(filename, _) = self {
|
||||
(PresetWallpaper.from(filename) ?? PresetWallpaper.cats).background[theme]!
|
||||
} else {
|
||||
themeBackground
|
||||
}
|
||||
}
|
||||
|
||||
public func defaultTintColor(_ theme: DefaultTheme) -> Color {
|
||||
if case let .Preset(filename, _) = self {
|
||||
(PresetWallpaper.from(filename) ?? PresetWallpaper.cats).tint[theme]!
|
||||
} else if case let .Image(_, _, scaleType) = self, scaleType == WallpaperScaleType.repeat {
|
||||
Color.clear
|
||||
} else {
|
||||
Color.clear
|
||||
}
|
||||
}
|
||||
|
||||
public static var cachedImages: [String: UIImage] = [:]
|
||||
|
||||
public static func from(_ wallpaper: ThemeWallpaper?) -> WallpaperType? {
|
||||
if wallpaper == nil {
|
||||
return nil
|
||||
} else if let preset = wallpaper?.preset {
|
||||
return WallpaperType.Preset(preset, wallpaper?.scale)
|
||||
} else if let imageFile = wallpaper?.imageFile {
|
||||
return WallpaperType.Image(imageFile, wallpaper?.scale, wallpaper?.scaleType)
|
||||
} else {
|
||||
return WallpaperType.Empty
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
//
|
||||
// Color.swift
|
||||
// SimpleX (iOS)
|
||||
//
|
||||
// Created by Avently on 05.06.2024.
|
||||
// Copyright © 2024 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
let Purple200 = Color(0xFFBB86FC)
|
||||
let Purple500 = Color(0xFF6200EE)
|
||||
let Purple700 = Color(0xFF3700B3)
|
||||
let Teal200 = Color(0xFF03DAC5)
|
||||
let Gray = Color(0x22222222)
|
||||
let Indigo = Color(0xFF9966FF)
|
||||
let SimplexBlue = Color(0, 136, 255, a: 255)
|
||||
let SimplexGreen = Color(77, 218, 103, a: 255)
|
||||
let SecretColor = Color(0x40808080)
|
||||
let LightGray = Color(241, 242, 246, a: 255)
|
||||
let DarkGray = Color(43, 44, 46, a: 255)
|
||||
let HighOrLowlight = Color(139, 135, 134, a: 255)
|
||||
let MessagePreviewDark = Color(179, 175, 174, a: 255)
|
||||
let MessagePreviewLight = Color(49, 45, 44, a: 255)
|
||||
let ToolbarLight = Color(220, 220, 220, a: 12)
|
||||
let ToolbarDark = Color(80, 80, 80, a: 12)
|
||||
let SettingsSecondaryLight = Color(200, 196, 195, a: 90)
|
||||
let GroupDark = Color(80, 80, 80, a: 60)
|
||||
let IncomingCallLight = Color(239, 237, 236, a: 255)
|
||||
let WarningOrange = Color(255, 127, 0, a: 255)
|
||||
let WarningYellow = Color(255, 192, 0, a: 255)
|
||||
let FileLight = Color(183, 190, 199, a: 255)
|
||||
let FileDark = Color(101, 101, 106, a: 255)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
public func toReadableHex() -> String {
|
||||
let uiColor: UIColor = .init(self)
|
||||
var (r, g, b, a): (CGFloat, CGFloat, CGFloat, CGFloat) = (0, 0, 0, 0)
|
||||
uiColor.getRed(&r, green: &g, blue: &b, alpha: &a)
|
||||
return String(format: "#%02x%02x%02x%02x",
|
||||
Int(a * 255),
|
||||
Int(r * 255),
|
||||
Int(g * 255),
|
||||
Int(b * 255)
|
||||
)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension String {
|
||||
func colorFromReadableHex() -> Color {
|
||||
// https://stackoverflow.com/a/56874327
|
||||
let hex = self.trimmingCharacters(in: ["#", " "])
|
||||
var int: UInt64 = 0
|
||||
Scanner(string: hex).scanHexInt64(&int)
|
||||
let a, r, g, b: UInt64
|
||||
switch hex.count {
|
||||
case 3: // RGB (12-bit)
|
||||
(a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
|
||||
case 6: // RGB (24-bit)
|
||||
(a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
|
||||
case 8: // ARGB (32-bit)
|
||||
(a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
|
||||
default:
|
||||
(a, r, g, b) = (1, 1, 1, 0)
|
||||
}
|
||||
|
||||
return Color(
|
||||
.sRGB,
|
||||
red: Double(r) / 255,
|
||||
green: Double(g) / 255,
|
||||
blue: Double(b) / 255,
|
||||
opacity: Double(a) / 255
|
||||
)
|
||||
}
|
||||
}
|
||||
+138
-206
@@ -7,26 +7,25 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SimpleXChat
|
||||
import SwiftUI
|
||||
|
||||
enum DefaultTheme: String, Codable {
|
||||
public enum DefaultTheme: String, Codable {
|
||||
case LIGHT
|
||||
case DARK
|
||||
case SIMPLEX
|
||||
case BLACK
|
||||
|
||||
static let SYSTEM_THEME_NAME: String = "SYSTEM"
|
||||
public static let SYSTEM_THEME_NAME: String = "SYSTEM"
|
||||
|
||||
var themeName: String { self.rawValue }
|
||||
public var themeName: String { self.rawValue }
|
||||
|
||||
var mode: DefaultThemeMode {
|
||||
public var mode: DefaultThemeMode {
|
||||
self == .LIGHT
|
||||
? DefaultThemeMode.light
|
||||
: DefaultThemeMode.dark
|
||||
}
|
||||
|
||||
func hasChangedAnyColor(_ overrides: ThemeOverrides?) -> Bool {
|
||||
public func hasChangedAnyColor(_ overrides: ThemeOverrides?) -> Bool {
|
||||
if let overrides {
|
||||
overrides.colors != ThemeColors() || overrides.wallpaper != nil && (overrides.wallpaper?.background != nil || overrides.wallpaper?.tint != nil)
|
||||
} else {
|
||||
@@ -35,24 +34,24 @@ enum DefaultTheme: String, Codable {
|
||||
}
|
||||
}
|
||||
|
||||
enum DefaultThemeMode: String, Codable {
|
||||
public enum DefaultThemeMode: String, Codable {
|
||||
case light
|
||||
case dark
|
||||
}
|
||||
|
||||
class Colors: ObservableObject, NSCopying {
|
||||
@Published var primary: Color
|
||||
@Published var primaryVariant: Color
|
||||
@Published var secondary: Color
|
||||
@Published var secondaryVariant: Color
|
||||
@Published var background: Color
|
||||
@Published var surface: Color
|
||||
@Published var error: Color
|
||||
@Published var onBackground: Color
|
||||
@Published var onSurface: Color
|
||||
@Published var isLight: Bool
|
||||
public class Colors: ObservableObject, NSCopying {
|
||||
@Published public var primary: Color
|
||||
@Published public var primaryVariant: Color
|
||||
@Published public var secondary: Color
|
||||
@Published public var secondaryVariant: Color
|
||||
@Published public var background: Color
|
||||
@Published public var surface: Color
|
||||
@Published public var error: Color
|
||||
@Published public var onBackground: Color
|
||||
@Published public var onSurface: Color
|
||||
@Published public var isLight: Bool
|
||||
|
||||
init(primary: Color, primaryVariant: Color, secondary: Color, secondaryVariant: Color, background: Color, surface: Color, error: Color, onBackground: Color, onSurface: Color, isLight: Bool) {
|
||||
public init(primary: Color, primaryVariant: Color, secondary: Color, secondaryVariant: Color, background: Color, surface: Color, error: Color, onBackground: Color, onSurface: Color, isLight: Bool) {
|
||||
self.primary = primary
|
||||
self.primaryVariant = primaryVariant
|
||||
self.secondary = secondary
|
||||
@@ -64,22 +63,22 @@ class Colors: ObservableObject, NSCopying {
|
||||
self.onSurface = onSurface
|
||||
self.isLight = isLight
|
||||
}
|
||||
func copy(with zone: NSZone? = nil) -> Any {
|
||||
public func copy(with zone: NSZone? = nil) -> Any {
|
||||
Colors(primary: self.primary, primaryVariant: self.primaryVariant, secondary: self.secondary, secondaryVariant: self.secondaryVariant, background: self.background, surface: self.surface, error: self.error, onBackground: self.onBackground, onSurface: self.onSurface, isLight: self.isLight)
|
||||
}
|
||||
|
||||
func clone() -> Colors { copy() as! Colors }
|
||||
public func clone() -> Colors { copy() as! Colors }
|
||||
}
|
||||
|
||||
class AppColors: ObservableObject, NSCopying {
|
||||
@Published var title: Color
|
||||
@Published var primaryVariant2: Color
|
||||
@Published var sentMessage: Color
|
||||
@Published var sentQuote: Color
|
||||
@Published var receivedMessage: Color
|
||||
@Published var receivedQuote: Color
|
||||
public class AppColors: ObservableObject, NSCopying {
|
||||
@Published public var title: Color
|
||||
@Published public var primaryVariant2: Color
|
||||
@Published public var sentMessage: Color
|
||||
@Published public var sentQuote: Color
|
||||
@Published public var receivedMessage: Color
|
||||
@Published public var receivedQuote: Color
|
||||
|
||||
init(title: Color, primaryVariant2: Color, sentMessage: Color, sentQuote: Color, receivedMessage: Color, receivedQuote: Color) {
|
||||
public init(title: Color, primaryVariant2: Color, sentMessage: Color, sentQuote: Color, receivedMessage: Color, receivedQuote: Color) {
|
||||
self.title = title
|
||||
self.primaryVariant2 = primaryVariant2
|
||||
self.sentMessage = sentMessage
|
||||
@@ -88,13 +87,13 @@ class AppColors: ObservableObject, NSCopying {
|
||||
self.receivedQuote = receivedQuote
|
||||
}
|
||||
|
||||
func copy(with zone: NSZone? = nil) -> Any {
|
||||
public func copy(with zone: NSZone? = nil) -> Any {
|
||||
AppColors(title: self.title, primaryVariant2: self.primaryVariant2, sentMessage: self.sentMessage, sentQuote: self.sentQuote, receivedMessage: self.receivedMessage, receivedQuote: self.receivedQuote)
|
||||
}
|
||||
|
||||
func clone() -> AppColors { copy() as! AppColors }
|
||||
public func clone() -> AppColors { copy() as! AppColors }
|
||||
|
||||
func copy(
|
||||
public func copy(
|
||||
title: Color?,
|
||||
primaryVariant2: Color?,
|
||||
sentMessage: Color?,
|
||||
@@ -113,24 +112,24 @@ class AppColors: ObservableObject, NSCopying {
|
||||
}
|
||||
}
|
||||
|
||||
class AppWallpaper: ObservableObject, NSCopying {
|
||||
@Published var background: Color? = nil
|
||||
@Published var tint: Color? = nil
|
||||
@Published var type: WallpaperType = WallpaperType.Empty
|
||||
public class AppWallpaper: ObservableObject, NSCopying {
|
||||
@Published public var background: Color? = nil
|
||||
@Published public var tint: Color? = nil
|
||||
@Published public var type: WallpaperType = WallpaperType.Empty
|
||||
|
||||
init(background: Color?, tint: Color?, type: WallpaperType) {
|
||||
public init(background: Color?, tint: Color?, type: WallpaperType) {
|
||||
self.background = background
|
||||
self.tint = tint
|
||||
self.type = type
|
||||
}
|
||||
|
||||
func copy(with zone: NSZone? = nil) -> Any {
|
||||
public func copy(with zone: NSZone? = nil) -> Any {
|
||||
AppWallpaper(background: self.background, tint: self.tint, type: self.type)
|
||||
}
|
||||
|
||||
func clone() -> AppWallpaper { copy() as! AppWallpaper }
|
||||
public func clone() -> AppWallpaper { copy() as! AppWallpaper }
|
||||
|
||||
func copyWithoutDefault(_ background: Color?, _ tint: Color?, _ type: WallpaperType) -> AppWallpaper {
|
||||
public func copyWithoutDefault(_ background: Color?, _ tint: Color?, _ type: WallpaperType) -> AppWallpaper {
|
||||
AppWallpaper(
|
||||
background: background,
|
||||
tint: tint,
|
||||
@@ -139,7 +138,7 @@ class AppWallpaper: ObservableObject, NSCopying {
|
||||
}
|
||||
}
|
||||
|
||||
enum ThemeColor {
|
||||
public enum ThemeColor {
|
||||
case PRIMARY
|
||||
case PRIMARY_VARIANT
|
||||
case SECONDARY
|
||||
@@ -155,7 +154,7 @@ enum ThemeColor {
|
||||
case WALLPAPER_BACKGROUND
|
||||
case WALLPAPER_TINT
|
||||
|
||||
func fromColors(_ colors: Colors, _ appColors: AppColors, _ appWallpaper: AppWallpaper) -> Color? {
|
||||
public func fromColors(_ colors: Colors, _ appColors: AppColors, _ appWallpaper: AppWallpaper) -> Color? {
|
||||
switch (self) {
|
||||
case .PRIMARY: colors.primary
|
||||
case .PRIMARY_VARIANT: colors.primaryVariant
|
||||
@@ -174,7 +173,7 @@ enum ThemeColor {
|
||||
}
|
||||
}
|
||||
|
||||
var text: LocalizedStringKey {
|
||||
public var text: LocalizedStringKey {
|
||||
switch (self) {
|
||||
case .PRIMARY: "Accent"
|
||||
case .PRIMARY_VARIANT: "Additional accent"
|
||||
@@ -194,19 +193,34 @@ enum ThemeColor {
|
||||
}
|
||||
}
|
||||
|
||||
struct ThemeColors: Codable, Equatable{
|
||||
var primary: String? = nil
|
||||
var primaryVariant: String? = nil
|
||||
var secondary: String? = nil
|
||||
var secondaryVariant: String? = nil
|
||||
var background: String? = nil
|
||||
var surface: String? = nil
|
||||
var title: String? = nil
|
||||
var primaryVariant2: String? = nil
|
||||
var sentMessage: String? = nil
|
||||
var sentQuote: String? = nil
|
||||
var receivedMessage: String? = nil
|
||||
var receivedQuote: String? = nil
|
||||
public struct ThemeColors: Codable, Equatable{
|
||||
public var primary: String? = nil
|
||||
public var primaryVariant: String? = nil
|
||||
public var secondary: String? = nil
|
||||
public var secondaryVariant: String? = nil
|
||||
public var background: String? = nil
|
||||
public var surface: String? = nil
|
||||
public var title: String? = nil
|
||||
public var primaryVariant2: String? = nil
|
||||
public var sentMessage: String? = nil
|
||||
public var sentQuote: String? = nil
|
||||
public var receivedMessage: String? = nil
|
||||
public var receivedQuote: String? = nil
|
||||
|
||||
public init(primary: String? = nil, primaryVariant: String? = nil, secondary: String? = nil, secondaryVariant: String? = nil, background: String? = nil, surface: String? = nil, title: String? = nil, primaryVariant2: String? = nil, sentMessage: String? = nil, sentQuote: String? = nil, receivedMessage: String? = nil, receivedQuote: String? = nil) {
|
||||
self.primary = primary
|
||||
self.primaryVariant = primaryVariant
|
||||
self.secondary = secondary
|
||||
self.secondaryVariant = secondaryVariant
|
||||
self.background = background
|
||||
self.surface = surface
|
||||
self.title = title
|
||||
self.primaryVariant2 = primaryVariant2
|
||||
self.sentMessage = sentMessage
|
||||
self.sentQuote = sentQuote
|
||||
self.receivedMessage = receivedMessage
|
||||
self.receivedQuote = receivedQuote
|
||||
}
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case primary = "accent"
|
||||
@@ -223,7 +237,7 @@ struct ThemeColors: Codable, Equatable{
|
||||
case receivedQuote = "receivedReply"
|
||||
}
|
||||
|
||||
static func from(sentMessage: String, sentQuote: String, receivedMessage: String, receivedQuote: String) -> ThemeColors {
|
||||
public static func from(sentMessage: String, sentQuote: String, receivedMessage: String, receivedQuote: String) -> ThemeColors {
|
||||
var c = ThemeColors()
|
||||
c.sentMessage = sentMessage
|
||||
c.sentQuote = sentQuote
|
||||
@@ -232,7 +246,7 @@ struct ThemeColors: Codable, Equatable{
|
||||
return c
|
||||
}
|
||||
|
||||
static func from(_ colors: Colors, _ appColors: AppColors) -> ThemeColors {
|
||||
public static func from(_ colors: Colors, _ appColors: AppColors) -> ThemeColors {
|
||||
ThemeColors(
|
||||
primary: colors.primary.toReadableHex(),
|
||||
primaryVariant: colors.primaryVariant.toReadableHex(),
|
||||
@@ -250,7 +264,7 @@ struct ThemeColors: Codable, Equatable{
|
||||
}
|
||||
}
|
||||
|
||||
public struct ThemeWallpaper: Codable {
|
||||
public struct ThemeWallpaper: Codable, Equatable {
|
||||
public var preset: String?
|
||||
public var scale: Float?
|
||||
public var scaleType: WallpaperScaleType?
|
||||
@@ -259,7 +273,17 @@ public struct ThemeWallpaper: Codable {
|
||||
public var image: String?
|
||||
public var imageFile: String?
|
||||
|
||||
func toAppWallpaper() -> AppWallpaper {
|
||||
public init(preset: String? = nil, scale: Float? = nil, scaleType: WallpaperScaleType? = nil, background: String? = nil, tint: String? = nil, image: String? = nil, imageFile: String? = nil) {
|
||||
self.preset = preset
|
||||
self.scale = scale
|
||||
self.scaleType = scaleType
|
||||
self.background = background
|
||||
self.tint = tint
|
||||
self.image = image
|
||||
self.imageFile = imageFile
|
||||
}
|
||||
|
||||
public func toAppWallpaper() -> AppWallpaper {
|
||||
AppWallpaper (
|
||||
background: background?.colorFromReadableHex(),
|
||||
tint: tint?.colorFromReadableHex(),
|
||||
@@ -267,25 +291,7 @@ public struct ThemeWallpaper: Codable {
|
||||
)
|
||||
}
|
||||
|
||||
func withFilledWallpaperBase64() -> ThemeWallpaper {
|
||||
let aw = toAppWallpaper()
|
||||
let type = aw.type
|
||||
let preset: String? = if case let WallpaperType.Preset(filename, _) = type { filename } else { nil }
|
||||
let scale: Float? = if case let WallpaperType.Preset(_, scale) = type { scale } else { if case let WallpaperType.Image(_, scale, _) = type { scale } else { 1.0 } }
|
||||
let scaleType: WallpaperScaleType? = if case let WallpaperType.Image(_, _, scaleType) = type { scaleType } else { nil }
|
||||
let image: String? = if case WallpaperType.Image = type, let image = type.uiImage { resizeImageToStrSize(image, maxDataSize: 5_000_000) } else { nil }
|
||||
return ThemeWallpaper (
|
||||
preset: preset,
|
||||
scale: scale,
|
||||
scaleType: scaleType,
|
||||
background: aw.background?.toReadableHex(),
|
||||
tint: aw.tint?.toReadableHex(),
|
||||
image: image,
|
||||
imageFile: nil
|
||||
)
|
||||
}
|
||||
|
||||
func withFilledWallpaperPath() -> ThemeWallpaper {
|
||||
public func withFilledWallpaperPath() -> ThemeWallpaper {
|
||||
let aw = toAppWallpaper()
|
||||
let type = aw.type
|
||||
let preset: String? = if case let WallpaperType.Preset(filename, _) = type { filename } else { nil }
|
||||
@@ -311,25 +317,7 @@ public struct ThemeWallpaper: Codable {
|
||||
)
|
||||
}
|
||||
|
||||
func importFromString() -> ThemeWallpaper {
|
||||
self
|
||||
// LALAL
|
||||
//if preset == nil, let image {
|
||||
// Need to save image from string and to save its path
|
||||
// do {
|
||||
// let parsed = base64ToBitmap(image)
|
||||
// let filename = saveWallpaperFile(parsed)
|
||||
// return copy(image = nil, imageFile = filename)
|
||||
// } catch let e {
|
||||
// logger.error("Error while parsing/copying the image: \(e)")
|
||||
// return ThemeWallpaper()
|
||||
// }
|
||||
// } else {
|
||||
// self
|
||||
// }
|
||||
}
|
||||
|
||||
static func from(_ type: WallpaperType, _ background: String?, _ tint: String?) -> ThemeWallpaper {
|
||||
public static func from(_ type: WallpaperType, _ background: String?, _ tint: String?) -> ThemeWallpaper {
|
||||
let preset: String? = if case let WallpaperType.Preset(filename, _) = type { filename } else { nil }
|
||||
let scale: Float? = if case let WallpaperType.Preset(_, scale) = type { scale } else if case let WallpaperType.Image(_, scale, _) = type { scale } else { nil }
|
||||
let scaleType: WallpaperScaleType? = if case let WallpaperType.Image(_, _, scaleType) = type { scaleType } else { nil }
|
||||
@@ -346,13 +334,20 @@ public struct ThemeWallpaper: Codable {
|
||||
}
|
||||
}
|
||||
|
||||
public struct ThemeOverrides: Codable {
|
||||
var themeId: String = UUID().uuidString
|
||||
var base: DefaultTheme
|
||||
var colors: ThemeColors = ThemeColors()
|
||||
var wallpaper: ThemeWallpaper? = nil
|
||||
public struct ThemeOverrides: Codable, Equatable {
|
||||
public var themeId: String = UUID().uuidString
|
||||
public var base: DefaultTheme
|
||||
public var colors: ThemeColors = ThemeColors()
|
||||
public var wallpaper: ThemeWallpaper? = nil
|
||||
|
||||
func isSame(_ type: WallpaperType?, _ themeName: String) -> Bool {
|
||||
public init(themeId: String = UUID().uuidString, base: DefaultTheme, colors: ThemeColors = ThemeColors(), wallpaper: ThemeWallpaper? = nil) {
|
||||
self.themeId = themeId
|
||||
self.base = base
|
||||
self.colors = colors
|
||||
self.wallpaper = wallpaper
|
||||
}
|
||||
|
||||
public func isSame(_ type: WallpaperType?, _ themeName: String) -> Bool {
|
||||
if base.themeName != themeName {
|
||||
return false
|
||||
}
|
||||
@@ -369,7 +364,7 @@ public struct ThemeOverrides: Codable {
|
||||
}
|
||||
}
|
||||
|
||||
func withUpdatedColor(_ name: ThemeColor, _ color: String?) -> ThemeOverrides {
|
||||
public func withUpdatedColor(_ name: ThemeColor, _ color: String?) -> ThemeOverrides {
|
||||
var c = colors
|
||||
var w = wallpaper
|
||||
switch name {
|
||||
@@ -391,7 +386,7 @@ public struct ThemeOverrides: Codable {
|
||||
return ThemeOverrides(themeId: themeId, base: base, colors: c, wallpaper: w)
|
||||
}
|
||||
|
||||
func toColors(_ base: DefaultTheme, _ perChatTheme: ThemeColors?, _ perUserTheme: ThemeColors?, _ presetWallpaperTheme: ThemeColors?) -> Colors {
|
||||
public func toColors(_ base: DefaultTheme, _ perChatTheme: ThemeColors?, _ perUserTheme: ThemeColors?, _ presetWallpaperTheme: ThemeColors?) -> Colors {
|
||||
let baseColors = switch base {
|
||||
case DefaultTheme.LIGHT: LightColorPalette
|
||||
case DefaultTheme.DARK: DarkColorPalette
|
||||
@@ -408,7 +403,7 @@ public struct ThemeOverrides: Codable {
|
||||
return c
|
||||
}
|
||||
|
||||
func toAppColors(_ base: DefaultTheme, _ perChatTheme: ThemeColors?, _ perChatWallpaperType: WallpaperType?, _ perUserTheme: ThemeColors?, _ perUserWallpaperType: WallpaperType?, _ presetWallpaperTheme: ThemeColors?) -> AppColors {
|
||||
public func toAppColors(_ base: DefaultTheme, _ perChatTheme: ThemeColors?, _ perChatWallpaperType: WallpaperType?, _ perUserTheme: ThemeColors?, _ perUserWallpaperType: WallpaperType?, _ presetWallpaperTheme: ThemeColors?) -> AppColors {
|
||||
let baseColors = switch base {
|
||||
case DefaultTheme.LIGHT: LightColorPaletteApp
|
||||
case DefaultTheme.DARK: DarkColorPaletteApp
|
||||
@@ -432,7 +427,7 @@ public struct ThemeOverrides: Codable {
|
||||
return c
|
||||
}
|
||||
|
||||
func toAppWallpaper(_ themeOverridesForType: WallpaperType?, _ perChatTheme: ThemeModeOverride?, _ perUserTheme: ThemeModeOverride?, _ themeBackgroundColor: Color) -> AppWallpaper {
|
||||
public func toAppWallpaper(_ themeOverridesForType: WallpaperType?, _ perChatTheme: ThemeModeOverride?, _ perUserTheme: ThemeModeOverride?, _ themeBackgroundColor: Color) -> AppWallpaper {
|
||||
let mainType: WallpaperType
|
||||
if let t = themeOverridesForType { mainType = t }
|
||||
// type can be nil if override is empty `"wallpaper": "{}"`, in this case no wallpaper is needed, empty.
|
||||
@@ -464,7 +459,7 @@ public struct ThemeOverrides: Codable {
|
||||
return AppWallpaper(background: background, tint: tint, type: wallpaper)
|
||||
}
|
||||
|
||||
func withFilledColors(_ base: DefaultTheme, _ perChatTheme: ThemeColors?, _ perChatWallpaperType: WallpaperType?, _ perUserTheme: ThemeColors?, _ perUserWallpaperType: WallpaperType?, _ presetWallpaperTheme: ThemeColors?) -> ThemeColors {
|
||||
public func withFilledColors(_ base: DefaultTheme, _ perChatTheme: ThemeColors?, _ perChatWallpaperType: WallpaperType?, _ perUserTheme: ThemeColors?, _ perUserWallpaperType: WallpaperType?, _ presetWallpaperTheme: ThemeColors?) -> ThemeColors {
|
||||
let c = toColors(base, perChatTheme, perUserTheme, presetWallpaperTheme)
|
||||
let ac = toAppColors(base, perChatTheme, perChatWallpaperType, perUserTheme, perUserWallpaperType, presetWallpaperTheme)
|
||||
return ThemeColors(
|
||||
@@ -485,15 +480,15 @@ public struct ThemeOverrides: Codable {
|
||||
}
|
||||
|
||||
extension [ThemeOverrides] {
|
||||
func getTheme(_ themeId: String?) -> ThemeOverrides? {
|
||||
public func getTheme(_ themeId: String?) -> ThemeOverrides? {
|
||||
self.first { $0.themeId == themeId }
|
||||
}
|
||||
|
||||
func getTheme(_ themeId: String?, _ type: WallpaperType?, _ base: DefaultTheme) -> ThemeOverrides? {
|
||||
public func getTheme(_ themeId: String?, _ type: WallpaperType?, _ base: DefaultTheme) -> ThemeOverrides? {
|
||||
self.first { $0.themeId == themeId || $0.isSame(type, base.themeName) }
|
||||
}
|
||||
|
||||
func replace(_ theme: ThemeOverrides) -> [ThemeOverrides] {
|
||||
public func replace(_ theme: ThemeOverrides) -> [ThemeOverrides] {
|
||||
let index = self.firstIndex { $0.themeId == theme.themeId ||
|
||||
// prevent situation when two themes has the same type but different theme id (maybe something was changed in prefs by hand)
|
||||
$0.isSame(WallpaperType.from(theme.wallpaper), theme.base.themeName)
|
||||
@@ -507,9 +502,9 @@ extension [ThemeOverrides] {
|
||||
return a
|
||||
}
|
||||
|
||||
func sameTheme(_ type: WallpaperType?, _ themeName: String) -> ThemeOverrides? { first { $0.isSame(type, themeName) } }
|
||||
public func sameTheme(_ type: WallpaperType?, _ themeName: String) -> ThemeOverrides? { first { $0.isSame(type, themeName) } }
|
||||
|
||||
func skipDuplicates() -> [ThemeOverrides] {
|
||||
public func skipDuplicates() -> [ThemeOverrides] {
|
||||
var res: [ThemeOverrides] = []
|
||||
self.forEach { theme in
|
||||
let themeType = WallpaperType.from(theme.wallpaper)
|
||||
@@ -522,23 +517,29 @@ extension [ThemeOverrides] {
|
||||
|
||||
}
|
||||
|
||||
struct ThemeModeOverrides: Codable {
|
||||
var light: ThemeModeOverride? = nil
|
||||
var dark: ThemeModeOverride? = nil
|
||||
public struct ThemeModeOverrides: Codable {
|
||||
public var light: ThemeModeOverride? = nil
|
||||
public var dark: ThemeModeOverride? = nil
|
||||
|
||||
func preferredMode(_ darkTheme: Bool) -> ThemeModeOverride? {
|
||||
public func preferredMode(_ darkTheme: Bool) -> ThemeModeOverride? {
|
||||
darkTheme ? dark : light
|
||||
}
|
||||
}
|
||||
|
||||
struct ThemeModeOverride: Codable {
|
||||
var mode: DefaultThemeMode = CurrentColors.base.mode
|
||||
var colors: ThemeColors = ThemeColors()
|
||||
var wallpaper: ThemeWallpaper? = nil
|
||||
public struct ThemeModeOverride: Codable {
|
||||
public var mode: DefaultThemeMode// = CurrentColors.base.mode
|
||||
public var colors: ThemeColors = ThemeColors()
|
||||
public var wallpaper: ThemeWallpaper? = nil
|
||||
|
||||
var type: WallpaperType? { WallpaperType.from(wallpaper) }
|
||||
public init(mode: DefaultThemeMode, colors: ThemeColors = ThemeColors(), wallpaper: ThemeWallpaper? = nil) {
|
||||
self.mode = mode
|
||||
self.colors = colors
|
||||
self.wallpaper = wallpaper
|
||||
}
|
||||
|
||||
func withUpdatedColor(_ name: ThemeColor, _ color: String?) -> ThemeModeOverride {
|
||||
public var type: WallpaperType? { WallpaperType.from(wallpaper) }
|
||||
|
||||
public func withUpdatedColor(_ name: ThemeColor, _ color: String?) -> ThemeModeOverride {
|
||||
var c = colors
|
||||
var w = wallpaper
|
||||
switch (name) {
|
||||
@@ -560,7 +561,7 @@ struct ThemeModeOverride: Codable {
|
||||
return ThemeModeOverride(mode: mode, colors: c, wallpaper: w)
|
||||
}
|
||||
|
||||
static func withFilledAppDefaults(_ mode: DefaultThemeMode, _ base: DefaultTheme) -> ThemeModeOverride {
|
||||
public static func withFilledAppDefaults(_ mode: DefaultThemeMode, _ base: DefaultTheme) -> ThemeModeOverride {
|
||||
ThemeModeOverride(
|
||||
mode: mode,
|
||||
colors: ThemeOverrides(base: base).withFilledColors(base, nil, nil, nil, nil, nil),
|
||||
@@ -569,36 +570,7 @@ struct ThemeModeOverride: Codable {
|
||||
}
|
||||
}
|
||||
|
||||
struct ThemedBackground: ViewModifier {
|
||||
@EnvironmentObject var theme: AppTheme
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
.background(
|
||||
theme.base == DefaultTheme.SIMPLEX
|
||||
? LinearGradient(
|
||||
colors: [
|
||||
theme.colors.background.lighter(0.4),
|
||||
theme.colors.background.darker(0.4)
|
||||
],
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
: LinearGradient(
|
||||
colors: [],
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
)
|
||||
.background(
|
||||
theme.base == DefaultTheme.SIMPLEX
|
||||
? Color.clear
|
||||
: theme.colors.background
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
let DarkColorPalette = Colors(
|
||||
public let DarkColorPalette = Colors(
|
||||
primary: SimplexBlue,
|
||||
primaryVariant: SimplexBlue,
|
||||
secondary: HighOrLowlight,
|
||||
@@ -610,7 +582,7 @@ let DarkColorPalette = Colors(
|
||||
onSurface: Color(0xFFFFFBFA),
|
||||
isLight: false
|
||||
)
|
||||
let DarkColorPaletteApp = AppColors(
|
||||
public let DarkColorPaletteApp = AppColors(
|
||||
title: SimplexBlue,
|
||||
primaryVariant2: Color(0xFF18262E),
|
||||
sentMessage: Color(0xFF18262E),
|
||||
@@ -619,7 +591,7 @@ let DarkColorPaletteApp = AppColors(
|
||||
receivedQuote: Color(0xff373739)
|
||||
)
|
||||
|
||||
let LightColorPalette = Colors (
|
||||
public let LightColorPalette = Colors (
|
||||
primary: SimplexBlue,
|
||||
primaryVariant: SimplexBlue,
|
||||
secondary: HighOrLowlight,
|
||||
@@ -631,7 +603,7 @@ let LightColorPalette = Colors (
|
||||
onSurface: Color.black,
|
||||
isLight: true
|
||||
)
|
||||
let LightColorPaletteApp = AppColors(
|
||||
public let LightColorPaletteApp = AppColors(
|
||||
title: SimplexBlue,
|
||||
primaryVariant2: Color(0xFFE9F7FF),
|
||||
sentMessage: Color(0xFFE9F7FF),
|
||||
@@ -640,7 +612,7 @@ let LightColorPaletteApp = AppColors(
|
||||
receivedQuote: Color(0xffececee)
|
||||
)
|
||||
|
||||
let SimplexColorPalette = Colors(
|
||||
public let SimplexColorPalette = Colors(
|
||||
primary: Color(0xFF70F0F9),
|
||||
primaryVariant: Color(0xFF1298A5),
|
||||
secondary: HighOrLowlight,
|
||||
@@ -652,7 +624,7 @@ let SimplexColorPalette = Colors(
|
||||
onSurface: Color(0xFFFFFBFA),
|
||||
isLight: false
|
||||
)
|
||||
let SimplexColorPaletteApp = AppColors(
|
||||
public let SimplexColorPaletteApp = AppColors(
|
||||
title: Color(0xFF267BE5),
|
||||
primaryVariant2: Color(0xFF172941),
|
||||
sentMessage: Color(0xFF172941),
|
||||
@@ -661,7 +633,7 @@ let SimplexColorPaletteApp = AppColors(
|
||||
receivedQuote: Color(0xff36394a)
|
||||
)
|
||||
|
||||
let BlackColorPalette = Colors(
|
||||
public let BlackColorPalette = Colors(
|
||||
primary: Color(0xff0077e0),
|
||||
primaryVariant: Color(0xff0077e0),
|
||||
secondary: HighOrLowlight,
|
||||
@@ -673,7 +645,7 @@ let BlackColorPalette = Colors(
|
||||
onSurface: Color(0xFFFFFBFA),
|
||||
isLight: false
|
||||
)
|
||||
let BlackColorPaletteApp = AppColors(
|
||||
public let BlackColorPaletteApp = AppColors(
|
||||
title: Color(0xff0077e0),
|
||||
primaryVariant2: Color(0xff243747),
|
||||
sentMessage: Color(0xFF18262E),
|
||||
@@ -682,43 +654,12 @@ let BlackColorPaletteApp = AppColors(
|
||||
receivedQuote: Color(0xff29292b)
|
||||
)
|
||||
|
||||
var systemInDarkThemeCurrently: Bool = false
|
||||
|
||||
var CurrentColors: ThemeManager.ActiveTheme = ThemeManager.currentColors(nil, nil, ChatModel.shared.currentUser?.uiThemes, themeOverridesDefault.get()) {
|
||||
didSet {
|
||||
AppTheme.shared.name = CurrentColors.name
|
||||
AppTheme.shared.base = CurrentColors.base
|
||||
AppTheme.shared.colors.updateColorsFrom(CurrentColors.colors)
|
||||
AppTheme.shared.appColors.updateColorsFrom(CurrentColors.appColors)
|
||||
AppTheme.shared.wallpaper.updateWallpaperFrom(CurrentColors.wallpaper)
|
||||
AppTheme.shared.objectWillChange.send()
|
||||
}
|
||||
}
|
||||
|
||||
func isInDarkTheme() -> Bool { !CurrentColors.colors.isLight }
|
||||
public var systemInDarkThemeCurrently: Bool = false
|
||||
|
||||
//func isSystemInDarkTheme(): Bool
|
||||
|
||||
class AppTheme: ObservableObject {
|
||||
static let shared = AppTheme(name: CurrentColors.name, base: CurrentColors.base, colors: CurrentColors.colors, appColors: CurrentColors.appColors, wallpaper: CurrentColors.wallpaper)
|
||||
|
||||
var name: String
|
||||
var base: DefaultTheme
|
||||
@ObservedObject var colors: Colors
|
||||
@ObservedObject var appColors: AppColors
|
||||
@ObservedObject var wallpaper: AppWallpaper
|
||||
|
||||
init(name: String, base: DefaultTheme, colors: Colors, appColors: AppColors, wallpaper: AppWallpaper) {
|
||||
self.name = name
|
||||
self.base = base
|
||||
self.colors = colors
|
||||
self.appColors = appColors
|
||||
self.wallpaper = wallpaper
|
||||
}
|
||||
}
|
||||
|
||||
extension Colors {
|
||||
func updateColorsFrom(_ other: Colors) {
|
||||
public func updateColorsFrom(_ other: Colors) {
|
||||
primary = other.primary
|
||||
primaryVariant = other.primaryVariant
|
||||
secondary = other.secondary
|
||||
@@ -733,7 +674,7 @@ extension Colors {
|
||||
}
|
||||
|
||||
extension AppColors {
|
||||
func updateColorsFrom(_ other: AppColors) {
|
||||
public func updateColorsFrom(_ other: AppColors) {
|
||||
title = other.title
|
||||
primaryVariant2 = other.primaryVariant2
|
||||
sentMessage = other.sentMessage
|
||||
@@ -744,22 +685,13 @@ extension AppColors {
|
||||
}
|
||||
|
||||
extension AppWallpaper {
|
||||
func updateWallpaperFrom(_ other: AppWallpaper) {
|
||||
public func updateWallpaperFrom(_ other: AppWallpaper) {
|
||||
background = other.background
|
||||
tint = other.tint
|
||||
type = other.type
|
||||
}
|
||||
}
|
||||
|
||||
func reactOnDarkThemeChanges(_ isDark: Bool) {
|
||||
systemInDarkThemeCurrently = isDark
|
||||
//sceneDelegate.window?.overrideUserInterfaceStyle == .unspecified
|
||||
if currentThemeDefault.get() == DefaultTheme.SYSTEM_THEME_NAME && CurrentColors.colors.isLight == isDark {
|
||||
// Change active colors from light to dark and back based on system theme
|
||||
ThemeManager.applyTheme(DefaultTheme.SYSTEM_THEME_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
//@Composable
|
||||
//func SimpleXTheme(darkTheme: Bool? = nil, content: @Composable () -> Void) {
|
||||
// val systemDark = rememberUpdatedState(isSystemInDarkTheme())
|
||||
Reference in New Issue
Block a user