mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
batteria finale, waiting for approve
This commit is contained in:
parent
1d53bbac13
commit
945707425a
9 changed files with 1091 additions and 89 deletions
|
|
@ -85,6 +85,15 @@ struct ContentView: View {
|
|||
@Default(.hideNonNotchUntilHover) var hideNonNotchUntilHover
|
||||
@Default(.terminalStickyMode) var terminalStickyMode
|
||||
|
||||
// Battery settings reactivity
|
||||
@Default(.showPowerStatusNotifications) var showPowerStatusNotifications
|
||||
@Default(.showChargingBatteryHUD) var showChargingBatteryHUD
|
||||
@Default(.showLowBatteryHUD) var showLowBatteryHUD
|
||||
@Default(.showFullBatteryHUD) var showFullBatteryHUD
|
||||
@Default(.showOnAllDisplays) var showOnAllDisplays
|
||||
@Default(.lowBatteryHUDStyle) var lowBatteryHUDStyle
|
||||
@Default(.fullBatteryHUDStyle) var fullBatteryHUDStyle
|
||||
|
||||
// Dynamic sizing based on view type and graph count with smooth transitions
|
||||
var dynamicNotchSize: CGSize {
|
||||
let baseSize = Defaults[.enableMinimalisticUI] ? minimalisticOpenNotchSize : openNotchSize
|
||||
|
|
@ -101,6 +110,39 @@ struct ContentView: View {
|
|||
return CGSize(width: max(baseSize.width, inlineWidth), height: baseSize.height)
|
||||
}
|
||||
|
||||
// Handle battery HUD expansion sizing
|
||||
if vm.notchState == .closed &&
|
||||
coordinator.expandingView.show &&
|
||||
coordinator.expandingView.type == .battery &&
|
||||
isBatteryHUDVisibleOnCurrentScreen {
|
||||
|
||||
if let kind = batteryModel.activeTemporaryHUDKind {
|
||||
let style: BatteryNotificationStyle = {
|
||||
switch kind {
|
||||
case .charging: return .compact
|
||||
case .lowBattery: return Defaults[.lowBatteryHUDStyle]
|
||||
case .fullBattery: return Defaults[.fullBatteryHUDStyle]
|
||||
}
|
||||
}()
|
||||
|
||||
var width = vm.closedNotchSize.width
|
||||
var height = vm.effectiveClosedNotchHeight
|
||||
|
||||
switch (kind, style) {
|
||||
case (.charging, _), (.lowBattery, .compact), (.fullBattery, .compact):
|
||||
width += 180
|
||||
case (.lowBattery, .standard):
|
||||
width += 100
|
||||
height += 75
|
||||
case (.fullBattery, .standard):
|
||||
width += 80
|
||||
height += 70
|
||||
}
|
||||
|
||||
return CGSize(width: width, height: height)
|
||||
}
|
||||
}
|
||||
|
||||
if coordinator.currentView == .timer {
|
||||
return CGSize(width: baseSize.width, height: 250) // Extra height for timer presets
|
||||
}
|
||||
|
|
@ -383,9 +425,78 @@ struct ContentView: View {
|
|||
return DynamicIslandPillShape(cornerRadius: radius)
|
||||
}
|
||||
|
||||
private var isBatteryHUDVisibleOnCurrentScreen: Bool {
|
||||
guard coordinator.expandingView.show, coordinator.expandingView.type == .battery else { return false }
|
||||
guard showPowerStatusNotifications else { return false }
|
||||
guard batteryModel.activeTemporaryHUDKind != nil else { return false }
|
||||
if showOnAllDisplays { return true }
|
||||
guard let targetScreenName = batteryModel.activeTemporaryHUDTargetScreenName else { return true }
|
||||
return currentScreenName == targetScreenName
|
||||
}
|
||||
|
||||
private var isCurrentScreenExpansionVisible: Bool {
|
||||
guard coordinator.expandingView.show else { return false }
|
||||
if coordinator.expandingView.type == .battery {
|
||||
return isBatteryHUDVisibleOnCurrentScreen
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private var currentScreenExpansionType: SneakContentType? {
|
||||
isCurrentScreenExpansionVisible ? coordinator.expandingView.type : nil
|
||||
}
|
||||
|
||||
private var displayedBatteryHUDLevel: Int {
|
||||
let resolvedLevel = batteryModel.activeTemporaryHUDLevelOverride
|
||||
?? Int(batteryModel.levelBattery.rounded())
|
||||
return min(max(resolvedLevel, 0), 100)
|
||||
}
|
||||
|
||||
private var displayedBatteryHUDUsesLowPowerMode: Bool {
|
||||
batteryModel.activeTemporaryHUDLowPowerModeOverride ?? batteryModel.isInLowPowerMode
|
||||
}
|
||||
|
||||
|
||||
private var activeClosedBatterySurfaceShape: AnyShape? {
|
||||
guard vm.notchState == .closed else { return nil }
|
||||
guard isBatteryHUDVisibleOnCurrentScreen else { return nil }
|
||||
guard let kind = batteryModel.activeTemporaryHUDKind else { return nil }
|
||||
|
||||
if isDynamicIslandMode {
|
||||
let radius = dynamicIslandPillCornerRadiusInsets.opened
|
||||
return AnyShape(DynamicIslandPillShape(cornerRadius: radius))
|
||||
} else {
|
||||
let topRadius = activeCornerRadiusInsets.closed.top
|
||||
let bottomRadius: CGFloat = {
|
||||
switch resolvedBatteryNotificationStyle(for: kind) {
|
||||
case .compact:
|
||||
return activeCornerRadiusInsets.closed.bottom
|
||||
case .standard:
|
||||
return kind == .fullBattery ? 36 : 40
|
||||
}
|
||||
}()
|
||||
return AnyShape(NotchShape(topCornerRadius: topRadius, bottomCornerRadius: bottomRadius))
|
||||
}
|
||||
}
|
||||
|
||||
private func resolvedBatteryNotificationStyle(for kind: BatteryTemporaryHUDKind) -> BatteryNotificationStyle {
|
||||
switch kind {
|
||||
case .charging:
|
||||
return .compact
|
||||
case .lowBattery:
|
||||
return lowBatteryHUDStyle
|
||||
case .fullBattery:
|
||||
return fullBatteryHUDStyle
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Resolves the clip/content shape per-screen: pill on non-notch screens
|
||||
/// when dynamic island mode is active, standard notch shape otherwise.
|
||||
private var resolvedClipShape: AnyShape {
|
||||
if let activeClosedBatterySurfaceShape {
|
||||
return activeClosedBatterySurfaceShape
|
||||
}
|
||||
if isDynamicIslandMode {
|
||||
return AnyShape(currentPillShape)
|
||||
}
|
||||
|
|
@ -764,13 +875,13 @@ struct ContentView: View {
|
|||
guard let musicSecondary else { return false }
|
||||
switch musicSecondary {
|
||||
case .timer:
|
||||
return coordinator.expandingView.type == .timer
|
||||
return currentScreenExpansionType == .timer
|
||||
case .reminder:
|
||||
return coordinator.expandingView.type == .reminder
|
||||
return currentScreenExpansionType == .reminder
|
||||
case .recording:
|
||||
return coordinator.expandingView.type == .recording
|
||||
return currentScreenExpansionType == .recording
|
||||
case .focus:
|
||||
return coordinator.expandingView.type == .doNotDisturb
|
||||
return currentScreenExpansionType == .doNotDisturb
|
||||
case .capsLock:
|
||||
return false
|
||||
case .extensionPayload:
|
||||
|
|
@ -779,34 +890,26 @@ struct ContentView: View {
|
|||
return false
|
||||
}
|
||||
}()
|
||||
let canShowMusicDuringExpansion = !coordinator.expandingView.show
|
||||
|| coordinator.expandingView.type == .music
|
||||
let canShowMusicDuringExpansion = !isCurrentScreenExpansionVisible
|
||||
|| currentScreenExpansionType == .music
|
||||
|| expansionMatchesSecondary
|
||||
|
||||
if coordinator.expandingView.type == .battery && coordinator.expandingView.show && vm.notchState == .closed && Defaults[.showPowerStatusNotifications] {
|
||||
HStack(spacing: 0) {
|
||||
HStack {
|
||||
Text(batteryModel.statusText)
|
||||
.font(.subheadline)
|
||||
}
|
||||
|
||||
Rectangle()
|
||||
.fill(.black)
|
||||
.frame(width: vm.closedNotchSize.width + 10)
|
||||
|
||||
HStack {
|
||||
DynamicIslandBatteryView(
|
||||
batteryWidth: 30,
|
||||
isCharging: batteryModel.isCharging,
|
||||
isInLowPowerMode: batteryModel.isInLowPowerMode,
|
||||
isPluggedIn: batteryModel.isPluggedIn,
|
||||
levelBattery: batteryModel.levelBattery,
|
||||
isForNotification: true
|
||||
)
|
||||
}
|
||||
.frame(width: 76, alignment: .trailing)
|
||||
}
|
||||
.frame(height: vm.effectiveClosedNotchHeight + (isHovering ? 8 : 0), alignment: .center)
|
||||
if currentScreenExpansionType == .battery
|
||||
&& isBatteryHUDVisibleOnCurrentScreen
|
||||
&& vm.notchState == .closed
|
||||
&& Defaults[.showPowerStatusNotifications]
|
||||
&& batteryModel.activeTemporaryHUDKind != nil {
|
||||
BatteryTemporaryActivityView(
|
||||
kind: batteryModel.activeTemporaryHUDKind ?? .charging,
|
||||
batteryLevel: displayedBatteryHUDLevel,
|
||||
isLowPowerMode: displayedBatteryHUDUsesLowPowerMode,
|
||||
closedNotchWidth: vm.closedNotchSize.width + (isHovering ? 8 : 0),
|
||||
baseHeight: vm.effectiveClosedNotchHeight + (isHovering ? 8 : 0),
|
||||
isDynamicIslandMode: isDynamicIslandMode,
|
||||
topCornerRadius: activeCornerRadiusInsets.closed.top,
|
||||
styleOverride: batteryModel.activeTemporaryHUDKind.map { resolvedBatteryNotificationStyle(for: $0) }
|
||||
)
|
||||
.id(batteryModel.activeTemporaryHUDToken)
|
||||
} else if isSneakPeekVisibleOnCurrentScreen && Defaults[.inlineHUD] && (coordinator.sneakPeek.type != .music) && (coordinator.sneakPeek.type != .battery) && (coordinator.sneakPeek.type != .timer) && (coordinator.sneakPeek.type != .reminder) && !coordinator.sneakPeek.type.isExtensionPayload && ((coordinator.sneakPeek.type != .volume && coordinator.sneakPeek.type != .brightness && coordinator.sneakPeek.type != .backlight) || vm.notchState == .closed) {
|
||||
InlineHUD(type: $coordinator.sneakPeek.type, value: $coordinator.sneakPeek.value, icon: $coordinator.sneakPeek.icon, hoverAnimation: $isHovering, gestureProgress: $gestureProgress)
|
||||
.transition(
|
||||
|
|
@ -821,25 +924,25 @@ struct ContentView: View {
|
|||
MusicLiveActivity(secondary: musicSecondary)
|
||||
.id("closed-music-live-activity")
|
||||
.transition(closedLiveActivitySwapTransition)
|
||||
} else if (!coordinator.expandingView.show || coordinator.expandingView.type == .timer) && vm.notchState == .closed && timerManager.isTimerActive && coordinator.timerLiveActivityEnabled && !vm.hideOnClosed {
|
||||
} else if (!isCurrentScreenExpansionVisible || currentScreenExpansionType == .timer) && vm.notchState == .closed && timerManager.isTimerActive && coordinator.timerLiveActivityEnabled && !vm.hideOnClosed {
|
||||
TimerLiveActivity()
|
||||
} else if (!coordinator.expandingView.show || coordinator.expandingView.type == .reminder) && vm.notchState == .closed && reminderManager.isActive && enableReminderLiveActivity && !vm.hideOnClosed {
|
||||
} else if (!isCurrentScreenExpansionVisible || currentScreenExpansionType == .reminder) && vm.notchState == .closed && reminderManager.isActive && enableReminderLiveActivity && !vm.hideOnClosed {
|
||||
ReminderLiveActivity()
|
||||
} else if (!coordinator.expandingView.show || coordinator.expandingView.type == .recording) && vm.notchState == .closed && (recordingManager.isRecording || !recordingManager.isRecorderIdle) && Defaults[.enableScreenRecordingDetection] && !vm.hideOnClosed && !musicPairingEligible {
|
||||
} else if (!isCurrentScreenExpansionVisible || currentScreenExpansionType == .recording) && vm.notchState == .closed && (recordingManager.isRecording || !recordingManager.isRecorderIdle) && Defaults[.enableScreenRecordingDetection] && !vm.hideOnClosed && !musicPairingEligible {
|
||||
RecordingLiveActivity()
|
||||
} else if (!coordinator.expandingView.show || coordinator.expandingView.type == .download) && vm.notchState == .closed && downloadManager.isDownloading && Defaults[.enableDownloadListener] && !vm.hideOnClosed {
|
||||
} else if (!isCurrentScreenExpansionVisible || currentScreenExpansionType == .download) && vm.notchState == .closed && downloadManager.isDownloading && Defaults[.enableDownloadListener] && !vm.hideOnClosed {
|
||||
DownloadLiveActivity()
|
||||
.transition(.blurReplace.animation(.interactiveSpring(dampingFraction: 1.2)))
|
||||
} else if !coordinator.expandingView.show && vm.notchState == .closed && localSendLiveActivityActive && !vm.hideOnClosed {
|
||||
} else if !isCurrentScreenExpansionVisible && vm.notchState == .closed && localSendLiveActivityActive && !vm.hideOnClosed {
|
||||
LocalSendLiveActivity()
|
||||
.transition(.blurReplace.animation(.interactiveSpring(dampingFraction: 1.2)))
|
||||
} else if (!coordinator.expandingView.show || coordinator.expandingView.type == .doNotDisturb) && vm.notchState == .closed && Defaults[.enableDoNotDisturbDetection] && Defaults[.showDoNotDisturbIndicator] && (doNotDisturbManager.isDoNotDisturbActive || doNotDisturbManager.isFocusToastDismissing) && !vm.hideOnClosed && !lockScreenManager.isLocked {
|
||||
} else if (!isCurrentScreenExpansionVisible || currentScreenExpansionType == .doNotDisturb) && vm.notchState == .closed && Defaults[.enableDoNotDisturbDetection] && Defaults[.showDoNotDisturbIndicator] && (doNotDisturbManager.isDoNotDisturbActive || doNotDisturbManager.isFocusToastDismissing) && !vm.hideOnClosed && !lockScreenManager.isLocked {
|
||||
DoNotDisturbLiveActivity()
|
||||
} else if (!coordinator.expandingView.show || coordinator.expandingView.type == .lockScreen) && vm.notchState == .closed && (lockScreenManager.isLocked || !lockScreenManager.isLockIdle) && Defaults[.enableLockScreenLiveActivity] && !vm.hideOnClosed {
|
||||
} else if (!isCurrentScreenExpansionVisible || currentScreenExpansionType == .lockScreen) && vm.notchState == .closed && (lockScreenManager.isLocked || !lockScreenManager.isLockIdle) && Defaults[.enableLockScreenLiveActivity] && !vm.hideOnClosed {
|
||||
LockScreenLiveActivity()
|
||||
.id("lock-screen-live-activity")
|
||||
.transition(closedLiveActivitySwapTransition)
|
||||
} else if (!coordinator.expandingView.show || coordinator.expandingView.type == .privacy) && vm.notchState == .closed && privacyManager.hasAnyIndicator && (Defaults[.enableCameraDetection] || Defaults[.enableMicrophoneDetection]) && !vm.hideOnClosed {
|
||||
} else if (!isCurrentScreenExpansionVisible || currentScreenExpansionType == .privacy) && vm.notchState == .closed && privacyManager.hasAnyIndicator && (Defaults[.enableCameraDetection] || Defaults[.enableMicrophoneDetection]) && !vm.hideOnClosed {
|
||||
PrivacyLiveActivity()
|
||||
} else if let extensionPayload = extensionStandalonePayload {
|
||||
let layout = extensionStandaloneLayout(
|
||||
|
|
@ -856,6 +959,7 @@ struct ContentView: View {
|
|||
ShelfInlineLiveActivity()
|
||||
.transition(.opacity.animation(.smooth(duration: 0.25)))
|
||||
} else if !coordinator.expandingView.show && vm.notchState == .closed && (!musicManager.isPlaying && musicManager.isPlayerIdle) && Defaults[.showNotHumanFace] && !vm.hideOnClosed {
|
||||
} else if !isCurrentScreenExpansionVisible && vm.notchState == .closed && (!musicManager.isPlaying && musicManager.isPlayerIdle) && Defaults[.showNotHumanFace] && !vm.hideOnClosed {
|
||||
DynamicIslandFaceAnimation().animation(.interactiveSpring, value: musicManager.isPlayerIdle)
|
||||
} else if vm.notchState == .open {
|
||||
DynamicIslandHeader()
|
||||
|
|
@ -1631,10 +1735,10 @@ struct ContentView: View {
|
|||
return nil
|
||||
}
|
||||
|
||||
guard !coordinator.expandingView.show else {
|
||||
guard !isCurrentScreenExpansionVisible else {
|
||||
ExtensionRoutingDiagnostics.shared.logSuppression(
|
||||
.standalone,
|
||||
reason: "expanding view \(coordinator.expandingView.type) visible",
|
||||
reason: "expanding view \(String(describing: currentScreenExpansionType ?? coordinator.expandingView.type)) visible",
|
||||
pendingCount: candidates.count
|
||||
)
|
||||
return nil
|
||||
|
|
@ -1754,7 +1858,7 @@ struct ContentView: View {
|
|||
&& !vm.hideOnClosed
|
||||
&& !lockScreenManager.isLocked
|
||||
&& !isMusicHUDDeferredAfterUnlock
|
||||
&& !coordinator.expandingView.show
|
||||
&& !isCurrentScreenExpansionVisible
|
||||
&& (!musicManager.isPlayerIdle || musicManager.bundleIdentifier != nil)
|
||||
&& !coordinator.firstLaunch
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue