fix(mac): show disconnected sessions + sleeping eyes
parent
9d47b15575
commit
469c8a1a4b
|
|
@ -137,7 +137,7 @@ struct CritterStatusLabel: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.isSleeping {
|
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(
|
return Image(nsImage: CritterIconRenderer.makeIcon(
|
||||||
|
|
@ -268,6 +268,7 @@ enum CritterIconRenderer {
|
||||||
earWiggle: CGFloat = 0,
|
earWiggle: CGFloat = 0,
|
||||||
earScale: CGFloat = 1,
|
earScale: CGFloat = 1,
|
||||||
earHoles: Bool = false,
|
earHoles: Bool = false,
|
||||||
|
eyesClosedLines: Bool = false,
|
||||||
badge: Badge? = nil) -> NSImage
|
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.
|
// 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 legLift = snapY(legH * 0.35 * legWiggle)
|
||||||
let legYBase = snapY(bodyY - legH + h * 0.05)
|
let legYBase = snapY(bodyY - legH + h * 0.05)
|
||||||
|
|
||||||
let eyeOpen = max(0.05, 1 - blink)
|
|
||||||
let eyeW = snapX(bodyW * 0.2)
|
let eyeW = snapX(bodyW * 0.2)
|
||||||
let eyeH = snapY(bodyH * 0.26 * eyeOpen)
|
|
||||||
let eyeY = snapY(bodyY + bodyH * 0.56)
|
let eyeY = snapY(bodyY + bodyH * 0.56)
|
||||||
let eyeOffset = snapX(bodyW * 0.24)
|
let eyeOffset = snapX(bodyW * 0.24)
|
||||||
|
|
||||||
|
|
@ -405,6 +404,34 @@ enum CritterIconRenderer {
|
||||||
transform: nil))
|
transform: nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 left = CGMutablePath()
|
let left = CGMutablePath()
|
||||||
left.move(to: CGPoint(x: snapX(leftCenter.x - eyeW / 2), y: snapY(leftCenter.y - eyeH)))
|
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)))
|
||||||
|
|
@ -419,6 +446,8 @@ enum CritterIconRenderer {
|
||||||
|
|
||||||
context.cgContext.addPath(left)
|
context.cgContext.addPath(left)
|
||||||
context.cgContext.addPath(right)
|
context.cgContext.addPath(right)
|
||||||
|
}
|
||||||
|
|
||||||
context.cgContext.fillPath()
|
context.cgContext.fillPath()
|
||||||
context.cgContext.restoreGState()
|
context.cgContext.restoreGState()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -411,6 +411,16 @@ struct MenuContent: View {
|
||||||
self.sessionLoading = true
|
self.sessionLoading = true
|
||||||
self.sessionErrorText = nil
|
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 {
|
do {
|
||||||
let snapshot = try await SessionLoader.loadSnapshot(limit: 32)
|
let snapshot = try await SessionLoader.loadSnapshot(limit: 32)
|
||||||
self.sessionStorePath = snapshot.storePath
|
self.sessionStorePath = snapshot.storePath
|
||||||
|
|
@ -426,7 +436,8 @@ struct MenuContent: View {
|
||||||
return (lhs.updatedAt ?? .distantPast) > (rhs.updatedAt ?? .distantPast)
|
return (lhs.updatedAt ?? .distantPast) > (rhs.updatedAt ?? .distantPast)
|
||||||
}
|
}
|
||||||
} catch {
|
} 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)
|
self.sessionErrorText = self.compactSessionError(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -437,13 +448,13 @@ struct MenuContent: View {
|
||||||
if let loadError = error as? SessionLoadError {
|
if let loadError = error as? SessionLoadError {
|
||||||
switch loadError {
|
switch loadError {
|
||||||
case .gatewayUnavailable:
|
case .gatewayUnavailable:
|
||||||
return "Sessions unavailable — gateway unreachable"
|
return "No connection to gateway"
|
||||||
case .decodeFailed:
|
case .decodeFailed:
|
||||||
return "Sessions unavailable — invalid payload"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "Sessions unavailable"
|
return "Sessions unavailable"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return "No connection to gateway"
|
||||||
|
}
|
||||||
|
|
||||||
private func open(tab: SettingsTab) {
|
private func open(tab: SettingsTab) {
|
||||||
SettingsTabRouter.request(tab)
|
SettingsTabRouter.request(tab)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue