diff --git a/Linphone/Core/CoreContext.swift b/Linphone/Core/CoreContext.swift index 37d55a18e..664574dff 100644 --- a/Linphone/Core/CoreContext.swift +++ b/Linphone/Core/CoreContext.swift @@ -305,6 +305,7 @@ class CoreContext: ObservableObject { } }, onConfiguringStatus: { (_: Core, status: ConfiguringState, message: String) in Log.info("New configuration state is \(status) = \(message)\n") + let themeMainColor = CorePreferences.themeMainColor DispatchQueue.main.async { if status == ConfiguringState.Successful { var accountModels: [AccountModel] = [] @@ -312,6 +313,7 @@ class CoreContext: ObservableObject { accountModels.append(AccountModel(account: account, core: self.mCore)) } self.accounts = accountModels + ThemeManager.shared.applyTheme(named: themeMainColor) } } }, onLogCollectionUploadStateChanged: { (_: Core, _: Core.LogCollectionUploadState, info: String) in diff --git a/Linphone/SplashScreen.swift b/Linphone/SplashScreen.swift index e15c4aaac..8c9b2e48d 100644 --- a/Linphone/SplashScreen.swift +++ b/Linphone/SplashScreen.swift @@ -28,10 +28,13 @@ struct SplashScreen: View { HStack { Spacer() Image("linphone") + .renderingMode(.template) + .foregroundColor(ThemeManager.shared.currentTheme.main500) Spacer() } Spacer() } + } .ignoresSafeArea(.all) diff --git a/Linphone/Utils/Extensions/ColorExtension.swift b/Linphone/Utils/Extensions/ColorExtension.swift index 19fc96c2e..111472603 100644 --- a/Linphone/Utils/Extensions/ColorExtension.swift +++ b/Linphone/Utils/Extensions/ColorExtension.swift @@ -26,11 +26,11 @@ extension Color { static let black = Color(hex: "#000000") static let white = Color(hex: "#FFFFFF") - static let orangeMain700 = Color(hex: "#B72D00") - static let orangeMain500 = Color(hex: "#FF5E00") - static let orangeMain300 = Color(hex: "#FFB266") - static let orangeMain100 = Color(hex: "#FFEACB") - static let orangeMain100Alpha50 = Color(hex: "#80FFEACB") + static let orangeMain700 = ThemeManager.shared.currentTheme.main700 + static let orangeMain500 = ThemeManager.shared.currentTheme.main500 + static let orangeMain300 = ThemeManager.shared.currentTheme.main300 + static let orangeMain100 = ThemeManager.shared.currentTheme.main100 + static let orangeMain100Alpha50 = ThemeManager.shared.currentTheme.main100Alpha50 static let grayMain2c800 = Color(hex: "#22334D") static let grayMain2c800Alpha65 = Color(hex: "#A622334D") diff --git a/Linphone/Utils/Extensions/ConfigExtension.swift b/Linphone/Utils/Extensions/ConfigExtension.swift index 697b25221..843bb861b 100644 --- a/Linphone/Utils/Extensions/ConfigExtension.swift +++ b/Linphone/Utils/Extensions/ConfigExtension.swift @@ -38,6 +38,10 @@ extension Config { if _instance == nil { let factoryPath = FileUtil.bundleFilePath("linphonerc-factory")! _instance = Config.newForSharedCore(appGroupId: Config.appGroupName, configFilename: "linphonerc", factoryConfigFilename: factoryPath)! + let themeMainColor = CorePreferences.themeMainColor + DispatchQueue.main.async { + ThemeManager.shared.applyTheme(named: themeMainColor) + } } return _instance! } diff --git a/Linphone/Utils/ThemeManager.swift b/Linphone/Utils/ThemeManager.swift new file mode 100644 index 000000000..cc8a892fc --- /dev/null +++ b/Linphone/Utils/ThemeManager.swift @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2010-2025 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import SwiftUI + + +struct Theme { + let name: String + let main100: Color + let main100Alpha50: Color + let main300: Color + let main500: Color + let main700: Color +} + +class ThemeManager { + + static let shared = ThemeManager() + private let themeKey = "selectedTheme" + var currentTheme: Theme + + init () { + let storedName = UserDefaults.standard.string(forKey: themeKey) + currentTheme = themes[storedName ?? ""] ?? ThemeManager.orange + } + + func applyTheme(named name: String) { + guard let theme = themes[name] else { + return + } + self.currentTheme = theme + UserDefaults.standard.setValue(name, forKey: self.themeKey) + } + + // MARK: - Theme Instances + + let themes: [String: Theme] = [ + orange.name: orange, + yellow.name: yellow, + green.name: green, + blue.name: blue, + red.name: red, + pink.name: pink, + purple.name: purple + ] + + static let orange = Theme( + name: "orange", + main100: Color(hex: "#FFEACB"), + main100Alpha50: Color(hex: "#80FFEACB"), + main300: Color(hex: "#FFB266"), + main500: Color(hex: "#FF5E00"), + main700: Color(hex: "#B72D00") + ) + + static let yellow = Theme( + name: "yellow", + main100: Color(hex: "#FFF5D6"), + main100Alpha50: Color(hex: "#80FFF5D6"), + main300: Color(hex: "#FFE799"), + main500: Color(hex: "#F5BC00"), + main700: Color(hex: "#A37D00") + ) + + static let green = Theme( + name: "green", + main100: Color(hex: "#DCF9E7"), + main100Alpha50: Color(hex: "#80DCF9E7"), + main300: Color(hex: "#A8F0C2"), + main500: Color(hex: "#25D366"), + main700: Color(hex: "#1C9C4B") + ) + + static let blue = Theme( + name: "blue", + main100: Color(hex: "#D6F4FF"), + main100Alpha50: Color(hex: "#80D6F4FF"), + main300: Color(hex: "#99E4FF"), + main500: Color(hex: "#00AFF0"), + main700: Color(hex: "#0078A3") + ) + + static let red = Theme( + name: "red", + main100: Color(hex: "#FBE1DA"), + main100Alpha50: Color(hex: "#80FBE1DA"), + main300: Color(hex: "#F5B53A"), + main500: Color(hex: "#E14318"), + main700: Color(hex: "#A63211") + ) + + static let pink = Theme( + name: "pink", + main100: Color(hex: "#FFD6F1"), + main100Alpha50: Color(hex: "#80FFD6F1"), + main300: Color(hex: "#FF99DD"), + main500: Color(hex: "#FF00A9"), + main700: Color(hex: "#B8007A") + ) + + static let purple = Theme( + name: "purple", + main100: Color(hex: "#FFD6FF"), + main100Alpha50: Color(hex: "#80FFD6FF"), + main300: Color(hex: "#FF99FF"), + main500: Color(hex: "#800080"), + main700: Color(hex: "#520052") + ) + +} diff --git a/LinphoneApp.xcodeproj/project.pbxproj b/LinphoneApp.xcodeproj/project.pbxproj index 627028a27..a3573d7a7 100644 --- a/LinphoneApp.xcodeproj/project.pbxproj +++ b/LinphoneApp.xcodeproj/project.pbxproj @@ -47,6 +47,9 @@ C62817302C1C3DCC00DBA646 /* AccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C628172F2C1C3DCC00DBA646 /* AccountModel.swift */; }; C62817322C1C400A00DBA646 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62817312C1C400A00DBA646 /* StringExtension.swift */; }; C62817342C1C7C7400DBA646 /* HelpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62817332C1C7C7400DBA646 /* HelpView.swift */; }; + C642277B2E8E4AC50094FEDC /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C642277A2E8E4AC50094FEDC /* ThemeManager.swift */; }; + C642277C2E8E4D900094FEDC /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C642277A2E8E4AC50094FEDC /* ThemeManager.swift */; }; + C642277D2E8E4E2B0094FEDC /* ColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D717071D2AC5922E0037746F /* ColorExtension.swift */; }; C67586AE2C09F23C002E77BF /* URLExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586AD2C09F23C002E77BF /* URLExtension.swift */; }; C67586B02C09F247002E77BF /* URIHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586AF2C09F247002E77BF /* URIHandler.swift */; }; C67586B52C09F617002E77BF /* SingleSignOnManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586B22C09F617002E77BF /* SingleSignOnManager.swift */; }; @@ -268,6 +271,7 @@ C628172F2C1C3DCC00DBA646 /* AccountModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountModel.swift; sourceTree = ""; }; C62817312C1C400A00DBA646 /* StringExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtension.swift; sourceTree = ""; }; C62817332C1C7C7400DBA646 /* HelpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpView.swift; sourceTree = ""; }; + C642277A2E8E4AC50094FEDC /* ThemeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeManager.swift; sourceTree = ""; }; C67586AD2C09F23C002E77BF /* URLExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLExtension.swift; sourceTree = ""; }; C67586AF2C09F247002E77BF /* URIHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URIHandler.swift; sourceTree = ""; }; C67586B22C09F617002E77BF /* SingleSignOnManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleSignOnManager.swift; sourceTree = ""; }; @@ -585,6 +589,7 @@ D717071C2AC591EF0037746F /* Utils */ = { isa = PBXGroup; children = ( + C642277A2E8E4AC50094FEDC /* ThemeManager.swift */, D738ACED2E857BEF0039F7D1 /* KeyboardResponder.swift */, D7DF8BE82E2104E5003A3BC7 /* EmojiPickerView.swift */, D703F7072DC8C5FF005B8F75 /* FilePicker.swift */, @@ -1246,9 +1251,11 @@ 66FBFC482B83B8CC00BC6AB1 /* Log.swift in Sources */, 6691CA7E2B839C2D00B2A7B8 /* NotificationService.swift in Sources */, 66FBFC492B83BD2400BC6AB1 /* ConfigExtension.swift in Sources */, + C642277D2E8E4E2B0094FEDC /* ColorExtension.swift in Sources */, 66FBFC4A2B83BD3300BC6AB1 /* FileUtils.swift in Sources */, 66FBFC4B2B83BD7B00BC6AB1 /* CoreExtension.swift in Sources */, D756C8172D352C5F00A58F2F /* CorePreferences.swift in Sources */, + C642277C2E8E4D900094FEDC /* ThemeManager.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1400,6 +1407,7 @@ D7CEE0352B7A210300FD79B7 /* ConversationsView.swift in Sources */, D717071E2AC5922E0037746F /* ColorExtension.swift in Sources */, D71968922B86369D00DF4459 /* ChatBubbleView.swift in Sources */, + C642277B2E8E4AC50094FEDC /* ThemeManager.swift in Sources */, D732C38C2D311D2500F78100 /* SettingsFragment.swift in Sources */, D78290B82ADD3910004AA85C /* ContactsFragment.swift in Sources */, D7DA67642ACCB31700E95002 /* ProfileModeFragment.swift in Sources */,