mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
Temporary fix for glitch, TODO: remove push up animation
This commit is contained in:
parent
3eb9122b9f
commit
80d132a85f
5 changed files with 177 additions and 64 deletions
|
|
@ -276,33 +276,13 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
return CGSize(width: inlineSneakPeekWidth, height: vm.effectiveClosedNotchHeight)
|
||||
}
|
||||
|
||||
// Use minimalistic or normal size based on settings
|
||||
var baseSize = Defaults[.enableMinimalisticUI] ? minimalisticOpenNotchSize : openNotchSize
|
||||
|
||||
// Only apply dynamic sizing when on stats tab and stats are enabled
|
||||
guard coordinator.currentView == .stats && Defaults[.enableStatsFeature] else {
|
||||
return baseSize
|
||||
}
|
||||
|
||||
let enabledGraphsCount = [
|
||||
Defaults[.showCpuGraph],
|
||||
Defaults[.showMemoryGraph],
|
||||
Defaults[.showGpuGraph],
|
||||
Defaults[.showNetworkGraph],
|
||||
Defaults[.showDiskGraph]
|
||||
].filter { $0 }.count
|
||||
|
||||
// Calculate height based on layout: 1-3 graphs = single row, 4+ graphs = two rows
|
||||
var requiredHeight = baseSize.height
|
||||
|
||||
if enabledGraphsCount >= 4 {
|
||||
// Two rows needed - add height for second row plus spacing
|
||||
let extraHeight: CGFloat = 120 + 12 // Graph height + spacing
|
||||
requiredHeight = baseSize.height + extraHeight
|
||||
}
|
||||
|
||||
// Width stays constant - no horizontal expansion
|
||||
return CGSize(width: baseSize.width, height: requiredHeight)
|
||||
// Use minimalistic or normal size based on settings, then adjust for stats layout
|
||||
let baseSize = Defaults[.enableMinimalisticUI] ? minimalisticOpenNotchSize : openNotchSize
|
||||
return statsAdjustedNotchSize(
|
||||
from: baseSize,
|
||||
isStatsTabActive: coordinator.currentView == .stats,
|
||||
secondRowProgress: coordinator.statsSecondRowExpansion
|
||||
)
|
||||
}
|
||||
|
||||
func ensureWindowSize(_ size: CGSize, animated: Bool, force: Bool = false) {
|
||||
|
|
|
|||
|
|
@ -48,7 +48,16 @@ struct ExpandedItem {
|
|||
class DynamicIslandViewCoordinator: ObservableObject {
|
||||
static let shared = DynamicIslandViewCoordinator()
|
||||
|
||||
@Published var currentView: NotchViews = .home
|
||||
@Published var currentView: NotchViews = .home {
|
||||
didSet {
|
||||
handleStatsTabTransition(from: oldValue, to: currentView)
|
||||
}
|
||||
}
|
||||
|
||||
@Published var statsSecondRowExpansion: CGFloat = 1
|
||||
private var statsSecondRowWorkItem: DispatchWorkItem?
|
||||
private let statsSecondRowRevealDelay: TimeInterval = 0.5
|
||||
private let statsSecondRowAnimationDuration: TimeInterval = 0.3
|
||||
|
||||
|
||||
@AppStorage("firstLaunch") var firstLaunch: Bool = true
|
||||
|
|
@ -92,6 +101,27 @@ class DynamicIslandViewCoordinator: ObservableObject {
|
|||
selectedScreen = preferredScreen
|
||||
}
|
||||
|
||||
private func handleStatsTabTransition(from oldValue: NotchViews, to newValue: NotchViews) {
|
||||
guard oldValue != newValue else { return }
|
||||
statsSecondRowWorkItem?.cancel()
|
||||
if newValue == .stats && Defaults[.enableStatsFeature] {
|
||||
statsSecondRowExpansion = 0
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func toggleSneakPeek(status: Bool, type: SneakContentType, duration: TimeInterval = 1.5, value: CGFloat = 0, icon: String = "") {
|
||||
let resolvedDuration: TimeInterval
|
||||
switch type {
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ struct NotchStatsView: View {
|
|||
@State private var statsHoverGraceActive = false
|
||||
@State private var statsHoverGraceWorkItem: DispatchWorkItem?
|
||||
@EnvironmentObject var vm: DynamicIslandViewModel
|
||||
@ObservedObject var coordinator = DynamicIslandViewCoordinator.shared
|
||||
|
||||
var availableGraphs: [GraphData] {
|
||||
var graphs: [GraphData] = []
|
||||
|
|
@ -148,18 +149,35 @@ struct NotchStatsView: View {
|
|||
}
|
||||
}
|
||||
} else if graphCount == 4 {
|
||||
// 4 graphs: 2x2 grid
|
||||
// 4 graphs: second row scales from zero height on tab open
|
||||
VStack(spacing: 0) {
|
||||
LazyVGrid(
|
||||
columns: Array(repeating: GridItem(.flexible(), spacing: 8), count: 2),
|
||||
spacing: 12
|
||||
) {
|
||||
ForEach(0..<graphCount, id: \.self) { index in
|
||||
ForEach(0..<2, id: \.self) { index in
|
||||
graphViewForIndex(index)
|
||||
}
|
||||
}
|
||||
|
||||
StatsCollapsibleRow(
|
||||
expansion: coordinator.statsSecondRowExpansion,
|
||||
height: statsSecondRowContentHeight + statsGridSpacingHeight
|
||||
) {
|
||||
LazyVGrid(
|
||||
columns: Array(repeating: GridItem(.flexible(), spacing: 8), count: 2),
|
||||
spacing: 12
|
||||
) {
|
||||
ForEach(2..<graphCount, id: \.self) { index in
|
||||
graphViewForIndex(index)
|
||||
}
|
||||
}
|
||||
.padding(.top, statsGridSpacingHeight)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 5 graphs: First row 3 graphs, second row 2 graphs (half-width each)
|
||||
VStack(spacing: 12) {
|
||||
VStack(spacing: 0) {
|
||||
// First row: 3 graphs
|
||||
LazyVGrid(
|
||||
columns: Array(repeating: GridItem(.flexible(), spacing: 8), count: 3),
|
||||
|
|
@ -169,8 +187,11 @@ struct NotchStatsView: View {
|
|||
graphViewForIndex(index)
|
||||
}
|
||||
}
|
||||
|
||||
// Second row: 2 graphs (half-width each)
|
||||
StatsCollapsibleRow(
|
||||
expansion: coordinator.statsSecondRowExpansion,
|
||||
height: statsSecondRowContentHeight + statsGridSpacingHeight
|
||||
) {
|
||||
LazyVGrid(
|
||||
columns: Array(repeating: GridItem(.flexible(), spacing: 8), count: 2),
|
||||
spacing: 8
|
||||
|
|
@ -179,6 +200,8 @@ struct NotchStatsView: View {
|
|||
graphViewForIndex(index)
|
||||
}
|
||||
}
|
||||
.padding(.top, statsGridSpacingHeight)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -438,8 +461,53 @@ struct NotchStatsView: View {
|
|||
.onChange(of: isHoveringDiskPopover) { _, _ in
|
||||
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
|
||||
|
|
|
|||
|
|
@ -110,6 +110,23 @@ class DynamicIslandViewModel: NSObject, ObservableObject {
|
|||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
coordinator.$statsSecondRowExpansion
|
||||
.removeDuplicates()
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] _ in
|
||||
guard let self else { return }
|
||||
guard self.notchState == .open else { return }
|
||||
let updatedTarget = self.calculateDynamicNotchSize()
|
||||
guard self.notchSize != updatedTarget else { return }
|
||||
withAnimation(.easeInOut(duration: 0.3)) {
|
||||
self.notchSize = updatedTarget
|
||||
}
|
||||
if let delegate = AppDelegate.shared {
|
||||
delegate.ensureWindowSize(updatedTarget, animated: false, force: false)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
private func setupDetectorObserver() {
|
||||
|
|
@ -187,28 +204,12 @@ class DynamicIslandViewModel: NSObject, ObservableObject {
|
|||
|
||||
private func calculateDynamicNotchSize() -> CGSize {
|
||||
// Use minimalistic size if minimalistic UI is enabled
|
||||
var baseSize = Defaults[.enableMinimalisticUI] ? minimalisticOpenNotchSize : openNotchSize
|
||||
|
||||
// Only apply dynamic sizing when on stats tab and stats are enabled
|
||||
guard DynamicIslandViewCoordinator.shared.currentView == .stats && Defaults[.enableStatsFeature] else {
|
||||
return baseSize
|
||||
}
|
||||
|
||||
let enabledGraphsCount = [
|
||||
Defaults[.showCpuGraph],
|
||||
Defaults[.showMemoryGraph],
|
||||
Defaults[.showGpuGraph],
|
||||
Defaults[.showNetworkGraph],
|
||||
Defaults[.showDiskGraph]
|
||||
].filter { $0 }.count
|
||||
|
||||
// If 4+ graphs are enabled, increase width
|
||||
if enabledGraphsCount >= 4 {
|
||||
let extraWidth: CGFloat = CGFloat(enabledGraphsCount - 3) * 120
|
||||
return CGSize(width: baseSize.width + extraWidth, height: baseSize.height)
|
||||
}
|
||||
|
||||
return baseSize
|
||||
let baseSize = Defaults[.enableMinimalisticUI] ? minimalisticOpenNotchSize : openNotchSize
|
||||
return statsAdjustedNotchSize(
|
||||
from: baseSize,
|
||||
isStatsTabActive: DynamicIslandViewCoordinator.shared.currentView == .stats,
|
||||
secondRowProgress: coordinator.statsSecondRowExpansion
|
||||
)
|
||||
}
|
||||
|
||||
func close() {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ let batterySneakSize: CGSize = .init(width: 160, height: 1)
|
|||
let openNotchSize: CGSize = .init(width: 640, height: 190)
|
||||
private let minimalisticBaseOpenNotchSize: CGSize = .init(width: 420, height: 180)
|
||||
private let minimalisticLyricsExtraHeight: CGFloat = 40
|
||||
let statsSecondRowContentHeight: CGFloat = 120
|
||||
let statsGridSpacingHeight: CGFloat = 12
|
||||
|
||||
@MainActor
|
||||
var minimalisticOpenNotchSize: CGSize {
|
||||
|
|
@ -37,6 +39,38 @@ var minimalisticOpenNotchSize: CGSize {
|
|||
let cornerRadiusInsets: (opened: (top: CGFloat, bottom: CGFloat), closed: (top: CGFloat, bottom: CGFloat)) = (opened: (top: 19, bottom: 24), closed: (top: 6, bottom: 14))
|
||||
let minimalisticCornerRadiusInsets: (opened: (top: CGFloat, bottom: CGFloat), closed: (top: CGFloat, bottom: CGFloat)) = (opened: (top: 35, bottom: 35), closed: cornerRadiusInsets.closed)
|
||||
|
||||
func statsAdjustedNotchSize(
|
||||
from baseSize: CGSize,
|
||||
isStatsTabActive: Bool,
|
||||
secondRowProgress: CGFloat
|
||||
) -> CGSize {
|
||||
guard isStatsTabActive, Defaults[.enableStatsFeature] else {
|
||||
return baseSize
|
||||
}
|
||||
|
||||
let enabledGraphsCount = [
|
||||
Defaults[.showCpuGraph],
|
||||
Defaults[.showMemoryGraph],
|
||||
Defaults[.showGpuGraph],
|
||||
Defaults[.showNetworkGraph],
|
||||
Defaults[.showDiskGraph]
|
||||
].filter { $0 }.count
|
||||
|
||||
guard enabledGraphsCount >= 4 else {
|
||||
return baseSize
|
||||
}
|
||||
|
||||
let clampedProgress = max(0, min(secondRowProgress, 1))
|
||||
guard clampedProgress > 0 else {
|
||||
return baseSize
|
||||
}
|
||||
|
||||
var adjustedSize = baseSize
|
||||
let extraHeight = (statsSecondRowContentHeight + statsGridSpacingHeight) * clampedProgress
|
||||
adjustedSize.height += extraHeight
|
||||
return adjustedSize
|
||||
}
|
||||
|
||||
enum MusicPlayerImageSizes {
|
||||
static let cornerRadiusInset: (opened: CGFloat, closed: CGFloat) = (opened: 13.0, closed: 4.0)
|
||||
static let size = (opened: CGSize(width: 90, height: 90), closed: CGSize(width: 20, height: 20))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue