7cb5f92cf4
Deleted files: - AddTransactionView.swift - TransactionRepository.swift - Transaction+CoreDataClass.swift Cleaned files: - SourceDetailViewModel: removed transactions published property, showingAddTransaction flag, transactionRepository dependency, addTransaction() and deleteTransaction() methods - SourceDetailView: removed transactionsSection, TransactionRow struct, Add Transaction button from quickActions, sheet presentation - InvestmentSource+CoreDataClass: removed transactions NSManaged property, transactionsArray, totalInvested, totalDividends, totalFees computed properties, and all transaction Core Data accessors - SettingsViewModel: removed "Transaction" from resetAllData entity list - SampleDataService: removed transactionRepository and sample transaction Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
146 lines
4.8 KiB
Swift
146 lines
4.8 KiB
Swift
import SwiftUI
|
|
|
|
struct MonthlyCheckInShareCardView: View {
|
|
let summary: MonthlySummary
|
|
let appName: String
|
|
var qrCodeImage: UIImage? = nil
|
|
|
|
var body: some View {
|
|
VStack(alignment: .leading, spacing: 14) {
|
|
Text(summary.formattedMonthYear)
|
|
.font(.caption.weight(.semibold))
|
|
.foregroundColor(.white.opacity(0.85))
|
|
|
|
Text("Monthly Check-in")
|
|
.font(.title2.weight(.bold))
|
|
.foregroundColor(.white)
|
|
|
|
metricRow("Starting", summary.formattedStartingValue)
|
|
metricRow("Ending", summary.formattedEndingValue)
|
|
if summary.contributions != 0 {
|
|
metricRow("Contributions", summary.formattedContributions)
|
|
}
|
|
metricRow("Net performance", "\(summary.formattedNetPerformance) (\(summary.formattedNetPerformancePercentage))")
|
|
|
|
Spacer(minLength: 0)
|
|
shareFooter(appName: appName, qrCodeImage: qrCodeImage)
|
|
}
|
|
.padding(20)
|
|
.frame(width: 320, height: 300)
|
|
.background(LinearGradient.appPrimaryGradient)
|
|
.clipShape(RoundedRectangle(cornerRadius: 24, style: .continuous))
|
|
.overlay(
|
|
RoundedRectangle(cornerRadius: 24, style: .continuous)
|
|
.stroke(Color.white.opacity(0.2), lineWidth: 1)
|
|
)
|
|
}
|
|
}
|
|
|
|
struct PortfolioValueShareCardView: View {
|
|
let totalValue: String
|
|
let changeText: String
|
|
let changeLabel: String
|
|
let yearChange: String?
|
|
let sinceInceptionChange: String?
|
|
let appName: String
|
|
var qrCodeImage: UIImage? = nil
|
|
|
|
var body: some View {
|
|
VStack(alignment: .leading, spacing: 14) {
|
|
Text("Portfolio Snapshot")
|
|
.font(.caption.weight(.semibold))
|
|
.foregroundColor(.white.opacity(0.85))
|
|
|
|
Text("Total Portfolio Value")
|
|
.font(.headline.weight(.semibold))
|
|
.foregroundColor(.white.opacity(0.9))
|
|
|
|
Text(totalValue)
|
|
.font(.system(size: 34, weight: .bold, design: .rounded))
|
|
.foregroundColor(.white)
|
|
|
|
Text("\(changeText) \(changeLabel)")
|
|
.font(.subheadline.weight(.semibold))
|
|
.foregroundColor(.white.opacity(0.9))
|
|
|
|
if let yearChange {
|
|
metricRow("YoY", yearChange)
|
|
}
|
|
|
|
if let sinceInceptionChange {
|
|
metricRow("Since inception", sinceInceptionChange)
|
|
}
|
|
|
|
Spacer(minLength: 0)
|
|
shareFooter(appName: appName, qrCodeImage: qrCodeImage)
|
|
}
|
|
.padding(20)
|
|
.frame(width: 320, height: 290)
|
|
.background(
|
|
LinearGradient(
|
|
colors: [Color.appSecondary, Color.appPrimary],
|
|
startPoint: .topLeading,
|
|
endPoint: .bottomTrailing
|
|
)
|
|
)
|
|
.clipShape(RoundedRectangle(cornerRadius: 24, style: .continuous))
|
|
.overlay(
|
|
RoundedRectangle(cornerRadius: 24, style: .continuous)
|
|
.stroke(Color.white.opacity(0.2), lineWidth: 1)
|
|
)
|
|
}
|
|
}
|
|
|
|
private func metricRow(_ title: String, _ value: String) -> some View {
|
|
HStack {
|
|
Text(title)
|
|
.font(.caption.weight(.semibold))
|
|
.foregroundColor(.white.opacity(0.8))
|
|
Spacer()
|
|
Text(value)
|
|
.font(.subheadline.weight(.semibold))
|
|
.foregroundColor(.white)
|
|
.multilineTextAlignment(.trailing)
|
|
}
|
|
}
|
|
|
|
private func shareFooter(appName: String, qrCodeImage: UIImage?) -> some View {
|
|
VStack(spacing: 10) {
|
|
Rectangle()
|
|
.fill(Color.white.opacity(0.2))
|
|
.frame(height: 1)
|
|
|
|
HStack(spacing: 12) {
|
|
Image("BrandMark")
|
|
.resizable()
|
|
.aspectRatio(contentMode: .fit)
|
|
.frame(width: 36, height: 36)
|
|
.clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous))
|
|
|
|
VStack(alignment: .leading, spacing: 2) {
|
|
Text("Powered by")
|
|
.font(.caption2.weight(.medium))
|
|
.foregroundColor(.white.opacity(0.7))
|
|
Text(appName)
|
|
.font(.subheadline.weight(.bold))
|
|
.foregroundColor(.white)
|
|
}
|
|
|
|
Spacer()
|
|
|
|
if let qrCodeImage {
|
|
Image(uiImage: qrCodeImage)
|
|
.interpolation(.none)
|
|
.resizable()
|
|
.frame(width: 48, height: 48)
|
|
.background(Color.white)
|
|
.clipShape(RoundedRectangle(cornerRadius: 6, style: .continuous))
|
|
} else {
|
|
Image(systemName: "qrcode")
|
|
.font(.title3)
|
|
.foregroundColor(.white.opacity(0.9))
|
|
}
|
|
}
|
|
}
|
|
}
|