Mediensteuerung hochkant, Symbole wieder sichtbar, „Auto" als Zustand
Die Mediensteuerung stand nebeneinander: Cover links, alles andere in den verbleibenden gut hundert Punkten. Daher „Bernhard H…" statt eines Titels. Jetzt übereinander, wie es zu einer hochkanten Kachel passt. Das Cover ragte zusätzlich über die Kachel hinaus, weil `clipShape` vor dem Rahmen stand — beschnitten wurde damit auf die Eigengröße des Bildes, und die ist bei einem Podcast-Cover ein Vielfaches. Erst Rahmen, dann beschneiden. Menüleistensymbole waren kaum zu sehen. `color.set()` vor `image.draw(in:)` färbt ein Template-Bild nicht: es wird schwarz gezeichnet, auf einer dunklen Menüleiste also unsichtbar. AppKit färbt Template-Bilder nur ein, wenn sie als `image` eines Buttons gesetzt sind — in einer selbst gezeichneten Ansicht muss die Farbe in die Symbolkonfiguration. Betraf alle fünf Zeichenstellen, nicht nur die Lüfter. „fans.auto" stand als roher Schlüssel da: Xcode hatte ihn extrahiert, gefüllt wurde er nie. Beim Nachsehen waren es 35 solche Einträge über alle Kataloge hinweg — die meisten reine Formatschlüssel, die als Durchreicher trotzdem einen Wert brauchen. Der Automatik-Knopf ist jetzt eine gefüllte Pille, wenn sie greift. Blauer Text sieht aus wie ein Link und nicht wie ein Zustand. Und ein Absturz, der noch niemandem passiert ist: meldet der Helfer für einen stehenden Lüfter keine Grenzen, hätte `Slider(in: 0...0)` die App beendet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -98,22 +98,46 @@ private struct FanRow: View {
|
|||||||
.foregroundStyle(Onyx.Color.textPrimary)
|
.foregroundStyle(Onyx.Color.textPrimary)
|
||||||
}
|
}
|
||||||
|
|
||||||
HStack(spacing: 6) {
|
HStack(spacing: 8) {
|
||||||
// Automatik ist der Ruhezustand und bleibt einen Klick entfernt:
|
// Automatik ist der Ruhezustand und bleibt einen Klick entfernt:
|
||||||
// wer manuell geregelt hat, muss ohne Nachdenken zurückkönnen.
|
// wer manuell geregelt hat, muss ohne Nachdenken zurückkönnen.
|
||||||
|
// Als gefüllte Pille, wenn sie greift — ein blauer Text sieht
|
||||||
|
// aus wie ein Link und nicht wie ein Zustand.
|
||||||
Button { control.setAutomatic(index: index) } label: {
|
Button { control.setAutomatic(index: index) } label: {
|
||||||
Text("fans.auto")
|
Text("fans.auto")
|
||||||
.font(Onyx.Font.caption)
|
.font(Onyx.Font.metricSmall)
|
||||||
.foregroundStyle(fan.isManual ? Onyx.Color.textTertiary
|
.foregroundStyle(fan.isManual ? Onyx.Color.textTertiary
|
||||||
: Onyx.Color.accent)
|
: Onyx.Color.surface)
|
||||||
|
.padding(.horizontal, 7)
|
||||||
|
.padding(.vertical, 2)
|
||||||
|
.background {
|
||||||
|
Capsule()
|
||||||
|
.fill(fan.isManual ? Color.clear : Onyx.Color.accent)
|
||||||
|
.overlay {
|
||||||
|
Capsule().strokeBorder(
|
||||||
|
fan.isManual ? Onyx.Color.hairline : .clear,
|
||||||
|
lineWidth: 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
|
.disabled(!fan.isManual)
|
||||||
|
|
||||||
|
// Ein Regler über einen leeren Bereich stürzt ab. Meldet der
|
||||||
|
// Helfer keine brauchbaren Grenzen — etwa weil der Lüfter steht
|
||||||
|
// und der SMC nichts hergibt —, gibt es nichts zu ziehen.
|
||||||
|
if fan.limits.maximum > fan.limits.minimum {
|
||||||
Slider(value: Binding(
|
Slider(value: Binding(
|
||||||
get: { fan.targetRPM },
|
get: { min(max(fan.targetRPM, fan.limits.minimum), fan.limits.maximum) },
|
||||||
set: { control.setTarget(index: index, rpm: $0) }),
|
set: { control.setTarget(index: index, rpm: $0) }),
|
||||||
in: fan.limits.minimum...fan.limits.maximum)
|
in: fan.limits.minimum...fan.limits.maximum)
|
||||||
.controlSize(.mini)
|
.controlSize(.mini)
|
||||||
|
} else {
|
||||||
|
Text("fans.noRange")
|
||||||
|
.font(Onyx.Font.metricSmall)
|
||||||
|
.foregroundStyle(Onyx.Color.textTertiary)
|
||||||
|
Spacer(minLength: 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -219,19 +243,16 @@ private final class FanStatusView: NSView, WidthReporting {
|
|||||||
|
|
||||||
override func draw(_ dirtyRect: NSRect) {
|
override func draw(_ dirtyRect: NSRect) {
|
||||||
let color = NSColor.labelColor
|
let color = NSColor.labelColor
|
||||||
guard let image = NSImage(systemSymbolName: "fan", accessibilityDescription: nil)
|
|
||||||
else { return }
|
|
||||||
image.isTemplate = true
|
|
||||||
|
|
||||||
if presentation == .symbol {
|
if presentation == .symbol {
|
||||||
color.set()
|
MenuBarText.drawSymbol("fan", color: color,
|
||||||
image.draw(in: NSRect(x: bounds.midX - 7.5, y: bounds.midY - 7.5,
|
in: NSRect(x: bounds.midX - 7.5, y: bounds.midY - 7.5,
|
||||||
width: 15, height: 15))
|
width: 15, height: 15))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
color.set()
|
MenuBarText.drawSymbol("fan", color: color,
|
||||||
image.draw(in: NSRect(x: 0, y: bounds.midY - 6.5, width: 13, height: 13))
|
in: NSRect(x: 0, y: bounds.midY - 6.5, width: 13, height: 13))
|
||||||
MenuBarText.draw(rpm.map { String(Int($0.rounded())) } ?? "–",
|
MenuBarText.draw(rpm.map { String(Int($0.rounded())) } ?? "–",
|
||||||
color: color,
|
color: color,
|
||||||
in: NSRect(x: 15, y: 0, width: bounds.width - 15, height: bounds.height))
|
in: NSRect(x: 15, y: 0, width: bounds.width - 15, height: bounds.height))
|
||||||
|
|||||||
@@ -3,15 +3,75 @@
|
|||||||
"strings": {
|
"strings": {
|
||||||
"%@": {
|
"%@": {
|
||||||
"comment": "A label showing the minimum RPM of a fan.",
|
"comment": "A label showing the minimum RPM of a fan.",
|
||||||
"isCommentAutoGenerated": true
|
"isCommentAutoGenerated": true,
|
||||||
|
"localizations": {
|
||||||
|
"de": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "%@"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "%@"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"%@ U/min": {
|
"%@ U/min": {
|
||||||
"comment": "A label that shows the current speed of a fan. The argument is the current speed of the fan.",
|
"comment": "A label that shows the current speed of a fan. The argument is the current speed of the fan.",
|
||||||
"isCommentAutoGenerated": true
|
"isCommentAutoGenerated": true,
|
||||||
|
"localizations": {
|
||||||
|
"de": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "%@ U/min"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "%@ U/min"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"%@ °C": {
|
||||||
|
"comment": "A label showing the temperature of the hottest fan in the report, in degrees Celsius. The argument is the temperature in degrees Celsius.",
|
||||||
|
"isCommentAutoGenerated": true,
|
||||||
|
"localizations": {
|
||||||
|
"de": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "%@ °C"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "%@ °C"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"%@°": {
|
"%@°": {
|
||||||
"comment": "A temperature in °C.",
|
"comment": "A temperature in °C.",
|
||||||
"isCommentAutoGenerated": true
|
"isCommentAutoGenerated": true,
|
||||||
|
"localizations": {
|
||||||
|
"de": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "%@°"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "%@°"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"fans.approval.needed": {
|
"fans.approval.needed": {
|
||||||
"extractionState": "stale",
|
"extractionState": "stale",
|
||||||
@@ -64,6 +124,24 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fans.auto": {
|
||||||
|
"comment": "A button to set a fan to automatic mode.",
|
||||||
|
"isCommentAutoGenerated": true,
|
||||||
|
"localizations": {
|
||||||
|
"de": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Auto"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Auto"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"fans.connecting": {
|
"fans.connecting": {
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
@@ -80,7 +158,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fans.fan %@": {
|
||||||
|
"comment": "A label showing the index of a fan. The argument is the index of the fan.",
|
||||||
|
"isCommentAutoGenerated": true,
|
||||||
|
"localizations": {
|
||||||
|
"de": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Lüfter %@"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Fan %@"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"fans.fan %lld": {
|
"fans.fan %lld": {
|
||||||
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
@@ -162,6 +259,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fans.manual": {
|
||||||
|
"localizations": {
|
||||||
|
"de": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Manuell"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Manual"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"fans.mode.auto": {
|
"fans.mode.auto": {
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
@@ -195,6 +308,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fans.noData": {
|
"fans.noData": {
|
||||||
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
@@ -210,7 +324,24 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fans.noRange": {
|
||||||
|
"localizations": {
|
||||||
|
"de": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Kein Regelbereich"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "No adjustable range"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"fans.notInstalled": {
|
"fans.notInstalled": {
|
||||||
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
@@ -563,6 +694,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mixer.menubar.name": {
|
"mixer.menubar.name": {
|
||||||
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
@@ -596,6 +728,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"onboarding.allow": {
|
"onboarding.allow": {
|
||||||
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
@@ -612,6 +745,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"onboarding.audio": {
|
"onboarding.audio": {
|
||||||
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
@@ -628,6 +762,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"onboarding.audio.why": {
|
"onboarding.audio.why": {
|
||||||
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
@@ -644,6 +779,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"onboarding.calendar": {
|
"onboarding.calendar": {
|
||||||
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
@@ -660,6 +796,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"onboarding.calendar.why": {
|
"onboarding.calendar.why": {
|
||||||
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
@@ -676,6 +813,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"onboarding.done": {
|
"onboarding.done": {
|
||||||
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
@@ -692,6 +830,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"onboarding.helper": {
|
"onboarding.helper": {
|
||||||
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
@@ -708,6 +847,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"onboarding.helper.why": {
|
"onboarding.helper.why": {
|
||||||
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
@@ -740,6 +880,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"onboarding.location": {
|
"onboarding.location": {
|
||||||
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
@@ -756,6 +897,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"onboarding.location.why": {
|
"onboarding.location.why": {
|
||||||
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
@@ -772,6 +914,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"onboarding.openSettings": {
|
"onboarding.openSettings": {
|
||||||
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
@@ -951,6 +1094,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings.general": {
|
"settings.general": {
|
||||||
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
@@ -1100,6 +1244,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings.onboarding.show": {
|
"settings.onboarding.show": {
|
||||||
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
@@ -1252,7 +1397,21 @@
|
|||||||
},
|
},
|
||||||
"settings.shelf.count %@": {
|
"settings.shelf.count %@": {
|
||||||
"comment": "A label showing the number of items in the shelf. The argument is the number of items in the shelf.",
|
"comment": "A label showing the number of items in the shelf. The argument is the number of items in the shelf.",
|
||||||
"isCommentAutoGenerated": true
|
"isCommentAutoGenerated": true,
|
||||||
|
"localizations": {
|
||||||
|
"de": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "%@ Dateien abgelegt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "%@ files parked"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"settings.shelf.count %lld": {
|
"settings.shelf.count %lld": {
|
||||||
"extractionState": "stale",
|
"extractionState": "stale",
|
||||||
@@ -1273,7 +1432,21 @@
|
|||||||
},
|
},
|
||||||
"settings.shelf.days %@": {
|
"settings.shelf.days %@": {
|
||||||
"comment": "A label that lets the user select how many days to wait before automatically removing items from the shelf. The argument is the number of days.",
|
"comment": "A label that lets the user select how many days to wait before automatically removing items from the shelf. The argument is the number of days.",
|
||||||
"isCommentAutoGenerated": true
|
"isCommentAutoGenerated": true,
|
||||||
|
"localizations": {
|
||||||
|
"de": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Nach %@ Tagen"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "After %@ days"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"settings.shelf.days %lld": {
|
"settings.shelf.days %lld": {
|
||||||
"extractionState": "stale",
|
"extractionState": "stale",
|
||||||
@@ -1579,6 +1752,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings.widgets.hint.order": {
|
"settings.widgets.hint.order": {
|
||||||
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
@@ -1629,6 +1803,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"widget.fans.name": {
|
"widget.fans.name": {
|
||||||
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
|
|||||||
@@ -92,17 +92,14 @@ private final class MixerStatusView: NSView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func draw(_ dirtyRect: NSRect) {
|
override func draw(_ dirtyRect: NSRect) {
|
||||||
guard let image = NSImage(systemSymbolName: "slider.horizontal.3",
|
|
||||||
accessibilityDescription: nil) else { return }
|
|
||||||
image.isTemplate = true
|
|
||||||
// Ausgeschaltet bleibt es sichtbar, aber zurückgenommen: das Element
|
// Ausgeschaltet bleibt es sichtbar, aber zurückgenommen: das Element
|
||||||
// verschwinden zu lassen wäre die schlechtere Antwort — dann fände man
|
// verschwinden zu lassen wäre die schlechtere Antwort — dann fände man
|
||||||
// den Weg zum Einschalten nicht mehr.
|
// den Weg zum Einschalten nicht mehr.
|
||||||
let color = (isEnabled && managed > 0)
|
let color = (isEnabled && managed > 0)
|
||||||
? NSColor.labelColor
|
? NSColor.labelColor
|
||||||
: NSColor.labelColor.withAlphaComponent(0.55)
|
: NSColor.labelColor.withAlphaComponent(0.55)
|
||||||
color.set()
|
MenuBarText.drawSymbol("slider.horizontal.3", color: color,
|
||||||
image.draw(in: NSRect(x: bounds.midX - 7.5, y: bounds.midY - 7.5,
|
in: NSRect(x: bounds.midX - 7.5, y: bounds.midY - 7.5,
|
||||||
width: 15, height: 15))
|
width: 15, height: 15))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,21 @@
|
|||||||
"": {},
|
"": {},
|
||||||
"%lld %%": {
|
"%lld %%": {
|
||||||
"comment": "A row of controls for adjusting the volume and muting a process.",
|
"comment": "A row of controls for adjusting the volume and muting a process.",
|
||||||
"isCommentAutoGenerated": true
|
"isCommentAutoGenerated": true,
|
||||||
|
"localizations": {
|
||||||
|
"de": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "%lld %%"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "%lld %%"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"mixer.name": {
|
"mixer.name": {
|
||||||
"localizations": {
|
"localizations": {
|
||||||
|
|||||||
@@ -1,358 +1,404 @@
|
|||||||
{
|
{
|
||||||
"sourceLanguage" : "en",
|
"sourceLanguage": "en",
|
||||||
"strings" : {
|
"strings": {
|
||||||
"" : {
|
"": {},
|
||||||
|
"%lld": {
|
||||||
},
|
"comment": "A day of the month. The argument is the day of the month.",
|
||||||
"%lld" : {
|
"isCommentAutoGenerated": true,
|
||||||
"comment" : "A day of the month. The argument is the day of the month.",
|
"localizations": {
|
||||||
"isCommentAutoGenerated" : true
|
"de": {
|
||||||
},
|
"stringUnit": {
|
||||||
"calendar.source.apple" : {
|
"state": "translated",
|
||||||
"localizations" : {
|
"value": "%lld"
|
||||||
"de" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Apple Kalender"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Apple Calendar"
|
"value": "%lld"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"calendar.source.both" : {
|
"calendar.source.apple": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Beide"
|
"value": "Apple Kalender"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Both"
|
"value": "Apple Calendar"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"calendar.source.calendarr" : {
|
"calendar.source.both": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Calendarr"
|
"value": "Beide"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Calendarr"
|
"value": "Both"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"calendar.source.readOnly" : {
|
"calendar.source.calendarr": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Onyx liest nur. Es meldet sich nie selbst an und schreibt nie nach Calendarr."
|
"value": "Calendarr"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Onyx only reads. It never signs in and never writes to Calendarr."
|
"value": "Calendarr"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"calendar.source.status.coverage" : {
|
"calendar.source.readOnly": {
|
||||||
"extractionState" : "stale",
|
"localizations": {
|
||||||
"localizations" : {
|
"de": {
|
||||||
"de" : {
|
"stringUnit": {
|
||||||
"stringUnit" : {
|
"state": "translated",
|
||||||
"state" : "translated",
|
"value": "Onyx liest nur. Es meldet sich nie selbst an und schreibt nie nach Calendarr."
|
||||||
"value" : "Bekannt bis %@"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Known through %@"
|
"value": "Onyx only reads. It never signs in and never writes to Calendarr."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"calendar.source.status.coverage %@" : {
|
"calendar.source.status.coverage": {
|
||||||
"comment" : "A footnote in the Calendarr settings, indicating the end of the coverage window.",
|
"extractionState": "stale",
|
||||||
"isCommentAutoGenerated" : true
|
"localizations": {
|
||||||
},
|
"de": {
|
||||||
"calendar.source.status.incompatible" : {
|
"stringUnit": {
|
||||||
"localizations" : {
|
"state": "translated",
|
||||||
"de" : {
|
"value": "Bekannt bis %@"
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Calendarr schreibt ein neueres Format. Bitte Onyx aktualisieren."
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Calendarr writes a newer format. Please update Onyx."
|
"value": "Known through %@"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"calendar.source.status.loggedOut" : {
|
"calendar.source.status.coverage %@": {
|
||||||
"localizations" : {
|
"comment": "A footnote in the Calendarr settings, indicating the end of the coverage window.",
|
||||||
"de" : {
|
"isCommentAutoGenerated": true,
|
||||||
"stringUnit" : {
|
"localizations": {
|
||||||
"state" : "translated",
|
"de": {
|
||||||
"value" : "In Calendarr nicht angemeldet. Alte Termine werden nicht gezeigt."
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Bekannt bis %@"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Not signed in to Calendarr. Old events are not shown."
|
"value": "Known through %@"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"calendar.source.status.neverWritten" : {
|
"calendar.source.status.incompatible": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Calendarr einmal öffnen, damit ein Schnappschuss geschrieben wird."
|
"value": "Calendarr schreibt ein neueres Format. Bitte Onyx aktualisieren."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Open Calendarr once so it can write a snapshot."
|
"value": "Calendarr writes a newer format. Please update Onyx."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"calendar.source.status.ready" : {
|
"calendar.source.status.loggedOut": {
|
||||||
"extractionState" : "stale",
|
"localizations": {
|
||||||
"localizations" : {
|
"de": {
|
||||||
"de" : {
|
"stringUnit": {
|
||||||
"stringUnit" : {
|
"state": "translated",
|
||||||
"state" : "translated",
|
"value": "In Calendarr nicht angemeldet. Alte Termine werden nicht gezeigt."
|
||||||
"value" : "%@ Termine, Stand %@"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "%@ events, as of %@"
|
"value": "Not signed in to Calendarr. Old events are not shown."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"calendar.source.status.ready %@ %@" : {
|
"calendar.source.status.neverWritten": {
|
||||||
"comment" : "Die Anzahl der Termine in der The argument is the string “–”.",
|
"localizations": {
|
||||||
"isCommentAutoGenerated" : true,
|
"de": {
|
||||||
"localizations" : {
|
"stringUnit": {
|
||||||
"en" : {
|
"state": "translated",
|
||||||
"stringUnit" : {
|
"value": "Calendarr einmal öffnen, damit ein Schnappschuss geschrieben wird."
|
||||||
"state" : "new",
|
}
|
||||||
"value" : "calendar.source.status.ready %1$@ %2$@"
|
},
|
||||||
|
"en": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Open Calendarr once so it can write a snapshot."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"calendar.source.status.unreadable" : {
|
"calendar.source.status.ready": {
|
||||||
"extractionState" : "stale",
|
"extractionState": "stale",
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Schnappschuss unlesbar: %@"
|
"value": "%@ Termine, Stand %@"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Snapshot unreadable: %@"
|
"value": "%@ events, as of %@"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"calendar.source.status.unreadable %@" : {
|
"calendar.source.status.ready %@ %@": {
|
||||||
"comment" : "A warning message explaining that a Calendarr source is not readable. The argument is a human-readable description of the problem.",
|
"comment": "Die Anzahl der Termine in der The argument is the string “–”.",
|
||||||
"isCommentAutoGenerated" : true
|
"isCommentAutoGenerated": true,
|
||||||
},
|
"localizations": {
|
||||||
"calendar.source.title" : {
|
"en": {
|
||||||
"localizations" : {
|
"stringUnit": {
|
||||||
"de" : {
|
"state": "new",
|
||||||
"stringUnit" : {
|
"value": "calendar.source.status.ready %1$@ %2$@"
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Terminquelle"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Calendar source"
|
"value": "%@ Termine, Stand %@"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"widget.calendar.allDay" : {
|
"calendar.source.status.unreadable": {
|
||||||
"localizations" : {
|
"extractionState": "stale",
|
||||||
"de" : {
|
"localizations": {
|
||||||
"stringUnit" : {
|
"de": {
|
||||||
"state" : "translated",
|
"stringUnit": {
|
||||||
"value" : "Ganztägig"
|
"state": "translated",
|
||||||
|
"value": "Schnappschuss unlesbar: %@"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "All day"
|
"value": "Snapshot unreadable: %@"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"widget.calendar.day.unknown" : {
|
"calendar.source.status.unreadable %@": {
|
||||||
"comment" : "Erklärt einen ausgegrauten Tag: keine Information, nicht keine Termine",
|
"comment": "A warning message explaining that a Calendarr source is not readable. The argument is a human-readable description of the problem.",
|
||||||
"localizations" : {
|
"isCommentAutoGenerated": true,
|
||||||
"de" : {
|
"localizations": {
|
||||||
"stringUnit" : {
|
"de": {
|
||||||
"state" : "translated",
|
"stringUnit": {
|
||||||
"value" : "Für diesen Tag liegen keine Daten vor"
|
"state": "translated",
|
||||||
|
"value": "Schnappschuss unlesbar: %@"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "No data available for this day"
|
"value": "Snapshot unreadable: %@"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"widget.calendar.denied" : {
|
"calendar.source.title": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Kein Kalenderzugriff.\nIn den Systemeinstellungen erlauben."
|
"value": "Terminquelle"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "No calendar access.\nAllow it in System Settings."
|
"value": "Calendar source"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"widget.calendar.incompatible" : {
|
"widget.calendar.allDay": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Onyx ist zu alt für diese\nCalendarr-Version. Bitte aktualisieren."
|
"value": "Ganztägig"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Onyx is too old for this\nCalendarr version. Please update."
|
"value": "All day"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"widget.calendar.loggedOut" : {
|
"widget.calendar.day.unknown": {
|
||||||
"localizations" : {
|
"comment": "Erklärt einen ausgegrauten Tag: keine Information, nicht keine Termine",
|
||||||
"de" : {
|
"localizations": {
|
||||||
"stringUnit" : {
|
"de": {
|
||||||
"state" : "translated",
|
"stringUnit": {
|
||||||
"value" : "In Calendarr anmelden"
|
"state": "translated",
|
||||||
|
"value": "Für diesen Tag liegen keine Daten vor"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Sign in to Calendarr"
|
"value": "No data available for this day"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"widget.calendar.name" : {
|
"widget.calendar.denied": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Kalender"
|
"value": "Kein Kalenderzugriff.\nIn den Systemeinstellungen erlauben."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Calendar"
|
"value": "No calendar access.\nAllow it in System Settings."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"widget.calendar.neverWritten" : {
|
"widget.calendar.incompatible": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Calendarr einmal öffnen,\ndamit Termine bereitstehen."
|
"value": "Onyx ist zu alt für diese\nCalendarr-Version. Bitte aktualisieren."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Open Calendarr once\nso events become available."
|
"value": "Onyx is too old for this\nCalendarr version. Please update."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"widget.calendar.noUpcoming" : {
|
"widget.calendar.loggedOut": {
|
||||||
"comment" : "Nur zeigen, wenn der Zeitraum wirklich abgedeckt ist",
|
"localizations": {
|
||||||
"localizations" : {
|
"de": {
|
||||||
"de" : {
|
"stringUnit": {
|
||||||
"stringUnit" : {
|
"state": "translated",
|
||||||
"state" : "translated",
|
"value": "In Calendarr anmelden"
|
||||||
"value" : "Nichts mehr für heute"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Nothing left today"
|
"value": "Sign in to Calendarr"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"widget.calendar.unreadable" : {
|
"widget.calendar.name": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Termine nicht lesbar.\nKonfigurationsfehler."
|
"value": "Kalender"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Events unreadable.\nConfiguration error."
|
"value": "Calendar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"widget.calendar.neverWritten": {
|
||||||
|
"localizations": {
|
||||||
|
"de": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Calendarr einmal öffnen,\ndamit Termine bereitstehen."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Open Calendarr once\nso events become available."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"widget.calendar.noUpcoming": {
|
||||||
|
"comment": "Nur zeigen, wenn der Zeitraum wirklich abgedeckt ist",
|
||||||
|
"localizations": {
|
||||||
|
"de": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Nichts mehr für heute"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Nothing left today"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"widget.calendar.unreadable": {
|
||||||
|
"localizations": {
|
||||||
|
"de": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Termine nicht lesbar.\nKonfigurationsfehler."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Events unreadable.\nConfiguration error."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"version" : "1.1"
|
"version": "1.1"
|
||||||
}
|
}
|
||||||
@@ -1,25 +1,55 @@
|
|||||||
{
|
{
|
||||||
"sourceLanguage" : "en",
|
"sourceLanguage": "en",
|
||||||
"strings" : {
|
"strings": {
|
||||||
"widget.media.name" : {
|
"widget.media.name": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : { "stringUnit" : { "state" : "translated", "value" : "Medien" } },
|
"de": {
|
||||||
"en" : { "stringUnit" : { "state" : "translated", "value" : "Media" } }
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Medien"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"widget.media.nothing" : {
|
"en": {
|
||||||
"localizations" : {
|
"stringUnit": {
|
||||||
"de" : { "stringUnit" : { "state" : "translated", "value" : "Nichts läuft gerade" } },
|
"state": "translated",
|
||||||
"en" : { "stringUnit" : { "state" : "translated", "value" : "Nothing playing" } }
|
"value": "Media"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"widget.media.viaAppleScript" : {
|
|
||||||
"comment" : "Hinweis, dass die schwächere Quelle greift",
|
|
||||||
"localizations" : {
|
|
||||||
"de" : { "stringUnit" : { "state" : "translated", "value" : "Über AppleScript — ohne Cover, nur Spotify und Musik" } },
|
|
||||||
"en" : { "stringUnit" : { "state" : "translated", "value" : "Via AppleScript — no artwork, Spotify and Music only" } }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"version" : "1.0"
|
"widget.media.nothing": {
|
||||||
|
"localizations": {
|
||||||
|
"de": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Nichts läuft gerade"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Nothing playing"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"widget.media.viaAppleScript": {
|
||||||
|
"comment": "Hinweis, dass die schwächere Quelle greift",
|
||||||
|
"localizations": {
|
||||||
|
"de": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Über AppleScript — ohne Cover, nur Spotify und Musik"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Via AppleScript — no artwork, Spotify and Music only"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"version": "1.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,27 +56,36 @@ private struct Playing: View {
|
|||||||
let state: NowPlaying
|
let state: NowPlaying
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(spacing: 10) {
|
// Übereinander, nicht nebeneinander. Die Kachel ist hochkant: neben
|
||||||
|
// einem Cover blieben für den Titel noch gut hundert Punkte, und dann
|
||||||
|
// steht dort „Bernhard H…" statt eines Titels.
|
||||||
|
VStack(alignment: .leading, spacing: 7) {
|
||||||
Artwork(data: state.artwork)
|
Artwork(data: state.artwork)
|
||||||
.frame(width: artworkSize, height: artworkSize)
|
.frame(maxWidth: .infinity)
|
||||||
|
.frame(height: 88)
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 2) {
|
VStack(alignment: .leading, spacing: 1) {
|
||||||
Text(state.title)
|
Text(state.title)
|
||||||
.font(Onyx.Font.title)
|
.font(Onyx.Font.caption.weight(.medium))
|
||||||
.foregroundStyle(Onyx.Color.textPrimary)
|
.foregroundStyle(Onyx.Color.textPrimary)
|
||||||
.lineLimit(1)
|
.lineLimit(2)
|
||||||
Text(state.artist)
|
Text(state.artist)
|
||||||
.font(Onyx.Font.caption)
|
.font(Onyx.Font.caption)
|
||||||
.foregroundStyle(Onyx.Color.textSecondary)
|
.foregroundStyle(Onyx.Color.textSecondary)
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
|
||||||
Spacer(minLength: 2)
|
Spacer(minLength: 0)
|
||||||
|
|
||||||
Scrubber(model: model, state: state)
|
Scrubber(model: model, state: state)
|
||||||
|
|
||||||
HStack {
|
HStack(spacing: 0) {
|
||||||
|
Spacer(minLength: 0)
|
||||||
TransportControls(model: model, size: 15)
|
TransportControls(model: model, size: 15)
|
||||||
Spacer(minLength: 0)
|
Spacer(minLength: 0)
|
||||||
|
}
|
||||||
|
.overlay(alignment: .trailing) {
|
||||||
if state.origin == .appleScript {
|
if state.origin == .appleScript {
|
||||||
// Sichtbar machen, dass gerade die schwächere Quelle
|
// Sichtbar machen, dass gerade die schwächere Quelle
|
||||||
// greift: dann fehlen Cover und Browser-Wiedergaben,
|
// greift: dann fehlen Cover und Browser-Wiedergaben,
|
||||||
@@ -88,13 +97,10 @@ private struct Playing: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
|
|
||||||
.contentShape(Rectangle())
|
.contentShape(Rectangle())
|
||||||
.onTapGesture(count: 2) { model.activateSource() }
|
.onTapGesture(count: 2) { model.activateSource() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private let artworkSize: CGFloat = 56
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct Artwork: View {
|
private struct Artwork: View {
|
||||||
@@ -103,6 +109,9 @@ private struct Artwork: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
let shape = RoundedRectangle(cornerRadius: 8, style: .continuous)
|
let shape = RoundedRectangle(cornerRadius: 8, style: .continuous)
|
||||||
|
|
||||||
|
// Reihenfolge zählt: erst der Rahmen, dann das Beschneiden. Andersherum
|
||||||
|
// beschneidet man das Bild auf seine eigene, viel größere Größe — und es
|
||||||
|
// ragt anschließend über die Kachel hinaus, mitten in den Nachbarn.
|
||||||
Group {
|
Group {
|
||||||
if let data, let image = NSImage(data: data) {
|
if let data, let image = NSImage(data: data) {
|
||||||
Image(nsImage: image).resizable().aspectRatio(contentMode: .fill)
|
Image(nsImage: image).resizable().aspectRatio(contentMode: .fill)
|
||||||
@@ -118,6 +127,7 @@ private struct Artwork: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
.clipShape(shape)
|
.clipShape(shape)
|
||||||
.overlay(shape.strokeBorder(Onyx.Color.hairline, lineWidth: 1))
|
.overlay(shape.strokeBorder(Onyx.Color.hairline, lineWidth: 1))
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -173,14 +173,11 @@ final class MetricStatusView: NSView, WidthReporting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func drawSymbol(color: NSColor) {
|
private func drawSymbol(color: NSColor) {
|
||||||
guard let image = NSImage(systemSymbolName: metric.symbolName,
|
|
||||||
accessibilityDescription: nil) else { return }
|
|
||||||
image.isTemplate = true
|
|
||||||
let side: CGFloat = 15
|
let side: CGFloat = 15
|
||||||
let rect = NSRect(x: bounds.midX - side / 2, y: bounds.midY - side / 2,
|
MenuBarText.drawSymbol(metric.symbolName, color: color,
|
||||||
width: side, height: side)
|
in: NSRect(x: bounds.midX - side / 2,
|
||||||
color.set()
|
y: bounds.midY - side / 2,
|
||||||
image.draw(in: rect)
|
width: side, height: side))
|
||||||
}
|
}
|
||||||
|
|
||||||
private func drawGraph(color: NSColor, in rect: NSRect) {
|
private func drawGraph(color: NSColor, in rect: NSRect) {
|
||||||
|
|||||||
@@ -1,360 +1,360 @@
|
|||||||
{
|
{
|
||||||
"sourceLanguage" : "en",
|
"sourceLanguage": "en",
|
||||||
"strings" : {
|
"strings": {
|
||||||
"network.addresses" : {
|
"network.addresses": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Adressen"
|
"value": "Adressen"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Addresses"
|
"value": "Addresses"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network.download" : {
|
"network.download": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Download"
|
"value": "Download"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Download"
|
"value": "Download"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network.field.interface" : {
|
"network.field.interface": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Schnittstelle"
|
"value": "Schnittstelle"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Interface"
|
"value": "Interface"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network.field.ipv4" : {
|
"network.field.ipv4": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "IP"
|
"value": "IP"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "IP"
|
"value": "IP"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network.field.ipv6" : {
|
"network.field.ipv6": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "IPv6"
|
"value": "IPv6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "IPv6"
|
"value": "IPv6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network.field.router" : {
|
"network.field.router": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Router"
|
"value": "Router"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Router"
|
"value": "Router"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network.name" : {
|
"network.name": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Netzwerk"
|
"value": "Netzwerk"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Network"
|
"value": "Network"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network.offline" : {
|
"network.offline": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Nicht verbunden"
|
"value": "Nicht verbunden"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Not connected"
|
"value": "Not connected"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network.peak.download" : {
|
"network.peak.download": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Spitze ↓"
|
"value": "Spitze ↓"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Peak ↓"
|
"value": "Peak ↓"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network.peak.upload" : {
|
"network.peak.upload": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Spitze ↑"
|
"value": "Spitze ↑"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Peak ↑"
|
"value": "Peak ↑"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network.perProcess.unavailable" : {
|
"network.perProcess.unavailable": {
|
||||||
"extractionState" : "stale",
|
"extractionState": "stale",
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Durchsatz je Programm zeigt Onyx nicht: dafür gibt es ohne root keine Schnittstelle."
|
"value": "Durchsatz je Programm zeigt Onyx nicht: dafür gibt es ohne root keine Schnittstelle."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Onyx doesn't show per-app throughput: there is no interface for it without root."
|
"value": "Onyx doesn't show per-app throughput: there is no interface for it without root."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network.processes" : {
|
"network.processes": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Je Programm"
|
"value": "Je Programm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Per app"
|
"value": "Per app"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network.public" : {
|
"network.public": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Öffentliche Adresse"
|
"value": "Öffentliche Adresse"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Public address"
|
"value": "Public address"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network.public.enable" : {
|
"network.public.enable": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Öffentliche IP anzeigen"
|
"value": "Öffentliche IP anzeigen"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Show public IP"
|
"value": "Show public IP"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network.public.failed" : {
|
"network.public.failed": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Nicht abrufbar"
|
"value": "Nicht abrufbar"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Unavailable"
|
"value": "Unavailable"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network.public.hint" : {
|
"network.public.hint": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Dafür fragt Onyx einen fremden Dienst — standardmäßig aus, weil ein Systemmonitor nicht ungefragt nach draußen telefonieren sollte."
|
"value": "Dafür fragt Onyx einen fremden Dienst — standardmäßig aus, weil ein Systemmonitor nicht ungefragt nach draußen telefonieren sollte."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "This asks an external service — off by default, because a system monitor shouldn't phone home unasked."
|
"value": "This asks an external service — off by default, because a system monitor shouldn't phone home unasked."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network.total.received" : {
|
"network.total.received": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Empfangen"
|
"value": "Empfangen"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Received"
|
"value": "Received"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network.total.sent" : {
|
"network.total.sent": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Gesendet"
|
"value": "Gesendet"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Sent"
|
"value": "Sent"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network.transferred" : {
|
"network.transferred": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Übertragen"
|
"value": "Übertragen"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Transferred"
|
"value": "Transferred"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network.upload" : {
|
"network.upload": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Upload"
|
"value": "Upload"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Upload"
|
"value": "Upload"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network.vpn.active" : {
|
"network.vpn.active": {
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Verkehr läuft durch einen Tunnel"
|
"value": "Verkehr läuft durch einen Tunnel"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Traffic goes through a tunnel"
|
"value": "Traffic goes through a tunnel"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network.wifi.connected" : {
|
"network.wifi.connected": {
|
||||||
"comment" : "Wenn der Netzwerkname mangels Ortungsberechtigung fehlt",
|
"comment": "Wenn der Netzwerkname mangels Ortungsberechtigung fehlt",
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "WLAN verbunden"
|
"value": "WLAN verbunden"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Wi-Fi connected"
|
"value": "Wi-Fi connected"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"version" : "1.0"
|
"version": "1.0"
|
||||||
}
|
}
|
||||||
@@ -110,11 +110,8 @@ final class NetworkStatusView: NSView {
|
|||||||
|
|
||||||
switch presentation {
|
switch presentation {
|
||||||
case .symbol:
|
case .symbol:
|
||||||
guard let image = NSImage(systemSymbolName: snapshot.interfaceKind.symbolName,
|
MenuBarText.drawSymbol(snapshot.interfaceKind.symbolName, color: color,
|
||||||
accessibilityDescription: nil) else { return }
|
in: NSRect(x: bounds.midX - 7.5, y: bounds.midY - 7.5,
|
||||||
image.isTemplate = true
|
|
||||||
color.set()
|
|
||||||
image.draw(in: NSRect(x: bounds.midX - 7.5, y: bounds.midY - 7.5,
|
|
||||||
width: 15, height: 15))
|
width: 15, height: 15))
|
||||||
|
|
||||||
case .graph, .bars:
|
case .graph, .bars:
|
||||||
|
|||||||
@@ -1,56 +1,56 @@
|
|||||||
{
|
{
|
||||||
"sourceLanguage" : "en",
|
"sourceLanguage": "en",
|
||||||
"strings" : {
|
"strings": {
|
||||||
"singleInstance.blocked.message" : {
|
"common.ok": {
|
||||||
"comment" : "Titel des Dialogs, wenn eine zweite Instanz zurücktritt",
|
"localizations": {
|
||||||
"localizations" : {
|
"de": {
|
||||||
"de" : {
|
"stringUnit": {
|
||||||
"stringUnit" : {
|
"state": "translated",
|
||||||
"state" : "translated",
|
"value": "OK"
|
||||||
"value" : "Onyx läuft bereits"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Onyx is already running"
|
"value": "OK"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"singleInstance.blocked.informative" : {
|
"singleInstance.blocked.informative": {
|
||||||
"comment" : "Erklärung samt Hinweis auf Xcode. %@ ist der Pfad der laufenden Instanz.",
|
"comment": "Erklärung samt Hinweis auf Xcode. %@ ist der Pfad der laufenden Instanz.",
|
||||||
"localizations" : {
|
"localizations": {
|
||||||
"de" : {
|
"de": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Eine andere Onyx-Instanz läuft und ließ sich nicht beenden. Diese Instanz wird deshalb nicht gestartet, damit nicht zwei Panels gleichzeitig auf der Notch arbeiten.\n\nLäuft sie aus Xcode, beende sie dort mit ⌘. und starte erneut.\n\n%@"
|
"value": "Eine andere Onyx-Instanz läuft und ließ sich nicht beenden. Diese Instanz wird deshalb nicht gestartet, damit nicht zwei Panels gleichzeitig auf der Notch arbeiten.\n\nLäuft sie aus Xcode, beende sie dort mit ⌘. und starte erneut.\n\n%@"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "Another Onyx instance is running and could not be quit. This instance will not start, so that two panels don't fight over the same notch.\n\nIf it was launched from Xcode, stop it there with ⌘. and try again.\n\n%@"
|
"value": "Another Onyx instance is running and could not be quit. This instance will not start, so that two panels don't fight over the same notch.\n\nIf it was launched from Xcode, stop it there with ⌘. and try again.\n\n%@"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common.ok" : {
|
"singleInstance.blocked.message": {
|
||||||
"localizations" : {
|
"comment": "Titel des Dialogs, wenn eine zweite Instanz zurücktritt",
|
||||||
"de" : {
|
"localizations": {
|
||||||
"stringUnit" : {
|
"de": {
|
||||||
"state" : "translated",
|
"stringUnit": {
|
||||||
"value" : "OK"
|
"state": "translated",
|
||||||
|
"value": "Onyx läuft bereits"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en" : {
|
"en": {
|
||||||
"stringUnit" : {
|
"stringUnit": {
|
||||||
"state" : "translated",
|
"state": "translated",
|
||||||
"value" : "OK"
|
"value": "Onyx is already running"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"version" : "1.0"
|
"version": "1.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,24 @@ public enum MenuBarText {
|
|||||||
itemWidth(textWidth: width(of: reference), includesSymbol: includesSymbol)
|
itemWidth(textWidth: width(of: reference), includesSymbol: includesSymbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Zeichnet ein SF-Symbol in der gewünschten Farbe.
|
||||||
|
///
|
||||||
|
/// `color.set()` vor `image.draw(in:)` reicht **nicht**. Ein Template-Bild
|
||||||
|
/// trägt seine Farbe nicht aus dem Grafikzustand, sondern wird schwarz
|
||||||
|
/// gezeichnet — auf einer dunklen Menüleiste also unsichtbar. AppKit färbt
|
||||||
|
/// Template-Bilder nur ein, wenn sie als `image` eines Buttons gesetzt sind;
|
||||||
|
/// in einer selbst gezeichneten Ansicht muss die Farbe in die
|
||||||
|
/// Symbolkonfiguration.
|
||||||
|
public static func drawSymbol(_ name: String, color: NSColor, in rect: NSRect) {
|
||||||
|
guard let image = NSImage(systemSymbolName: name, accessibilityDescription: nil)
|
||||||
|
else { return }
|
||||||
|
let configuration = NSImage.SymbolConfiguration(pointSize: rect.height,
|
||||||
|
weight: .regular)
|
||||||
|
.applying(NSImage.SymbolConfiguration(paletteColors: [color]))
|
||||||
|
let tinted = image.withSymbolConfiguration(configuration) ?? image
|
||||||
|
tinted.draw(in: rect)
|
||||||
|
}
|
||||||
|
|
||||||
public static func draw(_ text: String, color: NSColor, in rect: NSRect) {
|
public static func draw(_ text: String, color: NSColor, in rect: NSRect) {
|
||||||
let string = NSAttributedString(string: text,
|
let string = NSAttributedString(string: text,
|
||||||
attributes: [.font: font, .foregroundColor: color])
|
attributes: [.font: font, .foregroundColor: color])
|
||||||
|
|||||||
@@ -1,14 +1,6 @@
|
|||||||
{
|
{
|
||||||
"sourceLanguage": "en",
|
"sourceLanguage": "en",
|
||||||
"strings": {
|
"strings": {
|
||||||
"↑ %@": {
|
|
||||||
"comment": "A label that shows the high temperature. The argument is the high temperature.",
|
|
||||||
"isCommentAutoGenerated": true
|
|
||||||
},
|
|
||||||
"↓ %@": {
|
|
||||||
"comment": "A label that reads \"low\" in the weather app.",
|
|
||||||
"isCommentAutoGenerated": true
|
|
||||||
},
|
|
||||||
"widget.weather.asOf": {
|
"widget.weather.asOf": {
|
||||||
"comment": "%@ ist die Uhrzeit des Messwerts",
|
"comment": "%@ ist die Uhrzeit des Messwerts",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
@@ -42,6 +34,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"widget.weather.locationUndetermined": {
|
||||||
|
"localizations": {
|
||||||
|
"de": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Standort noch nicht erlaubt.\nIn den Einstellungen freigeben."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "Location not allowed yet.\nGrant it in settings."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"widget.weather.name": {
|
"widget.weather.name": {
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
@@ -74,18 +82,38 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"widget.weather.locationUndetermined": {
|
"↑ %@": {
|
||||||
|
"comment": "A label that shows the high temperature. The argument is the high temperature.",
|
||||||
|
"isCommentAutoGenerated": true,
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
"state": "translated",
|
"state": "translated",
|
||||||
"value": "Standort noch nicht erlaubt.\nIn den Einstellungen freigeben."
|
"value": "↑ %@"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"en": {
|
"en": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
"state": "translated",
|
"state": "translated",
|
||||||
"value": "Location not allowed yet.\nGrant it in settings."
|
"value": "↑ %@"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"↓ %@": {
|
||||||
|
"comment": "A label that reads \"low\" in the weather app.",
|
||||||
|
"isCommentAutoGenerated": true,
|
||||||
|
"localizations": {
|
||||||
|
"de": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "↓ %@"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en": {
|
||||||
|
"stringUnit": {
|
||||||
|
"state": "translated",
|
||||||
|
"value": "↓ %@"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user