From 793a07795f148e43d964760fc3fbd6663a5056e7 Mon Sep 17 00:00:00 2001 From: Hariharan Mudaliar Date: Sun, 21 Dec 2025 15:00:19 +0530 Subject: [PATCH 1/3] Lock Screen Album art parallax --- DynamicIsland/models/Constants.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DynamicIsland/models/Constants.swift b/DynamicIsland/models/Constants.swift index 74fadb2..206a553 100644 --- a/DynamicIsland/models/Constants.swift +++ b/DynamicIsland/models/Constants.swift @@ -442,7 +442,7 @@ extension Defaults.Keys { static let sneakPeekStyles = Key("sneakPeekStyles", default: .standard) static let showSneakPeekOnTrackChange = Key("showSneakPeekOnTrackChange", default: true) static let enableFullscreenMediaDetection = Key("enableFullscreenMediaDetection", default: true) - static let enableParallaxEffect = Key("enableParallaxEffect", default: false) + static let enableParallaxEffect = Key("enableParallaxEffect", default: true) static let waitInterval = Key("waitInterval", default: 3) static let showShuffleAndRepeat = Key("showShuffleAndRepeat", default: true) static let showMediaOutputControl = Key("showMediaOutputControl", default: false) @@ -474,7 +474,7 @@ extension Defaults.Keys { static let lockScreenWeatherProviderSource = Key("lockScreenWeatherProviderSource", default: .openMeteo) static let lockScreenWeatherVerticalOffset = Key("lockScreenWeatherVerticalOffset", default: 0) static let lockScreenMusicVerticalOffset = Key("lockScreenMusicVerticalOffset", default: 0) - static let lockScreenMusicAlbumParallaxEnabled = Key("lockScreenMusicAlbumParallaxEnabled", default: true) + static let lockScreenMusicAlbumParallaxEnabled = Key("lockScreenMusicAlbumParallaxEnabled", default: false) static let lockScreenTimerVerticalOffset = Key("lockScreenTimerVerticalOffset", default: 0) static let lockScreenGlassStyle = Key("lockScreenGlassStyle", default: .liquid) static let lockScreenShowAppIcon = Key("lockScreenShowAppIcon", default: false) From 78ae27a7fe650400c49d56b1d14b9b8c442e17d3 Mon Sep 17 00:00:00 2001 From: Hariharan Mudaliar Date: Sun, 21 Dec 2025 15:29:29 +0530 Subject: [PATCH 2/3] BugFix: Focus Live Activity --- .../Focus/DoNotDisturbLiveActivity.swift | 92 +++++++++++++------ 1 file changed, 65 insertions(+), 27 deletions(-) diff --git a/DynamicIsland/components/Focus/DoNotDisturbLiveActivity.swift b/DynamicIsland/components/Focus/DoNotDisturbLiveActivity.swift index d4114a7..8040ce1 100644 --- a/DynamicIsland/components/Focus/DoNotDisturbLiveActivity.swift +++ b/DynamicIsland/components/Focus/DoNotDisturbLiveActivity.swift @@ -22,7 +22,6 @@ struct DoNotDisturbLiveActivity: View { @State private var scaleResetTask: Task? @State private var collapseTask: Task? @State private var cleanupTask: Task? - @State private var labelIntrinsicWidth: CGFloat = 0 private enum ToastTiming { static let activeDisplay: UInt64 = 1800 // focus enabled toast linger @@ -119,14 +118,17 @@ struct DoNotDisturbLiveActivity: View { } private var desiredLabelWidth: CGFloat { - let measuredWidth = labelIntrinsicWidth + 8 // horizontal padding inside the label let fallbackWidth = max(collapsedNotchWidth * 0.52, 136) - var width = max(measuredWidth, fallbackWidth) + var width = fallbackWidth if focusMode == .doNotDisturb && shouldShowLabel { width = max(width, 164) } + if !shouldMarqueeLabel { + width = max(width, labelIntrinsicWidth + 8) + } + return width } @@ -134,6 +136,31 @@ struct DoNotDisturbLiveActivity: View { focusToastMode ? (isExpanded && !labelText.isEmpty) : (showLabelSetting && isExpanded && !labelText.isEmpty) } + private var labelIntrinsicWidth: CGFloat { + guard !labelText.isEmpty else { return 0 } + return (labelText as NSString).size(withAttributes: [.font: focusLabelNSFont]).width + } + + private var shouldMarqueeLabel: Bool { + shouldShowLabel && labelIntrinsicWidth > focusLabelBaselineWidth + } + + private var marqueeFrameWidth: CGFloat { + max(48, labelWingWidth - 8) + } + + private var focusLabelFont: Font { + .system(size: 12, weight: .semibold, design: .rounded) + } + + private var focusLabelNSFont: NSFont { + NSFont.systemFont(ofSize: 12, weight: .semibold) + } + + private var focusLabelBaselineWidth: CGFloat { + FocusLabelMetrics.baselineWidth + } + // MARK: - Focus metadata private var focusMode: FocusModeType { @@ -247,25 +274,31 @@ struct DoNotDisturbLiveActivity: View { Color.clear .overlay(alignment: .trailing) { if shouldShowLabel { - Text(labelText) - .font(.system(size: 12, weight: .semibold, design: .rounded)) - .foregroundColor(labelColor) - .lineLimit(1) - .minimumScaleFactor(0.8) - .contentTransition(.opacity) - .background( - GeometryReader { proxy in - Color.clear - .preference(key: FocusLabelWidthPreferenceKey.self, value: proxy.size.width) - } - ) - .padding(.horizontal, 4) + Group { + if shouldMarqueeLabel { + MarqueeText( + .constant(labelText), + font: focusLabelFont, + nsFont: .caption1, + textColor: labelColor, + minDuration: 0.4, + frameWidth: marqueeFrameWidth + ) + .frame(width: marqueeFrameWidth, alignment: .trailing) + } else { + Text(labelText) + .font(focusLabelFont) + .foregroundColor(labelColor) + .lineLimit(1) + .minimumScaleFactor(0.8) + .contentTransition(.opacity) + .frame(maxWidth: .infinity, alignment: .trailing) + } + } + .padding(.horizontal, 4) } } .animation(.smooth(duration: 0.3), value: shouldShowLabel) - .onPreferenceChange(FocusLabelWidthPreferenceKey.self) { value in - labelIntrinsicWidth = value - } } private var labelColor: Color { @@ -385,14 +418,6 @@ struct DoNotDisturbLiveActivity: View { .background(Color.black) } -private struct FocusLabelWidthPreferenceKey: PreferenceKey { - static var defaultValue: CGFloat = 0 - - static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { - value = max(value, nextValue()) - } -} - private final class SymbolAvailabilityCache { static let shared = SymbolAvailabilityCache() private var cache: [String: Bool] = [:] @@ -418,3 +443,16 @@ private final class SymbolAvailabilityCache { return available } } + +private enum FocusLabelMetrics { + static let baselineText = "Do Not Disturb" + + static let baselineWidth: CGFloat = { + #if canImport(AppKit) + let font = NSFont.systemFont(ofSize: 12, weight: .semibold) + return (baselineText as NSString).size(withAttributes: [.font: font]).width + #else + return 0 + #endif + }() +} From 7ce19dfe46bd2c03a7dbad7e40cd0a09dd194cce Mon Sep 17 00:00:00 2001 From: Hariharan Mudaliar Date: Sun, 21 Dec 2025 15:45:05 +0530 Subject: [PATCH 3/3] BugFix: System Share Menu Close --- DynamicIsland/ContentView.swift | 23 +++++++++++++++---- .../Shelf/Views/FileShareView.swift | 3 +++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/DynamicIsland/ContentView.swift b/DynamicIsland/ContentView.swift index ace6cff..8d2e3ea 100644 --- a/DynamicIsland/ContentView.swift +++ b/DynamicIsland/ContentView.swift @@ -248,14 +248,14 @@ struct ContentView: View { } .onChange(of: vm.isBatteryPopoverActive) { _, newPopoverState in runAfter(0.1) { - if !newPopoverState && !isHovering && vm.notchState == .open && !vm.isStatsPopoverActive && !vm.isMediaOutputPopoverActive && !vm.isReminderPopoverActive { + if !newPopoverState && !isHovering && vm.notchState == .open && !shouldPreventAutoClose() { vm.close() } } } .onChange(of: vm.isStatsPopoverActive) { _, newPopoverState in runAfter(0.1) { - if !newPopoverState && !isHovering && vm.notchState == .open && !vm.isBatteryPopoverActive && !vm.isClipboardPopoverActive && !vm.isColorPickerPopoverActive && !vm.isMediaOutputPopoverActive && !vm.isReminderPopoverActive { + if !newPopoverState && !isHovering && vm.notchState == .open && !shouldPreventAutoClose() { vm.close() } } @@ -263,7 +263,14 @@ struct ContentView: View { .onChange(of: vm.shouldRecheckHover) { _, _ in // Recheck hover state when popovers are closed runAfter(0.1) { - if vm.notchState == .open && !vm.isBatteryPopoverActive && !vm.isClipboardPopoverActive && !vm.isColorPickerPopoverActive && !vm.isStatsPopoverActive && !vm.isMediaOutputPopoverActive && !vm.isReminderPopoverActive && !isHovering { + if vm.notchState == .open && !shouldPreventAutoClose() && !isHovering { + vm.close() + } + } + } + .onReceive(NotificationCenter.default.publisher(for: .sharingDidFinish)) { _ in + runAfter(0.1) { + if vm.notchState == .open && !isHovering && !shouldPreventAutoClose() { vm.close() } } @@ -737,7 +744,9 @@ struct ContentView: View { } vm.dropEvent = false - vm.close() + if !shouldPreventAutoClose() { + vm.close() + } } } } else { @@ -800,7 +809,7 @@ struct ContentView: View { self.isHovering = false } - if self.vm.notchState == .open && !self.hasAnyActivePopovers() { + if self.vm.notchState == .open && !self.shouldPreventAutoClose() { self.vm.close() } } @@ -818,6 +827,10 @@ struct ContentView: View { vm.isMediaOutputPopoverActive || vm.isReminderPopoverActive } + + private func shouldPreventAutoClose() -> Bool { + hasAnyActivePopovers() || SharingStateManager.shared.preventNotchClose + } // Helper to prevent rapid haptic feedback private func triggerHapticIfAllowed() { diff --git a/DynamicIsland/components/Shelf/Views/FileShareView.swift b/DynamicIsland/components/Shelf/Views/FileShareView.swift index ee1ca47..f70c5df 100644 --- a/DynamicIsland/components/Shelf/Views/FileShareView.swift +++ b/DynamicIsland/components/Shelf/Views/FileShareView.swift @@ -87,9 +87,12 @@ struct FileShareView: View { Text(selectedProvider.id) .font(.system(.headline, design: .rounded)) .foregroundColor(.white.opacity(0.8)) + .multilineTextAlignment(.center) + .frame(maxWidth: .infinity) } .padding(18) + .frame(maxWidth: .infinity) // Loading overlay if isProcessing || quickShare.isPickerOpen {