vOOice/VoiceInk/PowerMode/PowerModeConfig.swift
2025-08-05 14:33:08 +05:45

282 lines
11 KiB
Swift

import Foundation
struct PowerModeConfig: Codable, Identifiable, Equatable {
var id: UUID
var name: String
var emoji: String
var appConfigs: [AppConfig]?
var urlConfigs: [URLConfig]?
var isAIEnhancementEnabled: Bool
var selectedPrompt: String?
var selectedTranscriptionModelName: String?
var selectedLanguage: String?
var useScreenCapture: Bool
var selectedAIProvider: String?
var selectedAIModel: String?
var isAutoSendEnabled: Bool = false
var isEnabled: Bool = true
enum CodingKeys: String, CodingKey {
case id, name, emoji, appConfigs, urlConfigs, isAIEnhancementEnabled, selectedPrompt, selectedLanguage, useScreenCapture, selectedAIProvider, selectedAIModel, isAutoSendEnabled, isEnabled
case selectedWhisperModel
case selectedTranscriptionModelName
}
init(id: UUID = UUID(), name: String, emoji: String, appConfigs: [AppConfig]? = nil,
urlConfigs: [URLConfig]? = nil, isAIEnhancementEnabled: Bool, selectedPrompt: String? = nil,
selectedTranscriptionModelName: String? = nil, selectedLanguage: String? = nil, useScreenCapture: Bool = false,
selectedAIProvider: String? = nil, selectedAIModel: String? = nil, isAutoSendEnabled: Bool = false, isEnabled: Bool = true) {
self.id = id
self.name = name
self.emoji = emoji
self.appConfigs = appConfigs
self.urlConfigs = urlConfigs
self.isAIEnhancementEnabled = isAIEnhancementEnabled
self.selectedPrompt = selectedPrompt
self.useScreenCapture = useScreenCapture
self.isAutoSendEnabled = isAutoSendEnabled
self.selectedAIProvider = selectedAIProvider ?? UserDefaults.standard.string(forKey: "selectedAIProvider")
self.selectedAIModel = selectedAIModel
self.selectedTranscriptionModelName = selectedTranscriptionModelName ?? UserDefaults.standard.string(forKey: "CurrentTranscriptionModel")
self.selectedLanguage = selectedLanguage ?? UserDefaults.standard.string(forKey: "SelectedLanguage") ?? "en"
self.isEnabled = isEnabled
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(UUID.self, forKey: .id)
name = try container.decode(String.self, forKey: .name)
emoji = try container.decode(String.self, forKey: .emoji)
appConfigs = try container.decodeIfPresent([AppConfig].self, forKey: .appConfigs)
urlConfigs = try container.decodeIfPresent([URLConfig].self, forKey: .urlConfigs)
isAIEnhancementEnabled = try container.decode(Bool.self, forKey: .isAIEnhancementEnabled)
selectedPrompt = try container.decodeIfPresent(String.self, forKey: .selectedPrompt)
selectedLanguage = try container.decodeIfPresent(String.self, forKey: .selectedLanguage)
useScreenCapture = try container.decode(Bool.self, forKey: .useScreenCapture)
selectedAIProvider = try container.decodeIfPresent(String.self, forKey: .selectedAIProvider)
selectedAIModel = try container.decodeIfPresent(String.self, forKey: .selectedAIModel)
isAutoSendEnabled = try container.decodeIfPresent(Bool.self, forKey: .isAutoSendEnabled) ?? false
isEnabled = try container.decodeIfPresent(Bool.self, forKey: .isEnabled) ?? true
if let newModelName = try container.decodeIfPresent(String.self, forKey: .selectedTranscriptionModelName) {
selectedTranscriptionModelName = newModelName
} else if let oldModelName = try container.decodeIfPresent(String.self, forKey: .selectedWhisperModel) {
selectedTranscriptionModelName = oldModelName
} else {
selectedTranscriptionModelName = nil
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(name, forKey: .name)
try container.encode(emoji, forKey: .emoji)
try container.encodeIfPresent(appConfigs, forKey: .appConfigs)
try container.encodeIfPresent(urlConfigs, forKey: .urlConfigs)
try container.encode(isAIEnhancementEnabled, forKey: .isAIEnhancementEnabled)
try container.encodeIfPresent(selectedPrompt, forKey: .selectedPrompt)
try container.encodeIfPresent(selectedLanguage, forKey: .selectedLanguage)
try container.encode(useScreenCapture, forKey: .useScreenCapture)
try container.encodeIfPresent(selectedAIProvider, forKey: .selectedAIProvider)
try container.encodeIfPresent(selectedAIModel, forKey: .selectedAIModel)
try container.encode(isAutoSendEnabled, forKey: .isAutoSendEnabled)
try container.encodeIfPresent(selectedTranscriptionModelName, forKey: .selectedTranscriptionModelName)
try container.encode(isEnabled, forKey: .isEnabled)
}
static func == (lhs: PowerModeConfig, rhs: PowerModeConfig) -> Bool {
lhs.id == rhs.id
}
}
struct AppConfig: Codable, Identifiable, Equatable {
let id: UUID
var bundleIdentifier: String
var appName: String
init(id: UUID = UUID(), bundleIdentifier: String, appName: String) {
self.id = id
self.bundleIdentifier = bundleIdentifier
self.appName = appName
}
static func == (lhs: AppConfig, rhs: AppConfig) -> Bool {
lhs.id == rhs.id
}
}
struct URLConfig: Codable, Identifiable, Equatable {
let id: UUID
var url: String
init(id: UUID = UUID(), url: String) {
self.id = id
self.url = url
}
static func == (lhs: URLConfig, rhs: URLConfig) -> Bool {
lhs.id == rhs.id
}
}
class PowerModeManager: ObservableObject {
static let shared = PowerModeManager()
@Published var configurations: [PowerModeConfig] = []
@Published var activeConfiguration: PowerModeConfig?
private let configKey = "powerModeConfigurationsV2"
private let activeConfigIdKey = "activeConfigurationId"
private init() {
loadConfigurations()
if let activeConfigIdString = UserDefaults.standard.string(forKey: activeConfigIdKey),
let activeConfigId = UUID(uuidString: activeConfigIdString) {
activeConfiguration = configurations.first { $0.id == activeConfigId }
} else {
activeConfiguration = nil
}
}
private func loadConfigurations() {
if let data = UserDefaults.standard.data(forKey: configKey),
let configs = try? JSONDecoder().decode([PowerModeConfig].self, from: data) {
configurations = configs
}
}
func saveConfigurations() {
if let data = try? JSONEncoder().encode(configurations) {
UserDefaults.standard.set(data, forKey: configKey)
}
}
func addConfiguration(_ config: PowerModeConfig) {
if !configurations.contains(where: { $0.id == config.id }) {
configurations.append(config)
saveConfigurations()
}
}
func removeConfiguration(with id: UUID) {
configurations.removeAll { $0.id == id }
saveConfigurations()
}
func getConfiguration(with id: UUID) -> PowerModeConfig? {
return configurations.first { $0.id == id }
}
func updateConfiguration(_ config: PowerModeConfig) {
if let index = configurations.firstIndex(where: { $0.id == config.id }) {
configurations[index] = config
saveConfigurations()
}
}
func getConfigurationForURL(_ url: String) -> PowerModeConfig? {
let cleanedURL = cleanURL(url)
for config in configurations.filter({ $0.isEnabled }) {
if let urlConfigs = config.urlConfigs {
for urlConfig in urlConfigs {
let configURL = cleanURL(urlConfig.url)
if cleanedURL.contains(configURL) {
return config
}
}
}
}
return nil
}
func getConfigurationForApp(_ bundleId: String) -> PowerModeConfig? {
for config in configurations.filter({ $0.isEnabled }) {
if let appConfigs = config.appConfigs {
if appConfigs.contains(where: { $0.bundleIdentifier == bundleId }) {
return config
}
}
}
return nil
}
func enableConfiguration(with id: UUID) {
if let index = configurations.firstIndex(where: { $0.id == id }) {
configurations[index].isEnabled = true
saveConfigurations()
}
}
func disableConfiguration(with id: UUID) {
if let index = configurations.firstIndex(where: { $0.id == id }) {
configurations[index].isEnabled = false
saveConfigurations()
}
}
var enabledConfigurations: [PowerModeConfig] {
return configurations.filter { $0.isEnabled }
}
func addAppConfig(_ appConfig: AppConfig, to config: PowerModeConfig) {
if var updatedConfig = configurations.first(where: { $0.id == config.id }) {
var configs = updatedConfig.appConfigs ?? []
configs.append(appConfig)
updatedConfig.appConfigs = configs
updateConfiguration(updatedConfig)
}
}
func removeAppConfig(_ appConfig: AppConfig, from config: PowerModeConfig) {
if var updatedConfig = configurations.first(where: { $0.id == config.id }) {
updatedConfig.appConfigs?.removeAll(where: { $0.id == appConfig.id })
updateConfiguration(updatedConfig)
}
}
func addURLConfig(_ urlConfig: URLConfig, to config: PowerModeConfig) {
if var updatedConfig = configurations.first(where: { $0.id == config.id }) {
var configs = updatedConfig.urlConfigs ?? []
configs.append(urlConfig)
updatedConfig.urlConfigs = configs
updateConfiguration(updatedConfig)
}
}
func removeURLConfig(_ urlConfig: URLConfig, from config: PowerModeConfig) {
if var updatedConfig = configurations.first(where: { $0.id == config.id }) {
updatedConfig.urlConfigs?.removeAll(where: { $0.id == urlConfig.id })
updateConfiguration(updatedConfig)
}
}
func cleanURL(_ url: String) -> String {
return url.lowercased()
.replacingOccurrences(of: "https://", with: "")
.replacingOccurrences(of: "http://", with: "")
.replacingOccurrences(of: "www.", with: "")
.trimmingCharacters(in: .whitespacesAndNewlines)
}
func setActiveConfiguration(_ config: PowerModeConfig?) {
activeConfiguration = config
UserDefaults.standard.set(config?.id.uuidString, forKey: activeConfigIdKey)
self.objectWillChange.send()
}
var currentActiveConfiguration: PowerModeConfig? {
return activeConfiguration
}
func getAllAvailableConfigurations() -> [PowerModeConfig] {
return configurations
}
func isEmojiInUse(_ emoji: String) -> Bool {
return configurations.contains { $0.emoji == emoji }
}
}