5bc81d5b3b
iOS SwiftUI app with Supabase auth/realtime, Node.js backend, Docker/Supabase self-hosted infrastructure, and APNs scheduler. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
233 lines
8.6 KiB
Swift
233 lines
8.6 KiB
Swift
import SwiftUI
|
||
|
||
/// Impressum + Datenschutzerklärung
|
||
/// ⚠️ Muss vor dem Launch von einem Anwalt geprüft/ergänzt werden!
|
||
/// Kosten: ca. 300–500€ einmalig für Impressum + AGB + DSGVO-Datenschutzerklärung
|
||
struct LegalView: View {
|
||
@Environment(\.dismiss) var dismiss
|
||
@State private var tab = 0
|
||
|
||
var body: some View {
|
||
NavigationStack {
|
||
ZStack {
|
||
Color.nightBase.ignoresSafeArea()
|
||
|
||
VStack(spacing: 0) {
|
||
// Tab Switcher
|
||
HStack(spacing: 0) {
|
||
ForEach(["impressum", "datenschutz", "nutzungsbedingungen"], id: \.self) { label in
|
||
let idx = ["impressum", "datenschutz", "nutzungsbedingungen"].firstIndex(of: label)!
|
||
Button(label) { tab = idx }
|
||
.font(.nightLabel(12, weight: tab == idx ? .semibold : .regular))
|
||
.foregroundColor(tab == idx ? .nightPrimary : .nightSecondary)
|
||
.frame(maxWidth: .infinity)
|
||
.padding(.vertical, 12)
|
||
.overlay(
|
||
Rectangle()
|
||
.fill(tab == idx ? Color.nightPurple : .clear)
|
||
.frame(height: 2),
|
||
alignment: .bottom
|
||
)
|
||
}
|
||
}
|
||
.padding(.horizontal, 16)
|
||
.overlay(Rectangle().fill(Color.nightBorder).frame(height: 1), alignment: .bottom)
|
||
|
||
ScrollView {
|
||
VStack(alignment: .leading, spacing: 0) {
|
||
switch tab {
|
||
case 0: ImpressumContent()
|
||
case 1: DatenschutzContent()
|
||
default: NutzungsbedingungenContent()
|
||
}
|
||
}
|
||
.padding(20)
|
||
}
|
||
}
|
||
}
|
||
.navigationBarTitleDisplayMode(.inline)
|
||
.toolbar {
|
||
ToolbarItem(placement: .navigationBarTrailing) {
|
||
Button("Schließen") { dismiss() }
|
||
.foregroundColor(.nightSecondary)
|
||
}
|
||
}
|
||
}
|
||
.preferredColorScheme(.dark)
|
||
}
|
||
}
|
||
|
||
// MARK: - Impressum
|
||
|
||
struct ImpressumContent: View {
|
||
var body: some View {
|
||
LegalSection(title: "Impressum") {
|
||
// ⚠️ PFLICHTANGABEN — vor Launch ausfüllen!
|
||
LegalParagraph(title: "Angaben gemäß § 5 TMG") {
|
||
"""
|
||
[DEIN NAME]
|
||
[STRASSE HAUSNUMMER]
|
||
[PLZ ORT]
|
||
Deutschland
|
||
|
||
⚠️ Vor Launch ausfüllen!
|
||
"""
|
||
}
|
||
LegalParagraph(title: "Kontakt") {
|
||
"""
|
||
E-Mail: legal@xxx.dk0.dev
|
||
|
||
⚠️ Vor Launch ausfüllen!
|
||
"""
|
||
}
|
||
LegalParagraph(title: "Verantwortlich für den Inhalt nach § 18 Abs. 2 MStV") {
|
||
"[DEIN NAME], [ADRESSE]"
|
||
}
|
||
LegalParagraph(title: "Hinweis") {
|
||
"""
|
||
Diese App ist ein privates Projekt. Für die Richtigkeit, \
|
||
Vollständigkeit und Aktualität der Inhalte kann keine Gewähr übernommen werden.
|
||
"""
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// MARK: - Datenschutz
|
||
|
||
struct DatenschutzContent: View {
|
||
var body: some View {
|
||
LegalSection(title: "Datenschutzerklärung") {
|
||
LegalParagraph(title: "⚠️ Hinweis") {
|
||
"""
|
||
Diese Datenschutzerklärung ist ein Entwurf und muss vor dem Launch \
|
||
von einem Datenschutzanwalt geprüft und vervollständigt werden. \
|
||
Kosten: ca. 300–500€.
|
||
"""
|
||
}
|
||
LegalParagraph(title: "Verantwortlicher") {
|
||
"[DEIN NAME], [ADRESSE], [E-MAIL]"
|
||
}
|
||
LegalParagraph(title: "Welche Daten wir speichern") {
|
||
"""
|
||
• E-Mail-Adresse (für Account & Passwort-Reset)
|
||
• Benutzername und Anzeigename
|
||
• Posts, Reaktionen, Kommentare (Inhalte die du selbst erstellst)
|
||
• Push-Token (für Benachrichtigungen, optional)
|
||
• IP-Adresse in Server-Logs (max. 14 Tage)
|
||
"""
|
||
}
|
||
LegalParagraph(title: "Wofür wir Daten verwenden") {
|
||
"""
|
||
• Betrieb des Dienstes (Authentifizierung, Feed, Benachrichtigungen)
|
||
• Moderation (Meldungen von Inhalten)
|
||
• Keine Weitergabe an Dritte außer für den Betrieb notwendige Dienste
|
||
"""
|
||
}
|
||
LegalParagraph(title: "Serverstandort") {
|
||
"Alle Daten werden auf Servern in der EU gespeichert."
|
||
}
|
||
LegalParagraph(title: "Deine Rechte (DSGVO)") {
|
||
"""
|
||
• Auskunft über gespeicherte Daten: legal@xxx.dk0.dev
|
||
• Berichtigung falscher Daten
|
||
• Löschung: Account in den Einstellungen löschen — entfernt alle deine Daten sofort
|
||
• Datenübertragbarkeit: auf Anfrage per E-Mail
|
||
• Widerspruch gegen Verarbeitung: legal@xxx.dk0.dev
|
||
• Beschwerde bei der Datenschutzbehörde
|
||
"""
|
||
}
|
||
LegalParagraph(title: "Datenlöschung") {
|
||
"""
|
||
Posts werden 14 Stunden nach Erstellung aus dem öffentlichen Feed entfernt. \
|
||
Dein persönliches Tagebuch behältst du so lange du möchtest. \
|
||
Account-Löschung entfernt alle Daten dauerhaft und unwiderruflich.
|
||
"""
|
||
}
|
||
LegalParagraph(title: "Cookies / Tracking") {
|
||
"Wir verwenden keine Cookies, keine Tracker, keine Werbenetze."
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// MARK: - Nutzungsbedingungen
|
||
|
||
struct NutzungsbedingungenContent: View {
|
||
var body: some View {
|
||
LegalSection(title: "Nutzungsbedingungen") {
|
||
LegalParagraph(title: "⚠️ Entwurf") {
|
||
"Diese Nutzungsbedingungen sind ein Entwurf und müssen vor dem Launch von einem Anwalt geprüft werden."
|
||
}
|
||
LegalParagraph(title: "Nutzung") {
|
||
"""
|
||
nightly ist ein Dienst für Personen ab 17 Jahren. \
|
||
Du bist für die Inhalte die du postest selbst verantwortlich.
|
||
"""
|
||
}
|
||
LegalParagraph(title: "Verbotene Inhalte") {
|
||
"""
|
||
Folgende Inhalte sind verboten:
|
||
• Hassrede, Diskriminierung, Bedrohung
|
||
• Belästigung oder Mobbing
|
||
• Illegale Inhalte jeglicher Art
|
||
• Spam oder kommerzielle Werbung
|
||
• Inhalte die andere Personen ohne deren Zustimmung zeigen
|
||
"""
|
||
}
|
||
LegalParagraph(title: "Moderation") {
|
||
"""
|
||
Gemeldete Inhalte werden geprüft und können ohne Vorankündigung entfernt werden. \
|
||
Bei schwerwiegenden Verstößen behalten wir uns die Sperrung des Accounts vor.
|
||
"""
|
||
}
|
||
LegalParagraph(title: "Haftungsausschluss") {
|
||
"""
|
||
Wir übernehmen keine Haftung für nutzergenerierte Inhalte. \
|
||
Der Dienst wird ohne Gewähr für Verfügbarkeit bereitgestellt.
|
||
"""
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// MARK: - Reusable components
|
||
|
||
struct LegalSection<Content: View>: View {
|
||
let title: String
|
||
@ViewBuilder let content: Content
|
||
|
||
var body: some View {
|
||
VStack(alignment: .leading, spacing: 20) {
|
||
Text(title)
|
||
.font(.nightTitle(22))
|
||
.foregroundColor(.nightPrimary)
|
||
.padding(.bottom, 4)
|
||
content
|
||
}
|
||
}
|
||
}
|
||
|
||
struct LegalParagraph: View {
|
||
let title: String
|
||
let body: String
|
||
|
||
init(title: String, _ body: () -> String) {
|
||
self.title = title
|
||
self.body = body()
|
||
}
|
||
|
||
var body: some View {
|
||
VStack(alignment: .leading, spacing: 6) {
|
||
Text(title)
|
||
.font(.nightLabel(14, weight: .semibold))
|
||
.foregroundColor(.nightPrimary)
|
||
Text(body)
|
||
.font(.nightBody(14))
|
||
.foregroundColor(.nightSecondary)
|
||
.lineSpacing(4)
|
||
.fixedSize(horizontal: false, vertical: true)
|
||
}
|
||
}
|
||
}
|