Files
Firelink/Sources/Firelink/FirelinkApp.swift
T
nimbold 7802b612a4 feat: integrate settings and speed limiter into main window
- Refactor SettingsView to act as a flat detail pane instead of a nested sidebar or macOS native window
- Add custom horizontal tab bar for switching between setting categories
- Create SpeedLimiterView and add it as a primary tool in the sidebar
- Add state retention using AppStorage for settings tab selection and speed limits
- Fix EXC_BAD_ACCESS in DownloadTable by using sortableSize instead of debugDescription
2026-06-04 05:29:15 +03:30

99 lines
3.8 KiB
Swift

import SwiftUI
@main
struct FirelinkApp: App {
@StateObject private var settings: AppSettings
@StateObject private var controller: DownloadController
@StateObject private var schedulerController: SchedulerController
@AppStorage("showMenuBarIcon") private var showMenuBarIcon = true
// Server must be retained to keep listening
private let extensionServer: LocalExtensionServer?
init() {
let settings = AppSettings()
let controller = DownloadController(settings: settings)
_settings = StateObject(wrappedValue: settings)
_controller = StateObject(wrappedValue: controller)
_schedulerController = StateObject(wrappedValue: SchedulerController(downloadController: controller))
extensionServer = LocalExtensionServer(downloadController: controller)
extensionServer?.start()
}
var body: some Scene {
WindowGroup(id: "main") {
ContentView()
.environmentObject(controller)
.environmentObject(settings)
.environmentObject(schedulerController)
.modifier(AppThemeModifier(theme: settings.appTheme))
.modifier(AppFontSizeModifier(fontSize: settings.appFontSize))
.frame(minWidth: 1180, idealWidth: 1280, minHeight: 720, idealHeight: 760)
}
.windowStyle(.titleBar)
WindowGroup("Add Downloads", id: "add-downloads") {
AddDownloadsView()
.environmentObject(controller)
.environmentObject(settings)
.modifier(AppThemeModifier(theme: settings.appTheme))
.modifier(AppFontSizeModifier(fontSize: settings.appFontSize))
}
.windowResizability(.contentSize)
WindowGroup("Download Properties", for: UUID.self) { $downloadID in
if let downloadID {
DownloadPropertiesWindow(downloadID: downloadID)
.environmentObject(controller)
.environmentObject(settings)
.modifier(AppThemeModifier(theme: settings.appTheme))
.modifier(AppFontSizeModifier(fontSize: settings.appFontSize))
} else {
ContentUnavailableView("Download Not Found", systemImage: "questionmark.circle")
.modifier(AppThemeModifier(theme: settings.appTheme))
.modifier(AppFontSizeModifier(fontSize: settings.appFontSize))
}
}
.windowResizability(.contentSize)
.commands {
CommandGroup(after: .newItem) {
Button("Add Downloads...") {
NotificationCenter.default.post(name: NSNotification.Name("OpenAddDownloadsWindow"), object: nil)
}
.keyboardShortcut("n", modifiers: [.command])
Divider()
Button("Start Queue") {
controller.startQueue()
}
.keyboardShortcut("r", modifiers: [.command])
Button("Stop Downloads") {
controller.pauseActiveDownloads()
}
.disabled(controller.activeCount == 0)
}
}
MenuBarExtra(isInserted: $showMenuBarIcon) {
TrayMenuView()
.environmentObject(controller)
} label: {
if let nsImage = { () -> NSImage? in
guard let url = Bundle.main.url(forResource: "MenuBarIconTemplate", withExtension: "png"),
let img = NSImage(contentsOf: url) else { return nil }
img.size = NSSize(width: 21, height: 21)
img.isTemplate = true
return img
}() {
Image(nsImage: nsImage)
} else {
Image(systemName: "arrow.down.circle")
}
}
}
}