diff --git a/Onyx.xcodeproj/project.pbxproj b/Onyx.xcodeproj/project.pbxproj index eec3382..9ff6bed 100644 --- a/Onyx.xcodeproj/project.pbxproj +++ b/Onyx.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ 9C2E419014B7E04630FDF151 /* OnyxApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89CAC2A7DA89B8707D45D65 /* OnyxApp.swift */; }; 9EC9D57A96489F5578000822 /* NetworkProvider in Frameworks */ = {isa = PBXBuildFile; productRef = FF4E99C8BF0D8944C314A8AF /* NetworkProvider */; }; A529046C33E6B00C0E9508FF /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 508DECB5C05264E6130C373E /* Localizable.xcstrings */; }; + A89903046D47175EE68392FA /* thunder.svg in Resources */ = {isa = PBXBuildFile; fileRef = 19F96370F33A525437F6E691 /* thunder.svg */; }; A9617230F602C5D52F63A7E2 /* ShelfProvider in Frameworks */ = {isa = PBXBuildFile; productRef = FA6C9F90DF47DC0DFB9ED55D /* ShelfProvider */; }; B0FCCD92AF22F1636482EACD /* sound-waves.svg in Resources */ = {isa = PBXBuildFile; fileRef = 8BCDFD427ACD83B8AA7BA39E /* sound-waves.svg */; }; B309DD8966B5348250CEC6BD /* LaunchAtLogin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41C778876BEF3D8B04F7C3C9 /* LaunchAtLogin.swift */; }; @@ -58,6 +59,7 @@ 0804288DC4A8146DD9F3FC3E /* Onyx.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Onyx.app; sourceTree = BUILT_PRODUCTS_DIR; }; 085D860E654E09E4CD6E535A /* chip.svg */ = {isa = PBXFileReference; path = chip.svg; sourceTree = ""; }; 16F2B1B9A74594526F34F5C9 /* WidgetOptionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetOptionsView.swift; sourceTree = ""; }; + 19F96370F33A525437F6E691 /* thunder.svg */ = {isa = PBXFileReference; path = thunder.svg; sourceTree = ""; }; 1E6A1C208C7EA56971A055E1 /* graphic-card.svg */ = {isa = PBXFileReference; path = "graphic-card.svg"; sourceTree = ""; }; 24ADD22F5CE30B27020B479B /* MenuBarIcon.svg */ = {isa = PBXFileReference; path = MenuBarIcon.svg; sourceTree = ""; }; 41C778876BEF3D8B04F7C3C9 /* LaunchAtLogin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchAtLogin.swift; sourceTree = ""; }; @@ -179,6 +181,7 @@ 45BD2DF1B775C733C8F75635 /* SettingsView.swift */, 8E43384BA603C866D148D9D8 /* SettingsWindowController.swift */, 8BCDFD427ACD83B8AA7BA39E /* sound-waves.svg */, + 19F96370F33A525437F6E691 /* thunder.svg */, 16F2B1B9A74594526F34F5C9 /* WidgetOptionsView.swift */, ); path = Onyx; @@ -295,6 +298,7 @@ 3991CB2BF41C6C014EF4528F /* chip.svg in Resources */, F2A3AD184864422EA14A8C64 /* graphic-card.svg in Resources */, B0FCCD92AF22F1636482EACD /* sound-waves.svg in Resources */, + A89903046D47175EE68392FA /* thunder.svg in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Onyx/thunder.svg b/Onyx/thunder.svg new file mode 100644 index 0000000..fb30429 --- /dev/null +++ b/Onyx/thunder.svg @@ -0,0 +1,27 @@ + + + + diff --git a/Packages/OnyxKit/Sources/MetricsProvider/BatteryGlyph.swift b/Packages/OnyxKit/Sources/MetricsProvider/BatteryGlyph.swift index de929dc..3fce4df 100644 --- a/Packages/OnyxKit/Sources/MetricsProvider/BatteryGlyph.swift +++ b/Packages/OnyxKit/Sources/MetricsProvider/BatteryGlyph.swift @@ -68,6 +68,17 @@ public enum BatteryGlyph { return (filled, empty) } + /// Der Blitz als eigene Vorlage. + /// + /// SF Symbols' `bolt.fill` ist eine massive Fläche; die mitgelieferte + /// Kontur trifft die Form besser und bringt schon einen kräftigen Strich + /// mit. Fehlt die Datei, bleibt das Systemsymbol. + public static let chargingGlyph: NSImage? = { + guard let url = Bundle.main.url(forResource: "thunder", withExtension: "svg") + else { return nil } + return NSImage(contentsOf: url) + }() + /// Wie dick der Rand um das Zeichen ist. public static let outlineWidth: CGFloat = 1 @@ -186,18 +197,26 @@ public enum BatteryGlyph { return } - // Der Blitz: weiß mit dünnem dunklem Rand, und fadend. + // Der Blitz: mit dunklem Rand, und fadend. // - // Der Rand ist immer die Gegenfarbe zur Füllung. Damit bleibt er in - // **jedem** Moment des Fadens lesbar: über der hellen Füllung trägt ihn - // der Rand, über dem leeren Teil die Füllung selbst. + // Der Rand ist immer die Gegenfarbe zum Blitz selbst. Damit bleibt er + // in **jedem** Moment des Fadens lesbar: über der hellen Füllung trägt + // ihn der Rand, über dem leeren Teil der Blitz. let whiteness = boltWhiteness(phase: fadePhase) - if let outline = tint(glyph, with: NSColor(white: 1 - whiteness, alpha: 1)) { + let inverseColor = NSColor(white: 1 - whiteness, alpha: 1) + let boltColor = NSColor(white: whiteness, alpha: 1) + + if let custom = chargingGlyph { + MenuBarText.drawTemplate(custom, color: inverseColor, in: outlineRect(glyphRect)) + MenuBarText.drawTemplate(custom, color: boltColor, in: glyphRect) + return + } + if let outline = tint(glyph, with: inverseColor) { outline.draw(in: outlineRect(glyphRect), from: .zero, operation: .sourceOver, fraction: 1) } - if let body = tint(glyph, with: NSColor(white: whiteness, alpha: 1)) { - body.draw(in: glyphRect, from: .zero, operation: .sourceOver, fraction: 1) + if let filled = tint(glyph, with: boltColor) { + filled.draw(in: glyphRect, from: .zero, operation: .sourceOver, fraction: 1) } } } @@ -258,11 +277,9 @@ public struct BatteryGlyphView: View { / BatteryGlyph.fadeDuration let whiteness = BatteryGlyph.boltWhiteness(phase: phase) ZStack { - Image(systemName: name) - .font(.system(size: size + 2 * BatteryGlyph.outlineWidth)) + bolt(name: name, side: size + 2 * BatteryGlyph.outlineWidth) .foregroundStyle(Color(white: 1 - whiteness)) - Image(systemName: name) - .font(.system(size: size)) + bolt(name: name, side: size) .foregroundStyle(Color(white: whiteness)) } } @@ -282,6 +299,20 @@ public struct BatteryGlyphView: View { .frame(width: width, height: height) } + /// Dieselbe Vorlage wie in der Menüleiste, sonst das Systemsymbol. + @ViewBuilder + private func bolt(name: String, side: CGFloat) -> some View { + if let custom = BatteryGlyph.chargingGlyph { + Image(nsImage: custom) + .renderingMode(.template) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: side, height: side) + } else { + Image(systemName: name).font(.system(size: side)) + } + } + private var fillColor: Color { BatteryGlyph.isLow(charge: charge, isCharging: isCharging) ? .red : .primary }