浏览代码

Add a full-width settings page with share and external links.

Wire share, website, privacy, terms, and support actions through AppLinks and connect paywall footer links to the same URLs.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 1 月之前
父节点
当前提交
db64d17a2e

+ 15 - 0
Reddit App/Utilities/AppLinks.swift

@@ -0,0 +1,15 @@
+import Foundation
+
+enum AppLinks {
+    static let appName = "Reddora AI"
+
+    static let website = URL(string: "https://reddora.ai")!
+    static let privacy = URL(string: "https://reddora.ai/privacy")!
+    static let terms = URL(string: "https://reddora.ai/terms")!
+    static let support = URL(string: "mailto:support@reddora.ai")!
+    static let appStore = URL(string: "https://apps.apple.com/app/reddora-ai")!
+
+    static var shareMessage: String {
+        "Check out \(appName) — AI-powered tools for Reddit posts, titles, and comments."
+    }
+}

+ 29 - 0
Reddit App/ViewModels/SettingsViewModel.swift

@@ -0,0 +1,29 @@
+import AppKit
+import Foundation
+
+@MainActor
+@Observable
+final class SettingsViewModel {
+    let shareMessage = AppLinks.shareMessage
+    let shareURL = AppLinks.appStore
+
+    func openWebsite() {
+        open(AppLinks.website)
+    }
+
+    func openPrivacyPolicy() {
+        open(AppLinks.privacy)
+    }
+
+    func openTermsAndConditions() {
+        open(AppLinks.terms)
+    }
+
+    func openSupport() {
+        open(AppLinks.support)
+    }
+
+    private func open(_ url: URL) {
+        NSWorkspace.shared.open(url)
+    }
+}

+ 96 - 0
Reddit App/Views/Components/SettingsComponents.swift

@@ -0,0 +1,96 @@
+import SwiftUI
+
+struct SettingsShareAppButton: View {
+    let message: String
+    let url: URL
+
+    var body: some View {
+        ShareLink(item: url, message: Text(message)) {
+            HStack(spacing: 14) {
+                Image(systemName: "square.and.arrow.up")
+                    .font(.system(size: 16, weight: .semibold))
+                    .foregroundStyle(.white)
+                    .frame(width: 40, height: 40)
+                    .background(
+                        RoundedRectangle(cornerRadius: 10)
+                            .fill(AppTheme.accentPurple)
+                    )
+
+                VStack(alignment: .leading, spacing: 2) {
+                    Text("Share App")
+                        .font(.system(size: 14, weight: .semibold))
+                        .foregroundStyle(AppTheme.textPrimary)
+                    Text("Tell friends about \(AppLinks.appName)")
+                        .font(.system(size: 11))
+                        .foregroundStyle(AppTheme.textSecondary)
+                }
+
+                Spacer()
+
+                Image(systemName: "chevron.right")
+                    .font(.system(size: 11, weight: .semibold))
+                    .foregroundStyle(AppTheme.textTertiary)
+            }
+            .padding(14)
+            .background(
+                RoundedRectangle(cornerRadius: AppTheme.cornerRadiusSmall)
+                    .fill(AppTheme.cardBackground)
+                    .overlay(
+                        RoundedRectangle(cornerRadius: AppTheme.cornerRadiusSmall)
+                            .stroke(AppTheme.accentPurple.opacity(0.35), lineWidth: 1)
+                    )
+            )
+        }
+        .buttonStyle(.plain)
+        .frame(maxWidth: .infinity, alignment: .leading)
+    }
+}
+
+struct SettingsLinkRow: View {
+    let icon: String
+    let title: String
+    var subtitle: String?
+    let action: () -> Void
+
+    var body: some View {
+        Button(action: action) {
+            HStack(spacing: 12) {
+                Image(systemName: icon)
+                    .font(.system(size: 14, weight: .medium))
+                    .foregroundStyle(AppTheme.accentPurple)
+                    .frame(width: 32, height: 32)
+                    .background(
+                        RoundedRectangle(cornerRadius: 8)
+                            .fill(AppTheme.accentPurple.opacity(0.12))
+                    )
+
+                VStack(alignment: .leading, spacing: 2) {
+                    Text(title)
+                        .font(.system(size: 13, weight: .medium))
+                        .foregroundStyle(AppTheme.textPrimary)
+                    if let subtitle {
+                        Text(subtitle)
+                            .font(.system(size: 10))
+                            .foregroundStyle(AppTheme.textSecondary)
+                    }
+                }
+
+                Spacer()
+
+                Image(systemName: "arrow.up.right")
+                    .font(.system(size: 11, weight: .medium))
+                    .foregroundStyle(AppTheme.textTertiary)
+            }
+            .padding(.horizontal, 12)
+            .padding(.vertical, 10)
+            .background(AppTheme.panelBackground)
+            .clipShape(RoundedRectangle(cornerRadius: 8))
+            .overlay(
+                RoundedRectangle(cornerRadius: 8)
+                    .stroke(AppTheme.cardBorder, lineWidth: 1)
+            )
+        }
+        .buttonStyle(.plain)
+        .frame(maxWidth: .infinity, alignment: .leading)
+    }
+}

