YanDisk v1.0.1: тёмная иконка по теме системы, вкладки (Скриншоты скрыт, Файлы→Доступные мне), синк по умолчанию 'В облаке', ПРАВКИ.md
- Иконка: AppIconDark.icns + переключение Dock-иконки по effectiveAppearance (KVO)
- Сайдбар: убран 'Скриншоты', 'Файлы' → 'Доступные мне' (заглушка), первая вкладка — все файлы и папки
- SyncPolicyStore.globalMode по умолчанию .cloudOnly ('В облаке')
- build.sh/smoke_test.sh: SDKROOT из Xcode (фикс SDK-конфликта тулчейна 6.3.3/SDK 6.4)
- ПРАВКИ.md: полный аудит и план доработок
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
import SwiftUI
|
||||
import AppKit
|
||||
|
||||
final class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
private var mainWindowController: NSWindowController?
|
||||
private var store: AppStore?
|
||||
private var appearanceObserver: NSKeyValueObservation?
|
||||
|
||||
private func updateAppIcon() {
|
||||
let isDark = NSApp.effectiveAppearance.bestMatch(from: [.aqua, .darkAqua]) == .darkAqua
|
||||
let name = isDark ? "AppIconDark" : "AppIcon"
|
||||
if let icon = Bundle.main.image(forResource: NSImage.Name(name)) {
|
||||
NSApp.applicationIconImage = icon
|
||||
}
|
||||
}
|
||||
|
||||
func attach(store: AppStore) {
|
||||
self.store = store
|
||||
}
|
||||
|
||||
func applicationDidFinishLaunching(_ notification: Notification) {
|
||||
NSLog("YD didFinishLaunching")
|
||||
NSApp.setActivationPolicy(.regular)
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
updateAppIcon()
|
||||
appearanceObserver = NSApp.observe(\.effectiveAppearance, options: [.initial, .new]) { [weak self] _, _ in
|
||||
DispatchQueue.main.async {
|
||||
MainActor.assumeIsolated {
|
||||
self?.updateAppIcon()
|
||||
}
|
||||
}
|
||||
}
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
MainActor.assumeIsolated {
|
||||
self?.showMainWindow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
|
||||
false
|
||||
}
|
||||
|
||||
func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
|
||||
true
|
||||
}
|
||||
|
||||
@MainActor @objc func showMainWindow() {
|
||||
NSLog("YD showMainWindow store=\(self.store != nil) windows=\(NSApp.windows.count)")
|
||||
if let window = mainWindowController?.window {
|
||||
window.makeKeyAndOrderFront(nil)
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
return
|
||||
}
|
||||
|
||||
if let existing = NSApp.windows.first(where: {
|
||||
$0.canBecomeMain && ($0.title.contains("YanDisk") || $0.title.isEmpty)
|
||||
}) {
|
||||
NSLog("YD reuse existing window")
|
||||
existing.makeKeyAndOrderFront(nil)
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
return
|
||||
}
|
||||
|
||||
let store: AppStore
|
||||
if let s = self.store {
|
||||
store = s
|
||||
} else {
|
||||
NSLog("YD creating AppStore")
|
||||
store = AppStore()
|
||||
self.store = store
|
||||
}
|
||||
|
||||
NSLog("YD building hosting controller")
|
||||
let root = RootView().environment(store)
|
||||
let hosting = NSHostingController(rootView: root)
|
||||
let window = NSWindow(contentViewController: hosting)
|
||||
window.title = "YanDisk"
|
||||
window.setContentSize(NSSize(width: 980, height: 620))
|
||||
window.minSize = NSSize(width: 900, height: 560)
|
||||
window.styleMask = [.titled, .closable, .miniaturizable, .resizable]
|
||||
window.isReleasedWhenClosed = false
|
||||
window.center()
|
||||
window.makeKeyAndOrderFront(nil)
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
mainWindowController = NSWindowController(window: window)
|
||||
NSLog("YD window shown title=\(window.title) visible=\(window.isVisible)")
|
||||
}
|
||||
|
||||
@MainActor @objc func showPreferencesWindow(_ sender: Any?) {
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
if let window = NSApp.windows.first(where: { $0.title == "Настройки" }) {
|
||||
window.makeKeyAndOrderFront(nil)
|
||||
return
|
||||
}
|
||||
let store = self.store ?? AppStore()
|
||||
self.store = store
|
||||
let hosting = NSHostingController(
|
||||
rootView: PreferencesView().environment(store).frame(width: 520, height: 420)
|
||||
)
|
||||
let window = NSWindow(contentViewController: hosting)
|
||||
window.title = "Настройки"
|
||||
window.styleMask = [.titled, .closable]
|
||||
window.setContentSize(NSSize(width: 520, height: 420))
|
||||
window.isReleasedWhenClosed = false
|
||||
window.center()
|
||||
window.makeKeyAndOrderFront(nil)
|
||||
}
|
||||
}
|
||||
|
||||
@main
|
||||
struct YanDiskApp: App {
|
||||
@NSApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
|
||||
@State private var store = AppStore()
|
||||
@AppStorage("Appearance") private var appearance = "system"
|
||||
|
||||
var body: some Scene {
|
||||
MenuBarExtra {
|
||||
MenuBarView()
|
||||
.environment(store)
|
||||
.onAppear {
|
||||
appDelegate.attach(store: store)
|
||||
}
|
||||
} label: {
|
||||
Image(systemName: "cloud.fill")
|
||||
}
|
||||
.menuBarExtraStyle(.window)
|
||||
|
||||
Settings {
|
||||
PreferencesView()
|
||||
.environment(store)
|
||||
.frame(width: 520, height: 420)
|
||||
.preferredColorScheme(colorScheme)
|
||||
}
|
||||
.commands {
|
||||
CommandGroup(replacing: .appInfo) {
|
||||
Button("О YanDisk") {
|
||||
NSApp.orderFrontStandardAboutPanel(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var colorScheme: ColorScheme? {
|
||||
switch appearance {
|
||||
case "light": return .light
|
||||
case "dark": return .dark
|
||||
default: return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct RootView: View {
|
||||
@Environment(AppStore.self) private var store
|
||||
@AppStorage("Appearance") private var appearance = "system"
|
||||
|
||||
var body: some View {
|
||||
MainSplitView()
|
||||
.environment(store)
|
||||
.preferredColorScheme(colorScheme)
|
||||
.task {
|
||||
store.bootstrap()
|
||||
}
|
||||
}
|
||||
|
||||
private var colorScheme: ColorScheme? {
|
||||
switch appearance {
|
||||
case "light": return .light
|
||||
case "dark": return .dark
|
||||
default: return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user