mirror of
https://github.com/nimbold/Firelink.git
synced 2026-08-05 17:08:26 +00:00
2b820ec802
- Split monolithic SettingsView.swift into modular Settings panes - Add SOCKS5 proxy support to proxy configuration - Fix ListRowDensity application in DownloadTable - Improve discoverability of global speed limit by adding it to Downloads pane
182 lines
5.0 KiB
Swift
182 lines
5.0 KiB
Swift
import SwiftUI
|
|
import AppKit
|
|
|
|
enum AppFontSize: String, Codable, CaseIterable, Identifiable, Sendable {
|
|
case small = "Small"
|
|
case standard = "Standard"
|
|
case large = "Large"
|
|
|
|
var id: String { rawValue }
|
|
|
|
var dynamicTypeSize: DynamicTypeSize {
|
|
switch self {
|
|
case .small: return .xSmall
|
|
case .standard: return .medium
|
|
case .large: return .xxLarge
|
|
}
|
|
}
|
|
|
|
var defaultFont: Font {
|
|
switch self {
|
|
case .small:
|
|
return .system(size: 12)
|
|
case .standard:
|
|
return .system(size: 13)
|
|
case .large:
|
|
return .system(size: 15)
|
|
}
|
|
}
|
|
|
|
var controlSize: ControlSize {
|
|
switch self {
|
|
case .small:
|
|
return .small
|
|
case .standard:
|
|
return .regular
|
|
case .large:
|
|
return .large
|
|
}
|
|
}
|
|
}
|
|
|
|
enum ListRowDensity: String, Codable, CaseIterable, Identifiable, Sendable {
|
|
case compact = "Compact"
|
|
case standard = "Standard"
|
|
case relaxed = "Relaxed"
|
|
|
|
var id: String { rawValue }
|
|
|
|
var verticalPadding: CGFloat {
|
|
switch self {
|
|
case .compact: return 4
|
|
case .standard: return 8
|
|
case .relaxed: return 14
|
|
}
|
|
}
|
|
|
|
var minRowHeight: CGFloat {
|
|
switch self {
|
|
case .compact: return 24
|
|
case .standard: return 32
|
|
case .relaxed: return 44
|
|
}
|
|
}
|
|
}
|
|
|
|
enum AppTheme: String, Codable, CaseIterable, Identifiable, Sendable {
|
|
case system = "System Default"
|
|
case light = "Light"
|
|
case dark = "Dark"
|
|
case dracula = "Dracula"
|
|
case nord = "Nord"
|
|
|
|
var id: String { rawValue }
|
|
|
|
var theme: Theme {
|
|
switch self {
|
|
case .system, .dark:
|
|
return Theme.system
|
|
case .light:
|
|
return Theme.modernLight
|
|
case .dracula:
|
|
return Theme.dracula
|
|
case .nord:
|
|
return Theme.nord
|
|
}
|
|
}
|
|
|
|
var appearance: NSAppearance? {
|
|
switch self {
|
|
case .system: return nil
|
|
case .light: return NSAppearance(named: .aqua)
|
|
case .dark, .dracula, .nord: return NSAppearance(named: .darkAqua)
|
|
}
|
|
}
|
|
}
|
|
|
|
struct Theme: Equatable, Sendable {
|
|
var background: Color?
|
|
var secondaryBackground: Color?
|
|
var text: Color?
|
|
var secondaryText: Color?
|
|
var accent: Color?
|
|
|
|
static let system = Theme(
|
|
background: nil,
|
|
secondaryBackground: nil,
|
|
text: nil,
|
|
secondaryText: nil,
|
|
accent: nil
|
|
)
|
|
|
|
static let modernLight = Theme(
|
|
background: Color(nsColor: NSColor(calibratedRed: 0.98, green: 0.98, blue: 0.99, alpha: 1.0)),
|
|
secondaryBackground: Color(nsColor: NSColor(calibratedRed: 0.94, green: 0.94, blue: 0.96, alpha: 1.0)),
|
|
text: Color.primary,
|
|
secondaryText: Color.secondary,
|
|
accent: Color.accentColor
|
|
)
|
|
|
|
static let dracula = Theme(
|
|
background: Color(nsColor: NSColor(calibratedRed: 0.16, green: 0.16, blue: 0.21, alpha: 1.0)),
|
|
secondaryBackground: Color(nsColor: NSColor(calibratedRed: 0.27, green: 0.28, blue: 0.35, alpha: 1.0)),
|
|
text: Color(nsColor: NSColor(calibratedRed: 0.97, green: 0.97, blue: 0.95, alpha: 1.0)),
|
|
secondaryText: Color(nsColor: NSColor(calibratedRed: 0.38, green: 0.44, blue: 0.58, alpha: 1.0)),
|
|
accent: Color(nsColor: NSColor(calibratedRed: 1.00, green: 0.47, blue: 0.65, alpha: 1.0)) // Pink
|
|
)
|
|
|
|
static let nord = Theme(
|
|
background: Color(nsColor: NSColor(calibratedRed: 0.18, green: 0.20, blue: 0.25, alpha: 1.0)), // nord0
|
|
secondaryBackground: Color(nsColor: NSColor(calibratedRed: 0.23, green: 0.26, blue: 0.32, alpha: 1.0)), // nord1
|
|
text: Color(nsColor: NSColor(calibratedRed: 0.85, green: 0.87, blue: 0.91, alpha: 1.0)), // nord4
|
|
secondaryText: Color(nsColor: NSColor(calibratedRed: 0.57, green: 0.63, blue: 0.70, alpha: 1.0)), // nord3
|
|
accent: Color(nsColor: NSColor(calibratedRed: 0.53, green: 0.75, blue: 0.82, alpha: 1.0)) // nord8
|
|
)
|
|
}
|
|
|
|
struct AppThemeModifier: ViewModifier {
|
|
let theme: AppTheme
|
|
|
|
func body(content: Content) -> some View {
|
|
content
|
|
.tint(theme.theme.accent)
|
|
.onAppear {
|
|
NSApp.appearance = theme.appearance
|
|
}
|
|
.onChange(of: theme) { _, newTheme in
|
|
NSApp.appearance = newTheme.appearance
|
|
}
|
|
}
|
|
}
|
|
|
|
struct AppFontSizeModifier: ViewModifier {
|
|
let fontSize: AppFontSize
|
|
|
|
func body(content: Content) -> some View {
|
|
content
|
|
.font(fontSize.defaultFont)
|
|
.controlSize(fontSize.controlSize)
|
|
.dynamicTypeSize(fontSize.dynamicTypeSize)
|
|
}
|
|
}
|
|
|
|
struct ThemeBackgroundModifier: ViewModifier {
|
|
let color: Color?
|
|
|
|
func body(content: Content) -> some View {
|
|
if let color {
|
|
content
|
|
.scrollContentBackground(.hidden)
|
|
.background(color)
|
|
} else {
|
|
content
|
|
}
|
|
}
|
|
}
|
|
|
|
extension View {
|
|
func themeBackground(_ color: Color?) -> some View {
|
|
modifier(ThemeBackgroundModifier(color: color))
|
|
}
|
|
}
|