Files
InvestmentTrackerApp/PortfolioJournal/Views/Dashboard/MonthlySummaryShareView.swift
T
alexandrev-tibco a8a9ad64f3 Xcode 27: compila sin warnings y migra API deprecadas de SwiftUI
- Imports de CoreData que faltaban (MemberImportVisibility) en AccountsView,
  ImportDataView, ChartsContainerView y AddSourceView.
- Aislamiento MainActor: IsolatedDefaultValues en el target de la app,
  LinearGradient @MainActor, WatchSyncMessage nonisolated, closures de
  ReviewPromptService/MonthlyCheckInStore/AppIntents.
- Warnings de valores sin usar (SnapshotGapDetector, DashboardLayoutStore,
  OnboardingView, GoalEditorView, CoreDataStack, SettingsViewModel).
- foregroundColor→foregroundStyle, cornerRadius→clipShape,
  navigationBarLeading/Trailing→topBarLeading/Trailing,
  Task.sleep(nanoseconds:)→sleep(for:), NavigationLink(isActive:)→
  navigationDestination(isPresented:).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F1u4K16xy7eQVtgsYNZ9Vn
2026-09-16 11:44:49 +02:00

146 lines
5.4 KiB
Swift

import SwiftUI
/// A polished, branded card summarising the month designed to be rendered to
/// an image and shared (screenshot-worthy, marketing-facing). Pulls only from
/// data the Dashboard already computes.
struct MonthlySummaryShareView: View {
let monthLabel: String
let totalValue: String
let changeAmount: String
let changePercentage: String
let isPositive: Bool
let streak: Int
let mood: MonthlyCheckInMood?
let rating: Int?
let appName: String
var qrCodeImage: UIImage? = nil
var body: some View {
VStack(alignment: .leading, spacing: 0) {
// Header
HStack {
Text(monthLabel)
.font(.caption.weight(.semibold))
.foregroundStyle(.white.opacity(0.85))
.textCase(.uppercase)
Spacer()
if streak >= 2 {
HStack(spacing: 4) {
Image(systemName: "flame.fill")
.font(.caption2)
Text(String(format: String(localized: "share_summary_streak_badge"), streak))
.font(.caption2.weight(.bold))
}
.foregroundStyle(.white)
.padding(.horizontal, 10)
.padding(.vertical, 5)
.background(Color.white.opacity(0.18))
.clipShape(Capsule())
}
}
Text("Monthly Summary")
.font(.title.weight(.bold))
.foregroundStyle(.white)
.padding(.top, 6)
// Hero value
VStack(alignment: .leading, spacing: 6) {
Text("Portfolio Value")
.font(.subheadline.weight(.semibold))
.foregroundStyle(.white.opacity(0.85))
Text(totalValue)
.font(.system(size: 40, weight: .bold, design: .rounded))
.foregroundStyle(.white)
.minimumScaleFactor(0.6)
.lineLimit(1)
}
.padding(.top, 22)
// Change since last check-in
HStack(spacing: 8) {
Image(systemName: isPositive ? "arrow.up.right" : "arrow.down.right")
.font(.subheadline.weight(.bold))
Text("\(changeAmount) (\(changePercentage))")
.font(.headline.weight(.bold))
Spacer()
Text("since last check-in")
.font(.caption)
.foregroundStyle(.white.opacity(0.75))
}
.foregroundStyle(.white)
.padding(.horizontal, 14)
.padding(.vertical, 10)
.background(Color.white.opacity(0.15))
.clipShape(RoundedRectangle(cornerRadius: 14, style: .continuous))
.padding(.top, 18)
// Mood / rating
if mood != nil || rating != nil {
HStack(spacing: 14) {
if let mood {
HStack(spacing: 6) {
Image(systemName: mood.iconName)
.font(.subheadline)
Text(mood.title)
.font(.subheadline.weight(.semibold))
}
.foregroundStyle(.white)
}
if let rating {
HStack(spacing: 2) {
ForEach(1...5, id: \.self) { i in
Image(systemName: i <= rating ? "star.fill" : "star")
.font(.caption)
.foregroundStyle(.white.opacity(i <= rating ? 1 : 0.4))
}
}
}
Spacer()
}
.padding(.top, 16)
}
Spacer(minLength: 0)
// Footer / branding
HStack(spacing: 12) {
Image("BrandMark")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 40, height: 40)
.clipShape(RoundedRectangle(cornerRadius: 9, style: .continuous))
VStack(alignment: .leading, spacing: 2) {
Text("Tracked with")
.font(.caption2.weight(.medium))
.foregroundStyle(.white.opacity(0.7))
Text(appName)
.font(.subheadline.weight(.bold))
.foregroundStyle(.white)
}
Spacer()
if let qrCodeImage {
Image(uiImage: qrCodeImage)
.interpolation(.none)
.resizable()
.frame(width: 52, height: 52)
.background(Color.white)
.clipShape(RoundedRectangle(cornerRadius: 7, style: .continuous))
}
}
.padding(.top, 20)
}
.padding(24)
.frame(width: 340, height: 440)
.background(ShareCardBackground())
.clipShape(RoundedRectangle(cornerRadius: 28, style: .continuous))
.overlay(
RoundedRectangle(cornerRadius: 28, style: .continuous)
.stroke(Color.white.opacity(0.12), lineWidth: 1)
)
}
}