mirror of
https://github.com/nimbold/Firelink.git
synced 2026-07-26 12:08:27 +00:00
feat: add Font Size, List Row Density, and Menu Bar Icon settings
This commit is contained in:
@@ -68,6 +68,18 @@ final class AppSettings: ObservableObject {
|
||||
@Published var appTheme: AppTheme = .system {
|
||||
didSet { save() }
|
||||
}
|
||||
|
||||
@Published var appFontSize: AppFontSize = .standard {
|
||||
didSet { save() }
|
||||
}
|
||||
|
||||
@Published var listRowDensity: ListRowDensity = .standard {
|
||||
didSet { save() }
|
||||
}
|
||||
|
||||
@Published var showMenuBarIcon: Bool = true {
|
||||
didSet { save() }
|
||||
}
|
||||
|
||||
@Published var perServerConnections: Int {
|
||||
didSet {
|
||||
@@ -134,6 +146,9 @@ final class AppSettings: ObservableObject {
|
||||
if let data = defaults.data(forKey: storageKey),
|
||||
let stored = try? JSONDecoder().decode(StoredSettings.self, from: data) {
|
||||
appTheme = stored.appTheme ?? .system
|
||||
appFontSize = stored.appFontSize ?? .standard
|
||||
listRowDensity = stored.listRowDensity ?? .standard
|
||||
showMenuBarIcon = stored.showMenuBarIcon ?? true
|
||||
perServerConnections = min(max(stored.perServerConnections, 1), 16)
|
||||
maxConcurrentDownloads = min(max(stored.maxConcurrentDownloads ?? 3, 1), 12)
|
||||
globalSpeedLimitKiBPerSecond = min(max(stored.globalSpeedLimitKiBPerSecond ?? 0, 0), 10_485_760)
|
||||
@@ -143,6 +158,9 @@ final class AppSettings: ObservableObject {
|
||||
downloadDirectories = Self.decodeDirectories(stored.downloadDirectories)
|
||||
} else {
|
||||
appTheme = .system
|
||||
appFontSize = .standard
|
||||
listRowDensity = .standard
|
||||
showMenuBarIcon = true
|
||||
perServerConnections = 16
|
||||
maxConcurrentDownloads = 3
|
||||
globalSpeedLimitKiBPerSecond = 0
|
||||
@@ -225,6 +243,9 @@ final class AppSettings: ObservableObject {
|
||||
private func save() {
|
||||
let stored = StoredSettings(
|
||||
appTheme: appTheme,
|
||||
appFontSize: appFontSize,
|
||||
listRowDensity: listRowDensity,
|
||||
showMenuBarIcon: showMenuBarIcon,
|
||||
perServerConnections: perServerConnections,
|
||||
maxConcurrentDownloads: maxConcurrentDownloads,
|
||||
globalSpeedLimitKiBPerSecond: globalSpeedLimitKiBPerSecond,
|
||||
@@ -285,6 +306,9 @@ final class AppSettings: ObservableObject {
|
||||
|
||||
private struct StoredSettings: Codable {
|
||||
var appTheme: AppTheme?
|
||||
var appFontSize: AppFontSize?
|
||||
var listRowDensity: ListRowDensity?
|
||||
var showMenuBarIcon: Bool?
|
||||
var perServerConnections: Int
|
||||
var maxConcurrentDownloads: Int?
|
||||
var globalSpeedLimitKiBPerSecond: Int?
|
||||
|
||||
@@ -526,6 +526,7 @@ struct DownloadTable: View {
|
||||
}
|
||||
|
||||
private struct DownloadRow: View {
|
||||
@EnvironmentObject private var settings: AppSettings
|
||||
let item: DownloadItem
|
||||
let priorityNumber: Int?
|
||||
let visibleColumns: [DownloadColumn]
|
||||
@@ -537,7 +538,7 @@ private struct DownloadRow: View {
|
||||
ForEach(visibleColumns) { column in
|
||||
cell(for: column)
|
||||
.padding(.horizontal, 8)
|
||||
.padding(.vertical, 8)
|
||||
.padding(.vertical, settings.listRowDensity.verticalPadding)
|
||||
.frame(width: columnWidth(column), alignment: alignment(for: column))
|
||||
.clipped()
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ struct FirelinkApp: App {
|
||||
.environmentObject(settings)
|
||||
.environmentObject(schedulerController)
|
||||
.modifier(AppThemeModifier(theme: settings.appTheme))
|
||||
.dynamicTypeSize(settings.appFontSize.dynamicTypeSize)
|
||||
.frame(minWidth: 1180, idealWidth: 1280, minHeight: 720, idealHeight: 760)
|
||||
}
|
||||
.windowStyle(.titleBar)
|
||||
@@ -30,6 +31,7 @@ struct FirelinkApp: App {
|
||||
.environmentObject(controller)
|
||||
.environmentObject(settings)
|
||||
.modifier(AppThemeModifier(theme: settings.appTheme))
|
||||
.dynamicTypeSize(settings.appFontSize.dynamicTypeSize)
|
||||
}
|
||||
.windowResizability(.contentSize)
|
||||
|
||||
@@ -39,9 +41,11 @@ struct FirelinkApp: App {
|
||||
.environmentObject(controller)
|
||||
.environmentObject(settings)
|
||||
.modifier(AppThemeModifier(theme: settings.appTheme))
|
||||
.dynamicTypeSize(settings.appFontSize.dynamicTypeSize)
|
||||
} else {
|
||||
ContentUnavailableView("Download Not Found", systemImage: "questionmark.circle")
|
||||
.modifier(AppThemeModifier(theme: settings.appTheme))
|
||||
.dynamicTypeSize(settings.appFontSize.dynamicTypeSize)
|
||||
}
|
||||
}
|
||||
.windowResizability(.contentSize)
|
||||
@@ -55,7 +59,7 @@ struct FirelinkApp: App {
|
||||
}
|
||||
}
|
||||
|
||||
MenuBarExtra("Firelink", systemImage: "arrow.down.circle") {
|
||||
MenuBarExtra("Firelink", systemImage: "arrow.down.circle", isInserted: $settings.showMenuBarIcon) {
|
||||
TrayMenuView()
|
||||
.environmentObject(controller)
|
||||
}
|
||||
|
||||
@@ -137,6 +137,28 @@ private struct LookAndFeelSettingsPane: View {
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
Section("Display") {
|
||||
Picker("Font Size", selection: $settings.appFontSize) {
|
||||
ForEach(AppFontSize.allCases) { size in
|
||||
Text(size.rawValue).tag(size)
|
||||
}
|
||||
}
|
||||
|
||||
Picker("List Row Density", selection: $settings.listRowDensity) {
|
||||
ForEach(ListRowDensity.allCases) { density in
|
||||
Text(density.rawValue).tag(density)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Section("Menu Bar") {
|
||||
Toggle("Show menu bar icon", isOn: $settings.showMenuBarIcon)
|
||||
|
||||
Text("Provides quick access to downloads and queues from the macOS menu bar.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
.formStyle(.grouped)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,38 @@
|
||||
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 .small
|
||||
case .standard: return .medium
|
||||
case .large: return .xLarge
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum AppTheme: String, Codable, CaseIterable, Identifiable, Sendable {
|
||||
case system = "System Default"
|
||||
case light = "Light"
|
||||
|
||||
Reference in New Issue
Block a user