// // DynamicIslandHeader.swift // DynamicIsland // // Created by Harsh Vardhan Goswami on 04/08/24. // import Defaults import SwiftUI struct DynamicIslandHeader: View { @EnvironmentObject var vm: DynamicIslandViewModel @EnvironmentObject var webcamManager: WebcamManager @ObservedObject var batteryModel = BatteryStatusViewModel.shared @ObservedObject var coordinator = DynamicIslandViewCoordinator.shared @ObservedObject var clipboardManager = ClipboardManager.shared @StateObject var tvm = TrayDrop.shared @State private var showClipboardPopover = false @State private var showColorPickerPopover = false var body: some View { HStack(spacing: 0) { HStack { if (!tvm.isEmpty || coordinator.alwaysShowTabs) && Defaults[.dynamicShelf] { TabSelectionView() } else if vm.notchState == .open { EmptyView() } } .frame(maxWidth: .infinity, alignment: .leading) .opacity(vm.notchState == .closed ? 0 : 1) .blur(radius: vm.notchState == .closed ? 20 : 0) .animation(.smooth.delay(0.1), value: vm.notchState) .zIndex(2) if vm.notchState == .open { Rectangle() .fill(NSScreen.screens .first(where: { $0.localizedName == coordinator.selectedScreen })?.safeAreaInsets.top ?? 0 > 0 ? .black : .clear) .frame(width: vm.closedNotchSize.width) .mask { NotchShape() } } HStack(spacing: 4) { if vm.notchState == .open { if Defaults[.showMirror] { Button(action: { vm.toggleCameraPreview() }) { Capsule() .fill(.black) .frame(width: 30, height: 30) .overlay { Image(systemName: "web.camera") .foregroundColor(.white) .padding() .imageScale(.medium) } } .buttonStyle(PlainButtonStyle()) } if Defaults[.enableClipboardManager] && Defaults[.showClipboardIcon] { Button(action: { // Switch behavior based on display mode switch Defaults[.clipboardDisplayMode] { case .panel: ClipboardPanelManager.shared.toggleClipboardPanel() case .popover: showClipboardPopover.toggle() } }) { Capsule() .fill(.black) .frame(width: 30, height: 30) .overlay { Image(systemName: "doc.on.clipboard") .foregroundColor(.white) .padding() .imageScale(.medium) } } .buttonStyle(PlainButtonStyle()) .popover(isPresented: $showClipboardPopover, arrowEdge: .bottom) { ClipboardPopover() } .onChange(of: showClipboardPopover) { isActive in vm.isClipboardPopoverActive = isActive // If popover was closed, trigger a hover recheck if !isActive { DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { vm.shouldRecheckHover.toggle() } } } .onAppear { if Defaults[.enableClipboardManager] && !clipboardManager.isMonitoring { clipboardManager.startMonitoring() } } } // ColorPicker button if Defaults[.enableColorPickerFeature] { Button(action: { switch Defaults[.colorPickerDisplayMode] { case .panel: ColorPickerPanelManager.shared.toggleColorPickerPanel() case .popover: showColorPickerPopover.toggle() } }) { Capsule() .fill(.black) .frame(width: 30, height: 30) .overlay { Image(systemName: "eyedropper") .foregroundColor(.white) .padding() .imageScale(.medium) } } .buttonStyle(PlainButtonStyle()) .popover(isPresented: $showColorPickerPopover, arrowEdge: .bottom) { ColorPickerPopover() } .onChange(of: showColorPickerPopover) { isActive in vm.isColorPickerPopoverActive = isActive // If popover was closed, trigger a hover recheck if !isActive { DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { vm.shouldRecheckHover.toggle() } } } } if Defaults[.settingsIconInNotch] { Button(action: { SettingsWindowController.shared.showWindow() }) { Capsule() .fill(.black) .frame(width: 30, height: 30) .overlay { Image(systemName: "gear") .foregroundColor(.white) .padding() .imageScale(.medium) } } .buttonStyle(PlainButtonStyle()) } if Defaults[.showBatteryIndicator] { DynamicIslandBatteryView( batteryWidth: 30, isCharging: batteryModel.isCharging, isInLowPowerMode: batteryModel.isInLowPowerMode, isPluggedIn: batteryModel.isPluggedIn, levelBattery: batteryModel.levelBattery, maxCapacity: batteryModel.maxCapacity, timeToFullCharge: batteryModel.timeToFullCharge, isForNotification: false ) } } } .font(.system(.headline, design: .rounded)) .frame(maxWidth: .infinity, alignment: .trailing) .opacity(vm.notchState == .closed ? 0 : 1) .blur(radius: vm.notchState == .closed ? 20 : 0) .animation(.smooth.delay(0.1), value: vm.notchState) .zIndex(2) } .foregroundColor(.gray) .environmentObject(vm) .onChange(of: coordinator.shouldToggleClipboardPopover) { _ in // Only toggle if clipboard is enabled if Defaults[.enableClipboardManager] { switch Defaults[.clipboardDisplayMode] { case .panel: ClipboardPanelManager.shared.toggleClipboardPanel() case .popover: showClipboardPopover.toggle() } } } .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("ToggleClipboardPopover"))) { _ in // Handle keyboard shortcut for popover mode if Defaults[.enableClipboardManager] && Defaults[.clipboardDisplayMode] == .popover { showClipboardPopover.toggle() } } } } #Preview { DynamicIslandHeader() .environmentObject(DynamicIslandViewModel()) .environmentObject(WebcamManager.shared) }