fix(mac): show disconnected sessions + sleeping eyes

This commit is contained in:
Peter Steinberger
2025-12-22 21:13:33 +01:00
parent 9d47b15575
commit 469c8a1a4b
2 changed files with 59 additions and 19 deletions

View File

@@ -137,7 +137,7 @@ struct CritterStatusLabel: View {
}
if self.isSleeping {
return Image(nsImage: CritterIconRenderer.makeIcon(blink: 1, badge: nil))
return Image(nsImage: CritterIconRenderer.makeIcon(blink: 1, eyesClosedLines: true, badge: nil))
}
return Image(nsImage: CritterIconRenderer.makeIcon(
@@ -268,6 +268,7 @@ enum CritterIconRenderer {
earWiggle: CGFloat = 0,
earScale: CGFloat = 1,
earHoles: Bool = false,
eyesClosedLines: Bool = false,
badge: Badge? = nil) -> NSImage
{
// Force a 36×36px backing store (2× for the 18pt logical canvas) so the menu bar icon stays crisp on Retina.
@@ -333,9 +334,7 @@ enum CritterIconRenderer {
let legLift = snapY(legH * 0.35 * legWiggle)
let legYBase = snapY(bodyY - legH + h * 0.05)
let eyeOpen = max(0.05, 1 - blink)
let eyeW = snapX(bodyW * 0.2)
let eyeH = snapY(bodyH * 0.26 * eyeOpen)
let eyeY = snapY(bodyY + bodyH * 0.56)
let eyeOffset = snapX(bodyW * 0.24)
@@ -405,20 +404,50 @@ enum CritterIconRenderer {
transform: nil))
}
let left = CGMutablePath()
left.move(to: CGPoint(x: snapX(leftCenter.x - eyeW / 2), y: snapY(leftCenter.y - eyeH)))
left.addLine(to: CGPoint(x: snapX(leftCenter.x + eyeW / 2), y: snapY(leftCenter.y)))
left.addLine(to: CGPoint(x: snapX(leftCenter.x - eyeW / 2), y: snapY(leftCenter.y + eyeH)))
left.closeSubpath()
if eyesClosedLines {
let lineW = snapX(eyeW * 0.95)
let lineH = snapY(max(stepY * 2, bodyH * 0.06))
let corner = snapX(lineH * 0.6)
let leftRect = CGRect(
x: snapX(leftCenter.x - lineW / 2),
y: snapY(leftCenter.y - lineH / 2),
width: lineW,
height: lineH)
let rightRect = CGRect(
x: snapX(rightCenter.x - lineW / 2),
y: snapY(rightCenter.y - lineH / 2),
width: lineW,
height: lineH)
context.cgContext.addPath(CGPath(
roundedRect: leftRect,
cornerWidth: corner,
cornerHeight: corner,
transform: nil))
context.cgContext.addPath(CGPath(
roundedRect: rightRect,
cornerWidth: corner,
cornerHeight: corner,
transform: nil))
} else {
let eyeOpen = max(0.05, 1 - blink)
let eyeH = snapY(bodyH * 0.26 * eyeOpen)
let right = CGMutablePath()
right.move(to: CGPoint(x: snapX(rightCenter.x + eyeW / 2), y: snapY(rightCenter.y - eyeH)))
right.addLine(to: CGPoint(x: snapX(rightCenter.x - eyeW / 2), y: snapY(rightCenter.y)))
right.addLine(to: CGPoint(x: snapX(rightCenter.x + eyeW / 2), y: snapY(rightCenter.y + eyeH)))
right.closeSubpath()
let left = CGMutablePath()
left.move(to: CGPoint(x: snapX(leftCenter.x - eyeW / 2), y: snapY(leftCenter.y - eyeH)))
left.addLine(to: CGPoint(x: snapX(leftCenter.x + eyeW / 2), y: snapY(leftCenter.y)))
left.addLine(to: CGPoint(x: snapX(leftCenter.x - eyeW / 2), y: snapY(leftCenter.y + eyeH)))
left.closeSubpath()
let right = CGMutablePath()
right.move(to: CGPoint(x: snapX(rightCenter.x + eyeW / 2), y: snapY(rightCenter.y - eyeH)))
right.addLine(to: CGPoint(x: snapX(rightCenter.x - eyeW / 2), y: snapY(rightCenter.y)))
right.addLine(to: CGPoint(x: snapX(rightCenter.x + eyeW / 2), y: snapY(rightCenter.y + eyeH)))
right.closeSubpath()
context.cgContext.addPath(left)
context.cgContext.addPath(right)
}
context.cgContext.addPath(left)
context.cgContext.addPath(right)
context.cgContext.fillPath()
context.cgContext.restoreGState()

View File

@@ -411,6 +411,16 @@ struct MenuContent: View {
self.sessionLoading = true
self.sessionErrorText = nil
if case .connected = self.controlChannel.state {
// ok
} else {
self.sessionStorePath = nil
self.sessionMenu = []
self.sessionErrorText = "No connection to gateway"
self.sessionLoading = false
return
}
do {
let snapshot = try await SessionLoader.loadSnapshot(limit: 32)
self.sessionStorePath = snapshot.storePath
@@ -426,7 +436,8 @@ struct MenuContent: View {
return (lhs.updatedAt ?? .distantPast) > (rhs.updatedAt ?? .distantPast)
}
} catch {
// Keep the previous snapshot (if any) so the menu doesn't go empty while the gateway is flaky.
self.sessionStorePath = nil
self.sessionMenu = []
self.sessionErrorText = self.compactSessionError(error)
}
@@ -437,12 +448,12 @@ struct MenuContent: View {
if let loadError = error as? SessionLoadError {
switch loadError {
case .gatewayUnavailable:
return "Sessions unavailable — gateway unreachable"
return "No connection to gateway"
case .decodeFailed:
return "Sessions unavailable — invalid payload"
return "Sessions unavailable"
}
}
return "Sessions unavailable"
return "No connection to gateway"
}
private func open(tab: SettingsTab) {