Files
luma/Luma/IconPlaceholderView.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

49 lines
1.5 KiB
Swift

import LumaCore
import SwiftUI
struct IconPlaceholderView: View {
let seed: String
let displayName: String
var cornerRadius: CGFloat = 6
var body: some View {
GeometryReader { geo in
let side = min(geo.size.width, geo.size.height)
ZStack {
LinearGradient(
colors: gradientColors,
startPoint: .topLeading,
endPoint: .bottomTrailing
)
Text(IconPlaceholder.initials(for: displayName))
.font(.system(size: side * 0.46, weight: .semibold, design: .rounded))
.foregroundStyle(.white)
.minimumScaleFactor(0.5)
.lineLimit(1)
.allowsTightening(true)
.shadow(color: Color.black.opacity(0.15), radius: 1, y: 0.5)
}
.clipShape(RoundedRectangle(cornerRadius: cornerRadius, style: .continuous))
}
.aspectRatio(1, contentMode: .fit)
.accessibilityHidden(true)
}
private var gradientColors: [Color] {
let palette = IconPlaceholder.palette(for: seed)
return [
Color(
hue: palette.primaryHue,
saturation: palette.primarySaturation,
brightness: palette.primaryBrightness
),
Color(
hue: palette.secondaryHue,
saturation: palette.secondarySaturation,
brightness: palette.secondaryBrightness
),
]
}
}