Redesign nach Feedback. Statt Schritt-Karussell jetzt Apples What's-New-Sheet-Stil: pro Seite Titel + Zeilen-Liste (Icon+Titel+Text) + EIN Button unten, Indikator oben (nicht beim Button). - ManaOnboardingStep → ManaOnboardingPage (Titel/Vorspann/Row-Liste/ Fußnote). Voll Sendable, keine Action-Closures mehr. - Doktrin: fragt NIE Berechtigungen ab — die bleiben just-in-time. Onboarding informiert nur (kein Extrahieren auf Vorrat). - Präsentation als .sheet (.presentationDetents([.large]) + Griff) statt fullScreenCover → nicht mehr eingezwängt; per Wischen = gesehen. - Cross-Fade statt Swipe, reduced-motion-aware. 7 Tests (Seiten-Modell). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
65 lines
2.4 KiB
Swift
65 lines
2.4 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
|
|
|
|
/// Optionaler kurzer Vorspann unter dem Titel (ein Satz). `nil` =
|
|
/// kein Vorspann.
|
|
public let intro: String?
|
|
|
|
/// Die Inhalts-Zeilen (Apple-„Neue Funktionen“-Liste).
|
|
public let rows: [Row]
|
|
|
|
/// Optionaler, dezenter Fußnoten-Text über dem Button (z.B. ein
|
|
/// Hinweis aufs optionale Konto). `nil` = keine Fußnote.
|
|
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: SF-Symbol (links, brand-getönt) + Titel + Beschreibung.
|
|
public struct Row: Identifiable, Sendable {
|
|
public let id: String
|
|
public let symbol: String
|
|
public let title: String
|
|
public let text: String
|
|
|
|
public init(id: String? = nil, symbol: String, title: String, text: String) {
|
|
self.id = id ?? title
|
|
self.symbol = symbol
|
|
self.title = title
|
|
self.text = text
|
|
}
|
|
}
|
|
}
|