Share cards compartibles: brand header grande, fecha, Dark/Light (build 83) #35
- Header de marca arriba, grande (logo BrandMark 48px + nombre title2 rounded), nunca se corta en Story (9:16 real 360x640, Post 4:5 360x450). - Héroe = retorno % (privacy/branding-friendly), valor como apoyo. - Fecha del último check-in bajo el nombre (share_as_of) para dar contexto a quien no conoce la app; DashboardViewModel.shareAsOfDate. - Tema Dark + Light (ShareCardTheme) con selector en el sheet + preview vivo. - Sparkline real (viewModel.evolutionData), ya se pasaba. - CTA de descarga + QR con ct=snapshot_share (atribución App Analytics). - L10n x7 (as_of, theme_dark/light, cta, hero, metrics). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L38583J7AYWCVPevkivscj
This commit is contained in:
@@ -22,15 +22,18 @@ class ShareService {
|
||||
}
|
||||
|
||||
struct PortfolioCardStrings {
|
||||
/// The big number (an all-time/return %) — the hero of the card.
|
||||
let heroPercent: String?
|
||||
/// Supporting absolute value (empty in percent-only mode).
|
||||
let totalValue: String
|
||||
let changeText: String
|
||||
let yearChange: String?
|
||||
let sinceInceptionChange: String?
|
||||
}
|
||||
|
||||
/// Privacy transform: with `percentOnly` the card leads with the all-time
|
||||
/// return and every row drops absolute amounts. Nobody shares their net
|
||||
/// worth in euros; everybody shares +42%.
|
||||
/// The all-time return is always the hero (branding + shareable). With
|
||||
/// `percentOnly` every absolute amount is dropped — nobody posts their net
|
||||
/// worth in euros; everybody posts +42%.
|
||||
static func portfolioCardStrings(
|
||||
totalValue: String,
|
||||
changeText: String,
|
||||
@@ -38,20 +41,22 @@ class ShareService {
|
||||
sinceInceptionChange: String?,
|
||||
percentOnly: Bool
|
||||
) -> PortfolioCardStrings {
|
||||
guard percentOnly else {
|
||||
let hero = percentPart(sinceInceptionChange) ?? percentPart(changeText)
|
||||
if percentOnly {
|
||||
return PortfolioCardStrings(
|
||||
totalValue: totalValue, changeText: changeText,
|
||||
yearChange: yearChange, sinceInceptionChange: sinceInceptionChange
|
||||
heroPercent: hero ?? totalValue,
|
||||
totalValue: "",
|
||||
changeText: percentPart(changeText) ?? changeText,
|
||||
yearChange: percentPart(yearChange),
|
||||
sinceInceptionChange: percentPart(sinceInceptionChange)
|
||||
)
|
||||
}
|
||||
let heroPercent = percentPart(sinceInceptionChange)
|
||||
?? percentPart(changeText)
|
||||
?? totalValue
|
||||
return PortfolioCardStrings(
|
||||
totalValue: heroPercent,
|
||||
changeText: percentPart(changeText) ?? changeText,
|
||||
yearChange: percentPart(yearChange),
|
||||
sinceInceptionChange: percentPart(sinceInceptionChange)
|
||||
heroPercent: hero,
|
||||
totalValue: totalValue,
|
||||
changeText: changeText,
|
||||
yearChange: yearChange,
|
||||
sinceInceptionChange: sinceInceptionChange
|
||||
)
|
||||
}
|
||||
|
||||
@@ -168,6 +173,8 @@ class ShareService {
|
||||
sinceInceptionChange: String?,
|
||||
sparkline: [Double] = [],
|
||||
isPositive: Bool = true,
|
||||
asOf: String? = nil,
|
||||
theme: ShareCardTheme = .dark,
|
||||
percentOnly: Bool = false,
|
||||
storyFormat: Bool = false
|
||||
) {
|
||||
@@ -205,6 +212,9 @@ class ShareService {
|
||||
qrCodeImage: GoalShareService.generateQRCode(for: Self.snapshotShareURL, size: 200),
|
||||
sparkline: sparkline,
|
||||
isPositive: isPositive,
|
||||
heroPercent: display.heroPercent,
|
||||
asOf: asOf,
|
||||
theme: theme,
|
||||
storyFormat: storyFormat
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user