fix(mac): show disconnected sessions + sleeping eyes
This commit is contained in:
@@ -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()
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user