+ 2 - 1
Reddit App/Views/FrontPageView.swift

@@ -7,6 +7,7 @@ struct FrontPageView: View {
     @State private var postGeneratorViewModel = PostGeneratorViewModel()
     @State private var titleOptimizerViewModel = TitleOptimizerViewModel()
     @State private var commentWriterViewModel = CommentWriterViewModel()
+    @State private var settingsViewModel = SettingsViewModel()
 
     var body: some View {
         ZStack {
@@ -58,7 +59,7 @@ struct FrontPageView: View {
             .accessibilityHidden(!viewModel.isRedditActive)
 
             if viewModel.isSettingsActive {
-                SettingsView()
+                SettingsView(viewModel: settingsViewModel)
             } else if !viewModel.isRedditActive, let item = viewModel.selectedNavItem {
                 toolContent(for: item)
             }

+ 10 - 3
Reddit App/Views/PaywallView.swift

@@ -1,3 +1,4 @@
+import AppKit
 import SwiftUI
 
 struct PaywallView: View {
@@ -219,15 +220,21 @@ struct PaywallView: View {
 
             Spacer(minLength: metrics.footerLinkSpacing)
 
-            footerLink(PaywallContent.privacyPolicy, metrics: metrics) {}
+            footerLink(PaywallContent.privacyPolicy, metrics: metrics) {
+                NSWorkspace.shared.open(AppLinks.privacy)
+            }
 
             Spacer(minLength: metrics.footerLinkSpacing)
 
-            footerLink(PaywallContent.support, metrics: metrics) {}
+            footerLink(PaywallContent.support, metrics: metrics) {
+                NSWorkspace.shared.open(AppLinks.support)
+            }
 
             Spacer(minLength: metrics.footerLinkSpacing)
 
-            footerLink(PaywallContent.termsOfService, metrics: metrics) {}
+            footerLink(PaywallContent.termsOfService, metrics: metrics) {
+                NSWorkspace.shared.open(AppLinks.terms)
+            }
         }
         .padding(.horizontal, metrics.footerLinksHorizontalInset)
         .frame(maxWidth: .infinity)

+ 75 - 1
Reddit App/Views/SettingsView.swift

@@ -1,10 +1,26 @@
 import SwiftUI
 
 struct SettingsView: View {
+    @Bindable var viewModel: SettingsViewModel
+
+    private enum Layout {
+        static let horizontalPadding: CGFloat = 24
+    }
+
     var body: some View {
         VStack(spacing: 0) {
             header
-            Spacer()
+
+            ScrollView {
+                VStack(alignment: .leading, spacing: 12) {
+                    shareSection
+                    linksSection
+                }
+                .frame(maxWidth: .infinity, alignment: .leading)
+                .padding(.horizontal, Layout.horizontalPadding)
+                .padding(.top, 12)
+                .padding(.bottom, 24)
+            }
         }
         .background(AppTheme.background)
     }
@@ -32,4 +48,62 @@ struct SettingsView: View {
                 .frame(height: 1)
         }
     }
+
+    private var shareSection: some View {
+        PostFormCard(
+            title: "Share",
+            subtitle: "Spread the word about \(AppLinks.appName)"
+        ) {
+            SettingsShareAppButton(
+                message: viewModel.shareMessage,
+                url: viewModel.shareURL
+            )
+        }
+    }
+
+    private var linksSection: some View {
+        PostFormCard(
+            title: "About",
+            subtitle: "Website, legal, and help resources"
+        ) {
+            VStack(spacing: 8) {
+                SettingsLinkRow(
+                    icon: "globe",
+                    title: "Website",
+                    subtitle: AppLinks.website.host
+                ) {
+                    viewModel.openWebsite()
+                }
+
+                SettingsLinkRow(
+                    icon: "hand.raised.fill",
+                    title: "Privacy Policy",
+                    subtitle: "How we handle your data"
+                ) {
+                    viewModel.openPrivacyPolicy()
+                }
+
+                SettingsLinkRow(
+                    icon: "doc.text.fill",
+                    title: "Terms & Conditions",
+                    subtitle: "Terms of service"
+                ) {
+                    viewModel.openTermsAndConditions()
+                }
+
+                SettingsLinkRow(
+                    icon: "lifepreserver.fill",
+                    title: "Support",
+                    subtitle: "Get help or send feedback"
+                ) {
+                    viewModel.openSupport()
+                }
+            }
+        }
+    }
+}
+
+#Preview {
+    SettingsView(viewModel: SettingsViewModel())
+        .frame(width: 800, height: 600)
 }