// // SharePreviewView.swift // SportsTime // // Unified preview and customization UI for all shareable content. // import SwiftUI struct SharePreviewView: View { let content: Content @Environment(\.dismiss) private var dismiss @Environment(\.colorScheme) private var colorScheme @State private var selectedTheme: ShareTheme @State private var generatedImage: UIImage? @State private var isGenerating = false @State private var error: String? @State private var showCopiedToast = false init(content: Content) { self.content = content _selectedTheme = State(initialValue: ShareThemePreferences.theme(for: content.cardType)) } var body: some View { NavigationStack { ScrollView { VStack(spacing: Theme.Spacing.lg) { // Preview previewSection // Theme selector themeSelector // Action buttons actionButtons } .padding(Theme.Spacing.md) } .themedBackground() .navigationTitle("Share") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .cancellationAction) { Button("Cancel") { dismiss() } } } .alert("Error", isPresented: .constant(error != nil)) { Button("OK") { error = nil } } message: { Text(error ?? "") } .overlay { if showCopiedToast { copiedToast } } .task { await generatePreview() } .onChange(of: selectedTheme) { _, _ in Task { await generatePreview() } } } } // MARK: - Preview Section private var previewSection: some View { VStack(spacing: Theme.Spacing.sm) { Text("Preview") .font(.subheadline) .foregroundStyle(Theme.textMuted(colorScheme)) if let image = generatedImage { Image(uiImage: image) .resizable() .aspectRatio(9/16, contentMode: .fit) .frame(maxHeight: 400) .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.medium)) .shadow(color: .black.opacity(0.2), radius: 10, x: 0, y: 5) .accessibilityLabel("Share card preview") } else if isGenerating { RoundedRectangle(cornerRadius: Theme.CornerRadius.medium) .fill(Theme.cardBackground(colorScheme)) .aspectRatio(9/16, contentMode: .fit) .frame(maxHeight: 400) .overlay { ProgressView() } } } } // MARK: - Theme Selector private var themeSelector: some View { VStack(alignment: .leading, spacing: Theme.Spacing.sm) { Text("Theme") .font(.subheadline) .foregroundStyle(Theme.textMuted(colorScheme)) ScrollView(.horizontal, showsIndicators: false) { HStack(spacing: Theme.Spacing.sm) { ForEach(ShareTheme.all) { theme in themeButton(theme) } } } } } private func themeButton(_ theme: ShareTheme) -> some View { Button { withAnimation { selectedTheme = theme ShareThemePreferences.setTheme(theme, for: content.cardType) } } label: { VStack(spacing: 4) { ZStack { RoundedRectangle(cornerRadius: 8) .fill( LinearGradient( colors: theme.gradientColors, startPoint: .top, endPoint: .bottom ) ) .frame(width: 50, height: 50) Circle() .fill(theme.accentColor) .frame(width: 16, height: 16) } .overlay { if selectedTheme.id == theme.id { RoundedRectangle(cornerRadius: 8) .stroke(Theme.warmOrange, lineWidth: 3) } } Text(theme.name) .font(.caption2) .foregroundStyle(Theme.textSecondary(colorScheme)) } } .buttonStyle(.plain) .accessibilityLabel("Select \(theme.name) theme") .accessibilityHint(selectedTheme.id == theme.id ? "Currently selected" : "Double-tap to select this theme") .accessibilityAddTraits(selectedTheme.id == theme.id ? .isSelected : []) } // MARK: - Action Buttons private var actionButtons: some View { VStack(spacing: Theme.Spacing.sm) { // Primary: Share to Instagram Button { shareToInstagram() } label: { HStack { Image(systemName: "camera.fill") .accessibilityHidden(true) Text("Share to Instagram") } .frame(maxWidth: .infinity) .padding(Theme.Spacing.md) .background(Theme.warmOrange) .foregroundStyle(.white) .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.medium)) } .disabled(generatedImage == nil) // Copy Image Button { copyImage() } label: { HStack { Image(systemName: "doc.on.doc") .accessibilityHidden(true) Text("Copy to Clipboard") } .frame(maxWidth: .infinity) .padding(Theme.Spacing.md) .background(Theme.cardBackgroundElevated(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme)) .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.medium)) } .disabled(generatedImage == nil) } } // MARK: - Copied Toast private var copiedToast: some View { VStack { Spacer() HStack { Image(systemName: "checkmark.circle.fill") .accessibilityHidden(true) Text("Copied to clipboard") } .padding() .background(.ultraThinMaterial) .clipShape(Capsule()) .padding(.bottom, 100) } .transition(.move(edge: .bottom).combined(with: .opacity)) } // MARK: - Actions private func generatePreview() async { isGenerating = true do { generatedImage = try await content.render(theme: selectedTheme) } catch { self.error = error.localizedDescription } isGenerating = false } private func shareToInstagram() { guard let image = generatedImage else { return } if !ShareService.shared.shareToInstagram(image: image) { // Fallback to system share showSystemShare() } } private func copyImage() { guard let image = generatedImage else { return } ShareService.shared.copyToClipboard(image: image) withAnimation { showCopiedToast = true } DispatchQueue.main.asyncAfter(deadline: .now() + 2) { withAnimation { showCopiedToast = false } } } private func showSystemShare() { guard let image = generatedImage, let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, let rootVC = windowScene.windows.first?.rootViewController else { return } ShareService.shared.presentShareSheet(image: image, from: rootVC) } }