ManaPill(_:image:variant:size:action:) und Row(katalogSymbol:) für Apps mit eigenem Zeichensatz (seepuls). Rein additiv: bestehende Aufrufe mit systemImage/symbol laufen unverändert, kein Init wird mehrdeutig. Sitzung: 79964fc4 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0111BCGu1WXLkJzY5CGKXdC6
95 lines
3.6 KiB
Swift
95 lines
3.6 KiB
Swift
import SwiftUI
|
|
|
|
/// Eine Seite im Einstiegs-Flow — im Stil von Apples „Neue Funktionen“-
|
|
/// Sheet: ein großer Titel, optional ein kurzer Vorspann, darunter eine
|
|
/// **vertikale Liste von Zeilen** (Icon links, Titel + Text rechts), und
|
|
/// pro Seite genau **ein** Weiter-Button (der Container rendert ihn).
|
|
///
|
|
/// Inhalt ist **app-geliefert** — das Paket weiß nichts über Vorsätze,
|
|
/// Decks oder Memos. Eine App baut `[ManaOnboardingPage]` und übergibt
|
|
/// sie an ``SwiftUICore/View/manaOnboarding(storageKey:pages:onFinish:)``.
|
|
/// Die Optik (Farben) kommt aus `@Environment(\.manaTheme)`, das die App
|
|
/// sowieso setzt — dadurch sieht der Flow flottenweit einheitlich aus,
|
|
/// aber im Signatur-Theme der jeweiligen App.
|
|
///
|
|
/// **Bewusst ohne Berechtigungs-Schritte.** `ManaOnboardingUI` fragt
|
|
/// **nie** System-Rechte ab — Berechtigungen hängen an konkreten Features
|
|
/// und werden *just-in-time* erfragt, wenn das Feature zum ersten Mal
|
|
/// genutzt wird. Das Onboarding **informiert** nur. (Werte-Entscheidung
|
|
/// 2026-06-05: kein Extrahieren auf Vorrat.)
|
|
public struct ManaOnboardingPage: Identifiable, Sendable {
|
|
public let id: String
|
|
|
|
/// Große Überschrift oben auf der Seite.
|
|
public let title: String
|
|
|
|
/// Früherer Vorspann unter dem Titel. **Wird nicht mehr angezeigt**
|
|
/// (Design-Entscheidung 2026-06-09: Onboarding-Seiten tragen nur
|
|
/// Überschrift + Karten, keinen freien Text). Param bleibt aus
|
|
/// Quellkompatibilität bestehen, wird aber ignoriert.
|
|
public let intro: String?
|
|
|
|
/// Die Inhalts-Zeilen (Apple-„Neue Funktionen“-Liste).
|
|
public let rows: [Row]
|
|
|
|
/// Frühere Fußnote über dem Button. **Wird nicht mehr angezeigt**
|
|
/// (siehe `intro`). Param bleibt aus Quellkompatibilität, ignoriert.
|
|
public let footnote: String?
|
|
|
|
public init(
|
|
id: String? = nil,
|
|
title: String,
|
|
intro: String? = nil,
|
|
rows: [Row],
|
|
footnote: String? = nil
|
|
) {
|
|
self.id = id ?? title
|
|
self.title = title
|
|
self.intro = intro
|
|
self.rows = rows
|
|
self.footnote = footnote
|
|
}
|
|
|
|
/// Eine Zeile: Symbol (links, brand-getönt) + Titel + Beschreibung.
|
|
public struct Row: Identifiable, Sendable {
|
|
/// Woher das Symbol kommt.
|
|
public enum Quelle: Sendable, Hashable {
|
|
/// SF-Symbol.
|
|
case system
|
|
/// Symbol oder Bild aus dem Asset-Katalog der App (eigener Zeichensatz).
|
|
case katalog
|
|
}
|
|
|
|
public let id: String
|
|
/// SF-Symbol-Name oder, bei ``Quelle/katalog``, Asset-Name.
|
|
public let symbol: String
|
|
public let quelle: Quelle
|
|
public let title: String
|
|
public let text: String
|
|
|
|
public init(id: String? = nil, symbol: String, title: String, text: String) {
|
|
self.init(id: id, symbol: symbol, quelle: .system, title: title, text: text)
|
|
}
|
|
|
|
/// Zeile mit einem Symbol aus dem Asset-Katalog der App.
|
|
public init(id: String? = nil, katalogSymbol: String, title: String, text: String) {
|
|
self.init(id: id, symbol: katalogSymbol, quelle: .katalog, title: title, text: text)
|
|
}
|
|
|
|
private init(id: String?, symbol: String, quelle: Quelle, title: String, text: String) {
|
|
self.id = id ?? title
|
|
self.symbol = symbol
|
|
self.quelle = quelle
|
|
self.title = title
|
|
self.text = text
|
|
}
|
|
|
|
/// Das Bild der Zeile.
|
|
public var bild: Image {
|
|
switch quelle {
|
|
case .system: Image(systemName: symbol)
|
|
case .katalog: Image(symbol)
|
|
}
|
|
}
|
|
}
|
|
}
|