FrontPageView.swift 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import SwiftUI
  2. struct FrontPageView: View {
  3. @EnvironmentObject private var subscriptions: SubscriptionManager
  4. @Environment(AppearanceManager.self) private var appearanceManager
  5. @State private var viewModel = FrontPageViewModel()
  6. @State private var paywallViewModel = PaywallViewModel()
  7. @State private var postGeneratorViewModel = PostGeneratorViewModel()
  8. @State private var titleOptimizerViewModel = TitleOptimizerViewModel()
  9. @State private var commentWriterViewModel = CommentWriterViewModel()
  10. @State private var settingsViewModel = SettingsViewModel()
  11. var body: some View {
  12. let _ = appearanceManager.isDarkMode
  13. ZStack {
  14. HStack(spacing: 0) {
  15. SidebarView(
  16. viewModel: viewModel,
  17. isPremium: subscriptions.hasPremiumAccess
  18. )
  19. mainContent
  20. .frame(maxWidth: .infinity, maxHeight: .infinity)
  21. .environment(\.requirePremiumAccess, {
  22. if subscriptions.hasPremiumAccess { return true }
  23. viewModel.showPaywall()
  24. return false
  25. })
  26. }
  27. if viewModel.isPaywallPresented {
  28. PaywallView(viewModel: paywallViewModel) {
  29. viewModel.dismissPaywall()
  30. }
  31. .frame(maxWidth: .infinity, maxHeight: .infinity)
  32. .ignoresSafeArea()
  33. .zIndex(1)
  34. .transition(.opacity)
  35. }
  36. }
  37. .animation(.easeInOut(duration: 0.2), value: viewModel.isPaywallPresented)
  38. .onChange(of: subscriptions.hasPremiumAccess) { hasPremium in
  39. if hasPremium {
  40. viewModel.dismissPaywall()
  41. }
  42. }
  43. .frame(minWidth: AppWindow.minWidth, minHeight: AppWindow.minHeight)
  44. .background(AppTheme.background)
  45. .alert("Sign-in issue", isPresented: authErrorBinding) {
  46. Button("OK") {
  47. viewModel.clearAuthError()
  48. }
  49. } message: {
  50. Text(viewModel.authErrorMessage ?? "")
  51. }
  52. }
  53. private var authErrorBinding: Binding<Bool> {
  54. Binding(
  55. get: { viewModel.authErrorMessage != nil },
  56. set: { isPresented in
  57. if !isPresented {
  58. viewModel.clearAuthError()
  59. }
  60. }
  61. )
  62. }
  63. @ViewBuilder
  64. private var mainContent: some View {
  65. VStack(spacing: 0) {
  66. if viewModel.isRedditActive, viewModel.redditCanGoBack {
  67. RedditWebBackBar(
  68. canGoBack: true,
  69. onBack: { viewModel.goBackInReddit() }
  70. )
  71. }
  72. ZStack {
  73. RedditWebView(
  74. url: viewModel.redditLoadURL,
  75. reloadTrigger: viewModel.redditReloadTrigger,
  76. isDarkMode: appearanceManager.isDarkMode,
  77. goBackTrigger: viewModel.redditGoBackTrigger,
  78. onCanGoBackChange: { viewModel.updateRedditCanGoBack($0) },
  79. onAuthError: { viewModel.showAuthError($0) }
  80. )
  81. .id("reddit-webview")
  82. .frame(maxWidth: .infinity, maxHeight: .infinity)
  83. .allowsHitTesting(viewModel.isRedditActive)
  84. .accessibilityHidden(!viewModel.isRedditActive)
  85. if viewModel.isSettingsActive {
  86. SettingsView(viewModel: settingsViewModel)
  87. } else if !viewModel.isRedditActive, let item = viewModel.selectedNavItem {
  88. toolContent(for: item)
  89. }
  90. }
  91. }
  92. .background(AppTheme.background)
  93. }
  94. @ViewBuilder
  95. private func toolContent(for item: SidebarNavItem) -> some View {
  96. switch item.iconKind {
  97. case .postGenerator:
  98. PostGeneratorView(viewModel: postGeneratorViewModel)
  99. case .titleOptimizer:
  100. TitleOptimizerView(viewModel: titleOptimizerViewModel)
  101. case .commentWriter:
  102. CommentWriterView(viewModel: commentWriterViewModel)
  103. default:
  104. ToolPlaceholderView(item: item)
  105. }
  106. }
  107. }
  108. private struct ToolPlaceholderView: View {
  109. let item: SidebarNavItem
  110. var body: some View {
  111. VStack(spacing: 12) {
  112. ModernSidebarIconView(kind: item.iconKind, size: 56)
  113. Text(item.title)
  114. .font(.system(size: 20, weight: .semibold))
  115. .foregroundStyle(AppTheme.textPrimary)
  116. Text(item.subtitle)
  117. .font(.system(size: 13))
  118. .foregroundStyle(AppTheme.textSecondary)
  119. }
  120. .frame(maxWidth: .infinity, maxHeight: .infinity)
  121. .background(AppTheme.background)
  122. }
  123. }
  124. #Preview {
  125. FrontPageView()
  126. .environmentObject(SubscriptionManager())
  127. .environment(AppearanceManager.shared)
  128. .frame(width: AppWindow.width, height: AppWindow.height)
  129. }