1.4.1 (build 46): fix cambio de Chart Type roto por el cache de snapshots
El fetch del cache dependía del timeRange activo (monthsLimit = timeRange.months), así que al reutilizarlo entre chart types/rangos (optimización del build 45) los charts recibían historia truncada — Year vs Year o "All" con solo 12 meses, charts vacíos o incompletos al cambiar de tipo. Fix: el cache siempre guarda la historia completa (maxHistoryMonths) y el recorte por rango se hace en memoria (el filtro por cutoffDate ya existía justo después). Bonus: hiddenHistoryMonths ahora se calcula contra la ventana completa (teaser más preciso). Verificado en iPad Pro 13" simulador: Evolution 12M → All → Compare → Period vs Period → Evolution, todos renderizan con datos. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015qUZrBusG82T37R7PeokqJ
This commit is contained in:
@@ -459,7 +459,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = PortfolioJournal/PortfolioJournalDebug.entitlements;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 45;
|
||||
CURRENT_PROJECT_VERSION = 46;
|
||||
DEVELOPMENT_ASSET_PATHS = PortfolioJournal/Assets.xcassets;
|
||||
DEVELOPMENT_TEAM = 2825Q76T7H;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -498,7 +498,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = PortfolioJournal/PortfolioJournal.entitlements;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 45;
|
||||
CURRENT_PROJECT_VERSION = 46;
|
||||
DEVELOPMENT_ASSET_PATHS = PortfolioJournal/Assets.xcassets;
|
||||
DEVELOPMENT_TEAM = 2825Q76T7H;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -655,7 +655,7 @@
|
||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||
CODE_SIGN_ENTITLEMENTS = PortfolioJournalWidgetExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 45;
|
||||
CURRENT_PROJECT_VERSION = 46;
|
||||
DEVELOPMENT_ASSET_PATHS = PortfolioJournalWidget/Assets.xcassets;
|
||||
DEVELOPMENT_TEAM = 2825Q76T7H;
|
||||
GENERATE_INFOPLIST_FILE = NO;
|
||||
@@ -688,7 +688,7 @@
|
||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||
CODE_SIGN_ENTITLEMENTS = PortfolioJournalWidgetExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 45;
|
||||
CURRENT_PROJECT_VERSION = 46;
|
||||
DEVELOPMENT_ASSET_PATHS = PortfolioJournalWidget/Assets.xcassets;
|
||||
DEVELOPMENT_TEAM = 2825Q76T7H;
|
||||
GENERATE_INFOPLIST_FILE = NO;
|
||||
@@ -719,7 +719,7 @@
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 45;
|
||||
CURRENT_PROJECT_VERSION = 46;
|
||||
DEVELOPMENT_TEAM = 2825Q76T7H;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.6;
|
||||
@@ -743,7 +743,7 @@
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 45;
|
||||
CURRENT_PROJECT_VERSION = 46;
|
||||
DEVELOPMENT_TEAM = 2825Q76T7H;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.6;
|
||||
@@ -766,7 +766,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 45;
|
||||
CURRENT_PROJECT_VERSION = 46;
|
||||
DEVELOPMENT_TEAM = 2825Q76T7H;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.6;
|
||||
@@ -789,7 +789,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 45;
|
||||
CURRENT_PROJECT_VERSION = 46;
|
||||
DEVELOPMENT_TEAM = 2825Q76T7H;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.6;
|
||||
|
||||
@@ -448,17 +448,19 @@ class ChartsViewModel: ObservableObject {
|
||||
sources = sourceRepository.sources.filter { shouldIncludeSource($0) }
|
||||
}
|
||||
|
||||
let monthsLimit = timeRange.months ?? maxHistoryMonths
|
||||
let sourceIds = sources.compactMap { $0.id }
|
||||
|
||||
// Performance: Reuse cached snapshots when possible
|
||||
// Performance: cache the FULL history once and slice by time range in memory.
|
||||
// The cache is shared across chart types and ranges, so it must never be
|
||||
// fetched with a range-dependent months limit (that truncated Year vs Year
|
||||
// and "All" after visiting a chart with a shorter range).
|
||||
var snapshots: [Snapshot]
|
||||
if let cached = cachedSnapshots {
|
||||
snapshots = cached
|
||||
} else {
|
||||
snapshots = snapshotRepository.fetchSnapshots(
|
||||
for: sourceIds,
|
||||
months: monthsLimit
|
||||
months: maxHistoryMonths
|
||||
)
|
||||
hiddenHistoryMonths = freemiumValidator.hiddenHistoryMonths(in: snapshots)
|
||||
snapshots = freemiumValidator.filterSnapshots(snapshots)
|
||||
|
||||
@@ -151,10 +151,42 @@ final class PortfolioJournalUITests: XCTestCase {
|
||||
}
|
||||
Thread.sleep(forTimeInterval: 3.0)
|
||||
|
||||
let shot = XCTAttachment(screenshot: capture.screenshot())
|
||||
shot.name = "Charts_Redesign"
|
||||
shot.lifetime = .keepAlways
|
||||
add(shot)
|
||||
func snap(_ name: String) {
|
||||
let shot = XCTAttachment(screenshot: capture.screenshot())
|
||||
shot.name = name
|
||||
shot.lifetime = .keepAlways
|
||||
add(shot)
|
||||
}
|
||||
|
||||
snap("01_Evolution_default")
|
||||
|
||||
// Switch period to All (exercises the shared snapshot cache across ranges)
|
||||
let allSegment = capture.buttons["All"].firstMatch
|
||||
if allSegment.waitForExistence(timeout: 3) {
|
||||
allSegment.tap()
|
||||
Thread.sleep(forTimeInterval: 2.0)
|
||||
snap("02_Evolution_All")
|
||||
}
|
||||
|
||||
// Switch chart type to a free multi-control chart and back (cache reuse path)
|
||||
let compareTile = capture.buttons["Compare"].firstMatch
|
||||
if compareTile.waitForExistence(timeout: 3) {
|
||||
compareTile.tap()
|
||||
Thread.sleep(forTimeInterval: 2.0)
|
||||
snap("03_Compare")
|
||||
}
|
||||
let periodTile = capture.buttons["Period vs Period"].firstMatch
|
||||
if periodTile.waitForExistence(timeout: 3) {
|
||||
periodTile.tap()
|
||||
Thread.sleep(forTimeInterval: 2.0)
|
||||
snap("04_PeriodVsPeriod")
|
||||
}
|
||||
let evolutionTile = capture.buttons["Evolution"].firstMatch
|
||||
if evolutionTile.waitForExistence(timeout: 3) {
|
||||
evolutionTile.tap()
|
||||
Thread.sleep(forTimeInterval: 2.0)
|
||||
snap("05_Evolution_back")
|
||||
}
|
||||
}
|
||||
|
||||
/// Captures full-screen screenshots of the main tabs with demo data for App Store
|
||||
|
||||
Reference in New Issue
Block a user