From 3a875c3c8ebda769290f56eb482d916a4d96a75a Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 22 Dec 2025 16:15:02 -0600 Subject: [PATCH] Signed-off-by: Matt Bruce --- .../Views/Settings/PrivacyPolicyView.swift | 180 ++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 CasinoKit/Sources/CasinoKit/Views/Settings/PrivacyPolicyView.swift diff --git a/CasinoKit/Sources/CasinoKit/Views/Settings/PrivacyPolicyView.swift b/CasinoKit/Sources/CasinoKit/Views/Settings/PrivacyPolicyView.swift new file mode 100644 index 0000000..2e52c77 --- /dev/null +++ b/CasinoKit/Sources/CasinoKit/Views/Settings/PrivacyPolicyView.swift @@ -0,0 +1,180 @@ +// +// PrivacyPolicyView.swift +// CasinoKit +// +// A shared privacy policy view for casino game apps. +// + +import SwiftUI + +/// A view displaying the privacy policy for casino games. +/// This policy is designed for offline games that don't collect personal data. +public struct PrivacyPolicyView: View { + @Environment(\.dismiss) private var dismiss + + /// The developer/company name to display in the policy. + public let developerName: String + + /// Contact email for privacy inquiries. + public let contactEmail: String + + /// Last updated date string. + public let lastUpdated: String + + /// Creates a privacy policy view. + /// - Parameters: + /// - developerName: Your name or company name. + /// - contactEmail: Email for privacy questions. + /// - lastUpdated: Date string like "December 2024". + public init( + developerName: String, + contactEmail: String, + lastUpdated: String = "December 2024" + ) { + self.developerName = developerName + self.contactEmail = contactEmail + self.lastUpdated = lastUpdated + } + + public var body: some View { + NavigationStack { + ScrollView { + VStack(alignment: .leading, spacing: CasinoDesign.Spacing.large) { + // Header + Text(String(localized: "Privacy Policy", bundle: .module)) + .font(.system(size: CasinoDesign.BaseFontSize.largeTitle, weight: .bold)) + .foregroundStyle(.white) + + Text(String(localized: "Last updated: \(lastUpdated)", bundle: .module)) + .font(.system(size: CasinoDesign.BaseFontSize.body)) + .foregroundStyle(.white.opacity(CasinoDesign.Opacity.medium)) + + Divider() + .background(Color.white.opacity(CasinoDesign.Opacity.subtle)) + + // Introduction + PolicySection(title: String(localized: "Introduction", bundle: .module)) { + Text(String(localized: "\(developerName) (\"we\", \"our\", or \"us\") respects your privacy. This Privacy Policy explains how our casino game apps handle your information.", bundle: .module)) + } + + // Data Collection + PolicySection(title: String(localized: "Information We Collect", bundle: .module)) { + Text(String(localized: "Our games are designed to work offline and we collect minimal data:", bundle: .module)) + + BulletPoint(String(localized: "Game progress and statistics are stored locally on your device", bundle: .module)) + BulletPoint(String(localized: "If you enable iCloud sync, your game data is stored in your personal iCloud account", bundle: .module)) + BulletPoint(String(localized: "We do not collect personal information such as your name, email, or location", bundle: .module)) + BulletPoint(String(localized: "We do not use analytics or tracking services", bundle: .module)) + BulletPoint(String(localized: "We do not display advertisements", bundle: .module)) + } + + // iCloud + PolicySection(title: String(localized: "iCloud Sync", bundle: .module)) { + Text(String(localized: "If you choose to enable iCloud sync:", bundle: .module)) + + BulletPoint(String(localized: "Your game progress syncs across your devices using your Apple ID", bundle: .module)) + BulletPoint(String(localized: "This data is stored in your personal iCloud account, not on our servers", bundle: .module)) + BulletPoint(String(localized: "Apple's iCloud terms and privacy policy apply to this data", bundle: .module)) + BulletPoint(String(localized: "You can disable iCloud sync at any time in the app settings", bundle: .module)) + } + + // Data Storage + PolicySection(title: String(localized: "Data Storage", bundle: .module)) { + Text(String(localized: "All game data is stored:", bundle: .module)) + + BulletPoint(String(localized: "Locally on your device using iOS standard storage", bundle: .module)) + BulletPoint(String(localized: "In your iCloud account if you enable sync", bundle: .module)) + BulletPoint(String(localized: "We have no access to your game data", bundle: .module)) + } + + // Children + PolicySection(title: String(localized: "Children's Privacy", bundle: .module)) { + Text(String(localized: "Our games are simulated casino games for entertainment only. No real money gambling is involved. We do not knowingly collect information from children under 13.", bundle: .module)) + } + + // Third Parties + PolicySection(title: String(localized: "Third-Party Services", bundle: .module)) { + Text(String(localized: "Our apps do not integrate with third-party services that collect user data. We do not share any information with third parties.", bundle: .module)) + } + + // Changes + PolicySection(title: String(localized: "Changes to This Policy", bundle: .module)) { + Text(String(localized: "We may update this Privacy Policy from time to time. We will notify you of any changes by posting the new policy in the app and updating the \"Last updated\" date.", bundle: .module)) + } + + // Contact + PolicySection(title: String(localized: "Contact Us", bundle: .module)) { + Text(String(localized: "If you have questions about this Privacy Policy, please contact us at:", bundle: .module)) + + Text(contactEmail) + .font(.system(size: CasinoDesign.BaseFontSize.body, weight: .medium)) + .foregroundStyle(.yellow) + } + + Spacer(minLength: CasinoDesign.Spacing.xxLarge) + } + .padding(CasinoDesign.Spacing.large) + } + .background(Color.Sheet.background.ignoresSafeArea()) + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .topBarTrailing) { + Button(String(localized: "Done", bundle: .module)) { + dismiss() + } + .foregroundStyle(.yellow) + } + } + .toolbarBackground(Color.Sheet.background, for: .navigationBar) + .toolbarColorScheme(.dark, for: .navigationBar) + } + } +} + +// MARK: - Policy Section + +private struct PolicySection: View { + let title: String + @ViewBuilder let content: () -> Content + + var body: some View { + VStack(alignment: .leading, spacing: CasinoDesign.Spacing.small) { + Text(title) + .font(.system(size: CasinoDesign.BaseFontSize.xLarge, weight: .semibold)) + .foregroundStyle(.white) + + content() + .font(.system(size: CasinoDesign.BaseFontSize.body)) + .foregroundStyle(.white.opacity(CasinoDesign.Opacity.strong)) + } + } +} + +// MARK: - Bullet Point + +private struct BulletPoint: View { + let text: String + + init(_ text: String) { + self.text = text + } + + var body: some View { + HStack(alignment: .top, spacing: CasinoDesign.Spacing.small) { + Text("•") + .foregroundStyle(.yellow) + Text(text) + } + .font(.system(size: CasinoDesign.BaseFontSize.body)) + .foregroundStyle(.white.opacity(CasinoDesign.Opacity.strong)) + } +} + +// MARK: - Preview + +#Preview { + PrivacyPolicyView( + developerName: "Casino Games Studio", + contactEmail: "privacy@example.com" + ) +}