From 91f1159da17d29f9907c1c28eee88edd90715423 Mon Sep 17 00:00:00 2001 From: omeriadon Date: Thu, 4 Sep 2025 19:42:30 +0800 Subject: [PATCH 01/12] first potentially working version --- boringNotch.xcodeproj/project.pbxproj | 4 ++ boringNotch/ContentView.swift | 4 +- boringNotch/Localizable.xcstrings | 5 ++- .../components/Settings/SettingsView.swift | 17 ++++++++ boringNotch/enums/generic.swift | 6 +++ boringNotch/managers/BackgroundManager.swift | 43 +++++++++++++++++++ boringNotch/models/Constants.swift | 1 + 7 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 boringNotch/managers/BackgroundManager.swift diff --git a/boringNotch.xcodeproj/project.pbxproj b/boringNotch.xcodeproj/project.pbxproj index dfee6850..ec587f0f 100644 --- a/boringNotch.xcodeproj/project.pbxproj +++ b/boringNotch.xcodeproj/project.pbxproj @@ -82,6 +82,7 @@ 9A987A0D2C73CA66005CA465 /* NotchShelfView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A987A032C73CA66005CA465 /* NotchShelfView.swift */; }; 9A987A102C73CA8D005CA465 /* Collections in Frameworks */ = {isa = PBXBuildFile; productRef = 9A987A0F2C73CA8D005CA465 /* Collections */; }; 9AB0C6BD2C73C9CB00F7CD30 /* NotchHomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AB0C6BB2C73C9CB00F7CD30 /* NotchHomeView.swift */; }; + A79A415A2E6996BA001D3BC9 /* BackgroundManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79A41592E6996BA001D3BC9 /* BackgroundManager.swift */; }; B10348D92C74E56000475897 /* ConditionalModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10348D82C74E56000475897 /* ConditionalModifier.swift */; }; B10A848A2C7BCC940088BFFC /* AirDropView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A84892C7BCC940088BFFC /* AirDropView.swift */; }; B10A848C2C7BCD150088BFFC /* AirDrop.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A848B2C7BCD150088BFFC /* AirDrop.swift */; }; @@ -210,6 +211,7 @@ 9A987A022C73CA66005CA465 /* DropItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropItemView.swift; sourceTree = ""; }; 9A987A032C73CA66005CA465 /* NotchShelfView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotchShelfView.swift; sourceTree = ""; }; 9AB0C6BB2C73C9CB00F7CD30 /* NotchHomeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotchHomeView.swift; sourceTree = ""; }; + A79A41592E6996BA001D3BC9 /* BackgroundManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundManager.swift; sourceTree = ""; }; B10348D82C74E56000475897 /* ConditionalModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConditionalModifier.swift; sourceTree = ""; }; B10A84892C7BCC940088BFFC /* AirDropView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AirDropView.swift; sourceTree = ""; }; B10A848B2C7BCD150088BFFC /* AirDrop.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AirDrop.swift; sourceTree = ""; }; @@ -357,6 +359,7 @@ 149E0B962C737D00006418B1 /* WebcamManager.swift */, 147CB9562C8CCC980094C254 /* BoringExtensionManager.swift */, 14C08BB52C8DE42D000F8AA0 /* CalendarManager.swift */, + A79A41592E6996BA001D3BC9 /* BackgroundManager.swift */, ); path = managers; sourceTree = ""; @@ -726,6 +729,7 @@ B10A848C2C7BCD150088BFFC /* AirDrop.swift in Sources */, 1153BD9C2D98853B00979FB0 /* NowPlayingController.swift in Sources */, B141C2412CA5F53F00AC8CC8 /* SparkleView.swift in Sources */, + A79A415A2E6996BA001D3BC9 /* BackgroundManager.swift in Sources */, 116398962DF5D6C00052E6AF /* CalendarServiceProviding.swift in Sources */, 1163988D2DF5CAB40052E6AF /* EventModel.swift in Sources */, 14D570B92C5E98A20011E668 /* drop.swift in Sources */, diff --git a/boringNotch/ContentView.swift b/boringNotch/ContentView.swift index a2e4676d..6cb0fbf2 100644 --- a/boringNotch/ContentView.swift +++ b/boringNotch/ContentView.swift @@ -20,6 +20,7 @@ struct ContentView: View { @ObservedObject var coordinator = BoringViewCoordinator.shared @ObservedObject var musicManager = MusicManager.shared @ObservedObject var batteryModel = BatteryStatusViewModel.shared + @ObservedObject var backgroundManager = BackgroundManager() @State private var isHovering: Bool = false @State private var hoverWorkItem: DispatchWorkItem? @@ -53,7 +54,7 @@ struct ContentView: View { : cornerRadiusInsets.closed.bottom ) .padding([.horizontal, .bottom], vm.notchState == .open ? 12 : 0) - .background(.black) + .background(backgroundManager.background) .mask { ((vm.notchState == .open) && Defaults[.cornerRadiusScaling]) ? NotchShape( @@ -188,6 +189,7 @@ struct ContentView: View { ) .background(dragDetector) .environmentObject(vm) + preferredColorScheme(.dark) } @ViewBuilder diff --git a/boringNotch/Localizable.xcstrings b/boringNotch/Localizable.xcstrings index c9124027..a0c3721a 100644 --- a/boringNotch/Localizable.xcstrings +++ b/boringNotch/Localizable.xcstrings @@ -3110,6 +3110,9 @@ } } } + }, + "Background" : { + }, "Battery" : { "localizations" : { @@ -20015,4 +20018,4 @@ } }, "version" : "1.0" -} +} \ No newline at end of file diff --git a/boringNotch/components/Settings/SettingsView.swift b/boringNotch/components/Settings/SettingsView.swift index 2546d943..0b65f0b9 100644 --- a/boringNotch/components/Settings/SettingsView.swift +++ b/boringNotch/components/Settings/SettingsView.swift @@ -959,7 +959,11 @@ struct Appearance: View { @State private var name: String = "" @State private var url: String = "" @State private var speed: CGFloat = 1.0 + + var body: some View { + @Default(.background) var background: Background + Form { Section { Toggle("Always show tabs", isOn: $coordinator.alwaysShowTabs) @@ -979,6 +983,19 @@ struct Appearance: View { Text("General") } + Section { + Picker("", selection: $background) { + ForEach(Background.allCases, id: \.self) { option in + + Text(option.rawValue).tag(option) + + } + } + .pickerStyle(.inline) + } header: { + Text("Background") + } + Section { Defaults.Toggle(key: .coloredSpectrogram) { Text("Enable colored spectrograms") diff --git a/boringNotch/enums/generic.swift b/boringNotch/enums/generic.swift index e70b4595..4891e735 100644 --- a/boringNotch/enums/generic.swift +++ b/boringNotch/enums/generic.swift @@ -67,3 +67,9 @@ enum SliderColorEnum: String, CaseIterable, Defaults.Serializable { case albumArt = "Match album art" case accent = "Accent color" } + +enum Background: String, CaseIterable, Defaults.Serializable { + case black = "Black" + case ultraThinMaterial = "Thin Material" + case blur = "Liquid Glass" +} diff --git a/boringNotch/managers/BackgroundManager.swift b/boringNotch/managers/BackgroundManager.swift new file mode 100644 index 00000000..90d4359f --- /dev/null +++ b/boringNotch/managers/BackgroundManager.swift @@ -0,0 +1,43 @@ +// +// BackgroundManager.swift +// boringNotch +// +// Created by Adon Omeri on 4/9/2025. +// + +import Defaults +import SwiftUI + +@MainActor +class BackgroundManager: ObservableObject { + let vm = BoringViewModel() + + var background: some View { + switch Defaults[.background] { + case .black: + return AnyView( + Color.black + ) + + case .ultraThinMaterial: + return AnyView( + Color.clear + .background(.ultraThinMaterial) + ) + + case .blur: + + if #available(macOS 26.0, *) { + return AnyView( + Color.clear + .glassEffect(.clear, in: Rectangle()) + ) + } else { + return AnyView( + Color.clear + ) + } + + } + } +} diff --git a/boringNotch/models/Constants.swift b/boringNotch/models/Constants.swift index 9e060349..7ffb987c 100644 --- a/boringNotch/models/Constants.swift +++ b/boringNotch/models/Constants.swift @@ -84,6 +84,7 @@ extension Defaults.Keys { //static let openLastTabByDefault = Key("openLastTabByDefault", default: false) // MARK: Appearance + static let background = Key("background", default: .black) static let showEmojis = Key("showEmojis", default: false) //static let alwaysShowTabs = Key("alwaysShowTabs", default: true) static let showMirror = Key("showMirror", default: false) From eb50805d4bfbd32db40d3b1e97aed0c7171c2154 Mon Sep 17 00:00:00 2001 From: omeriadon Date: Thu, 4 Sep 2025 20:58:40 +0800 Subject: [PATCH 02/12] Fix crashing bug, remove blur option until later, make BoringBattery not have stroke border for now --- boringNotch/ContentView.swift | 4 +- .../Live activities/BoringBattery.swift | 124 +++++++++++++----- .../components/Notch/BoringHeader.swift | 4 +- .../components/Settings/SettingsView.swift | 2 +- boringNotch/enums/generic.swift | 1 - boringNotch/managers/BackgroundManager.swift | 18 +-- 6 files changed, 100 insertions(+), 53 deletions(-) diff --git a/boringNotch/ContentView.swift b/boringNotch/ContentView.swift index 6cb0fbf2..bac4dabf 100644 --- a/boringNotch/ContentView.swift +++ b/boringNotch/ContentView.swift @@ -20,7 +20,7 @@ struct ContentView: View { @ObservedObject var coordinator = BoringViewCoordinator.shared @ObservedObject var musicManager = MusicManager.shared @ObservedObject var batteryModel = BatteryStatusViewModel.shared - @ObservedObject var backgroundManager = BackgroundManager() + @ObservedObject var backgroundManager = BackgroundManager.shared @State private var isHovering: Bool = false @State private var hoverWorkItem: DispatchWorkItem? @@ -189,7 +189,7 @@ struct ContentView: View { ) .background(dragDetector) .environmentObject(vm) - preferredColorScheme(.dark) + .preferredColorScheme(.dark) } @ViewBuilder diff --git a/boringNotch/components/Live activities/BoringBattery.swift b/boringNotch/components/Live activities/BoringBattery.swift index 5c540b38..dc2b345f 100644 --- a/boringNotch/components/Live activities/BoringBattery.swift +++ b/boringNotch/components/Live activities/BoringBattery.swift @@ -28,6 +28,19 @@ struct BatteryView: View { } } + /// Determines the icon to display when charging. + var iconStatusView: Image { + if isCharging { + return Image(systemName: "bolt") + } + else if isPluggedIn { + return Image(systemName: "powerplug.portrait.fill") + } + else { + return Image(systemName: "") + } + } + /// Determines the color of the battery based on its status. var batteryColor: Color { if isInLowPowerMode { @@ -41,41 +54,88 @@ struct BatteryView: View { } } - var body: some View { - ZStack(alignment: .leading) { +// var body: some View { +// ZStack(alignment: .leading) { +// +// Image(systemName: icon) +// .resizable() +// .fontWeight(.thin) +// .aspectRatio(contentMode: .fit) +// .foregroundColor(.white.opacity(0.5)) +// .frame( +// width: batteryWidth + 1 +// ) +// +// RoundedRectangle(cornerRadius: 2.5) +// .fill(batteryColor) +// .frame( +// width: CGFloat(((CGFloat(CFloat(levelBattery)) / 100) * (batteryWidth - 6))), +// height: (batteryWidth - 2.75) - 18 +// ) +// .padding(.leading, 2) +// +// if iconStatus != "" && (isForNotification || Defaults[.showPowerStatusIcons]) { +// ZStack { +// iconStatusView +// .resizable() +// .aspectRatio(contentMode: .fit) +// .foregroundColor(.white) +// .frame( +// width: 17, +// height: 17 +// ) +// .mask( +// iconStatusView +// .resizable() +// .frame( +// width: 17, +// height: 17 +// ) +// .padding(4) // expands the mask +// .compositingGroup() +// .luminanceToAlpha() +// ) +// .blendMode(.destinationOut) // removes underlying pixels +// +// +// } +// .frame(width: batteryWidth, height: batteryWidth) +// } +// } +// } + var body: some View { + ZStack(alignment: .center) { - Image(systemName: icon) - .resizable() - .fontWeight(.thin) - .aspectRatio(contentMode: .fit) - .foregroundColor(.white.opacity(0.5)) - .frame( - width: batteryWidth + 1 - ) + ZStack(alignment: .leading) { + Image(systemName: icon) + .resizable() + .fontWeight(.thin) + .aspectRatio(contentMode: .fit) + .foregroundColor(.white.opacity(0.5)) + .frame(width: batteryWidth + 1) - RoundedRectangle(cornerRadius: 2.5) - .fill(batteryColor) - .frame( - width: CGFloat(((CGFloat(CFloat(levelBattery)) / 100) * (batteryWidth - 6))), - height: (batteryWidth - 2.75) - 18 - ) - .padding(.leading, 2) - if iconStatus != "" && (isForNotification || Defaults[.showPowerStatusIcons]) { - ZStack { - Image(iconStatus) - .resizable() - .aspectRatio(contentMode: .fit) - .foregroundColor(.white) - .frame( - width: 17, - height: 17 - ) - } - .frame(width: batteryWidth, height: batteryWidth) - } - } - } + RoundedRectangle(cornerRadius: 2.5) + .fill(batteryColor) + .frame( + width: CGFloat((CGFloat(CFloat(levelBattery)) / 100) * (batteryWidth - 6)), + height: (batteryWidth - 2.75) - 18 + ) + .padding(.leading, 2) + + } + if iconStatus != "" && (isForNotification || Defaults[.showPowerStatusIcons]) { + iconStatusView + .resizable() + .aspectRatio(contentMode: .fit) + .foregroundStyle(.white) + .frame(width: 17, height: 17) + + } + + } + } + } /// A view that displays detailed battery information and settings. diff --git a/boringNotch/components/Notch/BoringHeader.swift b/boringNotch/components/Notch/BoringHeader.swift index 74e54564..732aa4ad 100644 --- a/boringNotch/components/Notch/BoringHeader.swift +++ b/boringNotch/components/Notch/BoringHeader.swift @@ -45,7 +45,7 @@ struct BoringHeader: View { vm.toggleCameraPreview() }) { Capsule() - .fill(.black) + .fill(.clear) .frame(width: 30, height: 30) .overlay { Image(systemName: "web.camera") @@ -61,7 +61,7 @@ struct BoringHeader: View { SettingsWindowController.shared.showWindow() }) { Capsule() - .fill(.black) + .fill(.clear) .frame(width: 30, height: 30) .overlay { Image(systemName: "gear") diff --git a/boringNotch/components/Settings/SettingsView.swift b/boringNotch/components/Settings/SettingsView.swift index 0b65f0b9..a4d83cbb 100644 --- a/boringNotch/components/Settings/SettingsView.swift +++ b/boringNotch/components/Settings/SettingsView.swift @@ -951,6 +951,7 @@ struct Appearance: View { @Default(.useMusicVisualizer) var useMusicVisualizer @Default(.customVisualizers) var customVisualizers @Default(.selectedVisualizer) var selectedVisualizer + @Default(.background) var background let icons: [String] = ["logo2"] @State private var selectedIcon: String = "logo2" @State private var selectedListVisualizer: CustomVisualizer? = nil @@ -962,7 +963,6 @@ struct Appearance: View { var body: some View { - @Default(.background) var background: Background Form { Section { diff --git a/boringNotch/enums/generic.swift b/boringNotch/enums/generic.swift index 4891e735..37a6ace4 100644 --- a/boringNotch/enums/generic.swift +++ b/boringNotch/enums/generic.swift @@ -71,5 +71,4 @@ enum SliderColorEnum: String, CaseIterable, Defaults.Serializable { enum Background: String, CaseIterable, Defaults.Serializable { case black = "Black" case ultraThinMaterial = "Thin Material" - case blur = "Liquid Glass" } diff --git a/boringNotch/managers/BackgroundManager.swift b/boringNotch/managers/BackgroundManager.swift index 90d4359f..c6a31e57 100644 --- a/boringNotch/managers/BackgroundManager.swift +++ b/boringNotch/managers/BackgroundManager.swift @@ -10,7 +10,9 @@ import SwiftUI @MainActor class BackgroundManager: ObservableObject { - let vm = BoringViewModel() + static let shared = BackgroundManager() + + private init() {} var background: some View { switch Defaults[.background] { @@ -24,20 +26,6 @@ class BackgroundManager: ObservableObject { Color.clear .background(.ultraThinMaterial) ) - - case .blur: - - if #available(macOS 26.0, *) { - return AnyView( - Color.clear - .glassEffect(.clear, in: Rectangle()) - ) - } else { - return AnyView( - Color.clear - ) - } - } } } From 846c343e843bfbb77f3fac5e472b6bcd6dc05620 Mon Sep 17 00:00:00 2001 From: omeriadon Date: Thu, 4 Sep 2025 21:06:00 +0800 Subject: [PATCH 03/12] Fix Calendar fading to black instead of clear --- .../components/Calendar/BoringCalendar.swift | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/boringNotch/components/Calendar/BoringCalendar.swift b/boringNotch/components/Calendar/BoringCalendar.swift index 8c5f6441..946e423a 100644 --- a/boringNotch/components/Calendar/BoringCalendar.swift +++ b/boringNotch/components/Calendar/BoringCalendar.swift @@ -199,17 +199,26 @@ struct CalendarView: View { ZStack(alignment: .top) { WheelPicker(selectedDate: $selectedDate, config: Config()) - HStack(alignment: .top) { - LinearGradient( - colors: [Color.black, .clear], startPoint: .leading, endPoint: .trailing - ) - .frame(width: 20) - Spacer() - LinearGradient( - colors: [.clear, Color.black], startPoint: .leading, endPoint: .trailing - ) - .frame(width: 20) - } + .mask( + HStack(spacing: 0) { + + LinearGradient(gradient: + Gradient( + colors: [Color.black.opacity(0), Color.black]), + startPoint: .leading, endPoint: .trailing + ) + .frame(width: 30) + + Rectangle().fill(Color.black) + + LinearGradient(gradient: + Gradient( + colors: [Color.black, Color.black.opacity(0)]), + startPoint: .leading, endPoint: .trailing + ) + .frame(width: 30) + } + ) } } From df1306062e4108e941ebff69c81b22e0ea8aff88 Mon Sep 17 00:00:00 2001 From: omeriadon Date: Fri, 5 Sep 2025 16:14:27 +0800 Subject: [PATCH 04/12] Changed BoringViewModel to use shared instance --- boringNotch/boringNotchApp.swift | 5 +- .../components/Calendar/BoringCalendar.swift | 2 +- .../Live activities/InlineHUD.swift | 2 +- .../components/Notch/BoringExtrasMenu.swift | 2 +- .../components/Notch/BoringHeader.swift | 2 +- .../components/Tabs/TabSelectionView.swift | 2 +- boringNotch/models/BoringViewModel.swift | 388 +++++++++--------- 7 files changed, 205 insertions(+), 198 deletions(-) diff --git a/boringNotch/boringNotchApp.swift b/boringNotch/boringNotchApp.swift index bee49b9d..327999ac 100644 --- a/boringNotch/boringNotchApp.swift +++ b/boringNotch/boringNotchApp.swift @@ -65,7 +65,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { var windows: [NSScreen: NSWindow] = [:] var viewModels: [NSScreen: BoringViewModel] = [:] var window: NSWindow? - let vm: BoringViewModel = .init() + let vm = BoringViewModel.shared @ObservedObject var coordinator = BoringViewCoordinator.shared var whatsNewWindow: NSWindow? var timer: Timer? @@ -326,7 +326,8 @@ class AppDelegate: NSObject, NSApplicationDelegate { for screen in currentScreens { if windows[screen] == nil { - let viewModel = BoringViewModel(screen: screen.localizedName) + let viewModel = BoringViewModel.shared + viewModel.screen = screen.localizedName let window = createBoringNotchWindow(for: screen, with: viewModel) windows[screen] = window diff --git a/boringNotch/components/Calendar/BoringCalendar.swift b/boringNotch/components/Calendar/BoringCalendar.swift index 946e423a..d7b22f7c 100644 --- a/boringNotch/components/Calendar/BoringCalendar.swift +++ b/boringNotch/components/Calendar/BoringCalendar.swift @@ -442,5 +442,5 @@ struct ReminderToggle: View { CalendarView() .frame(width: 215, height: 130) .background(.black) - .environmentObject(BoringViewModel()) + .environmentObject(BoringViewModel.shared) } diff --git a/boringNotch/components/Live activities/InlineHUD.swift b/boringNotch/components/Live activities/InlineHUD.swift index 19f92004..db236c3f 100644 --- a/boringNotch/components/Live activities/InlineHUD.swift +++ b/boringNotch/components/Live activities/InlineHUD.swift @@ -143,5 +143,5 @@ struct InlineHUD: View { .padding(.horizontal, 8) .background(Color.black) .padding() - .environmentObject(BoringViewModel()) + .environmentObject(BoringViewModel.shared) } diff --git a/boringNotch/components/Notch/BoringExtrasMenu.swift b/boringNotch/components/Notch/BoringExtrasMenu.swift index 63d12ed8..69b3348a 100644 --- a/boringNotch/components/Notch/BoringExtrasMenu.swift +++ b/boringNotch/components/Notch/BoringExtrasMenu.swift @@ -105,5 +105,5 @@ struct BoringExtrasMenu : View { #Preview { - BoringExtrasMenu(vm: .init()) + BoringExtrasMenu(vm: BoringViewModel.shared) } diff --git a/boringNotch/components/Notch/BoringHeader.swift b/boringNotch/components/Notch/BoringHeader.swift index 732aa4ad..a83213db 100644 --- a/boringNotch/components/Notch/BoringHeader.swift +++ b/boringNotch/components/Notch/BoringHeader.swift @@ -99,5 +99,5 @@ struct BoringHeader: View { } #Preview { - BoringHeader().environmentObject(BoringViewModel()) + BoringHeader().environmentObject(BoringViewModel.shared) } diff --git a/boringNotch/components/Tabs/TabSelectionView.swift b/boringNotch/components/Tabs/TabSelectionView.swift index b99d4af1..81cb7f0b 100644 --- a/boringNotch/components/Tabs/TabSelectionView.swift +++ b/boringNotch/components/Tabs/TabSelectionView.swift @@ -51,5 +51,5 @@ struct TabSelectionView: View { } #Preview { - BoringHeader().environmentObject(BoringViewModel()) + BoringHeader().environmentObject(BoringViewModel.shared) } diff --git a/boringNotch/models/BoringViewModel.swift b/boringNotch/models/BoringViewModel.swift index fed06bf7..da325653 100644 --- a/boringNotch/models/BoringViewModel.swift +++ b/boringNotch/models/BoringViewModel.swift @@ -11,195 +11,201 @@ import SwiftUI import TheBoringWorkerNotifier class BoringViewModel: NSObject, ObservableObject { - @ObservedObject var coordinator = BoringViewCoordinator.shared - @ObservedObject var detector = FullscreenMediaDetector.shared - - let animationLibrary: BoringAnimations = .init() - let animation: Animation? - - @Published var contentType: ContentType = .normal - @Published private(set) var notchState: NotchState = .closed - - @Published var dragDetectorTargeting: Bool = false - @Published var dropZoneTargeting: Bool = false - @Published var dropEvent: Bool = false - @Published var anyDropZoneTargeting: Bool = false - var cancellables: Set = [] - - @Published var hideOnClosed: Bool = true - @Published var isHoveringCalendar: Bool = false - @Published var isBatteryPopoverActive: Bool = false - - @Published var screen: String? - - @Published var notchSize: CGSize = getClosedNotchSize() - @Published var closedNotchSize: CGSize = getClosedNotchSize() - - let webcamManager = WebcamManager.shared - @Published var isCameraExpanded: Bool = false - @Published var isRequestingAuthorization: Bool = false - - deinit { - destroy() - } - - func destroy() { - cancellables.forEach { $0.cancel() } - cancellables.removeAll() - } - - init(screen: String? = nil) { - animation = animationLibrary.animation - - super.init() - - self.screen = screen - notchSize = getClosedNotchSize(screen: screen) - closedNotchSize = notchSize - - Publishers.CombineLatest($dropZoneTargeting, $dragDetectorTargeting) - .map { value1, value2 in - value1 || value2 - } - .assign(to: \.anyDropZoneTargeting, on: self) - .store(in: &cancellables) - - setupDetectorObserver() - } - - private func setupDetectorObserver() { - // Publisher for the user’s fullscreen detection setting - let enabledPublisher = Defaults - .publisher(.enableFullscreenMediaDetection) - .map(\.newValue) - .removeDuplicates() - - // Publisher for the current screen name (non-nil, distinct) - let screenPublisher = $screen - .compactMap { $0 } - .removeDuplicates() - - // Publisher for fullscreen status dictionary - let fullscreenStatusPublisher = detector.$fullscreenStatus - .removeDuplicates() - - // Combine all three: screen name, fullscreen status, and enabled setting - Publishers.CombineLatest3(screenPublisher, fullscreenStatusPublisher, enabledPublisher) - .map { screenName, fullscreenStatus, enabled in - let isFullscreen = fullscreenStatus[screenName] ?? false - return enabled && isFullscreen - } - .removeDuplicates() - .receive(on: RunLoop.main) - .sink { [weak self] shouldHide in - withAnimation(.smooth) { - self?.hideOnClosed = shouldHide - } - } - .store(in: &cancellables) - } - - // Computed property for effective notch height - var effectiveClosedNotchHeight: CGFloat { - let currentScreen = NSScreen.screens.first { $0.localizedName == screen } - let noNotchAndFullscreen = hideOnClosed && (currentScreen?.safeAreaInsets.top ?? 0 <= 0 || currentScreen == nil) - return noNotchAndFullscreen ? 0 : closedNotchSize.height - } - - func toggleCameraPreview() { - if isRequestingAuthorization { - return - } - - switch webcamManager.authorizationStatus { - case .authorized: - if webcamManager.isSessionRunning { - webcamManager.stopSession() - isCameraExpanded = false - } else if webcamManager.cameraAvailable { - webcamManager.startSession() - isCameraExpanded = true - } - - case .denied, .restricted: - DispatchQueue.main.async { - NSApp.setActivationPolicy(.regular) - NSApp.activate(ignoringOtherApps: true) - - let alert = NSAlert() - alert.messageText = "Camera Access Required" - alert.informativeText = "Please allow camera access in System Settings." - alert.addButton(withTitle: "Open Settings") - alert.addButton(withTitle: "Cancel") - - if alert.runModal() == .alertFirstButtonReturn { - if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Camera") { - NSWorkspace.shared.open(url) - } - } - - NSApp.setActivationPolicy(.accessory) - NSApp.deactivate() - } - - case .notDetermined: - isRequestingAuthorization = true - webcamManager.checkAndRequestVideoAuthorization() - DispatchQueue.main.asyncAfter(deadline: .now() + 2) { - self.isRequestingAuthorization = false - } - - default: - break - } - } - - func isMouseHovering(position: NSPoint = NSEvent.mouseLocation) -> Bool { - let screenFrame = getScreenFrame(screen) - if let frame = screenFrame { - - let baseY = frame.maxY - notchSize.height - let baseX = frame.midX - notchSize.width / 2 - - return position.y >= baseY && position.x >= baseX && position.x <= baseX + notchSize.width - } - - return false - } - - func open() { - withAnimation(.bouncy) { - self.notchSize = openNotchSize - self.notchState = .open - } - - // Force music information update when notch is opened - MusicManager.shared.forceUpdate() - } - - func close() { - withAnimation(.smooth) { [weak self] in - guard let self = self else { return } - self.notchSize = getClosedNotchSize(screen: self.screen) - self.closedNotchSize = self.notchSize - self.notchState = .closed - } - - // Set the current view to shelf if it contains files and the user enables openShelfByDefault - // Otherwise, if the user has not enabled openLastShelfByDefault, set the view to home - if !TrayDrop.shared.isEmpty && Defaults[.openShelfByDefault] { - coordinator.currentView = .shelf - } else if !coordinator.openLastTabByDefault { - coordinator.currentView = .home - } - } - - func closeHello() { - DispatchQueue.main.asyncAfter(deadline: .now() + 3.5) { [weak self] in - self?.coordinator.firstLaunch = false - withAnimation(self?.animationLibrary.animation) { - self?.close() - } - } - } + static let shared = BoringViewModel() // Singleton instance + + var coordinator = BoringViewCoordinator.shared + var detector = FullscreenMediaDetector.shared + + let animationLibrary: BoringAnimations = .init() + let animation: Animation? + + @Published var contentType: ContentType = .normal + @Published private(set) var notchState: NotchState = .closed + + @Published var dragDetectorTargeting: Bool = false + @Published var dropZoneTargeting: Bool = false + @Published var dropEvent: Bool = false + @Published var anyDropZoneTargeting: Bool = false + var cancellables: Set = [] + + @Published var hideOnClosed: Bool = true + @Published var isHoveringCalendar: Bool = false + @Published var isBatteryPopoverActive: Bool = false + + @Published var screen: String? + + @Published var notchSize: CGSize = getClosedNotchSize() + @Published var closedNotchSize: CGSize = getClosedNotchSize() + + let webcamManager = WebcamManager.shared + @Published var isCameraExpanded: Bool = false + @Published var isRequestingAuthorization: Bool = false + + @Published var keepUpdating: Bool = false + private var updateCancellable: AnyCancellable? + + func startContinuousUpdate() { + updateCancellable = Timer.publish(every: 0.01, on: .main, in: .common) + .autoconnect() + .sink { [weak self] _ in + guard let self = self, self.keepUpdating else { return } + // Place the code to update your variable here, e.g.: + self.screen = NSScreen.screens.first?.localizedName + } + } + + func stopContinuousUpdate() { + updateCancellable?.cancel() + updateCancellable = nil + } + + private override init() { + animation = animationLibrary.animation + super.init() + + notchSize = getClosedNotchSize(screen: screen) + closedNotchSize = notchSize + + setupCombine() + setupDetectorObserver() + } + + deinit { + destroy() + } + + func destroy() { + cancellables.forEach { $0.cancel() } + cancellables.removeAll() + } + + private func setupCombine() { + Publishers.CombineLatest($dropZoneTargeting, $dragDetectorTargeting) + .map { $0 || $1 } + .assign(to: \.anyDropZoneTargeting, on: self) + .store(in: &cancellables) + } + + private func setupDetectorObserver() { + let enabledPublisher = Defaults + .publisher(.enableFullscreenMediaDetection) + .map(\.newValue) + .removeDuplicates() + + let screenPublisher = $screen + .compactMap { $0 } + .removeDuplicates() + + let fullscreenStatusPublisher = detector.$fullscreenStatus + .removeDuplicates() + + Publishers.CombineLatest3(screenPublisher, fullscreenStatusPublisher, enabledPublisher) + .map { screenName, fullscreenStatus, enabled in + let isFullscreen = fullscreenStatus[screenName] ?? false + return enabled && isFullscreen + } + .removeDuplicates() + .receive(on: RunLoop.main) + .sink { [weak self] shouldHide in + withAnimation(.smooth) { + self?.hideOnClosed = shouldHide + } + } + .store(in: &cancellables) + } + + var effectiveClosedNotchHeight: CGFloat { + let currentScreen = NSScreen.screens.first { $0.localizedName == screen } + let noNotchAndFullscreen = hideOnClosed && (currentScreen?.safeAreaInsets.top ?? 0 <= 0 || currentScreen == nil) + return noNotchAndFullscreen ? 0 : closedNotchSize.height + } + + func toggleCameraPreview() { + if isRequestingAuthorization { return } + + switch webcamManager.authorizationStatus { + case .authorized: + if webcamManager.isSessionRunning { + webcamManager.stopSession() + isCameraExpanded = false + } else if webcamManager.cameraAvailable { + webcamManager.startSession() + isCameraExpanded = true + } + + case .denied, .restricted: + DispatchQueue.main.async { + NSApp.setActivationPolicy(.regular) + NSApp.activate(ignoringOtherApps: true) + + let alert = NSAlert() + alert.messageText = "Camera Access Required" + alert.informativeText = "Please allow camera access in System Settings." + alert.addButton(withTitle: "Open Settings") + alert.addButton(withTitle: "Cancel") + + if alert.runModal() == .alertFirstButtonReturn, + let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Camera") { + NSWorkspace.shared.open(url) + } + + NSApp.setActivationPolicy(.accessory) + NSApp.deactivate() + } + + case .notDetermined: + isRequestingAuthorization = true + webcamManager.checkAndRequestVideoAuthorization() + DispatchQueue.main.asyncAfter(deadline: .now() + 2) { + self.isRequestingAuthorization = false + } + + default: + break + } + } + + func isMouseHovering(position: NSPoint = NSEvent.mouseLocation) -> Bool { + guard let frame = getScreenFrame(screen) else { return false } + + let baseY = frame.maxY - notchSize.height + let baseX = frame.midX - notchSize.width / 2 + + return position.y >= baseY && position.x >= baseX && position.x <= baseX + notchSize.width + } + + func open() { + withAnimation(.bouncy) { + self.notchSize = openNotchSize + self.notchState = .open + } + + MusicManager.shared.forceUpdate() + } + + func close() { + withAnimation(.smooth) { + self.notchSize = getClosedNotchSize(screen: self.screen) + self.closedNotchSize = self.notchSize + self.notchState = .closed + } + + if !TrayDrop.shared.isEmpty && Defaults[.openShelfByDefault] { + coordinator.currentView = .shelf + } else if !coordinator.openLastTabByDefault { + coordinator.currentView = .home + } + } + + func closeHello() { + DispatchQueue.main.asyncAfter(deadline: .now() + 3.5) { [weak self] in + guard let self = self else { return } + self.coordinator.firstLaunch = false + withAnimation(self.animationLibrary.animation) { + self.close() + } + } + } } + + From 4dec9dcdeef38deda410802d01b3b9d6911a911f Mon Sep 17 00:00:00 2001 From: omeriadon Date: Fri, 5 Sep 2025 16:24:32 +0800 Subject: [PATCH 05/12] cleanup --- boringNotch/ContentView.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/boringNotch/ContentView.swift b/boringNotch/ContentView.swift index bac4dabf..a930f0d1 100644 --- a/boringNotch/ContentView.swift +++ b/boringNotch/ContentView.swift @@ -207,12 +207,10 @@ struct ContentView: View { if coordinator.expandingView.type == .battery && coordinator.expandingView.show && vm.notchState == .closed && Defaults[.showPowerStatusNotifications] { - HStack(spacing: 0) { - HStack { Text(batteryModel.statusText) .font(.subheadline) .foregroundStyle(.white) - } + HStack(spacing: 0) { Rectangle() .fill(.black) From aa1dd4c81e3abbf2394481229a292f10dc687949 Mon Sep 17 00:00:00 2001 From: omeriadon Date: Fri, 5 Sep 2025 17:20:26 +0800 Subject: [PATCH 06/12] update settings and background system --- .../wallpaper.imageset/Contents.json | 21 + .../wallpaper.imageset/SCR-20250905-lpmt.jpeg | Bin 0 -> 121499 bytes boringNotch/ContentView.swift | 2 +- boringNotch/Localizable.xcstrings | 6 + .../components/Settings/SettingsView.swift | 2347 +++++++++-------- boringNotch/managers/BackgroundManager.swift | 28 +- boringNotch/models/Constants.swift | 2 +- 7 files changed, 1224 insertions(+), 1182 deletions(-) create mode 100644 boringNotch/Assets.xcassets/wallpaper.imageset/Contents.json create mode 100644 boringNotch/Assets.xcassets/wallpaper.imageset/SCR-20250905-lpmt.jpeg diff --git a/boringNotch/Assets.xcassets/wallpaper.imageset/Contents.json b/boringNotch/Assets.xcassets/wallpaper.imageset/Contents.json new file mode 100644 index 00000000..1ebc2713 --- /dev/null +++ b/boringNotch/Assets.xcassets/wallpaper.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "SCR-20250905-lpmt.jpeg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/boringNotch/Assets.xcassets/wallpaper.imageset/SCR-20250905-lpmt.jpeg b/boringNotch/Assets.xcassets/wallpaper.imageset/SCR-20250905-lpmt.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..37f5ea79888ff1a819f2e7e39b587032e5501c9a GIT binary patch literal 121499 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 z≧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 literal 0 HcmV?d00001 diff --git a/boringNotch/ContentView.swift b/boringNotch/ContentView.swift index a930f0d1..f53bf80b 100644 --- a/boringNotch/ContentView.swift +++ b/boringNotch/ContentView.swift @@ -580,7 +580,7 @@ struct FullScreenDropDelegate: DropDelegate { } #Preview { - let vm = BoringViewModel() + let vm = BoringViewModel.shared vm.open() return ContentView() .environmentObject(vm) diff --git a/boringNotch/Localizable.xcstrings b/boringNotch/Localizable.xcstrings index a0c3721a..ac2e0787 100644 --- a/boringNotch/Localizable.xcstrings +++ b/boringNotch/Localizable.xcstrings @@ -3513,6 +3513,9 @@ } } } + }, + "Black" : { + }, "Boost your productivity with Clipboard Manager" : { "localizations" : { @@ -18415,6 +18418,9 @@ } } } + }, + "Translucent" : { + }, "Two-finger swipe up on notch to close, two-finger swipe down on notch to open when **Open notch on hover** option is disabled" : { "localizations" : { diff --git a/boringNotch/components/Settings/SettingsView.swift b/boringNotch/components/Settings/SettingsView.swift index a4d83cbb..1b231ddd 100644 --- a/boringNotch/components/Settings/SettingsView.swift +++ b/boringNotch/components/Settings/SettingsView.swift @@ -1,9 +1,9 @@ -// -// SettingsView.swift -// boringNotch -// -// Created by Richard Kunkli on 07/08/2024. -// + // + // SettingsView.swift + // boringNotch + // + // Created by Richard Kunkli on 07/08/2024. + // import AVFoundation import Defaults @@ -16,352 +16,353 @@ import SwiftUI import SwiftUIIntrospect struct SettingsView: View { - @StateObject var extensionManager = BoringExtensionManager() - @State private var selectedTab = "General" + @StateObject var extensionManager = BoringExtensionManager() + @State private var selectedTab = "General" - let updaterController: SPUStandardUpdaterController? + let updaterController: SPUStandardUpdaterController? - init(updaterController: SPUStandardUpdaterController? = nil) { - self.updaterController = updaterController - } + init(updaterController: SPUStandardUpdaterController? = nil) { + self.updaterController = updaterController + } - var body: some View { - NavigationSplitView { - List(selection: $selectedTab) { - NavigationLink(value: "General") { - Label("General", systemImage: "gear") - } - NavigationLink(value: "Appearance") { - Label("Appearance", systemImage: "eye") - } - NavigationLink(value: "Media") { - Label("Media", systemImage: "play.laptopcomputer") - } - NavigationLink(value: "Calendar") { - Label("Calendar", systemImage: "calendar") - } - if extensionManager.installedExtensions - .contains(where: { $0.bundleIdentifier == hudExtension }) - { - NavigationLink(value: "HUD") { - Label("HUDs", systemImage: "dial.medium.fill") - } - } - NavigationLink(value: "Battery") { - Label("Battery", systemImage: "battery.100.bolt") - } - if extensionManager.installedExtensions - .contains(where: { $0.bundleIdentifier == downloadManagerExtension }) - { - NavigationLink(value: "Downloads") { - Label("Downloads", systemImage: "square.and.arrow.down") - } - } - NavigationLink(value: "Shelf") { - Label("Shelf", systemImage: "books.vertical") - } - NavigationLink(value: "Shortcuts") { - Label("Shortcuts", systemImage: "keyboard") - } - NavigationLink(value: "Extensions") { - Label("Extensions", systemImage: "puzzlepiece.extension") - } - NavigationLink(value: "About") { - Label("About", systemImage: "info.circle") - } - } - .listStyle(SidebarListStyle()) - .toolbar(removing: .sidebarToggle) - .navigationSplitViewColumnWidth(200) - } detail: { - Group { - switch selectedTab { - case "General": - GeneralSettings() - case "Appearance": - Appearance() - case "Media": - Media() - case "Calendar": - CalendarSettings() - case "HUD": - HUD() - case "Battery": - Charge() - case "Shelf": - Shelf() - case "Shortcuts": - Shortcuts() - case "Extensions": - Extensions() - case "About": - if let controller = updaterController { - About(updaterController: controller) - } else { - // Fallback with a default controller - About( - updaterController: SPUStandardUpdaterController( - startingUpdater: false, updaterDelegate: nil, - userDriverDelegate: nil)) - } - default: - GeneralSettings() - } - } - .frame(maxWidth: .infinity, maxHeight: .infinity) - } - .navigationSplitViewStyle(.balanced) - .toolbar(removing: .sidebarToggle) - .toolbar { - Button("") {} // Empty label, does nothing - .controlSize(.extraLarge) - .opacity(0) // Invisible, but reserves space for a consistent look between tabs - .disabled(true) - } - .environmentObject(extensionManager) - .formStyle(.grouped) - .frame(width: 700) - .background(Color(NSColor.windowBackgroundColor)) - } + var body: some View { + NavigationSplitView { + List(selection: $selectedTab) { + NavigationLink(value: "General") { + Label("General", systemImage: "gear") + } + NavigationLink(value: "Appearance") { + Label("Appearance", systemImage: "eye") + } + NavigationLink(value: "Media") { + Label("Media", systemImage: "play.laptopcomputer") + } + NavigationLink(value: "Calendar") { + Label("Calendar", systemImage: "calendar") + } + if extensionManager.installedExtensions + .contains(where: { $0.bundleIdentifier == hudExtension }) + { + NavigationLink(value: "HUD") { + Label("HUDs", systemImage: "dial.medium.fill") + } + } + NavigationLink(value: "Battery") { + Label("Battery", systemImage: "battery.100.bolt") + } + if extensionManager.installedExtensions + .contains(where: { $0.bundleIdentifier == downloadManagerExtension }) + { + NavigationLink(value: "Downloads") { + Label("Downloads", systemImage: "square.and.arrow.down") + } + } + NavigationLink(value: "Shelf") { + Label("Shelf", systemImage: "books.vertical") + } + NavigationLink(value: "Shortcuts") { + Label("Shortcuts", systemImage: "keyboard") + } + NavigationLink(value: "Extensions") { + Label("Extensions", systemImage: "puzzlepiece.extension") + } + NavigationLink(value: "About") { + Label("About", systemImage: "info.circle") + } + } + .listStyle(SidebarListStyle()) + .toolbar(removing: .sidebarToggle) + .navigationSplitViewColumnWidth(200) + } detail: { + Group { + switch selectedTab { + case "General": + GeneralSettings() + case "Appearance": + Appearance() + .environmentObject(BoringViewModel.shared) + case "Media": + Media() + case "Calendar": + CalendarSettings() + case "HUD": + HUD() + case "Battery": + Charge() + case "Shelf": + Shelf() + case "Shortcuts": + Shortcuts() + case "Extensions": + Extensions() + case "About": + if let controller = updaterController { + About(updaterController: controller) + } else { + // Fallback with a default controller + About( + updaterController: SPUStandardUpdaterController( + startingUpdater: false, updaterDelegate: nil, + userDriverDelegate: nil)) + } + default: + GeneralSettings() + } + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + } + .navigationSplitViewStyle(.balanced) + .toolbar(removing: .sidebarToggle) + .toolbar { + Button("") {} // Empty label, does nothing + .controlSize(.extraLarge) + .opacity(0) // Invisible, but reserves space for a consistent look between tabs + .disabled(true) + } + .environmentObject(extensionManager) + .formStyle(.grouped) + .frame(width: 700) + .background(Color(NSColor.windowBackgroundColor)) + } } struct GeneralSettings: View { - @State private var screens: [String] = NSScreen.screens.compactMap { $0.localizedName } - @EnvironmentObject var vm: BoringViewModel - @ObservedObject var coordinator = BoringViewCoordinator.shared + @State private var screens: [String] = NSScreen.screens.compactMap { $0.localizedName } + @EnvironmentObject var vm: BoringViewModel + @ObservedObject var coordinator = BoringViewCoordinator.shared - @Default(.mirrorShape) var mirrorShape - @Default(.showEmojis) var showEmojis - @Default(.gestureSensitivity) var gestureSensitivity - @Default(.minimumHoverDuration) var minimumHoverDuration - @Default(.nonNotchHeight) var nonNotchHeight - @Default(.nonNotchHeightMode) var nonNotchHeightMode - @Default(.notchHeight) var notchHeight - @Default(.notchHeightMode) var notchHeightMode - @Default(.showOnAllDisplays) var showOnAllDisplays - @Default(.automaticallySwitchDisplay) var automaticallySwitchDisplay - @Default(.enableGestures) var enableGestures - @Default(.openNotchOnHover) var openNotchOnHover + @Default(.mirrorShape) var mirrorShape + @Default(.showEmojis) var showEmojis + @Default(.gestureSensitivity) var gestureSensitivity + @Default(.minimumHoverDuration) var minimumHoverDuration + @Default(.nonNotchHeight) var nonNotchHeight + @Default(.nonNotchHeightMode) var nonNotchHeightMode + @Default(.notchHeight) var notchHeight + @Default(.notchHeightMode) var notchHeightMode + @Default(.showOnAllDisplays) var showOnAllDisplays + @Default(.automaticallySwitchDisplay) var automaticallySwitchDisplay + @Default(.enableGestures) var enableGestures + @Default(.openNotchOnHover) var openNotchOnHover - var body: some View { - Form { - Section { - Defaults.Toggle(key: .menubarIcon) { - Text("Menubar icon") - } - LaunchAtLogin.Toggle("Launch at login") - Defaults.Toggle(key: .showOnAllDisplays) { - Text("Show on all displays") - } - .onChange(of: showOnAllDisplays) { - NotificationCenter.default.post( - name: Notification.Name.showOnAllDisplaysChanged, object: nil) - } - Picker("Show on a specific display", selection: $coordinator.preferredScreen) { - ForEach(screens, id: \.self) { screen in - Text(screen) - } - } - .onChange(of: NSScreen.screens) { - screens = NSScreen.screens.compactMap({ $0.localizedName }) - } - .disabled(showOnAllDisplays) - Defaults.Toggle(key: .automaticallySwitchDisplay) { - Text("Automatically switch displays") - } - .onChange(of: automaticallySwitchDisplay) { - NotificationCenter.default.post( - name: Notification.Name.automaticallySwitchDisplayChanged, object: nil) - } - .disabled(showOnAllDisplays) - } header: { - Text("System features") - } + var body: some View { + Form { + Section { + Defaults.Toggle(key: .menubarIcon) { + Text("Menubar icon") + } + LaunchAtLogin.Toggle("Launch at login") + Defaults.Toggle(key: .showOnAllDisplays) { + Text("Show on all displays") + } + .onChange(of: showOnAllDisplays) { + NotificationCenter.default.post( + name: Notification.Name.showOnAllDisplaysChanged, object: nil) + } + Picker("Show on a specific display", selection: $coordinator.preferredScreen) { + ForEach(screens, id: \.self) { screen in + Text(screen) + } + } + .onChange(of: NSScreen.screens) { + screens = NSScreen.screens.compactMap({ $0.localizedName }) + } + .disabled(showOnAllDisplays) + Defaults.Toggle(key: .automaticallySwitchDisplay) { + Text("Automatically switch displays") + } + .onChange(of: automaticallySwitchDisplay) { + NotificationCenter.default.post( + name: Notification.Name.automaticallySwitchDisplayChanged, object: nil) + } + .disabled(showOnAllDisplays) + } header: { + Text("System features") + } - Section { - Picker( - selection: $notchHeightMode, - label: - Text("Notch display height") - ) { - Text("Match real notch size") - .tag(WindowHeightMode.matchRealNotchSize) - Text("Match menubar height") - .tag(WindowHeightMode.matchMenuBar) - Text("Custom height") - .tag(WindowHeightMode.custom) - } - .onChange(of: notchHeightMode) { - switch notchHeightMode { - case .matchRealNotchSize: - notchHeight = 38 - case .matchMenuBar: - notchHeight = 44 - case .custom: - notchHeight = 38 - } - NotificationCenter.default.post( - name: Notification.Name.notchHeightChanged, object: nil) - } - if notchHeightMode == .custom { - Slider(value: $notchHeight, in: 15...45, step: 1) { - Text("Custom notch size - \(notchHeight, specifier: "%.0f")") - } - .onChange(of: notchHeight) { - NotificationCenter.default.post( - name: Notification.Name.notchHeightChanged, object: nil) - } - } - Picker("Non-notch display height", selection: $nonNotchHeightMode) { - Text("Match menubar height") - .tag(WindowHeightMode.matchMenuBar) - Text("Match real notch size") - .tag(WindowHeightMode.matchRealNotchSize) - Text("Custom height") - .tag(WindowHeightMode.custom) - } - .onChange(of: nonNotchHeightMode) { - switch nonNotchHeightMode { - case .matchMenuBar: - nonNotchHeight = 24 - case .matchRealNotchSize: - nonNotchHeight = 32 - case .custom: - nonNotchHeight = 32 - } - NotificationCenter.default.post( - name: Notification.Name.notchHeightChanged, object: nil) - } - if nonNotchHeightMode == .custom { - Slider(value: $nonNotchHeight, in: 0...40, step: 1) { - Text("Custom notch size - \(nonNotchHeight, specifier: "%.0f")") - } - .onChange(of: nonNotchHeight) { - NotificationCenter.default.post( - name: Notification.Name.notchHeightChanged, object: nil) - } - } - } header: { - Text("Notch Height") - } + Section { + Picker( + selection: $notchHeightMode, + label: + Text("Notch display height") + ) { + Text("Match real notch size") + .tag(WindowHeightMode.matchRealNotchSize) + Text("Match menubar height") + .tag(WindowHeightMode.matchMenuBar) + Text("Custom height") + .tag(WindowHeightMode.custom) + } + .onChange(of: notchHeightMode) { + switch notchHeightMode { + case .matchRealNotchSize: + notchHeight = 38 + case .matchMenuBar: + notchHeight = 44 + case .custom: + notchHeight = 38 + } + NotificationCenter.default.post( + name: Notification.Name.notchHeightChanged, object: nil) + } + if notchHeightMode == .custom { + Slider(value: $notchHeight, in: 15...45, step: 1) { + Text("Custom notch size - \(notchHeight, specifier: "%.0f")") + } + .onChange(of: notchHeight) { + NotificationCenter.default.post( + name: Notification.Name.notchHeightChanged, object: nil) + } + } + Picker("Non-notch display height", selection: $nonNotchHeightMode) { + Text("Match menubar height") + .tag(WindowHeightMode.matchMenuBar) + Text("Match real notch size") + .tag(WindowHeightMode.matchRealNotchSize) + Text("Custom height") + .tag(WindowHeightMode.custom) + } + .onChange(of: nonNotchHeightMode) { + switch nonNotchHeightMode { + case .matchMenuBar: + nonNotchHeight = 24 + case .matchRealNotchSize: + nonNotchHeight = 32 + case .custom: + nonNotchHeight = 32 + } + NotificationCenter.default.post( + name: Notification.Name.notchHeightChanged, object: nil) + } + if nonNotchHeightMode == .custom { + Slider(value: $nonNotchHeight, in: 0...40, step: 1) { + Text("Custom notch size - \(nonNotchHeight, specifier: "%.0f")") + } + .onChange(of: nonNotchHeight) { + NotificationCenter.default.post( + name: Notification.Name.notchHeightChanged, object: nil) + } + } + } header: { + Text("Notch Height") + } - NotchBehaviour() + NotchBehaviour() - gestureControls() - } - .toolbar { - Button("Quit app") { - NSApp.terminate(self) - } - .controlSize(.extraLarge) - } - .navigationTitle("General") - .onChange(of: openNotchOnHover) { - if !openNotchOnHover { - enableGestures = true - } - } - } + gestureControls() + } + .toolbar { + Button("Quit app") { + NSApp.terminate(self) + } + .controlSize(.extraLarge) + } + .navigationTitle("General") + .onChange(of: openNotchOnHover) { + if !openNotchOnHover { + enableGestures = true + } + } + } - @ViewBuilder - func gestureControls() -> some View { - Section { - Defaults.Toggle(key: .enableGestures) { - Text("Enable gestures") - } - .disabled(!openNotchOnHover) - if enableGestures { - Toggle("Media change with horizontal gestures", isOn: .constant(false)) - .disabled(true) - Defaults.Toggle(key: .closeGestureEnabled) { - Text("Close gesture") - } - Slider(value: $gestureSensitivity, in: 100...300, step: 100) { - HStack { - Text("Gesture sensitivity") - Spacer() - Text( - Defaults[.gestureSensitivity] == 100 - ? "High" : Defaults[.gestureSensitivity] == 200 ? "Medium" : "Low" - ) - .foregroundStyle(.secondary) - } - } - } - } header: { - HStack { - Text("Gesture control") - customBadge(text: "Beta") - } - } footer: { - Text( - "Two-finger swipe up on notch to close, two-finger swipe down on notch to open when **Open notch on hover** option is disabled" - ) - .multilineTextAlignment(.trailing) - .foregroundStyle(.secondary) - .font(.caption) - } - } + @ViewBuilder + func gestureControls() -> some View { + Section { + Defaults.Toggle(key: .enableGestures) { + Text("Enable gestures") + } + .disabled(!openNotchOnHover) + if enableGestures { + Toggle("Media change with horizontal gestures", isOn: .constant(false)) + .disabled(true) + Defaults.Toggle(key: .closeGestureEnabled) { + Text("Close gesture") + } + Slider(value: $gestureSensitivity, in: 100...300, step: 100) { + HStack { + Text("Gesture sensitivity") + Spacer() + Text( + Defaults[.gestureSensitivity] == 100 + ? "High" : Defaults[.gestureSensitivity] == 200 ? "Medium" : "Low" + ) + .foregroundStyle(.secondary) + } + } + } + } header: { + HStack { + Text("Gesture control") + customBadge(text: "Beta") + } + } footer: { + Text( + "Two-finger swipe up on notch to close, two-finger swipe down on notch to open when **Open notch on hover** option is disabled" + ) + .multilineTextAlignment(.trailing) + .foregroundStyle(.secondary) + .font(.caption) + } + } - @ViewBuilder - func NotchBehaviour() -> some View { - Section { - Defaults.Toggle(key: .extendHoverArea) { - Text("Extend hover area") - } - Defaults.Toggle(key: .enableHaptics) { - Text("Enable haptics") - } - Defaults.Toggle(key: .openNotchOnHover) { - Text("Open notch on hover") - } - Toggle("Remember last tab", isOn: $coordinator.openLastTabByDefault) - if openNotchOnHover { - Slider(value: $minimumHoverDuration, in: 0...1, step: 0.1) { - HStack { - Text("Minimum hover duration") - Spacer() - Text("\(minimumHoverDuration, specifier: "%.1f")s") - .foregroundStyle(.secondary) - } - } - .onChange(of: minimumHoverDuration) { - NotificationCenter.default.post( - name: Notification.Name.notchHeightChanged, object: nil) - } - } - } header: { - Text("Notch behavior") - } - } + @ViewBuilder + func NotchBehaviour() -> some View { + Section { + Defaults.Toggle(key: .extendHoverArea) { + Text("Extend hover area") + } + Defaults.Toggle(key: .enableHaptics) { + Text("Enable haptics") + } + Defaults.Toggle(key: .openNotchOnHover) { + Text("Open notch on hover") + } + Toggle("Remember last tab", isOn: $coordinator.openLastTabByDefault) + if openNotchOnHover { + Slider(value: $minimumHoverDuration, in: 0...1, step: 0.1) { + HStack { + Text("Minimum hover duration") + Spacer() + Text("\(minimumHoverDuration, specifier: "%.1f")s") + .foregroundStyle(.secondary) + } + } + .onChange(of: minimumHoverDuration) { + NotificationCenter.default.post( + name: Notification.Name.notchHeightChanged, object: nil) + } + } + } header: { + Text("Notch behavior") + } + } } struct Charge: View { - var body: some View { - Form { - Section { - Defaults.Toggle(key: .showBatteryIndicator) { - Text("Show battery indicator") - } - Defaults.Toggle(key: .showPowerStatusNotifications) { - Text("Show power status notifications") - } - } header: { - Text("General") - } - Section { - Defaults.Toggle(key: .showBatteryPercentage) { - Text("Show battery percentage") - } - Defaults.Toggle(key: .showPowerStatusIcons) { - Text("Show power status icons") - } - } header: { - Text("Battery Information") - } - } - .navigationTitle("Battery") - } + var body: some View { + Form { + Section { + Defaults.Toggle(key: .showBatteryIndicator) { + Text("Show battery indicator") + } + Defaults.Toggle(key: .showPowerStatusNotifications) { + Text("Show power status notifications") + } + } header: { + Text("General") + } + Section { + Defaults.Toggle(key: .showBatteryPercentage) { + Text("Show battery percentage") + } + Defaults.Toggle(key: .showPowerStatusIcons) { + Text("Show power status icons") + } + } header: { + Text("Battery Information") + } + } + .navigationTitle("Battery") + } } //struct Downloads: View { @@ -445,897 +446,919 @@ struct Charge: View { //} struct HUD: View { - @EnvironmentObject var vm: BoringViewModel - @Default(.inlineHUD) var inlineHUD - @Default(.enableGradient) var enableGradient - @ObservedObject var coordinator = BoringViewCoordinator.shared - var body: some View { - Form { - Section { - Toggle("Enable HUD replacement", isOn: $coordinator.hudReplacement) - } header: { - Text("General") - } - Section { - Picker("HUD style", selection: $inlineHUD) { - Text("Default") - .tag(false) - Text("Inline") - .tag(true) - } - .onChange(of: Defaults[.inlineHUD]) { - if Defaults[.inlineHUD] { - withAnimation { - Defaults[.systemEventIndicatorShadow] = false - Defaults[.enableGradient] = false - } - } - } - Picker("Progressbar style", selection: $enableGradient) { - Text("Hierarchical") - .tag(false) - Text("Gradient") - .tag(true) - } - Defaults.Toggle(key: .systemEventIndicatorShadow) { - Text("Enable glowing effect") - } - Defaults.Toggle(key: .systemEventIndicatorUseAccent) { - Text("Use accent color") - } - } header: { - HStack { - Text("Appearance") - } - } - } - .navigationTitle("HUDs") - } + @EnvironmentObject var vm: BoringViewModel + @Default(.inlineHUD) var inlineHUD + @Default(.enableGradient) var enableGradient + @ObservedObject var coordinator = BoringViewCoordinator.shared + var body: some View { + Form { + Section { + Toggle("Enable HUD replacement", isOn: $coordinator.hudReplacement) + } header: { + Text("General") + } + Section { + Picker("HUD style", selection: $inlineHUD) { + Text("Default") + .tag(false) + Text("Inline") + .tag(true) + } + .onChange(of: Defaults[.inlineHUD]) { + if Defaults[.inlineHUD] { + withAnimation { + Defaults[.systemEventIndicatorShadow] = false + Defaults[.enableGradient] = false + } + } + } + Picker("Progressbar style", selection: $enableGradient) { + Text("Hierarchical") + .tag(false) + Text("Gradient") + .tag(true) + } + Defaults.Toggle(key: .systemEventIndicatorShadow) { + Text("Enable glowing effect") + } + Defaults.Toggle(key: .systemEventIndicatorUseAccent) { + Text("Use accent color") + } + } header: { + HStack { + Text("Appearance") + } + } + } + .navigationTitle("HUDs") + } } struct Media: View { - @Default(.waitInterval) var waitInterval - @Default(.mediaController) var mediaController - @ObservedObject var coordinator = BoringViewCoordinator.shared - @Default(.hideNotchOption) var hideNotchOption - @Default(.enableSneakPeek) private var enableSneakPeek - @Default(.sneakPeekStyles) var sneakPeekStyles + @Default(.waitInterval) var waitInterval + @Default(.mediaController) var mediaController + @ObservedObject var coordinator = BoringViewCoordinator.shared + @Default(.hideNotchOption) var hideNotchOption + @Default(.enableSneakPeek) private var enableSneakPeek + @Default(.sneakPeekStyles) var sneakPeekStyles - var body: some View { - Form { - Section { - Picker("Music Source", selection: $mediaController) { - ForEach(availableMediaControllers) { controller in - Text(controller.rawValue).tag(controller) - } - } - .onChange(of: mediaController) { _, _ in - NotificationCenter.default.post( - name: Notification.Name.mediaControllerChanged, - object: nil - ) - } - } header: { - Text("Media Source") - } footer: { - if MusicManager.shared.isNowPlayingDeprecated { - HStack { - Text("YouTube Music requires this third-party app to be installed: ") - .foregroundStyle(.secondary) - .font(.caption) - Link( - "https://github.com/th-ch/youtube-music", - destination: URL(string: "https://github.com/th-ch/youtube-music")! - ) - .font(.caption) - .foregroundColor(.blue) // Ensures it's visibly a link - } - } else { - Text( - "'Now Playing' was the only option on previous versions and works with all media apps." - ) - .foregroundStyle(.secondary) - .font(.caption) - } - } - Section { - Defaults.Toggle(key: .showShuffleAndRepeat) { - HStack { - Text("Show shuffle and repeat buttons") - customBadge(text: "Beta") - } - } - } header: { - Text("Media controls") - } - Section { - Toggle( - "Enable music live activity", - isOn: $coordinator.musicLiveActivityEnabled.animation() - ) - Toggle("Enable sneak peek", isOn: $enableSneakPeek) - Picker("Sneak Peek Style", selection: $sneakPeekStyles) { - ForEach(SneakPeekStyle.allCases) { style in - Text(style.rawValue).tag(style) - } - }.disabled(!enableSneakPeek) - HStack { - Stepper(value: $waitInterval, in: 0...10, step: 1) { - HStack { - Text("Media inactivity timeout") - Spacer() - Text("\(Defaults[.waitInterval], specifier: "%.0f") seconds") - .foregroundStyle(.secondary) - } - } - } - } header: { - Text("Media playback live activity") - } + var body: some View { + Form { + Section { + Picker("Music Source", selection: $mediaController) { + ForEach(availableMediaControllers) { controller in + Text(controller.rawValue).tag(controller) + } + } + .onChange(of: mediaController) { _, _ in + NotificationCenter.default.post( + name: Notification.Name.mediaControllerChanged, + object: nil + ) + } + } header: { + Text("Media Source") + } footer: { + if MusicManager.shared.isNowPlayingDeprecated { + HStack { + Text("YouTube Music requires this third-party app to be installed: ") + .foregroundStyle(.secondary) + .font(.caption) + Link( + "https://github.com/th-ch/youtube-music", + destination: URL(string: "https://github.com/th-ch/youtube-music")! + ) + .font(.caption) + .foregroundColor(.blue) // Ensures it's visibly a link + } + } else { + Text( + "'Now Playing' was the only option on previous versions and works with all media apps." + ) + .foregroundStyle(.secondary) + .font(.caption) + } + } + Section { + Defaults.Toggle(key: .showShuffleAndRepeat) { + HStack { + Text("Show shuffle and repeat buttons") + customBadge(text: "Beta") + } + } + } header: { + Text("Media controls") + } + Section { + Toggle( + "Enable music live activity", + isOn: $coordinator.musicLiveActivityEnabled.animation() + ) + Toggle("Enable sneak peek", isOn: $enableSneakPeek) + Picker("Sneak Peek Style", selection: $sneakPeekStyles) { + ForEach(SneakPeekStyle.allCases) { style in + Text(style.rawValue).tag(style) + } + }.disabled(!enableSneakPeek) + HStack { + Stepper(value: $waitInterval, in: 0...10, step: 1) { + HStack { + Text("Media inactivity timeout") + Spacer() + Text("\(Defaults[.waitInterval], specifier: "%.0f") seconds") + .foregroundStyle(.secondary) + } + } + } + } header: { + Text("Media playback live activity") + } - Picker( - selection: $hideNotchOption, - label: - HStack { - Text("Hide BoringNotch Options") - customBadge(text: "Beta") - } - ) { - Text("Always hide in fullscreen").tag(HideNotchOption.always) - Text("Hide only when NowPlaying app is in fullscreen").tag( - HideNotchOption.nowPlayingOnly) - Text("Never hide").tag(HideNotchOption.never) - } - .onChange(of: hideNotchOption) { - Defaults[.enableFullscreenMediaDetection] = hideNotchOption != .never - } - } - .navigationTitle("Media") - } + Picker( + selection: $hideNotchOption, + label: + HStack { + Text("Hide BoringNotch Options") + customBadge(text: "Beta") + } + ) { + Text("Always hide in fullscreen").tag(HideNotchOption.always) + Text("Hide only when NowPlaying app is in fullscreen").tag( + HideNotchOption.nowPlayingOnly) + Text("Never hide").tag(HideNotchOption.never) + } + .onChange(of: hideNotchOption) { + Defaults[.enableFullscreenMediaDetection] = hideNotchOption != .never + } + } + .navigationTitle("Media") + } - // Only show controller options that are available on this macOS version - private var availableMediaControllers: [MediaControllerType] { - if MusicManager.shared.isNowPlayingDeprecated { - return MediaControllerType.allCases.filter { $0 != .nowPlaying } - } else { - return MediaControllerType.allCases - } - } + // Only show controller options that are available on this macOS version + private var availableMediaControllers: [MediaControllerType] { + if MusicManager.shared.isNowPlayingDeprecated { + return MediaControllerType.allCases.filter { $0 != .nowPlaying } + } else { + return MediaControllerType.allCases + } + } } struct CalendarSettings: View { - @ObservedObject private var calendarManager = CalendarManager.shared - @Default(.showCalendar) var showCalendar: Bool - @Default(.hideCompletedReminders) var hideCompletedReminders + @ObservedObject private var calendarManager = CalendarManager.shared + @Default(.showCalendar) var showCalendar: Bool + @Default(.hideCompletedReminders) var hideCompletedReminders - var body: some View { - Form { - Defaults.Toggle(key: .showCalendar) { - Text("Show calendar") - } - Defaults.Toggle(key: .hideCompletedReminders) { - Text("Hide completed reminders") - } - Section(header: Text("Calendars")) { - if calendarManager.calendarAuthorizationStatus != .fullAccess { - Text("Calendar access is denied. Please enable it in System Settings.") - .foregroundColor(.red) - .multilineTextAlignment(.center) - .padding() - Button("Open Calendar Settings") { - if let settingsURL = URL( - string: - "x-apple.systempreferences:com.apple.preference.security?Privacy_Calendars" - ) { - NSWorkspace.shared.open(settingsURL) - } - } - } else { - List { - ForEach(calendarManager.eventCalendars, id: \.id) { calendar in - Toggle( - isOn: Binding( - get: { calendarManager.getCalendarSelected(calendar) }, - set: { isSelected in - Task { - await calendarManager.setCalendarSelected( - calendar, isSelected: isSelected) - } - } - ) - ) { - Text(calendar.title) - } - .disabled(!showCalendar) - } - } - } - } - Section(header: Text("Reminders")) { - if calendarManager.reminderAuthorizationStatus != .fullAccess { - Text("Reminder access is denied. Please enable it in System Settings.") - .foregroundColor(.red) - .multilineTextAlignment(.center) - .padding() - Button("Open Reminder Settings") { - if let settingsURL = URL( - string: - "x-apple.systempreferences:com.apple.preference.security?Privacy_Reminders" - ) { - NSWorkspace.shared.open(settingsURL) - } - } - } else { - List { - ForEach(calendarManager.reminderLists, id: \.id) { calendar in - Toggle( - isOn: Binding( - get: { calendarManager.getCalendarSelected(calendar) }, - set: { isSelected in - Task { - await calendarManager.setCalendarSelected( - calendar, isSelected: isSelected) - } - } - ) - ) { - Text(calendar.title) - } - .disabled(!showCalendar) - } - } - } - } - } - .onAppear { - Task { - await calendarManager.checkCalendarAuthorization() - await calendarManager.checkReminderAuthorization() - } - } - } + var body: some View { + Form { + Defaults.Toggle(key: .showCalendar) { + Text("Show calendar") + } + Defaults.Toggle(key: .hideCompletedReminders) { + Text("Hide completed reminders") + } + Section(header: Text("Calendars")) { + if calendarManager.calendarAuthorizationStatus != .fullAccess { + Text("Calendar access is denied. Please enable it in System Settings.") + .foregroundColor(.red) + .multilineTextAlignment(.center) + .padding() + Button("Open Calendar Settings") { + if let settingsURL = URL( + string: + "x-apple.systempreferences:com.apple.preference.security?Privacy_Calendars" + ) { + NSWorkspace.shared.open(settingsURL) + } + } + } else { + List { + ForEach(calendarManager.eventCalendars, id: \.id) { calendar in + Toggle( + isOn: Binding( + get: { calendarManager.getCalendarSelected(calendar) }, + set: { isSelected in + Task { + await calendarManager.setCalendarSelected( + calendar, isSelected: isSelected) + } + } + ) + ) { + Text(calendar.title) + } + .disabled(!showCalendar) + } + } + } + } + Section(header: Text("Reminders")) { + if calendarManager.reminderAuthorizationStatus != .fullAccess { + Text("Reminder access is denied. Please enable it in System Settings.") + .foregroundColor(.red) + .multilineTextAlignment(.center) + .padding() + Button("Open Reminder Settings") { + if let settingsURL = URL( + string: + "x-apple.systempreferences:com.apple.preference.security?Privacy_Reminders" + ) { + NSWorkspace.shared.open(settingsURL) + } + } + } else { + List { + ForEach(calendarManager.reminderLists, id: \.id) { calendar in + Toggle( + isOn: Binding( + get: { calendarManager.getCalendarSelected(calendar) }, + set: { isSelected in + Task { + await calendarManager.setCalendarSelected( + calendar, isSelected: isSelected) + } + } + ) + ) { + Text(calendar.title) + } + .disabled(!showCalendar) + } + } + } + } + } + .onAppear { + Task { + await calendarManager.checkCalendarAuthorization() + await calendarManager.checkReminderAuthorization() + } + } + } } struct About: View { - @State private var showBuildNumber: Bool = false - let updaterController: SPUStandardUpdaterController - @Environment(\.openWindow) var openWindow - var body: some View { - VStack { - Form { - Section { - HStack { - Text("Release name") - Spacer() - Text(Defaults[.releaseName]) - .foregroundStyle(.secondary) - } - HStack { - Text("Version") - Spacer() - if showBuildNumber { - Text("(\(Bundle.main.buildVersionNumber ?? ""))") - .foregroundStyle(.secondary) - } - Text(Bundle.main.releaseVersionNumber ?? "unkown") - .foregroundStyle(.secondary) - } - .onTapGesture { - withAnimation { - showBuildNumber.toggle() - } - } - } header: { - Text("Version info") - } + @State private var showBuildNumber: Bool = false + let updaterController: SPUStandardUpdaterController + @Environment(\.openWindow) var openWindow + var body: some View { + VStack { + Form { + Section { + HStack { + Text("Release name") + Spacer() + Text(Defaults[.releaseName]) + .foregroundStyle(.secondary) + } + HStack { + Text("Version") + Spacer() + if showBuildNumber { + Text("(\(Bundle.main.buildVersionNumber ?? ""))") + .foregroundStyle(.secondary) + } + Text(Bundle.main.releaseVersionNumber ?? "unkown") + .foregroundStyle(.secondary) + } + .onTapGesture { + withAnimation { + showBuildNumber.toggle() + } + } + } header: { + Text("Version info") + } - UpdaterSettingsView(updater: updaterController.updater) + UpdaterSettingsView(updater: updaterController.updater) - HStack(spacing: 30) { - Spacer(minLength: 0) - Button { - NSWorkspace.shared.open(sponsorPage) - } label: { - VStack(spacing: 5) { - Image(systemName: "cup.and.saucer.fill") - .imageScale(.large) - Text("Support Us") - .foregroundStyle(.white) - } - .contentShape(Rectangle()) - } - Spacer(minLength: 0) - Button { - NSWorkspace.shared.open(productPage) - } label: { - VStack(spacing: 5) { - Image("Github") - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 18) - Text("GitHub") - .foregroundStyle(.white) - } - .contentShape(Rectangle()) - } - Spacer(minLength: 0) - } - .buttonStyle(PlainButtonStyle()) - } - VStack(spacing: 0) { - Divider() - Text("Made with 🫶🏻 by not so boring not.people") - .foregroundStyle(.secondary) - .padding(.top, 5) - .padding(.bottom, 7) - .multilineTextAlignment(.center) - .padding(.horizontal, 10) - } - .frame(maxWidth: .infinity, alignment: .center) - } - .toolbar { - // Button("Welcome window") { - // openWindow(id: "onboarding") - // } - // .controlSize(.extraLarge) - CheckForUpdatesView(updater: updaterController.updater) - } - .navigationTitle("About") - } + HStack(spacing: 30) { + Spacer(minLength: 0) + Button { + NSWorkspace.shared.open(sponsorPage) + } label: { + VStack(spacing: 5) { + Image(systemName: "cup.and.saucer.fill") + .imageScale(.large) + Text("Support Us") + .foregroundStyle(.white) + } + .contentShape(Rectangle()) + } + Spacer(minLength: 0) + Button { + NSWorkspace.shared.open(productPage) + } label: { + VStack(spacing: 5) { + Image("Github") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 18) + Text("GitHub") + .foregroundStyle(.white) + } + .contentShape(Rectangle()) + } + Spacer(minLength: 0) + } + .buttonStyle(PlainButtonStyle()) + } + VStack(spacing: 0) { + Divider() + Text("Made with 🫶🏻 by not so boring not.people") + .foregroundStyle(.secondary) + .padding(.top, 5) + .padding(.bottom, 7) + .multilineTextAlignment(.center) + .padding(.horizontal, 10) + } + .frame(maxWidth: .infinity, alignment: .center) + } + .toolbar { + // Button("Welcome window") { + // openWindow(id: "onboarding") + // } + // .controlSize(.extraLarge) + CheckForUpdatesView(updater: updaterController.updater) + } + .navigationTitle("About") + } } struct Shelf: View { - var body: some View { - Form { - Section { - Defaults.Toggle(key: .boringShelf) { - Text("Enable shelf") - } - Defaults.Toggle(key: .openShelfByDefault) { - Text("Open shelf by default if items are present") - } - } header: { - HStack { - Text("General") - } - } - } - .navigationTitle("Shelf") - } + var body: some View { + Form { + Section { + Defaults.Toggle(key: .boringShelf) { + Text("Enable shelf") + } + Defaults.Toggle(key: .openShelfByDefault) { + Text("Open shelf by default if items are present") + } + } header: { + HStack { + Text("General") + } + } + } + .navigationTitle("Shelf") + } } struct Extensions: View { - @EnvironmentObject var extensionManager: BoringExtensionManager - @State private var effectTrigger: Bool = false - var body: some View { - Form { - //warningBadge("We don't support extensions yet") // Uhhhh You do? <><><> Oori.S - Section { - List { - ForEach(extensionManager.installedExtensions.indices, id: \.self) { index in - let item = extensionManager.installedExtensions[index] - HStack { - AppIcon(for: item.bundleIdentifier) - .resizable() - .frame(width: 24, height: 24) - Text(item.name) - ListItemPopover { - Text("Description") - } - Spacer(minLength: 0) - HStack(spacing: 6) { - Circle() - .frame(width: 6, height: 6) - .foregroundColor( - isExtensionRunning(item.bundleIdentifier) - ? .green : item.status == .disabled ? .gray : .red - ) - .conditionalModifier(isExtensionRunning(item.bundleIdentifier)) - { view in - view - .shadow(color: .green, radius: 3) - } - Text( - isExtensionRunning(item.bundleIdentifier) - ? "Running" - : item.status == .disabled ? "Disabled" : "Stopped" - ) - .contentTransition(.numericText()) - .foregroundStyle(.secondary) - .font(.footnote) - } - .frame(width: 60, alignment: .leading) + @EnvironmentObject var extensionManager: BoringExtensionManager + @State private var effectTrigger: Bool = false + var body: some View { + Form { + //warningBadge("We don't support extensions yet") // Uhhhh You do? <><><> Oori.S + Section { + List { + ForEach(extensionManager.installedExtensions.indices, id: \.self) { index in + let item = extensionManager.installedExtensions[index] + HStack { + AppIcon(for: item.bundleIdentifier) + .resizable() + .frame(width: 24, height: 24) + Text(item.name) + ListItemPopover { + Text("Description") + } + Spacer(minLength: 0) + HStack(spacing: 6) { + Circle() + .frame(width: 6, height: 6) + .foregroundColor( + isExtensionRunning(item.bundleIdentifier) + ? .green : item.status == .disabled ? .gray : .red + ) + .conditionalModifier(isExtensionRunning(item.bundleIdentifier)) + { view in + view + .shadow(color: .green, radius: 3) + } + Text( + isExtensionRunning(item.bundleIdentifier) + ? "Running" + : item.status == .disabled ? "Disabled" : "Stopped" + ) + .contentTransition(.numericText()) + .foregroundStyle(.secondary) + .font(.footnote) + } + .frame(width: 60, alignment: .leading) - Menu( - content: { - Button("Restart") { - let ws = NSWorkspace.shared + Menu( + content: { + Button("Restart") { + let ws = NSWorkspace.shared - if let ext = ws.runningApplications.first(where: { - $0.bundleIdentifier == item.bundleIdentifier - }) { - ext.terminate() - } + if let ext = ws.runningApplications.first(where: { + $0.bundleIdentifier == item.bundleIdentifier + }) { + ext.terminate() + } - if let appURL = ws.urlForApplication( - withBundleIdentifier: item.bundleIdentifier) - { - ws.openApplication( - at: appURL, configuration: .init(), - completionHandler: nil) - } - } - .keyboardShortcut("R", modifiers: .command) - Button("Disable") { - if let ext = NSWorkspace.shared.runningApplications.first( - where: { $0.bundleIdentifier == item.bundleIdentifier }) - { - ext.terminate() - } - extensionManager.installedExtensions[index].status = - .disabled - } - .keyboardShortcut("D", modifiers: .command) - Divider() - Button("Uninstall", role: .destructive) { - // - } - }, - label: { - Image(systemName: "ellipsis.circle") - .foregroundStyle(.secondary) - } - ) - .controlSize(.regular) - } - .buttonStyle(PlainButtonStyle()) - .padding(.vertical, 5) - } - } - .frame(minHeight: 120) - .actionBar { - Button { - } label: { - HStack(spacing: 3) { - Image(systemName: "plus") - Text("Add manually") - } - .foregroundStyle(.secondary) - } - .disabled(true) - Spacer() - Button { - withAnimation(.linear(duration: 1)) { - effectTrigger.toggle() - } completion: { - effectTrigger.toggle() - } - extensionManager.checkIfExtensionsAreInstalled() - } label: { - HStack(spacing: 3) { - Image(systemName: "arrow.triangle.2.circlepath") - .rotationEffect(effectTrigger ? .degrees(360) : .zero) - } - .foregroundStyle(.secondary) - } - } - .controlSize(.small) - .buttonStyle(PlainButtonStyle()) - .overlay { - if extensionManager.installedExtensions.isEmpty { - Text("No extension installed") - .foregroundStyle(Color(.secondaryLabelColor)) - .padding(.bottom, 22) - } - } - } header: { - HStack(spacing: 0) { - Text("Installed extensions") - if !extensionManager.installedExtensions.isEmpty { - Text(" – \(extensionManager.installedExtensions.count)") - .foregroundStyle(.secondary) - } - } - } - } - .navigationTitle("Extensions") - // TipsView() - // .padding(.horizontal, 19) - } + if let appURL = ws.urlForApplication( + withBundleIdentifier: item.bundleIdentifier) + { + ws.openApplication( + at: appURL, configuration: .init(), + completionHandler: nil) + } + } + .keyboardShortcut("R", modifiers: .command) + Button("Disable") { + if let ext = NSWorkspace.shared.runningApplications.first( + where: { $0.bundleIdentifier == item.bundleIdentifier }) + { + ext.terminate() + } + extensionManager.installedExtensions[index].status = + .disabled + } + .keyboardShortcut("D", modifiers: .command) + Divider() + Button("Uninstall", role: .destructive) { + // + } + }, + label: { + Image(systemName: "ellipsis.circle") + .foregroundStyle(.secondary) + } + ) + .controlSize(.regular) + } + .buttonStyle(PlainButtonStyle()) + .padding(.vertical, 5) + } + } + .frame(minHeight: 120) + .actionBar { + Button { + } label: { + HStack(spacing: 3) { + Image(systemName: "plus") + Text("Add manually") + } + .foregroundStyle(.secondary) + } + .disabled(true) + Spacer() + Button { + withAnimation(.linear(duration: 1)) { + effectTrigger.toggle() + } completion: { + effectTrigger.toggle() + } + extensionManager.checkIfExtensionsAreInstalled() + } label: { + HStack(spacing: 3) { + Image(systemName: "arrow.triangle.2.circlepath") + .rotationEffect(effectTrigger ? .degrees(360) : .zero) + } + .foregroundStyle(.secondary) + } + } + .controlSize(.small) + .buttonStyle(PlainButtonStyle()) + .overlay { + if extensionManager.installedExtensions.isEmpty { + Text("No extension installed") + .foregroundStyle(Color(.secondaryLabelColor)) + .padding(.bottom, 22) + } + } + } header: { + HStack(spacing: 0) { + Text("Installed extensions") + if !extensionManager.installedExtensions.isEmpty { + Text(" – \(extensionManager.installedExtensions.count)") + .foregroundStyle(.secondary) + } + } + } + } + .navigationTitle("Extensions") + // TipsView() + // .padding(.horizontal, 19) + } } struct Appearance: View { - @ObservedObject var coordinator = BoringViewCoordinator.shared - @Default(.mirrorShape) var mirrorShape - @Default(.sliderColor) var sliderColor - @Default(.useMusicVisualizer) var useMusicVisualizer - @Default(.customVisualizers) var customVisualizers - @Default(.selectedVisualizer) var selectedVisualizer - @Default(.background) var background - let icons: [String] = ["logo2"] - @State private var selectedIcon: String = "logo2" - @State private var selectedListVisualizer: CustomVisualizer? = nil - - @State private var isPresented: Bool = false - @State private var name: String = "" - @State private var url: String = "" - @State private var speed: CGFloat = 1.0 + @ObservedObject var coordinator = BoringViewCoordinator.shared + @EnvironmentObject var vm: BoringViewModel + @ObservedObject var backgroundManager = BackgroundManager.shared + @Default(.mirrorShape) var mirrorShape + @Default(.sliderColor) var sliderColor + @Default(.useMusicVisualizer) var useMusicVisualizer + @Default(.customVisualizers) var customVisualizers + @Default(.selectedVisualizer) var selectedVisualizer + @Default(.backgroundBlackGradient) var backgroundBlackGradient + let icons: [String] = ["logo2"] + @State private var selectedIcon: String = "logo2" + @State private var selectedListVisualizer: CustomVisualizer? = nil + @State private var isPresented: Bool = false + @State private var name: String = "" + @State private var url: String = "" + @State private var speed: CGFloat = 1.0 - var body: some View { + var body: some View { - Form { - Section { - Toggle("Always show tabs", isOn: $coordinator.alwaysShowTabs) - Defaults.Toggle(key: .settingsIconInNotch) { - Text("Settings icon in notch") - } - Defaults.Toggle(key: .enableShadow) { - Text("Enable window shadow") - } - Defaults.Toggle(key: .cornerRadiusScaling) { - Text("Corner radius scaling") - } - Defaults.Toggle(key: .useModernCloseAnimation) { - Text("Use simpler close animation") - } - } header: { - Text("General") - } + Form { + Section { + Toggle("Always show tabs", isOn: $coordinator.alwaysShowTabs) + Defaults.Toggle(key: .settingsIconInNotch) { + Text("Settings icon in notch") + } + Defaults.Toggle(key: .enableShadow) { + Text("Enable window shadow") + } + Defaults.Toggle(key: .cornerRadiusScaling) { + Text("Corner radius scaling") + } + Defaults.Toggle(key: .useModernCloseAnimation) { + Text("Use simpler close animation") + } + } header: { + Text("General") + } Section { - Picker("", selection: $background) { - ForEach(Background.allCases, id: \.self) { option in - Text(option.rawValue).tag(option) + Slider( + value: $backgroundBlackGradient, + in: 0...1, + ) { + ZStack(alignment: .top) { + Image("wallpaper") + .resizable() + .aspectRatio(contentMode: .fill) + .frame(width: 180, height: 100) + .clipShape(RoundedRectangle(cornerRadius: 10)) - } + Rectangle() + .fill(Color.clear) + .background(backgroundManager.background) + .frame(width: 150, height: 40) + .mask { + NotchShape( + topCornerRadius: cornerRadiusInsets.opened.top, + bottomCornerRadius: cornerRadiusInsets.closed.bottom + ) + .drawingGroup() + } + } + } minimumValueLabel: { + Text("Translucent") + } maximumValueLabel: { + Text("Black") } - .pickerStyle(.inline) } header: { Text("Background") } - Section { - Defaults.Toggle(key: .coloredSpectrogram) { - Text("Enable colored spectrograms") - } - Defaults - .Toggle("Player tinting", key: .playerColorTinting) - Defaults.Toggle(key: .lightingEffect) { - Text("Enable blur effect behind album art") - } - Picker("Slider color", selection: $sliderColor) { - ForEach(SliderColorEnum.allCases, id: \.self) { option in - Text(option.rawValue) - } - } - } header: { - Text("Media") - } + Section { + Defaults.Toggle(key: .coloredSpectrogram) { + Text("Enable colored spectrograms") + } + Defaults + .Toggle("Player tinting", key: .playerColorTinting) + Defaults.Toggle(key: .lightingEffect) { + Text("Enable blur effect behind album art") + } + Picker("Slider color", selection: $sliderColor) { + ForEach(SliderColorEnum.allCases, id: \.self) { option in + Text(option.rawValue) + } + } + } header: { + Text("Media") + } - Section { - Toggle( - "Use music visualizer spectrogram", - isOn: $useMusicVisualizer.animation() - ) - .disabled(true) - if !useMusicVisualizer { - if customVisualizers.count > 0 { - Picker( - "Selected animation", - selection: $selectedVisualizer - ) { - ForEach( - customVisualizers, - id: \.self - ) { visualizer in - Text(visualizer.name) - .tag(visualizer) - } - } - } else { - HStack { - Text("Selected animation") - Spacer() - Text("No custom animation available") - .foregroundStyle(.secondary) - } - } - } - } header: { - HStack { - Text("Custom music live activity animation") - customBadge(text: "Coming soon") - } - } + Section { + Toggle( + "Use music visualizer spectrogram", + isOn: $useMusicVisualizer.animation() + ) + .disabled(true) + if !useMusicVisualizer { + if customVisualizers.count > 0 { + Picker( + "Selected animation", + selection: $selectedVisualizer + ) { + ForEach( + customVisualizers, + id: \.self + ) { visualizer in + Text(visualizer.name) + .tag(visualizer) + } + } + } else { + HStack { + Text("Selected animation") + Spacer() + Text("No custom animation available") + .foregroundStyle(.secondary) + } + } + } + } header: { + HStack { + Text("Custom music live activity animation") + customBadge(text: "Coming soon") + } + } - Section { - List { - ForEach(customVisualizers, id: \.self) { visualizer in - HStack { - LottieView( - state: LUStateData( - type: .loadedFrom(visualizer.url), speed: visualizer.speed, - loopMode: .loop) - ) - .frame(width: 30, height: 30, alignment: .center) - Text(visualizer.name) - Spacer(minLength: 0) - if selectedVisualizer == visualizer { - Text("selected") - .font(.caption) - .fontWeight(.medium) - .foregroundStyle(.secondary) - .padding(.trailing, 8) - } - } - .buttonStyle(PlainButtonStyle()) - .padding(.vertical, 2) - .background( - selectedListVisualizer != nil - ? selectedListVisualizer == visualizer - ? Color.accentColor : Color.clear : Color.clear, - in: RoundedRectangle(cornerRadius: 5) - ) - .contentShape(Rectangle()) - .onTapGesture { - if selectedListVisualizer == visualizer { - selectedListVisualizer = nil - return - } - selectedListVisualizer = visualizer - } - } - } - .safeAreaPadding( - EdgeInsets(top: 5, leading: 0, bottom: 5, trailing: 0) - ) - .frame(minHeight: 120) - .actionBar { - HStack(spacing: 5) { - Button { - name = "" - url = "" - speed = 1.0 - isPresented.toggle() - } label: { - Image(systemName: "plus") - .foregroundStyle(.secondary) - .contentShape(Rectangle()) - } - Divider() - Button { - if selectedListVisualizer != nil { - let visualizer = selectedListVisualizer! - selectedListVisualizer = nil - customVisualizers.remove( - at: customVisualizers.firstIndex(of: visualizer)!) - if visualizer == selectedVisualizer && customVisualizers.count > 0 { - selectedVisualizer = customVisualizers[0] - } - } - } label: { - Image(systemName: "minus") - .foregroundStyle(.secondary) - .contentShape(Rectangle()) - } - } - } - .controlSize(.small) - .buttonStyle(PlainButtonStyle()) - .overlay { - if customVisualizers.isEmpty { - Text("No custom visualizer") - .foregroundStyle(Color(.secondaryLabelColor)) - .padding(.bottom, 22) - } - } - .sheet(isPresented: $isPresented) { - VStack(alignment: .leading) { - Text("Add new visualizer") - .font(.largeTitle.bold()) - .padding(.vertical) - TextField("Name", text: $name) - TextField("Lottie JSON URL", text: $url) - HStack { - Text("Speed") - Spacer(minLength: 80) - Text("\(speed, specifier: "%.1f")s") - .multilineTextAlignment(.trailing) - .foregroundStyle(.secondary) - Slider(value: $speed, in: 0...2, step: 0.1) - } - .padding(.vertical) - HStack { - Button { - isPresented.toggle() - } label: { - Text("Cancel") - .frame(maxWidth: .infinity, alignment: .center) - } + Section { + List { + ForEach(customVisualizers, id: \.self) { visualizer in + HStack { + LottieView( + state: LUStateData( + type: .loadedFrom(visualizer.url), speed: visualizer.speed, + loopMode: .loop) + ) + .frame(width: 30, height: 30, alignment: .center) + Text(visualizer.name) + Spacer(minLength: 0) + if selectedVisualizer == visualizer { + Text("selected") + .font(.caption) + .fontWeight(.medium) + .foregroundStyle(.secondary) + .padding(.trailing, 8) + } + } + .buttonStyle(PlainButtonStyle()) + .padding(.vertical, 2) + .background( + selectedListVisualizer != nil + ? selectedListVisualizer == visualizer + ? Color.accentColor : Color.clear : Color.clear, + in: RoundedRectangle(cornerRadius: 5) + ) + .contentShape(Rectangle()) + .onTapGesture { + if selectedListVisualizer == visualizer { + selectedListVisualizer = nil + return + } + selectedListVisualizer = visualizer + } + } + } + .safeAreaPadding( + EdgeInsets(top: 5, leading: 0, bottom: 5, trailing: 0) + ) + .frame(minHeight: 120) + .actionBar { + HStack(spacing: 5) { + Button { + name = "" + url = "" + speed = 1.0 + isPresented.toggle() + } label: { + Image(systemName: "plus") + .foregroundStyle(.secondary) + .contentShape(Rectangle()) + } + Divider() + Button { + if selectedListVisualizer != nil { + let visualizer = selectedListVisualizer! + selectedListVisualizer = nil + customVisualizers.remove( + at: customVisualizers.firstIndex(of: visualizer)!) + if visualizer == selectedVisualizer && customVisualizers.count > 0 { + selectedVisualizer = customVisualizers[0] + } + } + } label: { + Image(systemName: "minus") + .foregroundStyle(.secondary) + .contentShape(Rectangle()) + } + } + } + .controlSize(.small) + .buttonStyle(PlainButtonStyle()) + .overlay { + if customVisualizers.isEmpty { + Text("No custom visualizer") + .foregroundStyle(Color(.secondaryLabelColor)) + .padding(.bottom, 22) + } + } + .sheet(isPresented: $isPresented) { + VStack(alignment: .leading) { + Text("Add new visualizer") + .font(.largeTitle.bold()) + .padding(.vertical) + TextField("Name", text: $name) + TextField("Lottie JSON URL", text: $url) + HStack { + Text("Speed") + Spacer(minLength: 80) + Text("\(speed, specifier: "%.1f")s") + .multilineTextAlignment(.trailing) + .foregroundStyle(.secondary) + Slider(value: $speed, in: 0...2, step: 0.1) + } + .padding(.vertical) + HStack { + Button { + isPresented.toggle() + } label: { + Text("Cancel") + .frame(maxWidth: .infinity, alignment: .center) + } - Button { - let visualizer: CustomVisualizer = .init( - UUID: UUID(), - name: name, - url: URL(string: url)!, - speed: speed - ) + Button { + let visualizer: CustomVisualizer = .init( + UUID: UUID(), + name: name, + url: URL(string: url)!, + speed: speed + ) - if !customVisualizers.contains(visualizer) { - customVisualizers.append(visualizer) - } + if !customVisualizers.contains(visualizer) { + customVisualizers.append(visualizer) + } - isPresented.toggle() - } label: { - Text("Add") - .frame(maxWidth: .infinity, alignment: .center) - } - .buttonStyle(BorderedProminentButtonStyle()) - } - } - .textFieldStyle(RoundedBorderTextFieldStyle()) - .controlSize(.extraLarge) - .padding() - } - } header: { - HStack(spacing: 0) { - Text("Custom vizualizers (Lottie)") - if !Defaults[.customVisualizers].isEmpty { - Text(" – \(Defaults[.customVisualizers].count)") - .foregroundStyle(.secondary) - } - } - } + isPresented.toggle() + } label: { + Text("Add") + .frame(maxWidth: .infinity, alignment: .center) + } + .buttonStyle(BorderedProminentButtonStyle()) + } + } + .textFieldStyle(RoundedBorderTextFieldStyle()) + .controlSize(.extraLarge) + .padding() + } + } header: { + HStack(spacing: 0) { + Text("Custom vizualizers (Lottie)") + if !Defaults[.customVisualizers].isEmpty { + Text(" – \(Defaults[.customVisualizers].count)") + .foregroundStyle(.secondary) + } + } + } - Section { - Defaults.Toggle(key: .showMirror) { - Text("Enable boring mirror") - } - .disabled(!checkVideoInput()) - Picker("Mirror shape", selection: $mirrorShape) { - Text("Circle") - .tag(MirrorShapeEnum.circle) - Text("Square") - .tag(MirrorShapeEnum.rectangle) - } - Defaults.Toggle(key: .showNotHumanFace) { - Text("Show cool face animation while inactivity") - } - } header: { - HStack { - Text("Additional features") - } - } + Section { + Defaults.Toggle(key: .showMirror) { + Text("Enable boring mirror") + } + .disabled(!checkVideoInput()) + Picker("Mirror shape", selection: $mirrorShape) { + Text("Circle") + .tag(MirrorShapeEnum.circle) + Text("Square") + .tag(MirrorShapeEnum.rectangle) + } + Defaults.Toggle(key: .showNotHumanFace) { + Text("Show cool face animation while inactivity") + } + } header: { + HStack { + Text("Additional features") + } + } - Section { - HStack { - ForEach(icons, id: \.self) { icon in - Spacer() - VStack { - Image(icon) - .resizable() - .frame(width: 80, height: 80) - .background( - RoundedRectangle(cornerRadius: 20, style: .circular) - .strokeBorder( - icon == selectedIcon ? Color.accentColor : .clear, - lineWidth: 2.5 - ) - ) + Section { + HStack { + ForEach(icons, id: \.self) { icon in + Spacer() + VStack { + Image(icon) + .resizable() + .frame(width: 80, height: 80) + .background( + RoundedRectangle(cornerRadius: 20, style: .circular) + .strokeBorder( + icon == selectedIcon ? Color.accentColor : .clear, + lineWidth: 2.5 + ) + ) - Text("Default") - .fontWeight(.medium) - .font(.caption) - .foregroundStyle(icon == selectedIcon ? .white : .secondary) - .padding(.horizontal, 10) - .padding(.vertical, 3) - .background( - Capsule() - .fill(icon == selectedIcon ? Color.accentColor : .clear) - ) - } - .onTapGesture { - withAnimation { - selectedIcon = icon - } - NSApp.applicationIconImage = NSImage(named: icon) - } - Spacer() - } - } - .disabled(true) - } header: { - HStack { - Text("App icon") - customBadge(text: "Coming soon") - } - } - } - .navigationTitle("Appearance") - } + Text("Default") + .fontWeight(.medium) + .font(.caption) + .foregroundStyle(icon == selectedIcon ? .white : .secondary) + .padding(.horizontal, 10) + .padding(.vertical, 3) + .background( + Capsule() + .fill(icon == selectedIcon ? Color.accentColor : .clear) + ) + } + .onTapGesture { + withAnimation { + selectedIcon = icon + } + NSApp.applicationIconImage = NSImage(named: icon) + } + Spacer() + } + } + .disabled(true) + } header: { + HStack { + Text("App icon") + customBadge(text: "Coming soon") + } + } + } + .navigationTitle("Appearance") + } - func checkVideoInput() -> Bool { - if AVCaptureDevice.default(for: .video) != nil { - return true - } + func checkVideoInput() -> Bool { + if AVCaptureDevice.default(for: .video) != nil { + return true + } - return false - } + return false + } } struct Shortcuts: View { - var body: some View { - Form { - Section { - KeyboardShortcuts.Recorder("Toggle Sneak Peek:", name: .toggleSneakPeek) - } header: { - Text("Media") - } footer: { - Text( - "Sneak Peek shows the media title and artist under the notch for a few seconds." - ) - .multilineTextAlignment(.trailing) - .foregroundStyle(.secondary) - .font(.caption) - } - Section { - KeyboardShortcuts.Recorder("Toggle Notch Open:", name: .toggleNotchOpen) - } - } - .navigationTitle("Shortcuts") - } + var body: some View { + Form { + Section { + KeyboardShortcuts.Recorder("Toggle Sneak Peek:", name: .toggleSneakPeek) + } header: { + Text("Media") + } footer: { + Text( + "Sneak Peek shows the media title and artist under the notch for a few seconds." + ) + .multilineTextAlignment(.trailing) + .foregroundStyle(.secondary) + .font(.caption) + } + Section { + KeyboardShortcuts.Recorder("Toggle Notch Open:", name: .toggleNotchOpen) + } + } + .navigationTitle("Shortcuts") + } } func proFeatureBadge() -> some View { - Text("Upgrade to Pro") - .foregroundStyle(Color(red: 0.545, green: 0.196, blue: 0.98)) - .font(.footnote.bold()) - .padding(.vertical, 3) - .padding(.horizontal, 6) - .background( - RoundedRectangle(cornerRadius: 4).stroke( - Color(red: 0.545, green: 0.196, blue: 0.98), lineWidth: 1)) + Text("Upgrade to Pro") + .foregroundStyle(Color(red: 0.545, green: 0.196, blue: 0.98)) + .font(.footnote.bold()) + .padding(.vertical, 3) + .padding(.horizontal, 6) + .background( + RoundedRectangle(cornerRadius: 4).stroke( + Color(red: 0.545, green: 0.196, blue: 0.98), lineWidth: 1)) } func comingSoonTag() -> some View { - Text("Coming soon") - .foregroundStyle(.secondary) - .font(.footnote.bold()) - .padding(.vertical, 3) - .padding(.horizontal, 6) - .background(Color(nsColor: .secondarySystemFill)) - .clipShape(.capsule) + Text("Coming soon") + .foregroundStyle(.secondary) + .font(.footnote.bold()) + .padding(.vertical, 3) + .padding(.horizontal, 6) + .background(Color(nsColor: .secondarySystemFill)) + .clipShape(.capsule) } func customBadge(text: String) -> some View { - Text(text) - .foregroundStyle(.secondary) - .font(.footnote.bold()) - .padding(.vertical, 3) - .padding(.horizontal, 6) - .background(Color(nsColor: .secondarySystemFill)) - .clipShape(.capsule) + Text(text) + .foregroundStyle(.secondary) + .font(.footnote.bold()) + .padding(.vertical, 3) + .padding(.horizontal, 6) + .background(Color(nsColor: .secondarySystemFill)) + .clipShape(.capsule) } func warningBadge(_ text: String, _ description: String) -> some View { - Section { - HStack(spacing: 12) { - Image(systemName: "exclamationmark.triangle.fill") - .font(.system(size: 22)) - .foregroundStyle(.yellow) - VStack(alignment: .leading) { - Text(text) - .font(.headline) - Text(description) - .foregroundStyle(.secondary) - } - Spacer() - } - } + Section { + HStack(spacing: 12) { + Image(systemName: "exclamationmark.triangle.fill") + .font(.system(size: 22)) + .foregroundStyle(.yellow) + VStack(alignment: .leading) { + Text(text) + .font(.headline) + Text(description) + .foregroundStyle(.secondary) + } + Spacer() + } + } } #Preview { - HUD() + HUD() } diff --git a/boringNotch/managers/BackgroundManager.swift b/boringNotch/managers/BackgroundManager.swift index c6a31e57..3819736e 100644 --- a/boringNotch/managers/BackgroundManager.swift +++ b/boringNotch/managers/BackgroundManager.swift @@ -1,9 +1,9 @@ -// -// BackgroundManager.swift -// boringNotch -// -// Created by Adon Omeri on 4/9/2025. -// + // + // BackgroundManager.swift + // boringNotch + // + // Created by Adon Omeri on 4/9/2025. + // import Defaults import SwiftUI @@ -15,17 +15,9 @@ class BackgroundManager: ObservableObject { private init() {} var background: some View { - switch Defaults[.background] { - case .black: - return AnyView( - Color.black - ) - - case .ultraThinMaterial: - return AnyView( - Color.clear - .background(.ultraThinMaterial) - ) - } + return AnyView( + Color.black.opacity(Defaults[.backgroundBlackGradient]) + .background(.ultraThinMaterial) + ) } } diff --git a/boringNotch/models/Constants.swift b/boringNotch/models/Constants.swift index 7ffb987c..8d6f94dc 100644 --- a/boringNotch/models/Constants.swift +++ b/boringNotch/models/Constants.swift @@ -84,7 +84,7 @@ extension Defaults.Keys { //static let openLastTabByDefault = Key("openLastTabByDefault", default: false) // MARK: Appearance - static let background = Key("background", default: .black) + static let backgroundBlackGradient = Key("backgroundBlackGradient", default: 1) static let showEmojis = Key("showEmojis", default: false) //static let alwaysShowTabs = Key("alwaysShowTabs", default: true) static let showMirror = Key("showMirror", default: false) From 74968af693f02528fb291ec93c8f52d496c1d81c Mon Sep 17 00:00:00 2001 From: omeriadon Date: Fri, 5 Sep 2025 17:24:29 +0800 Subject: [PATCH 07/12] Fix battery view bug --- boringNotch/components/Live activities/BoringBattery.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boringNotch/components/Live activities/BoringBattery.swift b/boringNotch/components/Live activities/BoringBattery.swift index dc2b345f..666538c6 100644 --- a/boringNotch/components/Live activities/BoringBattery.swift +++ b/boringNotch/components/Live activities/BoringBattery.swift @@ -31,7 +31,7 @@ struct BatteryView: View { /// Determines the icon to display when charging. var iconStatusView: Image { if isCharging { - return Image(systemName: "bolt") + return Image(systemName: "bolt.fill") } else if isPluggedIn { return Image(systemName: "powerplug.portrait.fill") From eb30b9c8df85b35d2a9d154bb18dcac654deb6fe Mon Sep 17 00:00:00 2001 From: omeriadon Date: Fri, 5 Sep 2025 17:32:13 +0800 Subject: [PATCH 08/12] Revert BoringViewModel to () not shared --- boringNotch/ContentView.swift | 2 +- boringNotch/boringNotchApp.swift | 4 ++-- boringNotch/components/Calendar/BoringCalendar.swift | 2 +- boringNotch/components/Live activities/InlineHUD.swift | 2 +- boringNotch/components/Notch/BoringExtrasMenu.swift | 2 +- boringNotch/components/Notch/BoringHeader.swift | 2 +- boringNotch/components/Settings/SettingsView.swift | 3 ++- boringNotch/components/Tabs/TabSelectionView.swift | 2 +- boringNotch/models/BoringViewModel.swift | 3 +-- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/boringNotch/ContentView.swift b/boringNotch/ContentView.swift index f53bf80b..7997c8cf 100644 --- a/boringNotch/ContentView.swift +++ b/boringNotch/ContentView.swift @@ -580,7 +580,7 @@ struct FullScreenDropDelegate: DropDelegate { } #Preview { - let vm = BoringViewModel.shared + let vm = BoringViewModel() vm.open() return ContentView() .environmentObject(vm) diff --git a/boringNotch/boringNotchApp.swift b/boringNotch/boringNotchApp.swift index 327999ac..21632df7 100644 --- a/boringNotch/boringNotchApp.swift +++ b/boringNotch/boringNotchApp.swift @@ -65,7 +65,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { var windows: [NSScreen: NSWindow] = [:] var viewModels: [NSScreen: BoringViewModel] = [:] var window: NSWindow? - let vm = BoringViewModel.shared + let vm = BoringViewModel() @ObservedObject var coordinator = BoringViewCoordinator.shared var whatsNewWindow: NSWindow? var timer: Timer? @@ -326,7 +326,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { for screen in currentScreens { if windows[screen] == nil { - let viewModel = BoringViewModel.shared + let viewModel = BoringViewModel() viewModel.screen = screen.localizedName let window = createBoringNotchWindow(for: screen, with: viewModel) diff --git a/boringNotch/components/Calendar/BoringCalendar.swift b/boringNotch/components/Calendar/BoringCalendar.swift index d7b22f7c..71c8acbc 100644 --- a/boringNotch/components/Calendar/BoringCalendar.swift +++ b/boringNotch/components/Calendar/BoringCalendar.swift @@ -442,5 +442,5 @@ struct ReminderToggle: View { CalendarView() .frame(width: 215, height: 130) .background(.black) - .environmentObject(BoringViewModel.shared) + .environmentObject(BoringViewModel()) } diff --git a/boringNotch/components/Live activities/InlineHUD.swift b/boringNotch/components/Live activities/InlineHUD.swift index db236c3f..0a627c4c 100644 --- a/boringNotch/components/Live activities/InlineHUD.swift +++ b/boringNotch/components/Live activities/InlineHUD.swift @@ -143,5 +143,5 @@ struct InlineHUD: View { .padding(.horizontal, 8) .background(Color.black) .padding() - .environmentObject(BoringViewModel.shared) + .environmentObject(BoringViewModel()) } diff --git a/boringNotch/components/Notch/BoringExtrasMenu.swift b/boringNotch/components/Notch/BoringExtrasMenu.swift index 69b3348a..81457bbb 100644 --- a/boringNotch/components/Notch/BoringExtrasMenu.swift +++ b/boringNotch/components/Notch/BoringExtrasMenu.swift @@ -105,5 +105,5 @@ struct BoringExtrasMenu : View { #Preview { - BoringExtrasMenu(vm: BoringViewModel.shared) + BoringExtrasMenu(vm: BoringViewModel()) } diff --git a/boringNotch/components/Notch/BoringHeader.swift b/boringNotch/components/Notch/BoringHeader.swift index a83213db..732aa4ad 100644 --- a/boringNotch/components/Notch/BoringHeader.swift +++ b/boringNotch/components/Notch/BoringHeader.swift @@ -99,5 +99,5 @@ struct BoringHeader: View { } #Preview { - BoringHeader().environmentObject(BoringViewModel.shared) + BoringHeader().environmentObject(BoringViewModel()) } diff --git a/boringNotch/components/Settings/SettingsView.swift b/boringNotch/components/Settings/SettingsView.swift index 1b231ddd..0bb3b754 100644 --- a/boringNotch/components/Settings/SettingsView.swift +++ b/boringNotch/components/Settings/SettingsView.swift @@ -78,9 +78,10 @@ struct SettingsView: View { switch selectedTab { case "General": GeneralSettings() + .environmentObject(BoringViewModel()) case "Appearance": Appearance() - .environmentObject(BoringViewModel.shared) + .environmentObject(BoringViewModel()) case "Media": Media() case "Calendar": diff --git a/boringNotch/components/Tabs/TabSelectionView.swift b/boringNotch/components/Tabs/TabSelectionView.swift index 81cb7f0b..b99d4af1 100644 --- a/boringNotch/components/Tabs/TabSelectionView.swift +++ b/boringNotch/components/Tabs/TabSelectionView.swift @@ -51,5 +51,5 @@ struct TabSelectionView: View { } #Preview { - BoringHeader().environmentObject(BoringViewModel.shared) + BoringHeader().environmentObject(BoringViewModel()) } diff --git a/boringNotch/models/BoringViewModel.swift b/boringNotch/models/BoringViewModel.swift index da325653..9d5bb52d 100644 --- a/boringNotch/models/BoringViewModel.swift +++ b/boringNotch/models/BoringViewModel.swift @@ -11,7 +11,6 @@ import SwiftUI import TheBoringWorkerNotifier class BoringViewModel: NSObject, ObservableObject { - static let shared = BoringViewModel() // Singleton instance var coordinator = BoringViewCoordinator.shared var detector = FullscreenMediaDetector.shared @@ -59,7 +58,7 @@ class BoringViewModel: NSObject, ObservableObject { updateCancellable = nil } - private override init() { + override init() { animation = animationLibrary.animation super.init() From fce42efafed6f7a39f67f1aad9009cbcf9244b74 Mon Sep 17 00:00:00 2001 From: omeriadon Date: Fri, 5 Sep 2025 17:38:20 +0800 Subject: [PATCH 09/12] Add fade-out to calendar event list --- .../components/Calendar/BoringCalendar.swift | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/boringNotch/components/Calendar/BoringCalendar.swift b/boringNotch/components/Calendar/BoringCalendar.swift index 71c8acbc..cebd3418 100644 --- a/boringNotch/components/Calendar/BoringCalendar.swift +++ b/boringNotch/components/Calendar/BoringCalendar.swift @@ -207,7 +207,7 @@ struct CalendarView: View { colors: [Color.black.opacity(0), Color.black]), startPoint: .leading, endPoint: .trailing ) - .frame(width: 30) + .frame(width: 15) Rectangle().fill(Color.black) @@ -216,7 +216,7 @@ struct CalendarView: View { colors: [Color.black, Color.black.opacity(0)]), startPoint: .leading, endPoint: .trailing ) - .frame(width: 30) + .frame(width: 15) } ) } @@ -226,6 +226,7 @@ struct CalendarView: View { events: calendarManager.events ) if filteredEvents.isEmpty { + Spacer(minLength: 0) EmptyEventsView() Spacer(minLength: 0) } else { @@ -292,6 +293,7 @@ struct EventListView: View { } var body: some View { + List { ForEach(filteredEvents) { event in Button(action: { @@ -312,7 +314,25 @@ struct EventListView: View { .scrollIndicators(.never) .scrollContentBackground(.hidden) .background(Color.clear) - Spacer(minLength: 0) + .mask { + VStack(spacing: 0) { + LinearGradient(gradient: + Gradient( + colors: [Color.black.opacity(0), Color.black]), + startPoint: .top, endPoint: .bottom + ) + .frame(height: 10) + + Rectangle().fill(Color.black) + + LinearGradient(gradient: + Gradient( + colors: [Color.black, Color.black.opacity(0)]), + startPoint: .top, endPoint: .bottom + ) + .frame(height: 10) + } + } } private func eventRow(_ event: EventModel) -> some View { From 3cec7b6081a756e1787523385b725ea3ea03f36f Mon Sep 17 00:00:00 2001 From: omeriadon Date: Fri, 5 Sep 2025 18:11:16 +0800 Subject: [PATCH 10/12] Updated background: closed -> black; open -> background And minor adjustments of syntax --- boringNotch/ContentView.swift | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/boringNotch/ContentView.swift b/boringNotch/ContentView.swift index 7997c8cf..eea339d8 100644 --- a/boringNotch/ContentView.swift +++ b/boringNotch/ContentView.swift @@ -42,6 +42,13 @@ struct ContentView: View { private let extendedHoverPadding: CGFloat = 30 private let zeroHeightHoverPadding: CGFloat = 10 + var effectiveBackground: some View { + backgroundManager.background + .opacity(vm.notchState == .open ? 1 : 0) + .background(Color.black.opacity(vm.notchState == .open ? 0 : 1)) + .animation(.easeInOut, value: vm.notchState) + } + var body: some View { ZStack(alignment: .top) { let mainLayout = NotchLayout() @@ -54,7 +61,7 @@ struct ContentView: View { : cornerRadiusInsets.closed.bottom ) .padding([.horizontal, .bottom], vm.notchState == .open ? 12 : 0) - .background(backgroundManager.background) + .background(effectiveBackground) .mask { ((vm.notchState == .open) && Defaults[.cornerRadiusScaling]) ? NotchShape( @@ -133,7 +140,7 @@ struct ContentView: View { handleUpGesture(translation: translation, phase: phase) } } - .onAppear(perform: { + .onAppear { DispatchQueue.main.asyncAfter(deadline: .now() + 1) { withAnimation(vm.animation) { if coordinator.firstLaunch { @@ -141,7 +148,7 @@ struct ContentView: View { } } } - }) + } .onChange(of: vm.notchState) { _, newState in // Reset hover state when notch state changes if newState == .closed && isHovering { @@ -213,8 +220,8 @@ struct ContentView: View { HStack(spacing: 0) { Rectangle() - .fill(.black) - .frame(width: vm.closedNotchSize.width + 10) + .fill(Color.clear) + .frame(width: vm.closedNotchSize.width + 10) HStack { BoringBatteryView( @@ -242,7 +249,12 @@ struct ContentView: View { .blur(radius: abs(gestureProgress) > 0.3 ? min(abs(gestureProgress), 8) : 0) .animation(.spring(response: 1, dampingFraction: 1, blendDuration: 0.8), value: vm.notchState) } else { - Rectangle().fill(.clear).frame(width: vm.closedNotchSize.width - 20, height: vm.effectiveClosedNotchHeight) + Rectangle() + .fill(Color.clear) + .frame( + width: vm.closedNotchSize.width - 20, + height: vm.effectiveClosedNotchHeight + ) } if coordinator.sneakPeek.show { From 5791198195f36ea95a8bb97f7804bc4c24b5a339 Mon Sep 17 00:00:00 2001 From: omeriadon Date: Fri, 5 Sep 2025 18:37:32 +0800 Subject: [PATCH 11/12] Fixed Music Live Activity --- boringNotch/ContentView.swift | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/boringNotch/ContentView.swift b/boringNotch/ContentView.swift index eea339d8..818636d3 100644 --- a/boringNotch/ContentView.swift +++ b/boringNotch/ContentView.swift @@ -319,21 +319,21 @@ struct ContentView: View { .frame(width: vm.closedNotchSize.width - 20) MinimalFaceFeatures() } - }.frame(height: vm.effectiveClosedNotchHeight + (isHovering ? 8 : 0), alignment: .center) + } + .frame(height: vm.effectiveClosedNotchHeight + (isHovering ? 8 : 0), alignment: .center) } @ViewBuilder func MusicLiveActivity() -> some View { HStack { HStack { - Color.clear + Color.clear .aspectRatio(1, contentMode: .fit) .background( Image(nsImage: musicManager.albumArt) .resizable() .aspectRatio(contentMode: .fill) ) - .clipped() .clipShape( RoundedRectangle( cornerRadius: MusicPlayerImageSizes.cornerRadiusInset.closed) @@ -349,7 +349,9 @@ struct ContentView: View { height: max(0, vm.effectiveClosedNotchHeight - (isHovering ? 0 : 12))) Rectangle() - .fill(.black) + .fill(.clear) + + .overlay( HStack(alignment: .top) { if coordinator.expandingView.show From 614346c79530a8a7c2829e9d2d424214eef3281c Mon Sep 17 00:00:00 2001 From: omeriadon Date: Fri, 5 Sep 2025 19:11:17 +0800 Subject: [PATCH 12/12] Fixed animation bug --- boringNotch/ContentView.swift | 14 +++++++--- boringNotch/Localizable.xcstrings | 6 +++++ .../components/Settings/SettingsView.swift | 16 ++++++++++-- boringNotch/managers/BackgroundManager.swift | 26 ++++++++++++------- boringNotch/models/Constants.swift | 1 + 5 files changed, 47 insertions(+), 16 deletions(-) diff --git a/boringNotch/ContentView.swift b/boringNotch/ContentView.swift index 818636d3..119160cd 100644 --- a/boringNotch/ContentView.swift +++ b/boringNotch/ContentView.swift @@ -43,10 +43,16 @@ struct ContentView: View { private let zeroHeightHoverPadding: CGFloat = 10 var effectiveBackground: some View { - backgroundManager.background - .opacity(vm.notchState == .open ? 1 : 0) - .background(Color.black.opacity(vm.notchState == .open ? 0 : 1)) - .animation(.easeInOut, value: vm.notchState) + if Defaults[.backgroundIsBlack] { + return AnyView(Color.black) + } else { + return AnyView( + backgroundManager.background + .opacity(vm.notchState == .open ? 1 : 0) + .background(Color.black.opacity(vm.notchState == .open ? 0 : 1)) + .animation(.easeInOut, value: vm.notchState) + ) + } } var body: some View { diff --git a/boringNotch/Localizable.xcstrings b/boringNotch/Localizable.xcstrings index ac2e0787..eac456e6 100644 --- a/boringNotch/Localizable.xcstrings +++ b/boringNotch/Localizable.xcstrings @@ -5016,6 +5016,9 @@ } } } + }, + "Content" : { + }, "Continue" : { "localizations" : { @@ -5716,6 +5719,9 @@ } } } + }, + "Dark" : { + }, "Default" : { "localizations" : { diff --git a/boringNotch/components/Settings/SettingsView.swift b/boringNotch/components/Settings/SettingsView.swift index 0bb3b754..275a8328 100644 --- a/boringNotch/components/Settings/SettingsView.swift +++ b/boringNotch/components/Settings/SettingsView.swift @@ -955,6 +955,7 @@ struct Appearance: View { @Default(.useMusicVisualizer) var useMusicVisualizer @Default(.customVisualizers) var customVisualizers @Default(.selectedVisualizer) var selectedVisualizer + @Default(.backgroundIsBlack) var backgroundIsBlack @Default(.backgroundBlackGradient) var backgroundBlackGradient let icons: [String] = ["logo2"] @State private var selectedIcon: String = "logo2" @@ -988,9 +989,15 @@ struct Appearance: View { Section { + Picker("Background", selection: $backgroundIsBlack) { + Text("Black").tag(true) + Text("Translucent").tag(false) + } + .pickerStyle(.segmented) + Slider( value: $backgroundBlackGradient, - in: 0...1, + in: 0...0.65, ) { ZStack(alignment: .top) { Image("wallpaper") @@ -1001,6 +1008,10 @@ struct Appearance: View { Rectangle() .fill(Color.clear) + .overlay(alignment: .center) { + Text("Content") + .foregroundStyle(.white) + } .background(backgroundManager.background) .frame(width: 150, height: 40) .mask { @@ -1014,8 +1025,9 @@ struct Appearance: View { } minimumValueLabel: { Text("Translucent") } maximumValueLabel: { - Text("Black") + Text("Dark") } + .disabled(Defaults[.backgroundIsBlack]) } header: { Text("Background") } diff --git a/boringNotch/managers/BackgroundManager.swift b/boringNotch/managers/BackgroundManager.swift index 3819736e..10844fe0 100644 --- a/boringNotch/managers/BackgroundManager.swift +++ b/boringNotch/managers/BackgroundManager.swift @@ -1,9 +1,9 @@ - // - // BackgroundManager.swift - // boringNotch - // - // Created by Adon Omeri on 4/9/2025. - // +// +// BackgroundManager.swift +// boringNotch +// +// Created by Adon Omeri on 4/9/2025. +// import Defaults import SwiftUI @@ -15,9 +15,15 @@ class BackgroundManager: ObservableObject { private init() {} var background: some View { - return AnyView( - Color.black.opacity(Defaults[.backgroundBlackGradient]) - .background(.ultraThinMaterial) - ) + if Defaults[.backgroundIsBlack] { + return AnyView( + Color.black + ) + } else { + return AnyView( + Color.black.opacity(Defaults[.backgroundBlackGradient]) + .background(.ultraThinMaterial) + ) + } } } diff --git a/boringNotch/models/Constants.swift b/boringNotch/models/Constants.swift index 8d6f94dc..b9ddddcf 100644 --- a/boringNotch/models/Constants.swift +++ b/boringNotch/models/Constants.swift @@ -84,6 +84,7 @@ extension Defaults.Keys { //static let openLastTabByDefault = Key("openLastTabByDefault", default: false) // MARK: Appearance + static let backgroundIsBlack = Key("backgroundIsBlack", default: true) static let backgroundBlackGradient = Key("backgroundBlackGradient", default: 1) static let showEmojis = Key("showEmojis", default: false) //static let alwaysShowTabs = Key("alwaysShowTabs", default: true)