Add AI mood report feature with PDF export for therapist sharing
Adds a Reports tab to the Insights view with date range selection, two report types (Quick Summary / Detailed), Foundation Models AI generation with batched concurrent processing, and clinical PDF export via WKWebView HTML rendering. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
86
Shared/Views/InsightsView/ReportGeneratingView.swift
Normal file
86
Shared/Views/InsightsView/ReportGeneratingView.swift
Normal file
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// ReportGeneratingView.swift
|
||||
// Reflect
|
||||
//
|
||||
// Overlay shown during AI report generation with progress and cancel.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ReportGeneratingView: View {
|
||||
let progress: Double
|
||||
let message: String
|
||||
let onCancel: () -> Void
|
||||
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
@State private var isPulsing = false
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
// Semi-transparent background
|
||||
Color.black.opacity(0.4)
|
||||
.ignoresSafeArea()
|
||||
|
||||
VStack(spacing: 24) {
|
||||
// Sparkles icon
|
||||
Image(systemName: "sparkles")
|
||||
.font(.system(size: 44))
|
||||
.foregroundStyle(
|
||||
LinearGradient(
|
||||
colors: [.purple, .blue],
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
)
|
||||
.scaleEffect(isPulsing ? 1.1 : 1.0)
|
||||
.opacity(isPulsing ? 0.8 : 1.0)
|
||||
.animation(
|
||||
UIAccessibility.isReduceMotionEnabled ? nil :
|
||||
.easeInOut(duration: 1.2).repeatForever(autoreverses: true),
|
||||
value: isPulsing
|
||||
)
|
||||
|
||||
// Progress bar
|
||||
VStack(spacing: 8) {
|
||||
ProgressView(value: progress)
|
||||
.progressViewStyle(.linear)
|
||||
.tint(
|
||||
LinearGradient(
|
||||
colors: [.purple, .blue],
|
||||
startPoint: .leading,
|
||||
endPoint: .trailing
|
||||
)
|
||||
)
|
||||
.accessibilityIdentifier(AccessibilityID.Reports.progressView)
|
||||
|
||||
Text(message)
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(.secondary)
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
|
||||
// Cancel button
|
||||
Button(role: .cancel) {
|
||||
onCancel()
|
||||
} label: {
|
||||
Text("Cancel")
|
||||
.font(.subheadline.weight(.medium))
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Reports.cancelButton)
|
||||
}
|
||||
.padding(32)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 20)
|
||||
.fill(colorScheme == .dark ? Color(.systemGray6) : .white)
|
||||
.shadow(radius: 20)
|
||||
)
|
||||
.padding(.horizontal, 40)
|
||||
}
|
||||
.onAppear {
|
||||
if !UIAccessibility.isReduceMotionEnabled {
|
||||
isPulsing = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user