mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
Hopefully fixed the Positioning
This commit is contained in:
parent
f411676d02
commit
40e805a785
3 changed files with 145 additions and 9 deletions
|
|
@ -827,6 +827,18 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"%@. Focus active: %@" : {
|
||||
"comment" : "A row that combines a calendar event with a focus indicator. The first argument is the text of the calendar event. The second argument is the name of the focus.",
|
||||
"isCommentAutoGenerated" : true,
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "%1$@. Focus active: %2$@"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"%@°" : {
|
||||
"comment" : "A label inside the temperature gauge that shows the current temperature. The value is shown in degrees Celsius (or Fahrenheit, if specified in the snapshot).",
|
||||
"isCommentAutoGenerated" : true,
|
||||
|
|
|
|||
|
|
@ -393,6 +393,14 @@ struct LockScreenWeatherWidget: View {
|
|||
lockScreenShowCalendarEvent && nextCalendarEvent != nil
|
||||
}
|
||||
|
||||
private var shouldShowFocusInCalendarSlot: Bool {
|
||||
shouldShowFocusWidget && !shouldShowCalendarRow
|
||||
}
|
||||
|
||||
private var shouldCombineFocusAndCalendar: Bool {
|
||||
shouldShowFocusWidget && shouldShowCalendarRow
|
||||
}
|
||||
|
||||
private enum RowKind {
|
||||
case weather
|
||||
case focus
|
||||
|
|
@ -422,6 +430,8 @@ struct LockScreenWeatherWidget: View {
|
|||
var enabled: Set<RowKind> = [.weather]
|
||||
if lockScreenShowCalendarEvent { enabled.insert(.calendar) }
|
||||
if shouldShowFocusWidget { enabled.insert(.focus) }
|
||||
if shouldShowFocusInCalendarSlot { enabled.insert(.calendar); enabled.remove(.focus) }
|
||||
if shouldCombineFocusAndCalendar { enabled.remove(.focus) }
|
||||
return orderedRowKinds.filter { enabled.contains($0) }
|
||||
}
|
||||
|
||||
|
|
@ -462,8 +472,13 @@ struct LockScreenWeatherWidget: View {
|
|||
private var isInline: Bool { snapshot.widgetStyle == .inline }
|
||||
private var stackAlignment: VerticalAlignment { isInline ? .firstTextBaseline : .top }
|
||||
private var stackSpacing: CGFloat { isInline ? 14 : 22 }
|
||||
private var mainRowAlignment: Alignment { isInline ? .leading : .center }
|
||||
private var secondaryRowAlignment: Alignment { isInline ? .leading : .center }
|
||||
private var mainRowAlignment: Alignment {
|
||||
if isInline {
|
||||
return shouldCombineFocusAndCalendar ? .center : .leading
|
||||
}
|
||||
return .center
|
||||
}
|
||||
private var secondaryRowAlignment: Alignment { .center }
|
||||
private var focusRowAlignment: Alignment { .center }
|
||||
private var gaugeDiameter: CGFloat { 64 }
|
||||
private var topPadding: CGFloat { isInline ? 6 : 22 }
|
||||
|
|
@ -570,15 +585,44 @@ struct LockScreenWeatherWidget: View {
|
|||
case .weather:
|
||||
mainWidgetRow
|
||||
case .calendar:
|
||||
nextEventRow
|
||||
if shouldCombineFocusAndCalendar {
|
||||
combinedFocusCalendarRow
|
||||
} else if shouldShowFocusInCalendarSlot {
|
||||
focusRowInCalendarSlot
|
||||
} else {
|
||||
nextEventRow
|
||||
}
|
||||
case .focus:
|
||||
focusWidget
|
||||
.opacity(shouldShowFocusWidget ? 1 : 0)
|
||||
.accessibilityHidden(!shouldShowFocusWidget)
|
||||
.allowsHitTesting(false)
|
||||
if shouldCombineFocusAndCalendar {
|
||||
EmptyView()
|
||||
} else {
|
||||
focusWidget
|
||||
.opacity(shouldShowFocusWidget ? 1 : 0)
|
||||
.accessibilityHidden(!shouldShowFocusWidget)
|
||||
.allowsHitTesting(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var focusRowInCalendarSlot: some View {
|
||||
HStack(alignment: .center, spacing: 8) {
|
||||
focusIcon
|
||||
.font(.system(size: 20, weight: .semibold))
|
||||
.frame(width: 26, height: 26)
|
||||
|
||||
Text(focusDisplayName)
|
||||
.font(inlinePrimaryFont)
|
||||
.lineLimit(1)
|
||||
.minimumScaleFactor(0.85)
|
||||
.allowsTightening(true)
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: secondaryRowAlignment)
|
||||
.padding(.horizontal, 2)
|
||||
.opacity(shouldShowFocusWidget ? 1 : 0)
|
||||
.accessibilityLabel("Focus active: \(focusDisplayName)")
|
||||
.allowsHitTesting(false)
|
||||
}
|
||||
|
||||
private var mainWidgetRow: some View {
|
||||
HStack(alignment: stackAlignment, spacing: stackSpacing) {
|
||||
if let charging = snapshot.charging {
|
||||
|
|
@ -627,6 +671,77 @@ struct LockScreenWeatherWidget: View {
|
|||
)
|
||||
}
|
||||
|
||||
private var combinedFocusCalendarRow: some View {
|
||||
let event = nextCalendarEvent
|
||||
let line = shouldShowCalendarRow ? eventLineText(for: event) : lastCalendarLine
|
||||
let iconConfig = calendarRowIconConfig(for: event)
|
||||
|
||||
return HStack(alignment: .center, spacing: 10) {
|
||||
HStack(alignment: .center, spacing: 6) {
|
||||
calendarIconView(iconConfig)
|
||||
.frame(width: 26, height: 26)
|
||||
|
||||
Text(line)
|
||||
.font(inlinePrimaryFont)
|
||||
.lineLimit(1)
|
||||
.minimumScaleFactor(0.85)
|
||||
.allowsTightening(true)
|
||||
}
|
||||
.layoutPriority(2)
|
||||
|
||||
Text("•")
|
||||
.font(inlinePrimaryFont)
|
||||
.foregroundStyle(secondaryLabelColor)
|
||||
.accessibilityHidden(true)
|
||||
|
||||
HStack(alignment: .center, spacing: 8) {
|
||||
focusIcon
|
||||
.font(.system(size: 20, weight: .semibold))
|
||||
.frame(width: 26, height: 26)
|
||||
|
||||
Text(focusDisplayName)
|
||||
.font(inlinePrimaryFont)
|
||||
.lineLimit(1)
|
||||
.minimumScaleFactor(0.85)
|
||||
.allowsTightening(true)
|
||||
}
|
||||
.layoutPriority(1)
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.padding(.horizontal, 2)
|
||||
.id(calendarRowRenderToken)
|
||||
.opacity(shouldShowFocusWidget && shouldShowCalendarRow ? 1 : 0)
|
||||
.accessibilityLabel("\(line). Focus active: \(focusDisplayName)")
|
||||
.allowsHitTesting(false)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func calendarIconView(_ iconConfig: (name: String, renderingMode: SymbolRenderingMode, colors: [Color])) -> some View {
|
||||
let image = Image(systemName: iconConfig.name)
|
||||
.font(.system(size: 20, weight: .semibold))
|
||||
|
||||
let isPalette = String(describing: iconConfig.renderingMode)
|
||||
.lowercased()
|
||||
.contains("palette")
|
||||
|
||||
if isPalette, iconConfig.colors.count >= 2 {
|
||||
image
|
||||
.symbolRenderingMode(.palette)
|
||||
.foregroundStyle(iconConfig.colors[0], iconConfig.colors[1])
|
||||
} else if iconConfig.colors.count >= 2 {
|
||||
image
|
||||
.symbolRenderingMode(iconConfig.renderingMode)
|
||||
.foregroundStyle(iconConfig.colors[0], iconConfig.colors[1])
|
||||
} else if iconConfig.colors.count == 1 {
|
||||
image
|
||||
.symbolRenderingMode(iconConfig.renderingMode)
|
||||
.foregroundStyle(iconConfig.colors[0])
|
||||
} else {
|
||||
image
|
||||
.symbolRenderingMode(iconConfig.renderingMode)
|
||||
}
|
||||
}
|
||||
|
||||
private func calendarRowIconConfig(for event: EventModel?) -> (name: String, renderingMode: SymbolRenderingMode, colors: [Color]) {
|
||||
guard let event else {
|
||||
return (name: "calendar.badge", renderingMode: .hierarchical, colors: [Color.white.opacity(0.9)])
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ final class LockScreenWeatherPanelManager {
|
|||
private(set) var latestFrame: NSRect?
|
||||
private var lastSnapshot: LockScreenWeatherSnapshot?
|
||||
private var lastContentSize: CGSize?
|
||||
private var lastInlineBaselineHeight: CGFloat = 0
|
||||
private var screenChangeObserver: NSObjectProtocol?
|
||||
private var workspaceObservers: [NSObjectProtocol] = []
|
||||
|
||||
|
|
@ -64,6 +65,9 @@ final class LockScreenWeatherPanelManager {
|
|||
let view = LockScreenWeatherWidget(snapshot: snapshot)
|
||||
let hostingView = NSHostingView(rootView: view)
|
||||
let fittingSize = hostingView.fittingSize
|
||||
if snapshot.widgetStyle == .inline {
|
||||
lastInlineBaselineHeight = max(lastInlineBaselineHeight, fittingSize.height)
|
||||
}
|
||||
hostingView.frame = NSRect(origin: .zero, size: fittingSize)
|
||||
|
||||
let targetFrame = frame(for: fittingSize, snapshot: snapshot, on: screen)
|
||||
|
|
@ -116,13 +120,18 @@ final class LockScreenWeatherPanelManager {
|
|||
let verticalOffset = screenFrame.height * 0.15
|
||||
let isCircular = snapshot.widgetStyle == .circular
|
||||
let topMargin: CGFloat = isCircular ? 120 : 48
|
||||
let maxY = screenFrame.maxY - size.height - topMargin
|
||||
let inlineBaselineHeight: CGFloat = max(lastInlineBaselineHeight, 80)
|
||||
let positionHeight = snapshot.widgetStyle == .inline
|
||||
? max(size.height, inlineBaselineHeight)
|
||||
: size.height
|
||||
let maxY = screenFrame.maxY - positionHeight - topMargin
|
||||
let baseY = min(maxY, screenFrame.midY + verticalOffset)
|
||||
let loweredY = baseY - 36
|
||||
|
||||
let inlineLift: CGFloat = snapshot.widgetStyle == .inline ? 44 : 0
|
||||
let circularDrop: CGFloat = isCircular ? 28 : 0
|
||||
let sizeDrop = max(0, size.height - 80) * 0.35
|
||||
let sizeDropHeight = positionHeight
|
||||
let sizeDrop = max(0, sizeDropHeight - 80) * 0.35
|
||||
let userOffset = CGFloat(Defaults[.lockScreenWeatherVerticalOffset])
|
||||
let clampedOffset = min(max(userOffset, -160), 160)
|
||||
let adjustedY = loweredY + inlineLift + clampedOffset - circularDrop - sizeDrop
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue