73 lines
2.3 KiB
Swift
73 lines
2.3 KiB
Swift
import Foundation
|
|
|
|
@MainActor
|
|
final class SettingsStore: ObservableObject {
|
|
@Published var serverURL: String? {
|
|
didSet { defaults.set(serverURL, forKey: Keys.serverURL) }
|
|
}
|
|
|
|
@Published private(set) var recentServers: [String] {
|
|
didSet { defaults.set(recentServers, forKey: Keys.recentServers) }
|
|
}
|
|
|
|
private let defaults: UserDefaults
|
|
private let maxRecentServers = 5
|
|
|
|
init(defaults: UserDefaults = .standard) {
|
|
self.defaults = defaults
|
|
#if DEBUG
|
|
serverURL =
|
|
ProcessInfo.processInfo.omnigentArgumentValue(after: "--omnigent-server-url")
|
|
?? ProcessInfo.processInfo.environment["OMNIGENT_SCREENSHOT_APP_URL"]
|
|
?? defaults.string(forKey: Keys.serverURL)
|
|
#else
|
|
serverURL = defaults.string(forKey: Keys.serverURL)
|
|
#endif
|
|
recentServers = defaults.stringArray(forKey: Keys.recentServers) ?? []
|
|
}
|
|
|
|
func rememberRecentServer(_ url: URL) {
|
|
let value = url.absoluteString
|
|
let deduped: [String] = [value] + recentServers.filter { $0 != value }
|
|
recentServers = Array(deduped.prefix(maxRecentServers))
|
|
}
|
|
|
|
func isProtocolAllowed(_ scheme: String, from origin: String) -> Bool {
|
|
allowedProtocols()[origin]?.contains(scheme.lowercased()) == true
|
|
}
|
|
|
|
func allowProtocol(_ scheme: String, from origin: String) {
|
|
var grants = allowedProtocols()
|
|
var schemes = grants[origin] ?? []
|
|
let normalized = scheme.lowercased()
|
|
if !schemes.contains(normalized) {
|
|
schemes.append(normalized)
|
|
}
|
|
grants[origin] = schemes
|
|
defaults.set(grants, forKey: Keys.allowedProtocols)
|
|
}
|
|
|
|
private func allowedProtocols() -> [String: [String]] {
|
|
defaults.dictionary(forKey: Keys.allowedProtocols) as? [String: [String]] ?? [:]
|
|
}
|
|
|
|
private enum Keys {
|
|
static let serverURL = "omnigent.serverURL"
|
|
static let recentServers = "omnigent.recentServers"
|
|
static let allowedProtocols = "omnigent.allowedProtocols"
|
|
}
|
|
}
|
|
|
|
#if DEBUG
|
|
extension ProcessInfo {
|
|
fileprivate func omnigentArgumentValue(after argumentName: String) -> String? {
|
|
guard let index = arguments.firstIndex(of: argumentName) else { return nil }
|
|
let valueIndex = arguments.index(after: index)
|
|
guard arguments.indices.contains(valueIndex) else { return nil }
|
|
|
|
let value = arguments[valueIndex].trimmingCharacters(in: .whitespacesAndNewlines)
|
|
return value.isEmpty ? nil : value
|
|
}
|
|
}
|
|
#endif
|