Merging trial

This commit is contained in:
Hariharan Mudaliar 2026-02-04 00:11:06 +05:30
commit cadc3c7b68
No known key found for this signature in database
GPG key ID: 025583EB0BE5640E
277 changed files with 5746 additions and 1768 deletions

8
COPYRIGHT_ASSETS Normal file
View file

@ -0,0 +1,8 @@
Atoll (DynamicIsland) - Assets Copyright
Unless otherwise noted, the original assets created specifically for Atoll
(DynamicIsland) are Copyright (C) 2024-2026 Atoll Contributors.
This includes original media, artwork, animations, and other creative assets
unique to Atoll. Third-party assets retain their original licenses and
copyrights; see NOTICE and any THIRD_PARTY_LICENSES files for details.

View file

@ -386,7 +386,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_STYLE = Manual; CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 3; CURRENT_PROJECT_VERSION = 4;
DEVELOPMENT_ASSET_PATHS = "\"DynamicIsland/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"DynamicIsland/Preview Content\"";
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
ENABLE_APP_SANDBOX = NO; ENABLE_APP_SANDBOX = NO;
@ -427,7 +427,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 14.6; MACOSX_DEPLOYMENT_TARGET = 14.6;
MARKETING_VERSION = "1.2.2-beta"; MARKETING_VERSION = "1.3.0-beta";
PRODUCT_BUNDLE_IDENTIFIER = com.Ebullioscopic.Atoll.dev; PRODUCT_BUNDLE_IDENTIFIER = com.Ebullioscopic.Atoll.dev;
PRODUCT_NAME = Atoll; PRODUCT_NAME = Atoll;
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
@ -457,7 +457,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_STYLE = Manual; CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 3; CURRENT_PROJECT_VERSION = 4;
DEVELOPMENT_ASSET_PATHS = "\"DynamicIsland/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"DynamicIsland/Preview Content\"";
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
ENABLE_APP_SANDBOX = NO; ENABLE_APP_SANDBOX = NO;
@ -498,7 +498,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 14.6; MACOSX_DEPLOYMENT_TARGET = 14.6;
MARKETING_VERSION = "1.2.2-beta"; MARKETING_VERSION = "1.3.0-beta";
PRODUCT_BUNDLE_IDENTIFIER = com.Ebullioscopic.Atoll; PRODUCT_BUNDLE_IDENTIFIER = com.Ebullioscopic.Atoll;
PRODUCT_NAME = Atoll; PRODUCT_NAME = Atoll;
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";

View file

