Add Tonuino Manager website and Sparkle updates
This commit is contained in:
commit
1cac427ff2
44 files changed
+5861
No files matched your search
@@ -0,0 +1,40 @@
|
||||
import AppKit
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
@MainActor
|
||||
final class AppModel: ObservableObject {
|
||||
enum Section: String, CaseIterable, Identifiable, Hashable {
|
||||
case library = "SD-Karte"
|
||||
case cards = "NFC-Karten"
|
||||
case tonuino = "TonUINO"
|
||||
case settings = "Einstellungen"
|
||||
var id: String { rawValue }
|
||||
var icon: String {
|
||||
switch self {
|
||||
case .library: "sdcard"
|
||||
case .cards: "wave.3.right"
|
||||
case .tonuino: "slider.horizontal.3"
|
||||
case .settings: "gearshape"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Published var section: Section = .library
|
||||
@Published var library = LibraryModel()
|
||||
@Published var cards = CardModel()
|
||||
@Published var status = "Bereit"
|
||||
@Published var errorMessage: String?
|
||||
@Published var showError = false
|
||||
private var childSubscriptions = Set<AnyCancellable>()
|
||||
|
||||
init() {
|
||||
library.objectWillChange.sink { [weak self] _ in self?.objectWillChange.send() }.store(in: &childSubscriptions)
|
||||
cards.objectWillChange.sink { [weak self] _ in self?.objectWillChange.send() }.store(in: &childSubscriptions)
|
||||
}
|
||||
|
||||
func report(_ error: Error) {
|
||||
errorMessage = error.localizedDescription
|
||||
showError = true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import SwiftUI
|
||||
|
||||
struct ContentView: View {
|
||||
@EnvironmentObject private var app: AppModel
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
NavigationSplitView {
|
||||
List(AppModel.Section.allCases, selection: $app.section) { item in
|
||||
Label(item.rawValue, systemImage: item.icon).tag(item)
|
||||
}
|
||||
.listStyle(.sidebar)
|
||||
.navigationTitle("Tonuino Manager")
|
||||
.safeAreaInset(edge: .bottom) {
|
||||
HStack(spacing: 8) {
|
||||
Circle().fill(app.library.rootURL == nil ? Color.secondary : Color.green).frame(width: 8, height: 8)
|
||||
Text(app.library.activeProfile.map { "Lokal · \($0.name)" } ?? (app.library.rootURL?.lastPathComponent ?? "Keine Bibliothek ausgewählt"))
|
||||
.lineLimit(1).foregroundStyle(.secondary)
|
||||
}
|
||||
.font(.caption).padding()
|
||||
}
|
||||
} detail: {
|
||||
switch app.section {
|
||||
case .library: LibraryView()
|
||||
case .cards: CardsView()
|
||||
case .tonuino: TonuinoSettingsView()
|
||||
case .settings: SettingsView()
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
|
||||
HStack {
|
||||
Spacer(minLength: 0)
|
||||
Text(app.status)
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.lineLimit(1)
|
||||
.truncationMode(.tail)
|
||||
.frame(maxWidth: 520, alignment: .trailing)
|
||||
}
|
||||
.padding(.horizontal, 14)
|
||||
.padding(.vertical, 6)
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(.regularMaterial)
|
||||
.overlay(alignment: .top) {
|
||||
Rectangle().fill(.primary.opacity(0.08)).frame(height: 1)
|
||||
}
|
||||
}
|
||||
.alert("Fehler", isPresented: $app.showError) {
|
||||
Button("OK", role: .cancel) { }
|
||||
} message: { Text(app.errorMessage ?? "Unbekannter Fehler") }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import SwiftUI
|
||||
import Sparkle
|
||||
import AppKit
|
||||
|
||||
final class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
static var updater: SPUStandardUpdaterController?
|
||||
func applicationDidFinishLaunching(_ notification: Notification) {
|
||||
guard let feed = Bundle.main.object(forInfoDictionaryKey: "SUFeedURL") as? String,
|
||||
URL(string: feed)?.scheme != nil,
|
||||
let key = Bundle.main.object(forInfoDictionaryKey: "SUPublicEDKey") as? String,
|
||||
!key.isEmpty else { return }
|
||||
Self.updater = SPUStandardUpdaterController(startingUpdater: true, updaterDelegate: nil, userDriverDelegate: nil)
|
||||
}
|
||||
}
|
||||
|
||||
@main
|
||||
struct TonuinoManagerApp: App {
|
||||
@NSApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
|
||||
@StateObject private var model = AppModel()
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
.environmentObject(model)
|
||||
.frame(minWidth: 980, minHeight: 640)
|
||||
}
|
||||
.commands {
|
||||
CommandGroup(replacing: .newItem) { }
|
||||
CommandGroup(after: .appInfo) {
|
||||
Button("Auf Updates prüfen…") { AppDelegate.updater?.checkForUpdates(nil) }
|
||||
.disabled(AppDelegate.updater?.updater.canCheckForUpdates != true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user