FrontPageView.swift 4.7 KB

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