@ -1,11 +1,24 @@
// /*
// ContentView.swift * Atoll (DynamicIsland)
// DynamicIslandApp * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Harsh Vardhan Goswami on 02/08/24 * Originally from boring.notch project
// Modified by Richard Kunkli on 24/08/2024. * Modified and adapted for Atoll (DynamicIsland)
// Modified by A Akhil on 13/01/2026. * See NOTICE for details.
// *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import AVFoundation import AVFoundation
import Combine import Combine
@ -66,6 +79,7 @@ struct ContentView: View {
@Default(.enableScreenRecordingDetection) var enableScreenRecordingDetection @Default(.enableScreenRecordingDetection) var enableScreenRecordingDetection
@Default(.enableCapsLockIndicator) var enableCapsLockIndicator @Default(.enableCapsLockIndicator) var enableCapsLockIndicator
@Default(.enableExtensionLiveActivities) var enableExtensionLiveActivities @Default(.enableExtensionLiveActivities) var enableExtensionLiveActivities
@Default(.showStandardMediaControls) var showStandardMediaControls
// Dynamic sizing based on view type and graph count with smooth transitions // Dynamic sizing based on view type and graph count with smooth transitions
var dynamicNotchSize: CGSize { var dynamicNotchSize: CGSize {
@ -161,10 +175,7 @@ struct ContentView: View {
enqueueMusicControlWindowSync(forceRefresh: forceRefresh, delay: delay) enqueueMusicControlWindowSync(forceRefresh: forceRefresh, delay: delay)
} }
private var dynamicNotchResizeAnimation: Animation? { private var dynamicNotchResizeAnimation: Animation? {
if enableMinimalisticUI && reminderManager.activeWindowReminders.isEmpty == false { nil
return nil
}
return .easeInOut(duration: 0.4)
} }
private let zeroHeightHoverPadding: CGFloat = 10 private let zeroHeightHoverPadding: CGFloat = 10
@ -172,6 +183,14 @@ struct ContentView: View {
private let musicControlPauseGrace: TimeInterval = 5 private let musicControlPauseGrace: TimeInterval = 5
private let musicControlResumeDelay: TimeInterval = 0.24 private let musicControlResumeDelay: TimeInterval = 0.24
private var standardMediaControlsActive: Bool {
showStandardMediaControls && !enableMinimalisticUI
}
private var closedMusicContentEnabled: Bool {
enableMinimalisticUI || showStandardMediaControls
}
// Use minimalistic corner radius ONLY when opened, keep normal when closed // Use minimalistic corner radius ONLY when opened, keep normal when closed
private var activeCornerRadiusInsets: (opened: (top: CGFloat, bottom: CGFloat), closed: (top: CGFloat, bottom: CGFloat)) { private var activeCornerRadiusInsets: (opened: (top: CGFloat, bottom: CGFloat), closed: (top: CGFloat, bottom: CGFloat)) {
if enableMinimalisticUI { if enableMinimalisticUI {
@ -197,14 +216,27 @@ struct ContentView: View {
var body: some View { var body: some View {
let interactionsEnabled = !lockScreenManager.isLocked let interactionsEnabled = !lockScreenManager.isLocked
let notchHorizontalPadding: CGFloat = {
guard vm.notchState == .open else {
return activeCornerRadiusInsets.closed.bottom
}
if Defaults[.cornerRadiusScaling] {
return activeCornerRadiusInsets.opened.top - 5
}
return activeCornerRadiusInsets.opened.bottom - 5
}()
let hoverAreaPadding: CGFloat = {
if vm.notchState == .open && Defaults[.extendHoverArea] {
return 0
}
return vm.effectiveClosedNotchHeight == 0 ? zeroHeightHoverPadding : 0
}()
let notchBottomPadding = currentShadowPadding + hoverAreaPadding
ZStack(alignment: .top) { ZStack(alignment: .top) {
let mainLayout = NotchLayout() let mainLayout = NotchLayout()
.frame(alignment: .top) .frame(alignment: .top)
.padding(.horizontal, vm.notchState == .open .padding(.horizontal, notchHorizontalPadding)
? Defaults[.cornerRadiusScaling] ? (activeCornerRadiusInsets.opened.top - 5) : (activeCornerRadiusInsets.opened.bottom - 5)
: activeCornerRadiusInsets.closed.bottom
)
.padding([.horizontal, .bottom], vm.notchState == .open ? 12 : 0) .padding([.horizontal, .bottom], vm.notchState == .open ? 12 : 0)
.background(.black) .background(.black)
.clipShape(currentNotchShape) .clipShape(currentNotchShape)
@ -215,23 +247,15 @@ struct ContentView: View {
: .clear, : .clear,
radius: Defaults[.cornerRadiusScaling] ? 10 : 5 radius: Defaults[.cornerRadiusScaling] ? 10 : 5
) )
.padding(.bottom, .padding(.bottom, notchBottomPadding)
currentShadowPadding + (
vm.notchState == .open && Defaults[.extendHoverArea]
? 0
: (vm.effectiveClosedNotchHeight == 0 ? zeroHeightHoverPadding : 0)
)
)
mainLayout mainLayout
.conditionalModifier(!useModernCloseAnimation) { view in .conditionalModifier(!useModernCloseAnimation) { view in
let hoverAnimation = Animation.bouncy.speed(1.2) let hoverAnimation = Animation.bouncy.speed(1.2)
let notchStateAnimation = Animation.spring.speed(1.2) let notchStateAnimation = Animation.spring.speed(1.2)
let viewTransitionAnimation = Animation.easeInOut(duration: 0.4)
return view return view
.animation(hoverAnimation, value: isHovering) .animation(hoverAnimation, value: isHovering)
.animation(notchStateAnimation, value: vm.notchState) .animation(notchStateAnimation, value: vm.notchState)
.animation(viewTransitionAnimation, value: coordinator.currentView)
.animation(.smooth, value: gestureProgress) .animation(.smooth, value: gestureProgress)
.transition(.blurReplace.animation(.interactiveSpring(dampingFraction: 1.2))) .transition(.blurReplace.animation(.interactiveSpring(dampingFraction: 1.2)))
} }
@ -239,12 +263,10 @@ struct ContentView: View {
let hoverAnimation = Animation.bouncy.speed(1.2) let hoverAnimation = Animation.bouncy.speed(1.2)
let openAnimation = Animation.spring(response: 0.42, dampingFraction: 0.8, blendDuration: 0) let openAnimation = Animation.spring(response: 0.42, dampingFraction: 0.8, blendDuration: 0)
let closeAnimation = Animation.spring(response: 0.45, dampingFraction: 1.0, blendDuration: 0) let closeAnimation = Animation.spring(response: 0.45, dampingFraction: 1.0, blendDuration: 0)
let viewTransitionAnimation = Animation.easeInOut(duration: 0.4)
let notchAnimation = vm.notchState == .open ? openAnimation : closeAnimation let notchAnimation = vm.notchState == .open ? openAnimation : closeAnimation
return view return view
.animation(hoverAnimation, value: isHovering) .animation(hoverAnimation, value: isHovering)
.animation(notchAnimation, value: vm.notchState) .animation(notchAnimation, value: vm.notchState)
.animation(viewTransitionAnimation, value: coordinator.currentView)
.animation(.smooth, value: gestureProgress) .animation(.smooth, value: gestureProgress)
} }
.conditionalModifier(interactionsEnabled) { view in .conditionalModifier(interactionsEnabled) { view in
@ -373,13 +395,10 @@ struct ContentView: View {
maxHeight: dynamicNotchSize.height + currentShadowPadding, maxHeight: dynamicNotchSize.height + currentShadowPadding,
alignment: .top alignment: .top
) )
.animation(dynamicNotchResizeAnimation, value: dynamicNotchSize)
.animation(.easeInOut(duration: 0.4), value: coordinator.currentView)
.environmentObject(privacyManager) .environmentObject(privacyManager)
.onChange(of: dynamicNotchSize) { oldSize, newSize in .onChange(of: dynamicNotchSize) { oldSize, newSize in
guard oldSize != newSize else { return } guard oldSize != newSize else { return }
let delay: TimeInterval = dynamicNotchResizeAnimation == nil ? 0.25 : 1.0 runAfter(0.1) {
runAfter(delay) {
vm.shouldRecheckHover.toggle() vm.shouldRecheckHover.toggle()
} }
} }
@ -449,6 +468,12 @@ struct ContentView: View {
enqueueMusicControlWindowSync(forceRefresh: true, delay: 0.05) enqueueMusicControlWindowSync(forceRefresh: true, delay: 0.05)
} }
} }
.onChange(of: showStandardMediaControls) { _, _ in
handleStandardMediaControlsAvailabilityChange()
}
.onChange(of: enableMinimalisticUI) { _, _ in
handleStandardMediaControlsAvailabilityChange()
}
.onChange(of: gestureProgress) { _, _ in .onChange(of: gestureProgress) { _, _ in
if shouldShowMusicControlWindow() { if shouldShowMusicControlWindow() {
enqueueMusicControlWindowSync(forceRefresh: true, delay: 0.05) enqueueMusicControlWindowSync(forceRefresh: true, delay: 0.05)
@ -506,6 +531,7 @@ struct ContentView: View {
let musicPairingEligible = vm.notchState == .closed let musicPairingEligible = vm.notchState == .closed
&& hasActiveMusicSnapshot && hasActiveMusicSnapshot
&& coordinator.musicLiveActivityEnabled && coordinator.musicLiveActivityEnabled
&& closedMusicContentEnabled
&& !vm.hideOnClosed && !vm.hideOnClosed
&& !lockScreenManager.isLocked && !lockScreenManager.isLocked
let musicSecondary = resolveMusicSecondaryLiveActivity(isMusicPairingEligible: musicPairingEligible) let musicSecondary = resolveMusicSecondaryLiveActivity(isMusicPairingEligible: musicPairingEligible)
@ -722,14 +748,9 @@ struct ContentView: View {
} }
} }
} }
.transition(.asymmetric(
insertion: .scale(scale: 0.8).combined(with: .opacity).animation(.easeInOut(duration: 0.4)),
removal: .scale(scale: 0.8).combined(with: .opacity).animation(.easeInOut(duration: 0.4))
))
.id(coordinator.currentView) // Force SwiftUI to treat each view as unique .id(coordinator.currentView) // Force SwiftUI to treat each view as unique
} }
} }
.animation(.easeInOut(duration: 0.4), value: coordinator.currentView)
.zIndex(1) .zIndex(1)
.allowsHitTesting(vm.notchState == .open) .allowsHitTesting(vm.notchState == .open)
.blur(radius: abs(gestureProgress) > 0.3 ? min(abs(gestureProgress), 8) : 0) .blur(radius: abs(gestureProgress) > 0.3 ? min(abs(gestureProgress), 8) : 0)
@ -1035,16 +1056,11 @@ struct ContentView: View {
.font(.system(size: badgeSize * 0.5, weight: .semibold)) .font(.system(size: badgeSize * 0.5, weight: .semibold))
.foregroundStyle(capsLockTintMode.color) .foregroundStyle(capsLockTintMode.color)
case .extensionPayload(let payload): case .extensionPayload(let payload):
ExtensionCompositeIconView( ExtensionBadgeIconView(
leading: payload.descriptor.leadingIcon, descriptor: payload.descriptor.leadingIcon,
badge: payload.descriptor.badgeIcon,
accent: payload.descriptor.accentColor.swiftUIColor, accent: payload.descriptor.accentColor.swiftUIColor,
size: badgeSize size: badgeSize
) )
.background(
Circle()
.fill(Color.black.opacity(0.85))
)
} }
} }
.frame(width: badgeSize, height: badgeSize) .frame(width: badgeSize, height: badgeSize)
@ -1058,8 +1074,6 @@ struct ContentView: View {
private func badgeDisplaySize(for secondary: MusicSecondaryLiveActivity?, baseSize: CGFloat) -> CGFloat { private func badgeDisplaySize(for secondary: MusicSecondaryLiveActivity?, baseSize: CGFloat) -> CGFloat {
guard let secondary else { return baseSize } guard let secondary else { return baseSize }
switch secondary { switch secondary {
case .extensionPayload:
return max(11, baseSize * 0.86)
default: default:
return baseSize return baseSize
} }
@ -1068,8 +1082,6 @@ struct ContentView: View {
private func badgeOverlayOffset(for secondary: MusicSecondaryLiveActivity?, badgeSize: CGFloat) -> CGSize { private func badgeOverlayOffset(for secondary: MusicSecondaryLiveActivity?, badgeSize: CGFloat) -> CGSize {
guard let secondary else { return CGSize(width: badgeSize * 0.2, height: badgeSize * 0.25) } guard let secondary else { return CGSize(width: badgeSize * 0.2, height: badgeSize * 0.25) }
switch secondary { switch secondary {
case .extensionPayload:
return CGSize(width: badgeSize * 0.14, height: badgeSize * 0.12)
default: default:
return CGSize(width: badgeSize * 0.2, height: badgeSize * 0.25) return CGSize(width: badgeSize * 0.2, height: badgeSize * 0.25)
} }
@ -1181,6 +1193,15 @@ struct ContentView: View {
return nil return nil
} }
guard closedMusicContentEnabled else {
ExtensionRoutingDiagnostics.shared.logSuppression(
.music,
reason: "music content disabled",
pendingCount: candidates.count
)
return nil
}
guard vm.notchState == .closed else { guard vm.notchState == .closed else {
ExtensionRoutingDiagnostics.shared.logSuppression( ExtensionRoutingDiagnostics.shared.logSuppression(
.music, .music,
@ -1706,6 +1727,26 @@ struct ContentView: View {
} }
} }
private func handleStandardMediaControlsAvailabilityChange() {
guard musicControlWindowEnabled else {
hideMusicControlWindow()
return
}
if standardMediaControlsActive {
if musicManager.isPlaying || !musicManager.isPlayerIdle {
clearMusicControlVisibilityDeadline()
}
enqueueMusicControlWindowSync(forceRefresh: true)
} else {
cancelMusicControlWindowSync()
hideMusicControlWindow()
clearMusicControlVisibilityDeadline()
hasPendingMusicControlSync = false
pendingMusicControlForceRefresh = false
}
}
private func extendMusicControlVisibilityAfterPause() { private func extendMusicControlVisibilityAfterPause() {
let deadline = Date().addingTimeInterval(musicControlPauseGrace) let deadline = Date().addingTimeInterval(musicControlPauseGrace)
musicControlVisibilityDeadline = deadline musicControlVisibilityDeadline = deadline
@ -1817,6 +1858,7 @@ struct ContentView: View {
private func shouldShowMusicControlWindow() -> Bool { private func shouldShowMusicControlWindow() -> Bool {
guard musicControlWindowEnabled, guard musicControlWindowEnabled,
coordinator.musicLiveActivityEnabled, coordinator.musicLiveActivityEnabled,
standardMediaControlsActive,
vm.notchState == .closed, vm.notchState == .closed,
!vm.hideOnClosed, !vm.hideOnClosed,
!lockScreenManager.isLocked, !lockScreenManager.isLocked,

View file

@ -1,9 +1,20 @@
// /*
// DynamicIslandApp.swift * Atoll (DynamicIsland)
// DynamicIslandApp * Copyright (C) 2024-2026 Atoll Contributors
// *
// Modified by Hariharan Mudaliar on 20/09/25. * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import AVFoundation import AVFoundation
import Combine import Combine
@ -90,6 +101,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
let idleAnimationManager = IdleAnimationManager.shared // NEW: Custom idle animations let idleAnimationManager = IdleAnimationManager.shared // NEW: Custom idle animations
let downloadManager = DownloadManager.shared // NEW: Chromium downloads detection let downloadManager = DownloadManager.shared // NEW: Chromium downloads detection
let lockScreenPanelManager = LockScreenPanelManager.shared // NEW: Lock screen music panel let lockScreenPanelManager = LockScreenPanelManager.shared // NEW: Lock screen music panel
let mediaControlsStateCoordinator = MediaControlsStateCoordinator.shared
let systemTimerBridge = SystemTimerBridge.shared let systemTimerBridge = SystemTimerBridge.shared
let extensionXPCServiceHost = ExtensionXPCServiceHost.shared let extensionXPCServiceHost = ExtensionXPCServiceHost.shared
var closeNotchWorkItem: DispatchWorkItem? var closeNotchWorkItem: DispatchWorkItem?
@ -209,6 +221,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
defer: false defer: false
) )
window.animationBehavior = .none
window.contentView = NSHostingView( window.contentView = NSHostingView(
rootView: ContentView() rootView: ContentView()
.environmentObject(viewModel) .environmentObject(viewModel)
@ -253,6 +267,11 @@ class AppDelegate: NSObject, NSApplicationDelegate {
resizeWindows(to: requiredSize, animated: animateResize, force: false) resizeWindows(to: requiredSize, animated: animateResize, force: false)
} }
private func updateWindowSizeForTabSwitch() {
let requiredSize = calculateRequiredNotchSize()
resizeWindows(to: requiredSize, animated: false, force: true)
}
private func calculateRequiredNotchSize() -> CGSize { private func calculateRequiredNotchSize() -> CGSize {
// Check if inline sneak peek is showing and notch is closed // Check if inline sneak peek is showing and notch is closed
let isInlineSneakPeekActive = vm.notchState == .closed && let isInlineSneakPeekActive = vm.notchState == .closed &&
@ -320,17 +339,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
let newY = screenFrame.origin.y + screenFrame.height - size.height let newY = screenFrame.origin.y + screenFrame.height - size.height
let targetFrame = NSRect(x: newX, y: newY, width: size.width, height: size.height) let targetFrame = NSRect(x: newX, y: newY, width: size.width, height: size.height)
if animated {
NSAnimationContext.runAnimationGroup { context in
context.duration = 0.25
context.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
context.allowsImplicitAnimation = true
window.animator().setFrame(targetFrame, display: true)
}
} else {
window.setFrame(targetFrame, display: true) window.setFrame(targetFrame, display: true)
} }
}
private func shouldAnimateResize(for newSize: CGSize) -> Bool { private func shouldAnimateResize(for newSize: CGSize) -> Bool {
if Defaults[.enableMinimalisticUI] && !ReminderLiveActivityManager.shared.activeWindowReminders.isEmpty { if Defaults[.enableMinimalisticUI] && !ReminderLiveActivityManager.shared.activeWindowReminders.isEmpty {
@ -353,6 +363,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
// Initialize idle animations (load bundled + built-in face) // Initialize idle animations (load bundled + built-in face)
idleAnimationManager.initializeDefaultAnimations() idleAnimationManager.initializeDefaultAnimations()
applySelectedAppIcon()
// Setup SystemHUD Manager // Setup SystemHUD Manager
SystemHUDManager.shared.setup(coordinator: coordinator) SystemHUDManager.shared.setup(coordinator: coordinator)
@ -369,9 +381,9 @@ class AppDelegate: NSObject, NSApplicationDelegate {
// Setup Privacy Indicator Manager (camera and microphone monitoring) // Setup Privacy Indicator Manager (camera and microphone monitoring)
PrivacyIndicatorManager.shared.startMonitoring() PrivacyIndicatorManager.shared.startMonitoring()
// Observe tab changes - use immediate updates to prevent clipping // Observe tab changes - use immediate resize to keep the notch pinned
coordinator.$currentView.sink { [weak self] newView in coordinator.$currentView.sink { [weak self] _ in
self?.updateWindowSizeIfNeeded() self?.updateWindowSizeForTabSwitch()
}.store(in: &cancellables) }.store(in: &cancellables)
coordinator.$notesLayoutState coordinator.$notesLayoutState
@ -889,3 +901,98 @@ extension CGRect: @retroactive Hashable {
return lhs.origin == rhs.origin && lhs.size == rhs.size return lhs.origin == rhs.origin && lhs.size == rhs.size
} }
} }
@MainActor
final class MediaControlsStateCoordinator {
static let shared = MediaControlsStateCoordinator()
private var cancellables = Set<AnyCancellable>()
private init() {
let masterPublisher = Defaults.publisher(.showStandardMediaControls)
let minimalisticPublisher = Defaults.publisher(.enableMinimalisticUI)
Publishers.CombineLatest(masterPublisher, minimalisticPublisher)
.receive(on: RunLoop.main)
.sink { [weak self] masterChange, minimalisticChange in
self?.handleStateChange(
showStandard: masterChange.newValue,
minimalistic: minimalisticChange.newValue
)
}
.store(in: &cancellables)
}
private func handleStateChange(showStandard: Bool, minimalistic: Bool) {
if !showStandard && !minimalistic {
cacheAndDisableMusicLiveActivity()
} else {
restoreMusicLiveActivity(clearCache: showStandard)
}
if showStandard {
restoreLockScreenPanelIfNeeded()
restoreMusicControlWindowIfNeeded()
} else {
cacheAndDisableLockScreenPanel()
cacheAndDisableMusicControlWindow()
}
}
private func cacheAndDisableMusicLiveActivity() {
if Defaults[.cachedMusicLiveActivityPreference] == nil {
Defaults[.cachedMusicLiveActivityPreference] = DynamicIslandViewCoordinator.shared.musicLiveActivityEnabled
}
if DynamicIslandViewCoordinator.shared.musicLiveActivityEnabled {
DynamicIslandViewCoordinator.shared.musicLiveActivityEnabled = false
}
}
private func restoreMusicLiveActivity(clearCache: Bool) {
guard let cached = Defaults[.cachedMusicLiveActivityPreference] else { return }
if DynamicIslandViewCoordinator.shared.musicLiveActivityEnabled != cached {
DynamicIslandViewCoordinator.shared.musicLiveActivityEnabled = cached
}
if clearCache {
Defaults[.cachedMusicLiveActivityPreference] = nil
}
}
private func cacheAndDisableLockScreenPanel() {
if Defaults[.cachedLockScreenMediaWidgetPreference] == nil {
Defaults[.cachedLockScreenMediaWidgetPreference] = Defaults[.enableLockScreenMediaWidget]
}
if Defaults[.enableLockScreenMediaWidget] {
Defaults[.enableLockScreenMediaWidget] = false
LockScreenPanelManager.shared.hidePanel()
}
}
private func restoreLockScreenPanelIfNeeded() {
guard let cached = Defaults[.cachedLockScreenMediaWidgetPreference] else { return }
Defaults[.enableLockScreenMediaWidget] = cached
Defaults[.cachedLockScreenMediaWidgetPreference] = nil
}
private func cacheAndDisableMusicControlWindow() {
if Defaults[.cachedMusicControlWindowPreference] == nil {
Defaults[.cachedMusicControlWindowPreference] = Defaults[.musicControlWindowEnabled]
}
if Defaults[.musicControlWindowEnabled] {
Defaults[.musicControlWindowEnabled] = false
}
MusicControlWindowManager.shared.hide()
}
private func restoreMusicControlWindowIfNeeded() {
guard let cached = Defaults[.cachedMusicControlWindowPreference] else { return }
Defaults[.musicControlWindowEnabled] = cached
Defaults[.cachedMusicControlWindowPreference] = nil
}
}

View file

@ -1,9 +1,20 @@
// /*
// DynamicIslandViewCoordinator.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Alexander on 2024-11-20. * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Combine import Combine
import Defaults import Defaults
@ -102,9 +113,6 @@ class DynamicIslandViewCoordinator: ObservableObject {
} }
@Published var statsSecondRowExpansion: CGFloat = 1 @Published var statsSecondRowExpansion: CGFloat = 1
private var statsSecondRowWorkItem: DispatchWorkItem?
private let statsSecondRowRevealDelay: TimeInterval = 0.5
private let statsSecondRowAnimationDuration: TimeInterval = 0.3
@Published var notesLayoutState: NotesLayoutState = .list @Published var notesLayoutState: NotesLayoutState = .list
@Published var selectedExtensionExperienceID: String? @Published var selectedExtensionExperienceID: String?
@ -206,22 +214,8 @@ class DynamicIslandViewCoordinator: ObservableObject {
private func handleStatsTabTransition(from oldValue: NotchViews, to newValue: NotchViews) { private func handleStatsTabTransition(from oldValue: NotchViews, to newValue: NotchViews) {
guard oldValue != newValue else { return } guard oldValue != newValue else { return }
statsSecondRowWorkItem?.cancel()
if newValue == .stats && Defaults[.enableStatsFeature] { if newValue == .stats && Defaults[.enableStatsFeature] {
statsSecondRowExpansion = 0 statsSecondRowExpansion = 1
let workItem = DispatchWorkItem { [weak self] in
guard let self else { return }
withAnimation(.easeInOut(duration: self.statsSecondRowAnimationDuration)) {
self.statsSecondRowExpansion = 1
}
self.statsSecondRowWorkItem = nil
}
statsSecondRowWorkItem = workItem
DispatchQueue.main.asyncAfter(deadline: .now() + statsSecondRowRevealDelay, execute: workItem)
} else {
withAnimation(.easeInOut(duration: 0.2)) {
statsSecondRowExpansion = 0
}
} }
} }

View file

@ -356,10 +356,6 @@
} }
} }
}, },
"\"Atoll\" vorrebbe accedere ai dati delle notifiche di sistema." : {
"comment" : "An alert message explaining that the app wants to access the user's notification database.",
"isCommentAutoGenerated" : true
},
"(%@)" : { "(%@)" : {
"localizations" : { "localizations" : {
"ar" : { "ar" : {
@ -1527,10 +1523,6 @@
} }
} }
}, },
">" : {
"comment" : "A symbol used to separate different parts of a Discord notification header.",
"isCommentAutoGenerated" : true
},
"0" : { "0" : {
"comment" : "A label displayed in a circular gauge to indicate the minimum battery level.", "comment" : "A label displayed in a circular gauge to indicate the minimum battery level.",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
@ -2326,6 +2318,9 @@
} }
} }
} }
},
"Add icon" : {
}, },
"Add manually" : { "Add manually" : {
"extractionState" : "stale", "extractionState" : "stale",
@ -3488,10 +3483,6 @@
} }
} }
}, },
"Annulla" : {
"comment" : "The text on a button that dismisses an alert.",
"isCommentAutoGenerated" : true
},
"API Configuration" : { "API Configuration" : {
"localizations" : { "localizations" : {
"fr" : { "fr" : {
@ -3758,10 +3749,6 @@
} }
} }
}, },
"Apri Impostazioni di Sistema" : {
"comment" : "A button that opens system settings to allow access to the app.",
"isCommentAutoGenerated" : true
},
"Are you sure you want to delete \"%@\"?" : { "Are you sure you want to delete \"%@\"?" : {
"comment" : "A confirmation prompt asking the user to confirm the deletion of a custom idle animation. The placeholder text inside the quotation marks should be replaced with the name of the animation.", "comment" : "A confirmation prompt asking the user to confirm the deletion of a custom idle animation. The placeholder text inside the quotation marks should be replaced with the name of the animation.",
"localizations" : { "localizations" : {
@ -3823,6 +3810,7 @@
"shouldTranslate" : false "shouldTranslate" : false
}, },
"Atoll can show all your upcoming events in one place. Access to your calendar is needed to display your schedule." : { "Atoll can show all your upcoming events in one place. Access to your calendar is needed to display your schedule." : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"pt-BR" : { "pt-BR" : {
"stringUnit" : { "stringUnit" : {
@ -3833,6 +3821,7 @@
} }
}, },
"Atoll includes a mirror feature that lets you quickly check your appearance using your camera, right from the notch. Camera access is required only to show this live preview. You can turn the mirror feature on or off at any time in the app." : { "Atoll includes a mirror feature that lets you quickly check your appearance using your camera, right from the notch. Camera access is required only to show this live preview. You can turn the mirror feature on or off at any time in the app." : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"pt-BR" : { "pt-BR" : {
"stringUnit" : { "stringUnit" : {
@ -3843,6 +3832,7 @@
} }
}, },
"Atoll needs Full Disk Access to read the system notification database. If Atoll does not appear in the list, use 'Reveal App in Finder' and drag it into the settings window." : { "Atoll needs Full Disk Access to read the system notification database. If Atoll does not appear in the list, use 'Reveal App in Finder' and drag it into the settings window." : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"pt-BR" : { "pt-BR" : {
"stringUnit" : { "stringUnit" : {
@ -6550,10 +6540,6 @@
} }
} }
}, },
"Close Setup" : {
"comment" : "A button that closes the WhatsApp setup view.",
"isCommentAutoGenerated" : true
},
"Collect the latest crash report to share with the developer when reporting lock screen or overlay issues." : { "Collect the latest crash report to share with the developer when reporting lock screen or overlay issues." : {
"comment" : "A footer for the \"Diagnostics\" section of the lock screen settings.", "comment" : "A footer for the \"Diagnostics\" section of the lock screen settings.",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
@ -6902,15 +6888,8 @@
} }
} }
}, },
"Connect" : {
"comment" : "A button that either manages or connects to WhatsApp.",
"isCommentAutoGenerated" : true
},
"Connect your web accounts to enable background replies. You only need to log in once." : {
"comment" : "A footer in the \"Messages\" settings page, explaining how to connect web accounts for background replies.",
"isCommentAutoGenerated" : true
},
"Connected" : { "Connected" : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"fr" : { "fr" : {
"stringUnit" : { "stringUnit" : {
@ -6920,14 +6899,6 @@
} }
} }
}, },
"Connected!" : {
"comment" : "A message displayed when the user successfully links their WhatsApp account to the app.",
"isCommentAutoGenerated" : true
},
"Consenti l'accesso a questa applicazione tramite le impostazioni \"Privacy e sicurezza\" in Impostazioni di Sistema per poter visualizzare i messaggi nella Dynamic Island." : {
"comment" : "A message displayed when the user denies access to the app's notifications.",
"isCommentAutoGenerated" : true
},
"Continue" : { "Continue" : {
"localizations" : { "localizations" : {
"ar" : { "ar" : {
@ -8450,6 +8421,9 @@
} }
} }
} }
},
"Disable Minimalistic UI to configure the standard notch media controls." : {
}, },
"Disabled" : { "Disabled" : {
"localizations" : { "localizations" : {
@ -8551,10 +8525,6 @@
} }
} }
}, },
"Discord" : {
"comment" : "The name of the Discord section in the settings menu.",
"isCommentAutoGenerated" : true
},
"Discrete transitions snap between Green (0–60%), Yellow (60–85%), and Red (85–100%)." : { "Discrete transitions snap between Green (0–60%), Yellow (60–85%), and Red (85–100%)." : {
"comment" : "A description of how the color-coded progress bars work when not using smooth transitions.", "comment" : "A description of how the color-coded progress bars work when not using smooth transitions.",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
@ -8674,6 +8644,10 @@
} }
} }
}, },
"Donate" : {
"comment" : "A button label that says \"Donate\".",
"isCommentAutoGenerated" : true
},
"Done" : { "Done" : {
"comment" : "A button label that indicates that the user has finished editing a note.", "comment" : "A button label that indicates that the user has finished editing a note.",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
@ -8991,6 +8965,9 @@
} }
} }
} }
},
"Drop a PNG, JPEG, TIFF, or ICNS file to add it to your icon library." : {
}, },
"Drop files here" : { "Drop files here" : {
"localizations" : { "localizations" : {
@ -9103,6 +9080,9 @@
} }
} }
} }
},
"Dynamic Island Visibility" : {
}, },
"dynamic.island" : { "dynamic.island" : {
"localizations" : { "localizations" : {
@ -9405,6 +9385,7 @@
} }
}, },
"Enable Calendar Access" : { "Enable Calendar Access" : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"pt-BR" : { "pt-BR" : {
"stringUnit" : { "stringUnit" : {
@ -9415,6 +9396,7 @@
} }
}, },
"Enable Camera Access" : { "Enable Camera Access" : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"pt-BR" : { "pt-BR" : {
"stringUnit" : { "stringUnit" : {
@ -9552,6 +9534,9 @@
} }
} }
} }
},
"Enable Dynamic Island media controls to manage the lock screen panel." : {
}, },
"Enable extensions to allow third-party apps to display live activities and lock screen widgets in Atoll." : { "Enable extensions to allow third-party apps to display live activities and lock screen widgets in Atoll." : {
"comment" : "A footer text that explains the purpose of enabling extensions.", "comment" : "A footer text that explains the purpose of enabling extensions.",
@ -10823,6 +10808,7 @@
} }
}, },
"Full Disk Access required" : { "Full Disk Access required" : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"pt-BR" : { "pt-BR" : {
"stringUnit" : { "stringUnit" : {
@ -10959,10 +10945,6 @@
} }
} }
}, },
"Generating QR Code..." : {
"comment" : "A message displayed while the QR code is being generated.",
"isCommentAutoGenerated" : true
},
"Gesture control" : { "Gesture control" : {
"localizations" : { "localizations" : {
"ar" : { "ar" : {
@ -11701,10 +11683,6 @@
} }
} }
}, },
"Hide Browser" : {
"comment" : "A button label that toggles the visibility of the web view in the WhatsApp link setup.",
"isCommentAutoGenerated" : true
},
"Hide completed reminders" : { "Hide completed reminders" : {
"comment" : "A toggle that lets the user hide completed reminders", "comment" : "A toggle that lets the user hide completed reminders",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
@ -12852,10 +12830,6 @@
} }
} }
}, },
"Intercept notifications from WhatsApp, Telegram, and Messages to see them in the Dynamic Island." : {
"comment" : "A footer description for the Messages settings view, explaining how to use the feature.",
"isCommentAutoGenerated" : true
},
"IPv4 · %@" : { "IPv4 · %@" : {
"comment" : "A label displaying an IP address for a network interface. The text inside the parentheses is the IP address of the interface.", "comment" : "A label displaying an IP address for a network interface. The text inside the parentheses is the IP address of the interface.",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
@ -13122,15 +13096,8 @@
} }
} }
}, },
"Link WhatsApp" : {
"comment" : "A button that links Atoll to WhatsApp.",
"isCommentAutoGenerated" : true
},
"Linked Accounts" : {
"comment" : "A section header that lists the user's linked web accounts.",
"isCommentAutoGenerated" : true
},
"LinkedIn" : { "LinkedIn" : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"fr" : { "fr" : {
"stringUnit" : { "stringUnit" : {
@ -13734,10 +13701,6 @@
} }
} }
}, },
"Manage" : {
"comment" : "The label of a button that, when pressed, shows a view allowing the user to manage their connected accounts.",
"isCommentAutoGenerated" : true
},
"Manage indicator preferences from Settings → Privacy. No manual microphone toggle is required." : { "Manage indicator preferences from Settings → Privacy. No manual microphone toggle is required." : {
"comment" : "A description of how to manage the microphone privacy indicator preferences.", "comment" : "A description of how to manage the microphone privacy indicator preferences.",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
@ -14960,6 +14923,7 @@
}, },
"Messages" : { "Messages" : {
"comment" : "The title of the \"Messages\" settings page.", "comment" : "The title of the \"Messages\" settings page.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
"localizations" : { "localizations" : {
"pt-BR" : { "pt-BR" : {
@ -16843,9 +16807,6 @@
} }
} }
} }
},
"No notifications" : {
}, },
"No presets configured. Add a preset to make it appear in the timer popover." : { "No presets configured. Add a preset to make it appear in the timer popover." : {
"comment" : "A message displayed when there are no timer presets configured, encouraging the user to add one.", "comment" : "A message displayed when there are no timer presets configured, encouraging the user to add one.",
@ -17033,10 +16994,6 @@
} }
} }
}, },
"Not Linked" : {
"comment" : "A description of a WhatsApp account that is not linked to the app.",
"isCommentAutoGenerated" : true
},
"Not Now" : { "Not Now" : {
"localizations" : { "localizations" : {
"ar" : { "ar" : {
@ -17464,10 +17421,6 @@
} }
} }
}, },
"Note: Normal mode requires Keychain access to save your session securely." : {
"comment" : "A note explaining that normal mode requires access to the user's keychain to securely save their session.",
"isCommentAutoGenerated" : true
},
"Notes" : { "Notes" : {
"comment" : "The title of the Notes settings page.", "comment" : "The title of the Notes settings page.",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
@ -17492,10 +17445,6 @@
} }
} }
}, },
"Now" : {
"comment" : "A label indicating the time the notification was sent.",
"isCommentAutoGenerated" : true
},
"OK" : { "OK" : {
"localizations" : { "localizations" : {
"ar" : { "ar" : {
@ -17743,10 +17692,6 @@
} }
} }
}, },
"Open Browser" : {
"comment" : "A button to open the web browser used for WhatsApp authentication.",
"isCommentAutoGenerated" : true
},
"Open Google AI Studio" : { "Open Google AI Studio" : {
"localizations" : { "localizations" : {
"pt-BR" : { "pt-BR" : {
@ -18301,10 +18246,6 @@
} }
} }
}, },
"Private mode: No keychain prompt, but you will need to re-link on every restart." : {
"comment" : "A description of the private mode feature in WhatsAppLinkView.",
"isCommentAutoGenerated" : true
},
"Progress bar" : { "Progress bar" : {
"extractionState" : "stale", "extractionState" : "stale",
"localizations" : { "localizations" : {
@ -18766,10 +18707,6 @@
} }
} }
}, },
"Reconnect" : {
"comment" : "A button that connects or reconnects to a Discord account.",
"isCommentAutoGenerated" : true
},
"Recording" : { "Recording" : {
"localizations" : { "localizations" : {
"fr" : { "fr" : {
@ -18820,10 +18757,6 @@
} }
} }
}, },
"Refresh" : {
"comment" : "A button label that refreshes the view.",
"isCommentAutoGenerated" : true
},
"Release name" : { "Release name" : {
"localizations" : { "localizations" : {
"ar" : { "ar" : {
@ -19096,9 +19029,8 @@
} }
} }
}, },
"Reply..." : { "Remove selected" : {
"comment" : "A placeholder text for a message reply field.",
"isCommentAutoGenerated" : true
}, },
"Request Access" : { "Request Access" : {
"localizations" : { "localizations" : {
@ -19415,10 +19347,6 @@
} }
} }
}, },
"Reveal App in Finder" : {
"comment" : "A button that reveals the app in the Finder when pressed.",
"isCommentAutoGenerated" : true
},
"Revoke Access" : { "Revoke Access" : {
"comment" : "A button that revokes access to an app.", "comment" : "A button that revokes access to an app.",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
@ -19654,10 +19582,6 @@
} }
} }
}, },
"Scan the QR code with your phone to enable background replies." : {
"comment" : "A description under the QR code that instructs the user to scan it with their phone to enable background replies.",
"isCommentAutoGenerated" : true
},
"Screen Assistant" : { "Screen Assistant" : {
"localizations" : { "localizations" : {
"pt-BR" : { "pt-BR" : {
@ -19870,10 +19794,6 @@
} }
} }
}, },
"Secure Private Mode" : {
"comment" : "A toggle that allows the user to enable or disable \"Secure Private Mode\" for the WhatsApp link.",
"isCommentAutoGenerated" : true
},
"Segmented" : { "Segmented" : {
"localizations" : { "localizations" : {
"fr" : { "fr" : {
@ -22035,6 +21955,12 @@
} }
} }
} }
},
"Standard notch media controls are hidden while this toggle is off." : {
},
"Standard notch media controls are hidden. Re-enable the toggle above to restore them." : {
}, },
"Start" : { "Start" : {
"localizations" : { "localizations" : {
@ -22613,10 +22539,6 @@
} }
} }
}, },
"Sync & Done" : {
"comment" : "A button that, when pressed, synchronizes the app with WhatsApp and then closes the setup view.",
"isCommentAutoGenerated" : true
},
"System" : { "System" : {
"comment" : "A label displayed above the system, load average, and uptime information.", "comment" : "A label displayed above the system, load average, and uptime information.",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
@ -22762,10 +22684,6 @@
} }
} }
}, },
"Telegram" : {
"comment" : "A section header for the Telegram account settings.",
"isCommentAutoGenerated" : true
},
"Temperature unit" : { "Temperature unit" : {
"localizations" : { "localizations" : {
"pt-BR" : { "pt-BR" : {
@ -24590,10 +24508,6 @@
} }
} }
}, },
"Voice Message" : {
"comment" : "A label describing a voice message.",
"isCommentAutoGenerated" : true
},
"Volume" : { "Volume" : {
"comment" : "A button that sets the preview to show a volume OSD.", "comment" : "A button that sets the preview to show a volume OSD.",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
@ -24902,10 +24816,6 @@
} }
} }
}, },
"WhatsApp" : {
"comment" : "A section header for settings related to WhatsApp.",
"isCommentAutoGenerated" : true
},
"When disabled, all keyboard shortcuts will be inactive. You can still use the UI controls." : { "When disabled, all keyboard shortcuts will be inactive. You can still use the UI controls." : {
"localizations" : { "localizations" : {
"pt-BR" : { "pt-BR" : {
@ -25232,6 +25142,7 @@
} }
}, },
"Your calendar data is only used to show your events and is never shared." : { "Your calendar data is only used to show your events and is never shared." : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"pt-BR" : { "pt-BR" : {
"stringUnit" : { "stringUnit" : {
@ -25242,6 +25153,7 @@
} }
}, },
"Your camera is never used without your consent, and nothing is recorded or stored." : { "Your camera is never used without your consent, and nothing is recorded or stored." : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"pt-BR" : { "pt-BR" : {
"stringUnit" : { "stringUnit" : {
@ -25251,6 +25163,10 @@
} }
} }
}, },
"Your support funds software development learning for students in 9th–12th grade." : {
"comment" : "A footer note explaining the app's funding.",
"isCommentAutoGenerated" : true
},
"YouTube Music requires this third-party app to be installed: " : { "YouTube Music requires this third-party app to be installed: " : {
"localizations" : { "localizations" : {
"ar" : { "ar" : {

View file

@ -1,9 +1,24 @@
// /*
// AppleMusicController.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Alexander on 2025-03-29. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Foundation import Foundation
import Combine import Combine

View file

@ -1,9 +1,24 @@
// /*
// MediaControllerProtocol.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Alexander Greco on 2025-03-29. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Foundation import Foundation
import AppKit import AppKit

View file

@ -1,9 +1,24 @@
// /*
// NowPlayingController.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Alexander on 2025-03-29. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import AppKit import AppKit
import Combine import Combine

View file

@ -1,9 +1,24 @@
// /*
// SpotifyController.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Alexander on 2025-03-29. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Foundation import Foundation
import Combine import Combine

View file

@ -1,9 +1,24 @@
// /*
// YouTubeMusicAuthentication.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Alexander on 2025-09-14. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Foundation import Foundation

View file

@ -1,10 +1,24 @@
// /*
// YouTubeMusicController.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created By Alexander on 2025-03-30. * Originally from boring.notch project
// Modified by Pranav on 2025-06-16. * Modified and adapted for Atoll (DynamicIsland)
// * See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Foundation import Foundation
import Combine import Combine

View file

@ -1,9 +1,24 @@
// /*
// YouTubeMusicModels.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Alexander on 2025-09-14. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Foundation import Foundation

View file

@ -1,9 +1,24 @@
// /*
// YouTubeMusicNetworking.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Alexander on 2025-09-14. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Foundation import Foundation

View file

@ -1,11 +1,24 @@
// /*
// CalendarServiceProvider.swift * Atoll (DynamicIsland)
// Calendr * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Paker on 31/12/20. * Originally from boring.notch project
// Original source: Original source: https://github.com/pakerwreah/Calendr * Modified and adapted for Atoll (DynamicIsland)
// Modified by Alexander on 08/06/25 * See NOTICE for details.
// *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Foundation import Foundation
import EventKit import EventKit

View file

@ -1,9 +1,24 @@
// /*
// Constants.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Richard Kunkli on 16/08/2024. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import KeyboardShortcuts import KeyboardShortcuts
import SwiftUI import SwiftUI

View file

@ -1,13 +1,24 @@
// /*
// HelloAnimation.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Harsh Vardhan Goswami on 04/08/24. * Originally from boring.notch project
// HelloAnimation.swift * Modified and adapted for Atoll (DynamicIsland)
// DynamicIsland * See NOTICE for details.
// *
// Created by Harsh Vardhan Goswami on 08/08/24. * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI

View file

@ -1,9 +1,24 @@
// /*
// drop.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Harsh Vardhan Goswami on 04/08/24. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Foundation import Foundation
import SwiftUI import SwiftUI

View file

@ -1,8 +1,24 @@
// /*
// AnimatedFace.swift * Atoll (DynamicIsland)
// * Copyright (C) 2024-2026 Atoll Contributors
// Created by Harsh Vardhan Goswami on 04/08/24. *
// * Originally from boring.notch project
* Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI

View file

@ -1,4 +1,24 @@
/*
* Atoll (DynamicIsland)
* Copyright (C) 2024-2026 Atoll Contributors
*
* Originally from boring.notch project
* Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI

View file

@ -1,9 +1,20 @@
// /*
// DynamicIslandCalendar.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Harsh Vardhan Goswami on 08/09/24. * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,9 +1,20 @@
// /*
// ReminderLiveActivity.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by GitHub Copilot on 2025-11-12. * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,9 +1,20 @@
// /*
// ClipboardPanel.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Ebullioscopic on 12/08/25. * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import AppKit import AppKit
import SwiftUI import SwiftUI

View file

@ -1,9 +1,20 @@
// /*
// ClipboardPopover.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Ebullioscopic on 13/08/25. * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,9 +1,20 @@
// /*
// ClipboardShared.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Ebullioscopic on 12/08/25. * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI

View file

@ -1,9 +1,20 @@
// /*
// ClipboardWindow.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Ebullioscopic on 12/08/25. * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,10 +1,20 @@
// /*
// ColorCodedProgressBar.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created for color-coded battery and volume displays * This program is free software: you can redistribute it and/or modify
// Provides smooth gradient transitions from red to green (or reversed) * it under the terms of the GNU General Public License as published by
// * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,9 +1,20 @@
// /*
// ColorPickedFeedbackView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Ebullioscopic on 14/08/25. * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,9 +1,20 @@
// /*
// ColorPickerPanel.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Ebullioscopic on 14/08/25. * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Cocoa import Cocoa

View file

@ -1,9 +1,20 @@
// /*
// ColorPickerPopover.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Ebullioscopic on 14/08/25. * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,10 +1,20 @@
// /*
// DownloadLiveActivity.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Shows a download indicator when Chromium-style downloads * This program is free software: you can redistribute it and/or modify
// are detected in the user's Downloads folder. * it under the terms of the GNU General Public License as published by
// * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,3 +1,21 @@
/*
* Atoll (DynamicIsland)
* Copyright (C) 2024-2026 Atoll Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
struct SpinningCircleDownloadView: View { struct SpinningCircleDownloadView: View {

View file

@ -1,13 +1,20 @@
// /*
// DynamicIslandSystemTiles.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Harsh Vardhan Goswami on 04/08/24. * This program is free software: you can redistribute it and/or modify
// DynamicIslandSystemTiles.swift * it under the terms of the GNU General Public License as published by
// DynamicIsland * the Free Software Foundation, either version 3 of the License, or
// * (at your option) any later version.
// Created by Harsh Vardhan Goswami on 16/08/24. *
// * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Foundation import Foundation
import SwiftUI import SwiftUI

View file

@ -1,8 +1,24 @@
// /*
// EmptyState.swift * Atoll (DynamicIsland)
// * Copyright (C) 2024-2026 Atoll Contributors
// Created by Harsh Vardhan Goswami on 04/08/24. *
// * Originally from boring.notch project
* Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI

View file

@ -1,3 +1,21 @@
/*
* Atoll (DynamicIsland)
* Copyright (C) 2024-2026 Atoll Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults
import AtollExtensionKit import AtollExtensionKit

View file

@ -1,3 +1,21 @@
/*
* Atoll (DynamicIsland)
* Copyright (C) 2024-2026 Atoll Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults
import AtollExtensionKit import AtollExtensionKit

View file

@ -1,3 +1,21 @@
/*
* Atoll (DynamicIsland)
* Copyright (C) 2024-2026 Atoll Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import AppKit import AppKit
import AtollExtensionKit import AtollExtensionKit
@ -202,6 +220,63 @@ struct ExtensionCompositeIconView: View {
} }
} }
struct ExtensionBadgeIconView: View {
let descriptor: AtollIconDescriptor
let accent: Color
let size: CGFloat
private var symbolSize: CGFloat { size * 0.5 }
private var imageSize: CGFloat { size * 0.62 }
private var imageCornerRadius: CGFloat { size * 0.18 }
var body: some View {
Group {
switch descriptor {
case let .symbol(name, _, weight):
Image(systemName: name)
.font(.system(size: symbolSize, weight: weight.swiftUI))
.foregroundStyle(accent)
case let .image(data, _, _):
if let image = NSImage(data: data) {
Image(nsImage: image)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: imageSize, height: imageSize)
.clipShape(RoundedRectangle(cornerRadius: imageCornerRadius, style: .continuous))
} else {
fallbackSymbol
}
case let .appIcon(bundleIdentifier, _, _):
if let icon = AppIconAsNSImage(for: bundleIdentifier) {
Image(nsImage: icon)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: imageSize, height: imageSize)
.clipShape(RoundedRectangle(cornerRadius: imageCornerRadius, style: .continuous))
} else {
fallbackSymbol
}
case let .lottie(animationData, _):
ExtensionLottieView(data: animationData, size: CGSize(width: imageSize, height: imageSize))
case .none:
fallbackSymbol
}
}
.frame(width: size, height: size)
}
private var fallbackSymbol: some View {
Image(systemName: "app.dashed")
.font(.system(size: symbolSize, weight: .medium))
.foregroundStyle(accent)
.frame(width: imageSize, height: imageSize)
.background(
RoundedRectangle(cornerRadius: imageCornerRadius, style: .continuous)
.fill(accent.opacity(0.15))
)
}
}
// MARK: - Lottie Rendering // MARK: - Lottie Rendering
struct ExtensionLottieView: View { struct ExtensionLottieView: View {

View file

@ -1,10 +1,20 @@
// /*
// DoNotDisturbLiveActivity.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Renders the closed-notch Focus indicator with per-mode colours and * This program is free software: you can redistribute it and/or modify
// an icon-first layout that collapses gracefully when Focus ends. * it under the terms of the GNU General Public License as published by
// * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import AppKit import AppKit
import Defaults import Defaults

View file

@ -1,9 +1,24 @@
// /*
// HoverButton.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Kraigo on 04.09.2024. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI

View file

@ -1,10 +1,20 @@
// /*
// IdleAnimationView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by AI Assistant on 11/10/2025. * This program is free software: you can redistribute it and/or modify
// Unified view for displaying idle animations (Lottie or built-in face) * it under the terms of the GNU General Public License as published by
// * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Lottie import Lottie

View file

@ -1,9 +1,24 @@
// /*
// DownloadView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Harsh Vardhan Goswami on 17/08/24. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Foundation import Foundation
import SwiftUI import SwiftUI

View file

@ -1,3 +1,21 @@
/*
* Atoll (DynamicIsland)
* Copyright (C) 2024-2026 Atoll Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,9 +1,24 @@
// /*
// InlineHUDs.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Richard Kunkli on 14/09/2024. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,9 +1,24 @@
// /*
// LiveActivityModifier.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Richard Kunkli on 12/08/2024. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI

View file

@ -1,9 +1,24 @@
// /*
// MarqueeTextView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Richard Kunkli on 08/08/2024. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI

View file

@ -1,9 +1,24 @@
// /*
// SystemEventIndicatorModifier.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Richard Kunkli on 12/08/2024. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,9 +1,20 @@
// /*
// LockIconAnimationView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Shared animator and SwiftUI Lottie rendering for the lock/unlock sequence. * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Lottie import Lottie

View file

@ -1 +1,18 @@
// Legacy placeholder file superseded by LockScreenLiveActivityOverlay.swift. /*
* Atoll (DynamicIsland)
* Copyright (C) 2024-2026 Atoll Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

View file

@ -1,9 +1,20 @@
// /*
// LockScreenLiveActivity.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created for lock screen live activity * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,3 +1,21 @@
/*
* Atoll (DynamicIsland)
* Copyright (C) 2024-2026 Atoll Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
final class LockScreenLiveActivityOverlayModel: ObservableObject { final class LockScreenLiveActivityOverlayModel: ObservableObject {

View file

@ -1,9 +1,20 @@
// /*
// LockScreenMusicPanel.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created for lock screen music panel with liquid glass effect * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,3 +1,21 @@
/*
* Atoll (DynamicIsland)
* Copyright (C) 2024-2026 Atoll Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
struct LockScreenReminderWidget: View { struct LockScreenReminderWidget: View {

View file

@ -1,3 +1,21 @@
/*
* Atoll (DynamicIsland)
* Copyright (C) 2024-2026 Atoll Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,3 +1,21 @@
/*
* Atoll (DynamicIsland)
* Copyright (C) 2024-2026 Atoll Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,10 +1,20 @@
// /*
// MinimalisticMusicView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created for minimalistic UI mode * This program is free software: you can redistribute it and/or modify
// A clean, focused music player for closed notch state * it under the terms of the GNU General Public License as published by
// * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,9 +1,20 @@
// /*
// LiveStreamProgressIndicator.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Shared indicator used for live stream playback timelines. * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI

View file

@ -1,9 +1,24 @@
// /*
// LottieAnimationView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Richard Kunkli on 2024. 10. 29.. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Lottie import Lottie

View file

@ -1,3 +1,21 @@
/*
* Atoll (DynamicIsland)
* Copyright (C) 2024-2026 Atoll Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,9 +1,25 @@
// /*
// MusicVisualizer.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Harsh Vardhan Goswami on 02/08/24. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import AppKit import AppKit
import Cocoa import Cocoa
import SwiftUI import SwiftUI

View file

@ -1,9 +1,20 @@
// /*
// ClipboardHistoryPopover.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Ebullioscopic on 17/07/25. * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI

View file

@ -1,9 +1,20 @@
// /*
// DynamicIslandExtrasMenu.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Harsh Vardhan Goswami on 04/08/24. * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI

View file

@ -1,9 +1,20 @@
// /*
// DynamicIslandHeader.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Harsh Vardhan Goswami on 04/08/24. * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Defaults import Defaults
import SwiftUI import SwiftUI

View file

@ -1,9 +1,24 @@
// /*
// DynamicIslandWindow.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Harsh Vardhan Goswami on 06/08/24. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Cocoa import Cocoa

View file

@ -1,9 +1,20 @@
// /*
// MinimalisticMusicPlayerView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created for minimalistic UI mode - Open state music player * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,9 +1,20 @@
// /*
// NotchColorPickerView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Ebullioscopic on 14/08/25. * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,10 +1,24 @@
// /*
// NotchHomeView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Hugo Persson on 2024-08-18. * Originally from boring.notch project
// Modified by Harsh Vardhan Goswami & Richard Kunkli & Mustafa Ramadan * Modified and adapted for Atoll (DynamicIsland)
// * See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Combine import Combine
import Defaults import Defaults
@ -383,6 +397,7 @@ struct NotchHomeView: View {
@ObservedObject var batteryModel = BatteryStatusViewModel.shared @ObservedObject var batteryModel = BatteryStatusViewModel.shared
@ObservedObject var coordinator = DynamicIslandViewCoordinator.shared @ObservedObject var coordinator = DynamicIslandViewCoordinator.shared
@ObservedObject private var extensionNotchExperienceManager = ExtensionNotchExperienceManager.shared @ObservedObject private var extensionNotchExperienceManager = ExtensionNotchExperienceManager.shared
@Default(.showStandardMediaControls) private var showStandardMediaControls
let albumArtNamespace: Namespace.ID let albumArtNamespace: Namespace.ID
var body: some View { var body: some View {
@ -407,8 +422,10 @@ struct NotchHomeView: View {
} }
} else { } else {
// Normal mode: Show full music player with optional calendar and webcam // Normal mode: Show full music player with optional calendar and webcam
if showStandardMediaControls {
MusicPlayerView(albumArtNamespace: albumArtNamespace) MusicPlayerView(albumArtNamespace: albumArtNamespace)
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
}
if Defaults[.showCalendar] { if Defaults[.showCalendar] {
CalendarView() CalendarView()

View file

@ -1,9 +1,20 @@
// /*
// NotchNotesView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Assistant * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,10 +1,24 @@
// /*
// NotchShape.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Kai Azim on 2023-08-24. * Originally from boring.notch project
// Original source: https://github.com/MrKai77/DynamicNotchKit * Modified and adapted for Atoll (DynamicIsland)
// Modified by Alexander on 2025-05-18. * See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI

View file

@ -1,3 +1,20 @@
/*
* Atoll (DynamicIsland)
* Copyright (C) 2024-2026 Atoll Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI

View file

@ -1,9 +1,20 @@
// /*
// NotchStatsView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Adapted from boring.notch StatsView * This program is free software: you can redistribute it and/or modify
// Stats tab view for system performance monitoring with clickable process popovers * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults
@ -63,9 +74,6 @@ struct NotchStatsView: View {
@State private var isHoveringGPUPopover = false @State private var isHoveringGPUPopover = false
@State private var isHoveringNetworkPopover = false @State private var isHoveringNetworkPopover = false
@State private var isHoveringDiskPopover = false @State private var isHoveringDiskPopover = false
@State private var isResizingForStats = false
@State private var statsHoverGraceActive = false
@State private var statsHoverGraceWorkItem: DispatchWorkItem?
@EnvironmentObject var vm: DynamicIslandViewModel @EnvironmentObject var vm: DynamicIslandViewModel
@ObservedObject var coordinator = DynamicIslandViewCoordinator.shared @ObservedObject var coordinator = DynamicIslandViewCoordinator.shared
@ -149,8 +157,8 @@ struct NotchStatsView: View {
} }
} }
} else if graphCount == 4 { } else if graphCount == 4 {
// 4 graphs: second row scales from zero height on tab open // 4 graphs: two rows (2x2) without a collapsible expansion
VStack(spacing: 0) { VStack(spacing: statsGridSpacingHeight) {
LazyVGrid( LazyVGrid(
columns: Array(repeating: GridItem(.flexible(), spacing: 8), count: 2), columns: Array(repeating: GridItem(.flexible(), spacing: 8), count: 2),
spacing: 12 spacing: 12
@ -159,11 +167,6 @@ struct NotchStatsView: View {
graphViewForIndex(index) graphViewForIndex(index)
} }
} }
StatsCollapsibleRow(
expansion: coordinator.statsSecondRowExpansion,
height: statsSecondRowContentHeight + statsGridSpacingHeight
) {
LazyVGrid( LazyVGrid(
columns: Array(repeating: GridItem(.flexible(), spacing: 8), count: 2), columns: Array(repeating: GridItem(.flexible(), spacing: 8), count: 2),
spacing: 12 spacing: 12
@ -172,13 +175,10 @@ struct NotchStatsView: View {
graphViewForIndex(index) graphViewForIndex(index)
} }
} }
.padding(.top, statsGridSpacingHeight)
}
} }
} else { } else {
// 5 graphs: First row 3 graphs, second row 2 graphs (half-width each) // 5 graphs: First row 3 graphs, second row 2 graphs (half-width each)
VStack(spacing: 0) { VStack(spacing: statsGridSpacingHeight) {
// First row: 3 graphs
LazyVGrid( LazyVGrid(
columns: Array(repeating: GridItem(.flexible(), spacing: 8), count: 3), columns: Array(repeating: GridItem(.flexible(), spacing: 8), count: 3),
spacing: 8 spacing: 8
@ -187,11 +187,6 @@ struct NotchStatsView: View {
graphViewForIndex(index) graphViewForIndex(index)
} }
} }
// Second row: 2 graphs (half-width each)
StatsCollapsibleRow(
expansion: coordinator.statsSecondRowExpansion,
height: statsSecondRowContentHeight + statsGridSpacingHeight
) {
LazyVGrid( LazyVGrid(
columns: Array(repeating: GridItem(.flexible(), spacing: 8), count: 2), columns: Array(repeating: GridItem(.flexible(), spacing: 8), count: 2),
spacing: 8 spacing: 8
@ -200,8 +195,6 @@ struct NotchStatsView: View {
graphViewForIndex(index) graphViewForIndex(index)
} }
} }
.padding(.top, statsGridSpacingHeight)
}
} }
} }
} }
@ -382,68 +375,26 @@ struct NotchStatsView: View {
.frame(maxWidth: .infinity, maxHeight: .infinity) .frame(maxWidth: .infinity, maxHeight: .infinity)
.onAppear { .onAppear {
// Note: Smart monitoring will handle starting/stopping based on notch state and current view // Note: Smart monitoring will handle starting/stopping based on notch state and current view
// Protect against hover interference during view transition
isResizingForStats = true
DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) {
isResizingForStats = false
}
} }
.onDisappear { .onDisappear {
statsHoverGraceWorkItem?.cancel()
statsHoverGraceWorkItem = nil
if statsHoverGraceActive {
statsHoverGraceActive = false
}
// Keep monitoring running when tab is not visible // Keep monitoring running when tab is not visible
updateStatsPopoverState() updateStatsPopoverState()
} }
.animation(.easeInOut(duration: 0.4), value: enableStatsFeature) .animation(.easeInOut(duration: 0.4), value: enableStatsFeature)
.animation(.easeInOut(duration: 0.4), value: availableGraphs.count) .animation(.easeInOut(duration: 0.4), value: availableGraphs.count)
.onChange(of: availableGraphs.count) { _, _ in
// Protect against hover interference during dynamic sizing
isResizingForStats = true
DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) {
isResizingForStats = false
}
}
.onChange(of: showingCPUPopover) { _, newValue in .onChange(of: showingCPUPopover) { _, newValue in
if newValue {
activateStatsHoverGrace()
} else {
deactivateStatsHoverGrace()
}
updateStatsPopoverState() updateStatsPopoverState()
} }
.onChange(of: showingMemoryPopover) { _, newValue in .onChange(of: showingMemoryPopover) { _, newValue in
if newValue {
activateStatsHoverGrace()
} else {
deactivateStatsHoverGrace()
}
updateStatsPopoverState() updateStatsPopoverState()
} }
.onChange(of: showingGPUPopover) { _, newValue in .onChange(of: showingGPUPopover) { _, newValue in
if newValue {
activateStatsHoverGrace()
} else {
deactivateStatsHoverGrace()
}
updateStatsPopoverState() updateStatsPopoverState()
} }
.onChange(of: showingNetworkPopover) { _, newValue in .onChange(of: showingNetworkPopover) { _, newValue in
if newValue {
activateStatsHoverGrace()
} else {
deactivateStatsHoverGrace()
}
updateStatsPopoverState() updateStatsPopoverState()
} }
.onChange(of: showingDiskPopover) { _, newValue in .onChange(of: showingDiskPopover) { _, newValue in
if newValue {
activateStatsHoverGrace()
} else {
deactivateStatsHoverGrace()
}
updateStatsPopoverState() updateStatsPopoverState()
} }
.onChange(of: isHoveringCPUPopover) { _, _ in .onChange(of: isHoveringCPUPopover) { _, _ in
@ -461,76 +412,10 @@ struct NotchStatsView: View {
.onChange(of: isHoveringDiskPopover) { _, _ in .onChange(of: isHoveringDiskPopover) { _, _ in
updateStatsPopoverState() updateStatsPopoverState()
} }
.onChange(of: coordinator.statsSecondRowExpansion) { _, newValue in
let shouldHold = availableGraphs.count >= 4 && newValue < 0.999
if shouldHold {
isResizingForStats = true
} else {
DispatchQueue.main.async {
isResizingForStats = false
} }
}
}
}
private struct StatsCollapsibleRow<Content: View>: View {
let expansion: CGFloat
let height: CGFloat
let content: () -> Content
private let minVisibleHeight: CGFloat = 0.5
init(expansion: CGFloat, height: CGFloat, @ViewBuilder content: @escaping () -> Content) {
self.expansion = expansion
self.height = height
self.content = content
}
var body: some View {
let clamped = max(0, min(expansion, 1))
let targetHeight = clamped == 0 ? 0 : max(height * clamped, minVisibleHeight)
return Group {
if targetHeight == 0 {
Color.clear.frame(height: 0)
} else {
content()
.frame(height: height, alignment: .top)
.clipped()
.mask(
Rectangle()
.frame(height: targetHeight)
.frame(maxWidth: .infinity, alignment: .top)
)
.frame(height: targetHeight, alignment: .top)
}
}
.animation(.easeInOut(duration: 0.3), value: clamped)
}
}
private func activateStatsHoverGrace(duration: TimeInterval = 0.45) {
statsHoverGraceWorkItem?.cancel()
statsHoverGraceActive = true
let workItem = DispatchWorkItem {
statsHoverGraceActive = false
statsHoverGraceWorkItem = nil
updateStatsPopoverState()
}
statsHoverGraceWorkItem = workItem
DispatchQueue.main.asyncAfter(deadline: .now() + duration, execute: workItem)
}
private func deactivateStatsHoverGrace() {
statsHoverGraceWorkItem?.cancel()
statsHoverGraceWorkItem = nil
if statsHoverGraceActive {
statsHoverGraceActive = false
}
}
private func updateStatsPopoverState() { private func updateStatsPopoverState() {
let anyPopoverOpen = showingCPUPopover || showingMemoryPopover || showingGPUPopover || showingNetworkPopover || showingDiskPopover let anyPopoverOpen = showingCPUPopover || showingMemoryPopover || showingGPUPopover || showingNetworkPopover || showingDiskPopover
let newState = anyPopoverOpen || isResizingForStats || statsHoverGraceActive let newState = anyPopoverOpen
if vm.isStatsPopoverActive != newState { if vm.isStatsPopoverActive != newState {
vm.isStatsPopoverActive = newState vm.isStatsPopoverActive = newState
#if DEBUG #if DEBUG
@ -540,8 +425,6 @@ private struct StatsCollapsibleRow<Content: View>: View {
print(" GPU open=\(showingGPUPopover)") print(" GPU open=\(showingGPUPopover)")
print(" Network open=\(showingNetworkPopover)") print(" Network open=\(showingNetworkPopover)")
print(" Disk open=\(showingDiskPopover)") print(" Disk open=\(showingDiskPopover)")
print(" Resizing: \(isResizingForStats)")
print(" Hover grace: \(statsHoverGraceActive)")
#endif #endif
} }
} }

View file

@ -1,9 +1,20 @@
// /*
// NotchTimerView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Timer tab interface for the Atoll * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,3 +1,21 @@
/*
* Atoll (DynamicIsland)
* Copyright (C) 2024-2026 Atoll Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if os(macOS) #if os(macOS)
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,3 +1,21 @@
/*
* Atoll (DynamicIsland)
* Copyright (C) 2024-2026 Atoll Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if os(macOS) #if os(macOS)
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,3 +1,21 @@
/*
* Atoll (DynamicIsland)
* Copyright (C) 2024-2026 Atoll Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if os(macOS) #if os(macOS)
import SwiftUI import SwiftUI

View file

@ -1,3 +1,21 @@
/*
* Atoll (DynamicIsland)
* Copyright (C) 2024-2026 Atoll Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if os(macOS) #if os(macOS)
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,9 +1,24 @@
// /*
// MusicControllerSelectionView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Alexander on 2025-06-23. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,10 +1,24 @@
// /*
// OnboardingFinishView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Alexander on 2025-06-23. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI

View file

@ -1,9 +1,24 @@
// /*
// OnboardingView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Alexander on 2025-06-23. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import AVFoundation import AVFoundation

View file

@ -1,9 +1,24 @@
// /*
// PermissionsRequestView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Alexander on 2025-06-23. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI

View file

@ -1,9 +1,20 @@
// /*
// ProOnboarding.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Richard Kunkli on 2024. 09. 26.. * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import SwiftUIIntrospect import SwiftUIIntrospect

View file

@ -1,9 +1,20 @@
// /*
// ProfileSelectionView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created on 2025-10-05. * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,9 +1,24 @@
// /*
// SparkleView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Richard Kunkli on 2024. 09. 26.. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import AppKit import AppKit

View file

@ -1,9 +1,24 @@
// /*
// WelcomeView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Richard Kunkli on 2024. 09. 26.. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import SwiftUIIntrospect import SwiftUIIntrospect

View file

@ -1,9 +1,20 @@
// /*
// PrivacyLiveActivity.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created for camera and microphone privacy indicators * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,10 +1,20 @@
// /*
// PrivacyIndicatorIcon.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created for privacy indicator feature * This program is free software: you can redistribute it and/or modify
// Visual component for camera and microphone privacy indicators * it under the terms of the GNU General Public License as published by
// * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI

View file

@ -1,9 +1,24 @@
// /*
// ProgressIndicator.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Harsh Vardhan Goswami on 11/08/24. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Foundation import Foundation
import SwiftUI import SwiftUI

View file

@ -1,9 +1,20 @@
// /*
// RecordingLiveActivity.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created for screen recording live activity * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,8 +1,20 @@
// /*
// ChatPanels.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Hariharan Mudaliar * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import AppKit import AppKit
import SwiftUI import SwiftUI

View file

@ -1,8 +1,20 @@
// /*
// ModelSelectionPanel.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Hariharan Mudaliar * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import AppKit import AppKit
import SwiftUI import SwiftUI

View file

@ -1,8 +1,20 @@
// /*
// ScreenAssistantPanel.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Hariharan Mudaliar * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import AppKit import AppKit
import SwiftUI import SwiftUI

View file

@ -1,8 +1,20 @@
// /*
// ScreenshotSnippingTool.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Assistant based on ScreenshotApp-main research * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import AppKit import AppKit
import SwiftUI import SwiftUI

View file

@ -1,10 +1,20 @@
// /*
// AnimationEditorView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by AI Assistant on 11/10/2025. * This program is free software: you can redistribute it and/or modify
// Editor for resizing, repositioning, and cropping Lottie animations * it under the terms of the GNU General Public License as published by
// * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import LottieUI import LottieUI

View file

@ -1,9 +1,24 @@
// /*
// EditPanelView.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Richard Kunkli on 12/08/2024. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI

View file

@ -1,9 +1,20 @@
// /*
// ExtensionsSettings.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created on 13/01/2026. * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,10 +1,20 @@
// /*
// IdleAnimationsSettingsSection.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by AI Assistant on 11/10/2025. * This program is free software: you can redistribute it and/or modify
// Settings section for custom idle animations * it under the terms of the GNU General Public License as published by
// * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Defaults import Defaults

View file

@ -1,9 +1,24 @@
// /*
// ListItemPopover.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Richard Kunkli on 15/09/2024. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI

View file

@ -1,3 +1,25 @@
/*
* Atoll (DynamicIsland)
* Copyright (C) 2024-2026 Atoll Contributors
*
* Originally from boring.notch project
* Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Defaults import Defaults
import SwiftUI import SwiftUI
import UniformTypeIdentifiers import UniformTypeIdentifiers

View file

@ -287,6 +287,17 @@ struct SettingsView: View {
Capsule() Capsule()
.fill(Color.blue) .fill(Color.blue)
) )
} else if tab == .extensions {
Spacer()
Text("ALPHA")
.font(.system(size: 9, weight: .bold))
.foregroundStyle(.white)
.padding(.horizontal, 6)
.padding(.vertical, 2)
.background(
Capsule()
.fill(Color.orange)
)
} }
} }
.padding(.vertical, 4) .padding(.vertical, 4)
@ -398,7 +409,6 @@ struct SettingsView: View {
.lockScreen, .lockScreen,
.media, .media,
.devices, .devices,
.extensions,
.timer, .timer,
.calendar, .calendar,
.hudAndOSD, .hudAndOSD,
@ -411,6 +421,7 @@ struct SettingsView: View {
.downloads, .downloads,
.shelf, .shelf,
.shortcuts, .shortcuts,
.extensions,
.about .about
] ]
@ -677,6 +688,7 @@ struct SettingsView: View {
SettingsSearchEntry(tab: .appearance, title: "Enable Dynamic mirror", keywords: ["mirror", "reflection"], highlightID: SettingsTab.appearance.highlightID(for: "Enable Dynamic mirror")), SettingsSearchEntry(tab: .appearance, title: "Enable Dynamic mirror", keywords: ["mirror", "reflection"], highlightID: SettingsTab.appearance.highlightID(for: "Enable Dynamic mirror")),
SettingsSearchEntry(tab: .appearance, title: "Mirror shape", keywords: ["mirror shape", "circle", "rectangle"], highlightID: SettingsTab.appearance.highlightID(for: "Mirror shape")), SettingsSearchEntry(tab: .appearance, title: "Mirror shape", keywords: ["mirror shape", "circle", "rectangle"], highlightID: SettingsTab.appearance.highlightID(for: "Mirror shape")),
SettingsSearchEntry(tab: .appearance, title: "Show cool face animation while inactivity", keywords: ["face animation", "idle"], highlightID: SettingsTab.appearance.highlightID(for: "Show cool face animation while inactivity")), SettingsSearchEntry(tab: .appearance, title: "Show cool face animation while inactivity", keywords: ["face animation", "idle"], highlightID: SettingsTab.appearance.highlightID(for: "Show cool face animation while inactivity")),
SettingsSearchEntry(tab: .appearance, title: "App icon", keywords: ["app icon", "custom icon"], highlightID: SettingsTab.appearance.highlightID(for: "App icon")),
// Lock Screen // Lock Screen
SettingsSearchEntry(tab: .lockScreen, title: "Enable lock screen live activity", keywords: ["lock screen", "live activity"], highlightID: SettingsTab.lockScreen.highlightID(for: "Enable lock screen live activity")), SettingsSearchEntry(tab: .lockScreen, title: "Enable lock screen live activity", keywords: ["lock screen", "live activity"], highlightID: SettingsTab.lockScreen.highlightID(for: "Enable lock screen live activity")),
@ -1964,11 +1976,16 @@ struct Media: View {
@Default(.lockScreenGlassStyle) private var lockScreenGlassStyle @Default(.lockScreenGlassStyle) private var lockScreenGlassStyle
@Default(.lockScreenGlassCustomizationMode) private var lockScreenGlassCustomizationMode @Default(.lockScreenGlassCustomizationMode) private var lockScreenGlassCustomizationMode
@Default(.lockScreenMusicAlbumParallaxEnabled) private var lockScreenMusicAlbumParallaxEnabled @Default(.lockScreenMusicAlbumParallaxEnabled) private var lockScreenMusicAlbumParallaxEnabled
@Default(.showStandardMediaControls) private var showStandardMediaControls
private func highlightID(_ title: String) -> String { private func highlightID(_ title: String) -> String {
SettingsTab.media.highlightID(for: title) SettingsTab.media.highlightID(for: title)
} }
private var standardControlsSuppressed: Bool {
!showStandardMediaControls && !enableMinimalisticUI
}
var body: some View { var body: some View {
Form { Form {
Section { Section {
@ -2002,6 +2019,23 @@ struct Media: View {
.font(.caption) .font(.caption)
} }
} }
Section {
Defaults.Toggle("Show media controls in Dynamic Island", key: .showStandardMediaControls)
.disabled(enableMinimalisticUI)
.settingsHighlight(id: highlightID("Show media controls in Dynamic Island"))
if enableMinimalisticUI {
Text("Disable Minimalistic UI to configure the standard notch media controls.")
.font(.caption)
.foregroundStyle(.secondary)
} else if standardControlsSuppressed {
Text("Standard notch media controls are hidden. Re-enable the toggle above to restore them.")
.font(.caption)
.foregroundStyle(.secondary)
}
} header: {
Text("Dynamic Island Visibility")
}
Section { Section {
Defaults.Toggle(key: .showShuffleAndRepeat) { Defaults.Toggle(key: .showShuffleAndRepeat) {
HStack { HStack {
@ -2053,11 +2087,13 @@ struct Media: View {
"Enable music live activity", "Enable music live activity",
isOn: $coordinator.musicLiveActivityEnabled.animation() isOn: $coordinator.musicLiveActivityEnabled.animation()
) )
.disabled(standardControlsSuppressed)
.help(standardControlsSuppressed ? "Standard notch media controls are hidden while this toggle is off." : "")
Defaults.Toggle( Defaults.Toggle(
"Show floating media controls", "Show floating media controls",
key: .musicControlWindowEnabled key: .musicControlWindowEnabled
) )
.disabled(!coordinator.musicLiveActivityEnabled) .disabled(!coordinator.musicLiveActivityEnabled || standardControlsSuppressed)
.help("Displays play/pause and skip buttons beside the notch while music is active. Disabled by default.") .help("Displays play/pause and skip buttons beside the notch while music is active. Disabled by default.")
Toggle("Enable sneak peek", isOn: $enableSneakPeek) Toggle("Enable sneak peek", isOn: $enableSneakPeek)
Toggle("Show sneak peek on playback changes", isOn: $showSneakPeekOnTrackChange) Toggle("Show sneak peek on playback changes", isOn: $showSneakPeekOnTrackChange)
@ -2124,6 +2160,8 @@ struct Media: View {
} footer: { } footer: {
Text("These controls mirror the Lock Screen tab so you can tune the media overlay while focusing on playback settings.") Text("These controls mirror the Lock Screen tab so you can tune the media overlay while focusing on playback settings.")
} }
.disabled(!showStandardMediaControls)
.opacity(showStandardMediaControls ? 1 : 0.5)
Picker(selection: $hideNotchOption, label: Picker(selection: $hideNotchOption, label:
HStack { HStack {
@ -2403,11 +2441,10 @@ struct About: View {
NSWorkspace.shared.open(sponsorPage) NSWorkspace.shared.open(sponsorPage)
} label: { } label: {
VStack(spacing: 5) { VStack(spacing: 5) {
Image("LinkedIn") Image(systemName: "cup.and.saucer.fill")
.resizable() .font(.system(size: 16, weight: .semibold))
.aspectRatio(contentMode: .fit) .foregroundStyle(.white)
.frame(width: 18) Text("Donate")
Text("LinkedIn")
.foregroundStyle(.white) .foregroundStyle(.white)
} }
.contentShape(Rectangle()) .contentShape(Rectangle())
@ -2429,6 +2466,10 @@ struct About: View {
Spacer(minLength: 0) Spacer(minLength: 0)
} }
.buttonStyle(PlainButtonStyle()) .buttonStyle(PlainButtonStyle())
Text("Your support funds software development learning for students in 9th–12th grade.")
.font(.caption)
.foregroundStyle(.secondary)
.frame(maxWidth: .infinity, alignment: .center)
} }
VStack(spacing: 0) { VStack(spacing: 0) {
Divider() Divider()
@ -2801,6 +2842,8 @@ struct Appearance: View {
@Default(.useMusicVisualizer) var useMusicVisualizer @Default(.useMusicVisualizer) var useMusicVisualizer
@Default(.customVisualizers) var customVisualizers @Default(.customVisualizers) var customVisualizers
@Default(.selectedVisualizer) var selectedVisualizer @Default(.selectedVisualizer) var selectedVisualizer
@Default(.customAppIcons) private var customAppIcons
@Default(.selectedAppIconID) private var selectedAppIconID
@Default(.openNotchWidth) var openNotchWidth @Default(.openNotchWidth) var openNotchWidth
@Default(.enableMinimalisticUI) var enableMinimalisticUI @Default(.enableMinimalisticUI) var enableMinimalisticUI
@Default(.lockScreenGlassCustomizationMode) private var lockScreenGlassCustomizationMode @Default(.lockScreenGlassCustomizationMode) private var lockScreenGlassCustomizationMode
@ -2812,10 +2855,12 @@ struct Appearance: View {
@Default(.lockScreenTimerWidgetUsesBlur) private var timerGlassModeIsGlass @Default(.lockScreenTimerWidgetUsesBlur) private var timerGlassModeIsGlass
@Default(.enableLockScreenMediaWidget) private var enableLockScreenMediaWidget @Default(.enableLockScreenMediaWidget) private var enableLockScreenMediaWidget
@Default(.enableLockScreenTimerWidget) private var enableLockScreenTimerWidget @Default(.enableLockScreenTimerWidget) private var enableLockScreenTimerWidget
let icons: [String] = ["logo2"]
@State private var selectedIcon: String = "logo2"
@State private var selectedListVisualizer: CustomVisualizer? = nil @State private var selectedListVisualizer: CustomVisualizer? = nil
@State private var isIconImporterPresented = false
@State private var isIconDropTarget = false
@State private var iconImportError: String?
@State private var isPresented: Bool = false @State private var isPresented: Bool = false
@State private var name: String = "" @State private var name: String = ""
@State private var url: String = "" @State private var url: String = ""
@ -3159,55 +3204,205 @@ struct Appearance: View {
IdleAnimationsSettingsSection() IdleAnimationsSettingsSection()
Section { Section {
HStack { VStack(alignment: .leading, spacing: 12) {
ForEach(icons, id: \.self) { icon in let columns = [GridItem(.adaptive(minimum: 90), spacing: 12)]
Spacer() LazyVGrid(columns: columns, spacing: 12) {
VStack { appIconCard(
Image(icon) title: "Default",
.resizable() image: defaultAppIconImage(),
.frame(width: 80, height: 80) isSelected: selectedAppIconID == nil
.background( ) {
RoundedRectangle(cornerRadius: 20, style: .circular) selectedAppIconID = nil
.strokeBorder( applySelectedAppIcon()
icon == selectedIcon ? Color.accentColor : .clear, }
lineWidth: 2.5
)
)
Text("Default") ForEach(customAppIcons) { icon in
.fontWeight(.medium) appIconCard(
.font(.caption) title: icon.name,
.foregroundStyle(icon == selectedIcon ? .white : .secondary) image: customIconImage(for: icon),
.padding(.horizontal, 10) isSelected: selectedAppIconID == icon.id.uuidString
.padding(.vertical, 3) ) {
selectedAppIconID = icon.id.uuidString
applySelectedAppIcon()
}
.contextMenu {
Button("Remove") {
removeCustomIcon(icon)
}
}
}
}
.padding(8)
.background( .background(
Capsule() RoundedRectangle(cornerRadius: 14, style: .continuous)
.fill(icon == selectedIcon ? Color.accentColor : .clear) .fill(Color.secondary.opacity(isIconDropTarget ? 0.18 : 0.1))
) )
.overlay(
RoundedRectangle(cornerRadius: 14, style: .continuous)
.strokeBorder(Color.accentColor.opacity(isIconDropTarget ? 0.8 : 0), lineWidth: 2)
)
.onDrop(of: [UTType.fileURL], isTargeted: $isIconDropTarget) { providers in
handleIconDrop(providers)
} }
.onTapGesture {
withAnimation { HStack(spacing: 8) {
selectedIcon = icon Button("Add icon") {
iconImportError = nil
isIconImporterPresented = true
} }
NSApp.applicationIconImage = NSImage(named: icon) .buttonStyle(.borderedProminent)
}
Spacer() Button("Remove selected") {
if let id = selectedAppIconID,
let icon = customAppIcons.first(where: { $0.id.uuidString == id }) {
removeCustomIcon(icon)
} }
} }
.disabled(true) .buttonStyle(.bordered)
.disabled(selectedAppIconID == nil)
}
if let iconImportError {
Text(iconImportError)
.font(.caption)
.foregroundStyle(.secondary)
} else {
Text("Drop a PNG, JPEG, TIFF, or ICNS file to add it to your icon library.")
.font(.caption)
.foregroundStyle(.secondary)
}
}
.settingsHighlight(id: highlightID("App icon"))
} header: { } header: {
HStack { HStack {
Text("App icon") Text("App icon")
customBadge(text: "Coming soon")
} }
} }
} }
.onAppear(perform: enforceLockScreenGlassConsistency) .onAppear(perform: enforceLockScreenGlassConsistency)
.onChange(of: lockScreenGlassStyle) { _, _ in enforceLockScreenGlassConsistency() } .onChange(of: lockScreenGlassStyle) { _, _ in enforceLockScreenGlassConsistency() }
.onChange(of: lockScreenGlassCustomizationMode) { _, _ in enforceLockScreenGlassConsistency() } .onChange(of: lockScreenGlassCustomizationMode) { _, _ in enforceLockScreenGlassConsistency() }
.fileImporter(
isPresented: $isIconImporterPresented,
allowedContentTypes: [.png, .jpeg, .tiff, .icns, .image]
) { result in
switch result {
case .success(let url):
importCustomIcon(from: url)
case .failure:
iconImportError = "Icon import was canceled or failed."
}
}
.navigationTitle("Appearance") .navigationTitle("Appearance")
} }
private func defaultAppIconImage() -> NSImage? {
let fallbackName = Bundle.main.iconFileName ?? "AppIcon"
return NSImage(named: fallbackName)
}
private func customIconImage(for icon: CustomAppIcon) -> NSImage? {
NSImage(contentsOf: icon.fileURL)
}
private func appIconCard(title: String, image: NSImage?, isSelected: Bool, action: @escaping () -> Void) -> some View {
Button(action: action) {
VStack(spacing: 6) {
Group {
if let image {
Image(nsImage: image)
.resizable()
.aspectRatio(contentMode: .fit)
} else {
Image(systemName: "app.dashed")
.font(.system(size: 28, weight: .medium))
.foregroundStyle(.secondary)
}
}
.frame(width: 64, height: 64)
.background(
RoundedRectangle(cornerRadius: 16, style: .continuous)
.fill(Color.black.opacity(0.08))
)
.overlay(
RoundedRectangle(cornerRadius: 16, style: .continuous)
.strokeBorder(isSelected ? Color.accentColor : .clear, lineWidth: 2)
)
Text(title)
.font(.caption)
.lineLimit(1)
.foregroundStyle(isSelected ? .white : .secondary)
.padding(.horizontal, 8)
.padding(.vertical, 3)
.background(
Capsule().fill(isSelected ? Color.accentColor : .clear)
)
}
.frame(maxWidth: .infinity)
}
.buttonStyle(.plain)
}
private func handleIconDrop(_ providers: [NSItemProvider]) -> Bool {
let matching = providers.first { $0.hasItemConformingToTypeIdentifier(UTType.fileURL.identifier) }
guard let provider = matching else { return false }
provider.loadItem(forTypeIdentifier: UTType.fileURL.identifier, options: nil) { item, _ in
let url: URL?
if let directURL = item as? URL {
url = directURL
} else if let data = item as? Data {
url = URL(dataRepresentation: data, relativeTo: nil)
} else {
url = nil
}
guard let url else { return }
Task { @MainActor in importCustomIcon(from: url) }
}
return true
}
private func importCustomIcon(from url: URL) {
guard let image = NSImage(contentsOf: url) else {
iconImportError = "That file could not be loaded as an image."
return
}
let name = url.deletingPathExtension().lastPathComponent
let ext = url.pathExtension.isEmpty ? "png" : url.pathExtension
let id = UUID()
let fileName = "custom-icon-\(id.uuidString).\(ext)"
let destination = CustomAppIcon.iconDirectory.appendingPathComponent(fileName)
do {
let data = try Data(contentsOf: url)
try data.write(to: destination, options: [.atomic])
} catch {
iconImportError = "Unable to save the icon file."
return
}
let newIcon = CustomAppIcon(id: id, name: name.isEmpty ? "Custom Icon" : name, fileName: fileName)
if !customAppIcons.contains(newIcon) {
customAppIcons.append(newIcon)
}
selectedAppIconID = newIcon.id.uuidString
NSApp.applicationIconImage = image
iconImportError = nil
}
private func removeCustomIcon(_ icon: CustomAppIcon) {
if let index = customAppIcons.firstIndex(of: icon) {
customAppIcons.remove(at: index)
}
if FileManager.default.fileExists(atPath: icon.fileURL.path) {
try? FileManager.default.removeItem(at: icon.fileURL)
}
if selectedAppIconID == icon.id.uuidString {
selectedAppIconID = nil
applySelectedAppIcon()
}
}
func checkVideoInput() -> Bool { func checkVideoInput() -> Bool {
if let _ = AVCaptureDevice.default(for: .video) { if let _ = AVCaptureDevice.default(for: .video) {
return true return true
@ -3301,6 +3496,7 @@ struct LockScreenSettings: View {
@Default(.lockScreenWeatherShowsAQI) private var lockScreenWeatherShowsAQI @Default(.lockScreenWeatherShowsAQI) private var lockScreenWeatherShowsAQI
@Default(.lockScreenWeatherShowsSunrise) private var lockScreenWeatherShowsSunrise @Default(.lockScreenWeatherShowsSunrise) private var lockScreenWeatherShowsSunrise
@Default(.lockScreenWeatherAQIScale) private var lockScreenWeatherAQIScale @Default(.lockScreenWeatherAQIScale) private var lockScreenWeatherAQIScale
@Default(.showStandardMediaControls) private var showStandardMediaControls
private func highlightID(_ title: String) -> String { private func highlightID(_ title: String) -> String {
SettingsTab.lockScreen.highlightID(for: title) SettingsTab.lockScreen.highlightID(for: title)
@ -3422,11 +3618,20 @@ struct LockScreenSettings: View {
.opacity(enableLockScreenMediaWidget ? 1 : 0.5) .opacity(enableLockScreenMediaWidget ? 1 : 0.5)
.settingsHighlight(id: highlightID("Enable media panel blur")) .settingsHighlight(id: highlightID("Enable media panel blur"))
} }
if !showStandardMediaControls {
Text("Enable Dynamic Island media controls to manage the lock screen panel.")
.font(.caption)
.foregroundStyle(.secondary)
.frame(maxWidth: .infinity, alignment: .leading)
}
} header: { } header: {
Text("Media Panel") Text("Media Panel")
} footer: { } footer: {
Text("Enable and style the media controls that appear above the system clock when the screen is locked.") Text("Enable and style the media controls that appear above the system clock when the screen is locked.")
} }
.disabled(!showStandardMediaControls)
.opacity(showStandardMediaControls ? 1 : 0.5)
Section { Section {
Defaults.Toggle("Show lock screen timer", key: .enableLockScreenTimerWidget) Defaults.Toggle("Show lock screen timer", key: .enableLockScreenTimerWidget)

View file

@ -1,9 +1,24 @@
// /*
// SettingsWindowController.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Alexander on 2025-06-14. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import AppKit import AppKit
import SwiftUI import SwiftUI

View file

@ -1,9 +1,24 @@
// /*
// SoftwareUpdater.swift * Atoll (DynamicIsland)
// DynamicIsland * Copyright (C) 2024-2026 Atoll Contributors
// *
// Created by Richard Kunkli on 09/08/2024. * Originally from boring.notch project
// * Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI import SwiftUI
import Sparkle import Sparkle

Some files were not shown because too many files have changed in this diff Show more