Calendar: fix weekday-header/week-number alignment to firstWeekday + tests
Root cause: a data-integrity bug, not visual. The month grid is built from
.weekOfMonth (respects Calendar.current.firstWeekday), but the weekday header
was hardcoded Sunday-first ("S M T W T F S") and the week-number label was gated
on isSunday (weekday == 1). On any non-Sunday-first locale (or when the user sets
"Start Week On" = Monday) every column was mislabeled by one and the W-number
landed on the wrong column — e.g. June 1 2026 (a Monday) appearing under "S".
Fix:
- Extract pure, testable date math into CalendarGrid (monthGrid + weekdaySymbols).
- Header now derived from firstWeekday, so it always matches the grid.
- Week-number label gated on isWeekStart (weekday == firstWeekday), not Sunday.
- Document that week numbers are locale weekOfYear (consistent with the layout),
not ISO.
- gridDays() and the year-view mini-month dedupe to CalendarGrid.
Verification:
- New KisaniCalTests target with 9 tests, all passing on simulator: exact
Sunday-first June 2026 grid, header↔grid alignment for firstWeekday 1...7,
cell date identity, month navigation (May/Jul/Feb 2026 + Feb 2028 leap +
Dec 2026→Jan 2027), and event-day bucketing (all-day, late-night, midnight-
crossing) across 4 timezones.
- Verified in the running app: header S M T W T F S, May 31 in the Sunday
column, June 1 under Monday, June 24 (Wednesday) selected.
Adds a DEBUG-only KISANI_INITIAL_TAB launch env (compiled out of Release) used
to screenshot the calendar past the sign-in gate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
5EF4A5B6CE91ADA0CCF72D0D /* ProfileSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C96EC00F6B021DBA3CC1A79 /* ProfileSetupView.swift */; };
|
||||
67CE1747E5DB3FDA79D0FDFD /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 106EEF572C6F8990408329F0 /* OnboardingView.swift */; };
|
||||
6921CB73A3257502FF778381 /* SplashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE2D50B4B4AC227BD21F4B60 /* SplashView.swift */; };
|
||||
6BCBF3902E38FBAA7348840D /* CalendarGridTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74FAA2B41FCEBC7E3F156F0F /* CalendarGridTests.swift */; };
|
||||
703E068364256D6F3F867961 /* ISSUES.md in Resources */ = {isa = PBXBuildFile; fileRef = 92824ED40ECD41EFD4F78BEC /* ISSUES.md */; };
|
||||
754D3DE3CEB998E36E585A61 /* LiveActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0506183945D16EC443A69651 /* LiveActivityManager.swift */; };
|
||||
79FC1DF6762C6F02D01AB643 /* KisaniCalWidgets.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 0D6D6740721F01A74E404EB9 /* KisaniCalWidgets.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
@@ -38,6 +39,7 @@
|
||||
9070521B1D36A5551976C275 /* CalendarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADF6CCD95A587E26E30F5712 /* CalendarView.swift */; };
|
||||
9E3F966F6B6AF2E4F8109E51 /* WorkoutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20DAD771EFCC8B3B1DBD4DD6 /* WorkoutView.swift */; };
|
||||
A1DBC4D2F09C02B8CEE6449E /* AddExerciseSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 768D4E314252E2A90A06CCF2 /* AddExerciseSheet.swift */; };
|
||||
A292B0492135BA40F6B6A951 /* CalendarGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FCB2077D9509CB5C0978E58 /* CalendarGrid.swift */; };
|
||||
A3B2D6622A2EE35C8D5A3C9B /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72308FEE0226F45414C04DDD /* SettingsView.swift */; };
|
||||
A9FF93259AE8FF0ABF69D71A /* DesignTokens.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD4A35C0E1270E2E15C03F23 /* DesignTokens.swift */; };
|
||||
AC0D814DA54D5EF5E25CEB99 /* WidgetData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61BFF3BA28331A16D0ADE9D0 /* WidgetData.swift */; };
|
||||
@@ -53,6 +55,13 @@
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
BF401FDD105729FB67DF02D6 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = AF6DE7A812408E3742522E90 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 297C0C2BFBA10AB52D5D49CE;
|
||||
remoteInfo = KisaniCal;
|
||||
};
|
||||
D04FCEE0BDF30AEFD1C969B6 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = AF6DE7A812408E3742522E90 /* Project object */;
|
||||
@@ -83,10 +92,12 @@
|
||||
0513EB8C7F6B6853B9E93E09 /* TaskLiveActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskLiveActivity.swift; sourceTree = "<group>"; };
|
||||
0C96EC00F6B021DBA3CC1A79 /* ProfileSetupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileSetupView.swift; sourceTree = "<group>"; };
|
||||
0D6D6740721F01A74E404EB9 /* KisaniCalWidgets.appex */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "wrapper.app-extension"; path = KisaniCalWidgets.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0FCB2077D9509CB5C0978E58 /* CalendarGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarGrid.swift; sourceTree = "<group>"; };
|
||||
106EEF572C6F8990408329F0 /* OnboardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingView.swift; sourceTree = "<group>"; };
|
||||
1AA7498EFED7692022F3E7E1 /* KisaniCal.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = KisaniCal.entitlements; sourceTree = "<group>"; };
|
||||
208F82348DEBD9FF7B0DCF17 /* MyTasksWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyTasksWidget.swift; sourceTree = "<group>"; };
|
||||
20DAD771EFCC8B3B1DBD4DD6 /* WorkoutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkoutView.swift; sourceTree = "<group>"; };
|
||||
20E29A9264577A89891DAEC1 /* KisaniCalTests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = KisaniCalTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
23A4491BFA50721082024756 /* SharedComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedComponents.swift; sourceTree = "<group>"; };
|
||||
326B77A7B317A7DB44E13EA5 /* ShortcutHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutHandler.swift; sourceTree = "<group>"; };
|
||||
35FF274EFF2361B7F3D2D227 /* WenzaWatch.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WenzaWatch.entitlements; sourceTree = "<group>"; };
|
||||
@@ -100,6 +111,7 @@
|
||||
670A8C6F8243EC973A1BC431 /* TaskContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskContextMenu.swift; sourceTree = "<group>"; };
|
||||
72308FEE0226F45414C04DDD /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
|
||||
72FDF9C8DD37134576356B89 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
74FAA2B41FCEBC7E3F156F0F /* CalendarGridTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarGridTests.swift; sourceTree = "<group>"; };
|
||||
768D4E314252E2A90A06CCF2 /* AddExerciseSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddExerciseSheet.swift; sourceTree = "<group>"; };
|
||||
7A9D47B284FD6A217AEF813B /* WenzaWatch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WenzaWatch.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
89550F2CD19B950CCC6AD37F /* AuthManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthManager.swift; sourceTree = "<group>"; };
|
||||
@@ -128,6 +140,14 @@
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
068B77B2F01C399C7A430292 /* KisaniCalTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
74FAA2B41FCEBC7E3F156F0F /* CalendarGridTests.swift */,
|
||||
);
|
||||
path = KisaniCalTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
21B93C269F283F11B415B18C /* Components */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -140,6 +160,7 @@
|
||||
23CBCF100C5EF55E737379CA /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0FCB2077D9509CB5C0978E58 /* CalendarGrid.swift */,
|
||||
5722CC4B59E3939724142710 /* ExerciseModels.swift */,
|
||||
DCC2AFB4FA765383740767CB /* TaskItem.swift */,
|
||||
);
|
||||
@@ -160,6 +181,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F70DA4746C68CD405435DAB6 /* KisaniCal */,
|
||||
068B77B2F01C399C7A430292 /* KisaniCalTests */,
|
||||
E8D727EEA0C3A4B8006FB087 /* KisaniCalWidgets */,
|
||||
48146B56E740528496663D47 /* WenzaWatch */,
|
||||
51BD1B5DEDE9FAD9CA2FF6DA /* Products */,
|
||||
@@ -170,6 +192,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9BD1F84B4F45B12CB9B9F1B2 /* KisaniCal.app */,
|
||||
20E29A9264577A89891DAEC1 /* KisaniCalTests.xctest */,
|
||||
0D6D6740721F01A74E404EB9 /* KisaniCalWidgets.appex */,
|
||||
7A9D47B284FD6A217AEF813B /* WenzaWatch.app */,
|
||||
);
|
||||
@@ -319,6 +342,24 @@
|
||||
productReference = 7A9D47B284FD6A217AEF813B /* WenzaWatch.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
75535A64153951A3C35F75FC /* KisaniCalTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = A0CF5E0496CC1077B2417541 /* Build configuration list for PBXNativeTarget "KisaniCalTests" */;
|
||||
buildPhases = (
|
||||
474D88E5A3251407875B5C24 /* Sources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
EEF70F5652B35E046A79A5A3 /* PBXTargetDependency */,
|
||||
);
|
||||
name = KisaniCalTests;
|
||||
packageProductDependencies = (
|
||||
);
|
||||
productName = KisaniCalTests;
|
||||
productReference = 20E29A9264577A89891DAEC1 /* KisaniCalTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
@@ -340,6 +381,9 @@
|
||||
DevelopmentTeam = K8BLMMR883;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
75535A64153951A3C35F75FC = {
|
||||
DevelopmentTeam = K8BLMMR883;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = EF1C4F3BDA4AA7E008FC2CDE /* Build configuration list for PBXProject "KisaniCal" */;
|
||||
@@ -357,6 +401,7 @@
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
297C0C2BFBA10AB52D5D49CE /* KisaniCal */,
|
||||
75535A64153951A3C35F75FC /* KisaniCalTests */,
|
||||
28B43516AD88946E21D9BFE0 /* KisaniCalWidgets */,
|
||||
403D989BDC6268361CFFB479 /* WenzaWatch */,
|
||||
);
|
||||
@@ -378,6 +423,14 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
474D88E5A3251407875B5C24 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6BCBF3902E38FBAA7348840D /* CalendarGridTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
6DEFD550940764CA28D993CE /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -394,6 +447,7 @@
|
||||
2CD2313EDC4BFCE6E89C6787 /* AppGroup.swift in Sources */,
|
||||
3B57EA3600AFE975850DF39A /* AuthManager.swift in Sources */,
|
||||
ECEAA5CF7309E5993D12B571 /* AuthView.swift in Sources */,
|
||||
A292B0492135BA40F6B6A951 /* CalendarGrid.swift in Sources */,
|
||||
9070521B1D36A5551976C275 /* CalendarView.swift in Sources */,
|
||||
06CA0F336E64D9F6D56F7472 /* CloudSyncManager.swift in Sources */,
|
||||
13E4B9854F595394FC9D5912 /* ContentView.swift in Sources */,
|
||||
@@ -445,6 +499,11 @@
|
||||
target = 28B43516AD88946E21D9BFE0 /* KisaniCalWidgets */;
|
||||
targetProxy = D04FCEE0BDF30AEFD1C969B6 /* PBXContainerItemProxy */;
|
||||
};
|
||||
EEF70F5652B35E046A79A5A3 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 297C0C2BFBA10AB52D5D49CE /* KisaniCal */;
|
||||
targetProxy = BF401FDD105729FB67DF02D6 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
@@ -481,6 +540,25 @@
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
1092C43DF580318C5090D54B /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.kutesir.KisaniCalTests;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_VERSION = 5.9;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/KisaniCal.app/KisaniCal";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
20E23A89279CC26778E21856 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
@@ -539,6 +617,25 @@
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
4F022C5E53C268A49F093011 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.kutesir.KisaniCalTests;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_VERSION = 5.9;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/KisaniCal.app/KisaniCal";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
B60AA89AB378D4EA773989AA /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
@@ -728,6 +825,15 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Debug;
|
||||
};
|
||||
A0CF5E0496CC1077B2417541 /* Build configuration list for PBXNativeTarget "KisaniCalTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
4F022C5E53C268A49F093011 /* Debug */,
|
||||
1092C43DF580318C5090D54B /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Debug;
|
||||
};
|
||||
B60FDD2C88D1D33CF1EC02B3 /* Build configuration list for PBXNativeTarget "KisaniCal" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
||||
Reference in New Issue
Block a user