Files
certain/ios/Bausteine/Darstellung.swift
T

121 lines
5.3 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import SwiftUI
extension Color {
/// Die Farben aus der Datenbank sind Hex-Zeichenketten wie `#3f51b5`.
/// Alles, was nicht passt, wird zum neutralen Grau – eine kaputte Farbe
/// darf keine Ansicht leer lassen.
init(hex: String) {
var text = hex.trimmingCharacters(in: .whitespacesAndNewlines)
if text.hasPrefix("#") { text.removeFirst() }
// Das Backend erlaubt acht Stellen (#rrggbbaa); die Durchsicht nehmen
// wir mit, der Rest wird ignoriert.
guard text.count == 6 || text.count == 8,
let zahl = UInt64(text, radix: 16) else {
self = Color(red: 0.42, green: 0.45, blue: 0.50)
return
}
let hatAlpha = text.count == 8
let r = Double((zahl >> (hatAlpha ? 24 : 16)) & 0xFF) / 255
let g = Double((zahl >> (hatAlpha ? 16 : 8)) & 0xFF) / 255
let b = Double((zahl >> (hatAlpha ? 8 : 0)) & 0xFF) / 255
let a = hatAlpha ? Double(zahl & 0xFF) / 255 : 1
self = Color(.sRGB, red: r, green: g, blue: b, opacity: a)
}
}
extension Color {
/// Die Markenfarbe: dasselbe Grün wie `--accent` in `web/src/styles.css`,
/// damit App, Weboberfläche und Appicon eine Familie sind. In Dunkel eine
/// Spur heller, sonst säuft das Grün auf dunklem Grund ab.
static let marke = Color(uiColor: UIColor { zug in
zug.userInterfaceStyle == .dark
? UIColor(red: 0.373, green: 0.741, blue: 0.569, alpha: 1) // #5fbd91
: UIColor(red: 0.247, green: 0.612, blue: 0.447, alpha: 1) // #3f9c72
})
}
/// Übersetzt die Symbolnamen aus der Datenbank in SF Symbols.
///
/// Die Weboberfläche benutzt Lucide-Namen und hält dafür ein eigenes
/// SVG-Verzeichnis (`web/src/components/Icon.jsx`, knapp 600 Zeilen). Nativ
/// wäre das Unsinn: iOS bringt die Symbole mit, sie passen zur Systemschrift
/// und können fett, farbig und in jeder Grösse. Nur die Namen muss jemand
/// zuordnen – das ist diese Tabelle.
///
/// Die Liste deckt `ACCOUNT_ICONS` und `CATEGORY_ICONS` aus
/// `web/src/components/IconPicker.jsx` ab. Unbekanntes wird zum Platzhalter,
/// nie zu einer leeren Stelle.
enum Symbole {
static let platzhalter = "circle.dashed"
private static let tabelle: [String: String] = [
// Konten
"wallet": "wallet.bifold", "landmark": "building.columns",
"piggy-bank": "banknote", "vault": "lock.square.stack",
"credit-card": "creditcard", "trending-up": "chart.line.uptrend.xyaxis",
"banknote": "banknote", "coins": "centsign.circle",
// Wohnen
"home": "house", "bed": "bed.double", "zap": "bolt",
"droplet": "drop", "flame": "flame", "wifi": "wifi",
"monitor": "display", "cloud": "cloud",
// Alltag
"shopping-cart": "cart", "shopping-bag": "bag", "store": "storefront",
"utensils": "fork.knife", "coffee": "cup.and.saucer",
"wine": "wineglass", "shirt": "tshirt", "scissors": "scissors",
"sparkle": "sparkles",
// Unterwegs
"car": "car", "fuel": "fuelpump", "bus": "bus", "bike": "bicycle",
"plane": "airplane", "ticket": "ticket",
// Gesundheit
"heart-pulse": "heart.text.square", "pill": "pills",
"dumbbell": "figure.strengthtraining.traditional",
// Freizeit
"film": "film", "music": "music.note", "book-open": "book",
"newspaper": "newspaper", "graduation-cap": "graduationcap",
"paw-print": "pawprint",
// Familie
"sprout": "leaf", "cake": "birthday.cake", "gift": "gift",
"baby": "figure.and.child.holdinghands", "heart": "heart",
// Vorsorge
"umbrella": "umbrella", "life-buoy": "lifepreserver",
"shield": "shield", "scale": "scalemass",
// Sonstiges
"briefcase": "briefcase", "wrench": "wrench.adjustable",
"hammer": "hammer", "phone": "phone", "refresh-ccw": "arrow.triangle.2.circlepath",
"percent": "percent", "receipt": "receipt",
"list": "list.bullet", "more-horizontal": "ellipsis",
// In der Oberfläche benutzt, nicht in der Auswahl
"tags": "tag", "inbox": "tray", "settings": "gearshape",
"arrow-left-right": "arrow.left.arrow.right", "pie-chart": "chart.pie",
"dashboard": "square.grid.2x2", "download": "square.and.arrow.down",
"calendar": "calendar", "search": "magnifyingglass",
"edit": "pencil", "trash": "trash", "plus": "plus", "check": "checkmark",
"close": "xmark", "chevron-down": "chevron.down",
]
static func sf(_ name: String?) -> String {
guard let name, let treffer = tabelle[name] else { return platzhalter }
return treffer
}
}
/// Ein farbiges Symbolplättchen – das native Gegenstück zum `IconChip` im Web.
struct Symbolplakette: View {
let symbol: String?
let farbe: String
var groesse: CGFloat = 34
var body: some View {
let farbwert = Color(hex: farbe)
RoundedRectangle(cornerRadius: groesse * 0.28, style: .continuous)
.fill(farbwert.opacity(0.16))
.frame(width: groesse, height: groesse)
.overlay {
Image(systemName: Symbole.sf(symbol))
.font(.system(size: groesse * 0.46, weight: .medium))
.foregroundStyle(farbwert)
}
.accessibilityHidden(true)
}
}