Files
luma/Sources/LumaCore/IconPlaceholder.swift
Ole André Vadla Ravnås a4abd75d0a placeholder: Generalize and use in target picker
The monogram placeholder wasn't really session-specific — the same
hue-from-seed + initials logic fits every target that has an
optional bundle icon. Rename `SessionPlaceholder` → `IconPlaceholder`
(data in LumaCore) and the two view wrappers to `IconPlaceholderView`
so the scope reads correctly, then wire the target picker's app and
process rows to fall back on it when no Frida-provided icon is
available. Seeds are app.identifier for applications and proc.name
for processes so repeat targets keep consistent colours.
2026-04-22 18:39:05 +02:00

54 lines
1.9 KiB
Swift

import Foundation
public enum IconPlaceholder {
public struct Palette: Sendable, Equatable {
public let primaryHue: Double
public let primarySaturation: Double
public let primaryBrightness: Double
public let secondaryHue: Double
public let secondarySaturation: Double
public let secondaryBrightness: Double
}
public static func initials(for displayName: String) -> String {
let trimmed = displayName.trimmingCharacters(in: .whitespacesAndNewlines)
let words = trimmed.split(whereSeparator: { !$0.isLetter && !$0.isNumber })
if words.count >= 2,
let firstChar = words.first?.first,
let secondChar = words.dropFirst().first?.first
{
return String([firstChar, secondChar]).uppercased()
}
if let firstChar = words.first?.first {
return String(firstChar).uppercased()
}
return String(trimmed.prefix(1)).uppercased()
}
public static func palette(for seed: String) -> Palette {
let hash = fnv1a64(seed)
let primary = Double(hash % 360) / 360.0
let secondary = (primary + 0.08).truncatingRemainder(dividingBy: 1.0)
return Palette(
primaryHue: primary,
primarySaturation: 0.55,
primaryBrightness: 0.78,
secondaryHue: secondary,
secondarySaturation: 0.70,
secondaryBrightness: 0.55
)
}
/// FNV-1a 64-bit — keep it stable across runs and platforms so a
/// given seed renders the same colour everywhere. Swift's
/// default `String.hashValue` is seeded per process.
private static func fnv1a64(_ s: String) -> UInt64 {
var hash: UInt64 = 0xcbf29ce484222325
for byte in s.utf8 {
hash ^= UInt64(byte)
hash &*= 0x100000001b3
}
return hash
}
}