Remove widget extension
Delete KisaniCalWidget target, Shared/WidgetDataStore, WidgetBridge, App Group entitlements, and all syncWidget() calls.
This commit is contained in:
@@ -10,10 +10,7 @@
|
|||||||
096804560A2F0A7D74E64780 /* TaskItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC2AFB4FA765383740767CB /* TaskItem.swift */; };
|
096804560A2F0A7D74E64780 /* TaskItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC2AFB4FA765383740767CB /* TaskItem.swift */; };
|
||||||
13E4B9854F595394FC9D5912 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC5E179A9189B0A8C3F856F6 /* ContentView.swift */; };
|
13E4B9854F595394FC9D5912 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC5E179A9189B0A8C3F856F6 /* ContentView.swift */; };
|
||||||
1A22EE21460821170E44B1DF /* ExerciseModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5722CC4B59E3939724142710 /* ExerciseModels.swift */; };
|
1A22EE21460821170E44B1DF /* ExerciseModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5722CC4B59E3939724142710 /* ExerciseModels.swift */; };
|
||||||
3256F64040E5BBCD30644047 /* WidgetDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3364C849866EAAA5FEB46A1 /* WidgetDataStore.swift */; };
|
|
||||||
3C793FD5DA00D3E9C0D51FEC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 72FDF9C8DD37134576356B89 /* Assets.xcassets */; };
|
3C793FD5DA00D3E9C0D51FEC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 72FDF9C8DD37134576356B89 /* Assets.xcassets */; };
|
||||||
46D78859DD34FDE6172F213D /* KisaniCalWidget.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 363924D4E7E82486E23C1C57 /* KisaniCalWidget.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
|
||||||
4F829CF0B3BD04CD2EAB8C73 /* WidgetBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8934E4F21B90C9650F71D0A2 /* WidgetBridge.swift */; };
|
|
||||||
67CE1747E5DB3FDA79D0FDFD /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 106EEF572C6F8990408329F0 /* OnboardingView.swift */; };
|
67CE1747E5DB3FDA79D0FDFD /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 106EEF572C6F8990408329F0 /* OnboardingView.swift */; };
|
||||||
6921CB73A3257502FF778381 /* SplashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE2D50B4B4AC227BD21F4B60 /* SplashView.swift */; };
|
6921CB73A3257502FF778381 /* SplashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE2D50B4B4AC227BD21F4B60 /* SplashView.swift */; };
|
||||||
7CEBC340BFA9238D121946AC /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 57714B79AFFF60DA90EB86E3 /* Preview Assets.xcassets */; };
|
7CEBC340BFA9238D121946AC /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 57714B79AFFF60DA90EB86E3 /* Preview Assets.xcassets */; };
|
||||||
@@ -24,57 +21,25 @@
|
|||||||
A3B2D6622A2EE35C8D5A3C9B /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72308FEE0226F45414C04DDD /* SettingsView.swift */; };
|
A3B2D6622A2EE35C8D5A3C9B /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72308FEE0226F45414C04DDD /* SettingsView.swift */; };
|
||||||
A9FF93259AE8FF0ABF69D71A /* DesignTokens.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD4A35C0E1270E2E15C03F23 /* DesignTokens.swift */; };
|
A9FF93259AE8FF0ABF69D71A /* DesignTokens.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD4A35C0E1270E2E15C03F23 /* DesignTokens.swift */; };
|
||||||
BEAFF968632A34C70B11C5AC /* MatrixView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D44530A77DF12A17E52AAF34 /* MatrixView.swift */; };
|
BEAFF968632A34C70B11C5AC /* MatrixView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D44530A77DF12A17E52AAF34 /* MatrixView.swift */; };
|
||||||
C1B3FC29820FCAF069D2C6FE /* KisaniCalWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C519927190A5CDB3CD4A8 /* KisaniCalWidget.swift */; };
|
|
||||||
C79C33BE2802E81AA00175CC /* TodayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C786EBC7DF879D64EB28165E /* TodayView.swift */; };
|
C79C33BE2802E81AA00175CC /* TodayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C786EBC7DF879D64EB28165E /* TodayView.swift */; };
|
||||||
CBE7295BF5ADE08FE93AFAAF /* FloatingTabState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9100804DB1E61EA882CC54DA /* FloatingTabState.swift */; };
|
CBE7295BF5ADE08FE93AFAAF /* FloatingTabState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9100804DB1E61EA882CC54DA /* FloatingTabState.swift */; };
|
||||||
CF130E143FC6FFE2FE853FB6 /* WidgetDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3364C849866EAAA5FEB46A1 /* WidgetDataStore.swift */; };
|
|
||||||
D591A72235A53D4038FBC2B4 /* KisaniCalApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 001F67ADC72FBAEC03EB7E01 /* KisaniCalApp.swift */; };
|
D591A72235A53D4038FBC2B4 /* KisaniCalApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 001F67ADC72FBAEC03EB7E01 /* KisaniCalApp.swift */; };
|
||||||
EF03EC9F974B14D100DD5528 /* NotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93D045FE3DEB1D22D908A29F /* NotificationManager.swift */; };
|
EF03EC9F974B14D100DD5528 /* NotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93D045FE3DEB1D22D908A29F /* NotificationManager.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
|
||||||
D4A1B57264F223C8871E1BC9 /* PBXContainerItemProxy */ = {
|
|
||||||
isa = PBXContainerItemProxy;
|
|
||||||
containerPortal = AF6DE7A812408E3742522E90 /* Project object */;
|
|
||||||
proxyType = 1;
|
|
||||||
remoteGlobalIDString = 532C52E96C1EE1E30A7E9157;
|
|
||||||
remoteInfo = KisaniCalWidget;
|
|
||||||
};
|
|
||||||
/* End PBXContainerItemProxy section */
|
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
|
||||||
B3BE3000B362E4DDC4EE9E76 /* Embed Foundation Extensions */ = {
|
|
||||||
isa = PBXCopyFilesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
dstPath = "";
|
|
||||||
dstSubfolderSpec = 13;
|
|
||||||
files = (
|
|
||||||
46D78859DD34FDE6172F213D /* KisaniCalWidget.appex in Embed Foundation Extensions */,
|
|
||||||
);
|
|
||||||
name = "Embed Foundation Extensions";
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXCopyFilesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
001F67ADC72FBAEC03EB7E01 /* KisaniCalApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KisaniCalApp.swift; sourceTree = "<group>"; };
|
001F67ADC72FBAEC03EB7E01 /* KisaniCalApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KisaniCalApp.swift; sourceTree = "<group>"; };
|
||||||
106EEF572C6F8990408329F0 /* OnboardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingView.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>"; };
|
|
||||||
20DAD771EFCC8B3B1DBD4DD6 /* WorkoutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkoutView.swift; sourceTree = "<group>"; };
|
20DAD771EFCC8B3B1DBD4DD6 /* WorkoutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkoutView.swift; sourceTree = "<group>"; };
|
||||||
23A4491BFA50721082024756 /* SharedComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedComponents.swift; sourceTree = "<group>"; };
|
23A4491BFA50721082024756 /* SharedComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedComponents.swift; sourceTree = "<group>"; };
|
||||||
363924D4E7E82486E23C1C57 /* KisaniCalWidget.appex */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "wrapper.app-extension"; path = KisaniCalWidget.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
5722CC4B59E3939724142710 /* ExerciseModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExerciseModels.swift; sourceTree = "<group>"; };
|
5722CC4B59E3939724142710 /* ExerciseModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExerciseModels.swift; sourceTree = "<group>"; };
|
||||||
57714B79AFFF60DA90EB86E3 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
57714B79AFFF60DA90EB86E3 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
||||||
72308FEE0226F45414C04DDD /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.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>"; };
|
72FDF9C8DD37134576356B89 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
74EE7C2E74094E3E27FD78E4 /* KisaniCalWidget.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = KisaniCalWidget.entitlements; sourceTree = "<group>"; };
|
|
||||||
768D4E314252E2A90A06CCF2 /* AddExerciseSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddExerciseSheet.swift; sourceTree = "<group>"; };
|
768D4E314252E2A90A06CCF2 /* AddExerciseSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddExerciseSheet.swift; sourceTree = "<group>"; };
|
||||||
825C519927190A5CDB3CD4A8 /* KisaniCalWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KisaniCalWidget.swift; sourceTree = "<group>"; };
|
|
||||||
8934E4F21B90C9650F71D0A2 /* WidgetBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetBridge.swift; sourceTree = "<group>"; };
|
|
||||||
9100804DB1E61EA882CC54DA /* FloatingTabState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingTabState.swift; sourceTree = "<group>"; };
|
9100804DB1E61EA882CC54DA /* FloatingTabState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingTabState.swift; sourceTree = "<group>"; };
|
||||||
93D045FE3DEB1D22D908A29F /* NotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationManager.swift; sourceTree = "<group>"; };
|
93D045FE3DEB1D22D908A29F /* NotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationManager.swift; sourceTree = "<group>"; };
|
||||||
9BD1F84B4F45B12CB9B9F1B2 /* KisaniCal.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = KisaniCal.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
9BD1F84B4F45B12CB9B9F1B2 /* KisaniCal.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = KisaniCal.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
A3364C849866EAAA5FEB46A1 /* WidgetDataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetDataStore.swift; sourceTree = "<group>"; };
|
|
||||||
ADF6CCD95A587E26E30F5712 /* CalendarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarView.swift; sourceTree = "<group>"; };
|
ADF6CCD95A587E26E30F5712 /* CalendarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarView.swift; sourceTree = "<group>"; };
|
||||||
BC5E179A9189B0A8C3F856F6 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
BC5E179A9189B0A8C3F856F6 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||||
BD4A35C0E1270E2E15C03F23 /* DesignTokens.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DesignTokens.swift; sourceTree = "<group>"; };
|
BD4A35C0E1270E2E15C03F23 /* DesignTokens.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DesignTokens.swift; sourceTree = "<group>"; };
|
||||||
@@ -85,15 +50,6 @@
|
|||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
10E8E769F7D262FF425B460B /* KisaniCalWidget */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
74EE7C2E74094E3E27FD78E4 /* KisaniCalWidget.entitlements */,
|
|
||||||
825C519927190A5CDB3CD4A8 /* KisaniCalWidget.swift */,
|
|
||||||
);
|
|
||||||
path = KisaniCalWidget;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
21B93C269F283F11B415B18C /* Components */ = {
|
21B93C269F283F11B415B18C /* Components */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -103,14 +59,6 @@
|
|||||||
path = Components;
|
path = Components;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
2217B7EEC45957B820311EC7 /* Shared */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
A3364C849866EAAA5FEB46A1 /* WidgetDataStore.swift */,
|
|
||||||
);
|
|
||||||
path = Shared;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
23CBCF100C5EF55E737379CA /* Models */ = {
|
23CBCF100C5EF55E737379CA /* Models */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -124,8 +72,6 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
F70DA4746C68CD405435DAB6 /* KisaniCal */,
|
F70DA4746C68CD405435DAB6 /* KisaniCal */,
|
||||||
10E8E769F7D262FF425B460B /* KisaniCalWidget */,
|
|
||||||
2217B7EEC45957B820311EC7 /* Shared */,
|
|
||||||
51BD1B5DEDE9FAD9CA2FF6DA /* Products */,
|
51BD1B5DEDE9FAD9CA2FF6DA /* Products */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -134,7 +80,6 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
9BD1F84B4F45B12CB9B9F1B2 /* KisaniCal.app */,
|
9BD1F84B4F45B12CB9B9F1B2 /* KisaniCal.app */,
|
||||||
363924D4E7E82486E23C1C57 /* KisaniCalWidget.appex */,
|
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -175,9 +120,7 @@
|
|||||||
children = (
|
children = (
|
||||||
72FDF9C8DD37134576356B89 /* Assets.xcassets */,
|
72FDF9C8DD37134576356B89 /* Assets.xcassets */,
|
||||||
BC5E179A9189B0A8C3F856F6 /* ContentView.swift */,
|
BC5E179A9189B0A8C3F856F6 /* ContentView.swift */,
|
||||||
1AA7498EFED7692022F3E7E1 /* KisaniCal.entitlements */,
|
|
||||||
001F67ADC72FBAEC03EB7E01 /* KisaniCalApp.swift */,
|
001F67ADC72FBAEC03EB7E01 /* KisaniCalApp.swift */,
|
||||||
8934E4F21B90C9650F71D0A2 /* WidgetBridge.swift */,
|
|
||||||
21B93C269F283F11B415B18C /* Components */,
|
21B93C269F283F11B415B18C /* Components */,
|
||||||
FB9BF734B9E493EEB09ACE21 /* Managers */,
|
FB9BF734B9E493EEB09ACE21 /* Managers */,
|
||||||
23CBCF100C5EF55E737379CA /* Models */,
|
23CBCF100C5EF55E737379CA /* Models */,
|
||||||
@@ -205,12 +148,10 @@
|
|||||||
buildPhases = (
|
buildPhases = (
|
||||||
82EA49FE155821D424C46912 /* Sources */,
|
82EA49FE155821D424C46912 /* Sources */,
|
||||||
E1F1A3EE4469B851B972E4AE /* Resources */,
|
E1F1A3EE4469B851B972E4AE /* Resources */,
|
||||||
B3BE3000B362E4DDC4EE9E76 /* Embed Foundation Extensions */,
|
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
3FA0FA885B1A4FC539D57049 /* PBXTargetDependency */,
|
|
||||||
);
|
);
|
||||||
name = KisaniCal;
|
name = KisaniCal;
|
||||||
packageProductDependencies = (
|
packageProductDependencies = (
|
||||||
@@ -219,23 +160,6 @@
|
|||||||
productReference = 9BD1F84B4F45B12CB9B9F1B2 /* KisaniCal.app */;
|
productReference = 9BD1F84B4F45B12CB9B9F1B2 /* KisaniCal.app */;
|
||||||
productType = "com.apple.product-type.application";
|
productType = "com.apple.product-type.application";
|
||||||
};
|
};
|
||||||
532C52E96C1EE1E30A7E9157 /* KisaniCalWidget */ = {
|
|
||||||
isa = PBXNativeTarget;
|
|
||||||
buildConfigurationList = 6B8469B838ACDD00336D1CAD /* Build configuration list for PBXNativeTarget "KisaniCalWidget" */;
|
|
||||||
buildPhases = (
|
|
||||||
B3D66A55B74C7B9AE6099149 /* Sources */,
|
|
||||||
);
|
|
||||||
buildRules = (
|
|
||||||
);
|
|
||||||
dependencies = (
|
|
||||||
);
|
|
||||||
name = KisaniCalWidget;
|
|
||||||
packageProductDependencies = (
|
|
||||||
);
|
|
||||||
productName = KisaniCalWidget;
|
|
||||||
productReference = 363924D4E7E82486E23C1C57 /* KisaniCalWidget.appex */;
|
|
||||||
productType = "com.apple.product-type.app-extension";
|
|
||||||
};
|
|
||||||
/* End PBXNativeTarget section */
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
/* Begin PBXProject section */
|
/* Begin PBXProject section */
|
||||||
@@ -248,9 +172,6 @@
|
|||||||
297C0C2BFBA10AB52D5D49CE = {
|
297C0C2BFBA10AB52D5D49CE = {
|
||||||
ProvisioningStyle = Automatic;
|
ProvisioningStyle = Automatic;
|
||||||
};
|
};
|
||||||
532C52E96C1EE1E30A7E9157 = {
|
|
||||||
ProvisioningStyle = Automatic;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
buildConfigurationList = EF1C4F3BDA4AA7E008FC2CDE /* Build configuration list for PBXProject "KisaniCal" */;
|
buildConfigurationList = EF1C4F3BDA4AA7E008FC2CDE /* Build configuration list for PBXProject "KisaniCal" */;
|
||||||
@@ -268,7 +189,6 @@
|
|||||||
projectRoot = "";
|
projectRoot = "";
|
||||||
targets = (
|
targets = (
|
||||||
297C0C2BFBA10AB52D5D49CE /* KisaniCal */,
|
297C0C2BFBA10AB52D5D49CE /* KisaniCal */,
|
||||||
532C52E96C1EE1E30A7E9157 /* KisaniCalWidget */,
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
@@ -305,38 +225,18 @@
|
|||||||
6921CB73A3257502FF778381 /* SplashView.swift in Sources */,
|
6921CB73A3257502FF778381 /* SplashView.swift in Sources */,
|
||||||
096804560A2F0A7D74E64780 /* TaskItem.swift in Sources */,
|
096804560A2F0A7D74E64780 /* TaskItem.swift in Sources */,
|
||||||
C79C33BE2802E81AA00175CC /* TodayView.swift in Sources */,
|
C79C33BE2802E81AA00175CC /* TodayView.swift in Sources */,
|
||||||
4F829CF0B3BD04CD2EAB8C73 /* WidgetBridge.swift in Sources */,
|
|
||||||
3256F64040E5BBCD30644047 /* WidgetDataStore.swift in Sources */,
|
|
||||||
9E3F966F6B6AF2E4F8109E51 /* WorkoutView.swift in Sources */,
|
9E3F966F6B6AF2E4F8109E51 /* WorkoutView.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
B3D66A55B74C7B9AE6099149 /* Sources */ = {
|
|
||||||
isa = PBXSourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
C1B3FC29820FCAF069D2C6FE /* KisaniCalWidget.swift in Sources */,
|
|
||||||
CF130E143FC6FFE2FE853FB6 /* WidgetDataStore.swift in Sources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXSourcesBuildPhase section */
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXTargetDependency section */
|
|
||||||
3FA0FA885B1A4FC539D57049 /* PBXTargetDependency */ = {
|
|
||||||
isa = PBXTargetDependency;
|
|
||||||
target = 532C52E96C1EE1E30A7E9157 /* KisaniCalWidget */;
|
|
||||||
targetProxy = D4A1B57264F223C8871E1BC9 /* PBXContainerItemProxy */;
|
|
||||||
};
|
|
||||||
/* End PBXTargetDependency section */
|
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
/* Begin XCBuildConfiguration section */
|
||||||
0CEA6637F45C32A237FBA20D /* Release */ = {
|
0CEA6637F45C32A237FBA20D /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_ENTITLEMENTS = KisaniCal/KisaniCal.entitlements;
|
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@@ -417,40 +317,6 @@
|
|||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
47C8DA15444717168992CD67 /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
CODE_SIGN_ENTITLEMENTS = KisaniCalWidget/KisaniCalWidget.entitlements;
|
|
||||||
CODE_SIGN_STYLE = Automatic;
|
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
|
||||||
INFOPLIST_KEY_NSExtensionPointIdentifier = "com.apple.widgetkit-extension";
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.kutesir.KisaniCal.widget;
|
|
||||||
SDKROOT = iphoneos;
|
|
||||||
SKIP_INSTALL = YES;
|
|
||||||
SWIFT_VERSION = 5.9;
|
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
9F668AA275094D23AACA2F61 /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
CODE_SIGN_ENTITLEMENTS = KisaniCalWidget/KisaniCalWidget.entitlements;
|
|
||||||
CODE_SIGN_STYLE = Automatic;
|
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
|
||||||
INFOPLIST_KEY_NSExtensionPointIdentifier = "com.apple.widgetkit-extension";
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.kutesir.KisaniCal.widget;
|
|
||||||
SDKROOT = iphoneos;
|
|
||||||
SKIP_INSTALL = YES;
|
|
||||||
SWIFT_VERSION = 5.9;
|
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
BD527AA54887489CC665FB9D /* Debug */ = {
|
BD527AA54887489CC665FB9D /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
@@ -519,7 +385,6 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_ENTITLEMENTS = KisaniCal/KisaniCal.entitlements;
|
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@@ -547,15 +412,6 @@
|
|||||||
/* End XCBuildConfiguration section */
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
/* Begin XCConfigurationList section */
|
||||||
6B8469B838ACDD00336D1CAD /* Build configuration list for PBXNativeTarget "KisaniCalWidget" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
47C8DA15444717168992CD67 /* Debug */,
|
|
||||||
9F668AA275094D23AACA2F61 /* Release */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Debug;
|
|
||||||
};
|
|
||||||
B60FDD2C88D1D33CF1EC02B3 /* Build configuration list for PBXNativeTarget "KisaniCal" */ = {
|
B60FDD2C88D1D33CF1EC02B3 /* Build configuration list for PBXNativeTarget "KisaniCal" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
|
|||||||
@@ -2,9 +2,7 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
|
||||||
<array>
|
<true/>
|
||||||
<string>group.com.kutesir.KisaniCal</string>
|
|
||||||
</array>
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
Binary file not shown.
@@ -76,18 +76,14 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
if !hasOnboarded { showOnboarding = true }
|
if !hasOnboarded { showOnboarding = true }
|
||||||
taskVM.syncWidget()
|
NotificationManager.shared.reschedule(workoutVM: workoutVM, taskVM: taskVM)
|
||||||
workoutVM.syncWidget()
|
|
||||||
}
|
}
|
||||||
.onChange(of: scenePhase) { phase in
|
.onChange(of: scenePhase) { phase in
|
||||||
if phase == .active {
|
if phase == .active {
|
||||||
NotificationManager.shared.reschedule(workoutVM: workoutVM, taskVM: taskVM)
|
NotificationManager.shared.reschedule(workoutVM: workoutVM, taskVM: taskVM)
|
||||||
taskVM.syncWidget()
|
|
||||||
workoutVM.syncWidget()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: taskVM.tasks) { _ in
|
.onChange(of: taskVM.tasks) { _ in
|
||||||
taskVM.syncWidget()
|
|
||||||
NotificationManager.shared.reschedule(workoutVM: workoutVM, taskVM: taskVM)
|
NotificationManager.shared.reschedule(workoutVM: workoutVM, taskVM: taskVM)
|
||||||
}
|
}
|
||||||
.onChange(of: workoutVM.doneSets) { _ in
|
.onChange(of: workoutVM.doneSets) { _ in
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
import WidgetKit
|
|
||||||
|
|
||||||
// Syncs app ViewModels into App Group UserDefaults so the widget can read them,
|
|
||||||
// then asks WidgetKit to reload all timelines.
|
|
||||||
|
|
||||||
extension TaskViewModel {
|
|
||||||
func syncWidget() {
|
|
||||||
let cal = Calendar.current
|
|
||||||
let start = cal.startOfDay(for: Date())
|
|
||||||
let end = cal.date(byAdding: .day, value: 1, to: start)!
|
|
||||||
|
|
||||||
let entries = tasks
|
|
||||||
.filter { !$0.isComplete }
|
|
||||||
.prefix(10)
|
|
||||||
.map { t in
|
|
||||||
WidgetDataStore.WidgetTask(
|
|
||||||
id: t.id,
|
|
||||||
title: t.title,
|
|
||||||
dueDate: t.dueDate,
|
|
||||||
isToday: t.dueDate.map { $0 >= start && $0 < end } ?? false,
|
|
||||||
isOverdue: t.dueDate.map { $0 < start } ?? false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
WidgetDataStore.saveTasks(Array(entries))
|
|
||||||
WidgetCenter.shared.reloadAllTimelines()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension WorkoutViewModel {
|
|
||||||
func syncWidget() {
|
|
||||||
let weekday = Calendar.current.component(.weekday, from: Date())
|
|
||||||
let todayProgram = program(for: Date())
|
|
||||||
let workout = WidgetDataStore.WidgetWorkout(
|
|
||||||
name: activeProgram?.name ?? "Workout",
|
|
||||||
sectionsCount: activeProgram?.sections.count ?? 0,
|
|
||||||
hasWorkoutToday: todayProgram != nil
|
|
||||||
)
|
|
||||||
WidgetDataStore.saveWorkout(workout)
|
|
||||||
WidgetCenter.shared.reloadAllTimelines()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>com.apple.security.application-groups</key>
|
|
||||||
<array>
|
|
||||||
<string>group.com.kutesir.KisaniCal</string>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,414 +0,0 @@
|
|||||||
import WidgetKit
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
// MARK: - Colors (no UIKit dependency)
|
|
||||||
|
|
||||||
private enum WC {
|
|
||||||
static let accent = Color(red: 232/255, green: 98/255, blue: 42/255)
|
|
||||||
static let green = Color(red: 62/255, green: 207/255, blue: 142/255)
|
|
||||||
static let blue = Color(red: 77/255, green: 157/255, blue: 224/255)
|
|
||||||
|
|
||||||
static func bg(_ s: ColorScheme) -> Color {
|
|
||||||
s == .dark ? Color(red: 9/255, green: 9/255, blue: 9/255)
|
|
||||||
: Color(red: 245/255, green: 243/255, blue: 240/255)
|
|
||||||
}
|
|
||||||
static func surface(_ s: ColorScheme) -> Color {
|
|
||||||
s == .dark ? Color(red: 19/255, green: 19/255, blue: 19/255)
|
|
||||||
: Color(red: 255/255, green: 253/255, blue: 250/255)
|
|
||||||
}
|
|
||||||
static func text(_ s: ColorScheme) -> Color {
|
|
||||||
s == .dark ? Color(red: 240/255, green: 237/255, blue: 232/255)
|
|
||||||
: Color(red: 26/255, green: 23/255, blue: 20/255)
|
|
||||||
}
|
|
||||||
static func text2(_ s: ColorScheme) -> Color { text(s).opacity(0.48) }
|
|
||||||
static func text3(_ s: ColorScheme) -> Color { text(s).opacity(0.30) }
|
|
||||||
static func border(_ s: ColorScheme) -> Color {
|
|
||||||
s == .dark ? Color.white.opacity(0.07) : Color.black.opacity(0.09)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Timeline Entry
|
|
||||||
|
|
||||||
struct KisaniEntry: TimelineEntry {
|
|
||||||
let date: Date
|
|
||||||
let todayTasks: [WidgetDataStore.WidgetTask]
|
|
||||||
let overdueTasks: [WidgetDataStore.WidgetTask]
|
|
||||||
let workout: WidgetDataStore.WidgetWorkout?
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Provider
|
|
||||||
|
|
||||||
struct KisaniProvider: TimelineProvider {
|
|
||||||
func placeholder(in context: Context) -> KisaniEntry {
|
|
||||||
KisaniEntry(
|
|
||||||
date: Date(),
|
|
||||||
todayTasks: previewTasks,
|
|
||||||
overdueTasks: [],
|
|
||||||
workout: WidgetDataStore.WidgetWorkout(
|
|
||||||
name: "Shoulders & Arms", sectionsCount: 4, hasWorkoutToday: true)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSnapshot(in context: Context, completion: @escaping (KisaniEntry) -> Void) {
|
|
||||||
completion(entry())
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTimeline(in context: Context, completion: @escaping (Timeline<KisaniEntry>) -> Void) {
|
|
||||||
let next = Calendar.current.date(byAdding: .minute, value: 30, to: Date())!
|
|
||||||
completion(Timeline(entries: [entry()], policy: .after(next)))
|
|
||||||
}
|
|
||||||
|
|
||||||
private func entry() -> KisaniEntry {
|
|
||||||
let all = WidgetDataStore.loadTasks()
|
|
||||||
let today = all.filter { $0.isToday }
|
|
||||||
let overdue = all.filter { $0.isOverdue }
|
|
||||||
let workout = WidgetDataStore.loadWorkout()
|
|
||||||
return KisaniEntry(date: Date(), todayTasks: today, overdueTasks: overdue, workout: workout)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var previewTasks: [WidgetDataStore.WidgetTask] {
|
|
||||||
[
|
|
||||||
.init(id: UUID(), title: "Azure exam prep", dueDate: Date(), isToday: true, isOverdue: false),
|
|
||||||
.init(id: UUID(), title: "Push AWS project", dueDate: Date(), isToday: true, isOverdue: false),
|
|
||||||
.init(id: UUID(), title: "Review PR #42", dueDate: Date(), isToday: false, isOverdue: true),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Widget Bundle
|
|
||||||
|
|
||||||
@main
|
|
||||||
struct KisaniCalWidgetBundle: WidgetBundle {
|
|
||||||
var body: some Widget {
|
|
||||||
KisaniCalWidget()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct KisaniCalWidget: Widget {
|
|
||||||
let kind = "KisaniCalWidget"
|
|
||||||
|
|
||||||
var body: some WidgetConfiguration {
|
|
||||||
StaticConfiguration(kind: kind, provider: KisaniProvider()) { entry in
|
|
||||||
KisaniWidgetView(entry: entry)
|
|
||||||
.containerBackground(for: .widget) { Color.clear }
|
|
||||||
}
|
|
||||||
.configurationDisplayName("Kisani Cal")
|
|
||||||
.description("Today's tasks and workout at a glance.")
|
|
||||||
.supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Root Widget View
|
|
||||||
|
|
||||||
struct KisaniWidgetView: View {
|
|
||||||
@Environment(\.widgetFamily) private var family
|
|
||||||
let entry: KisaniEntry
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
switch family {
|
|
||||||
case .systemSmall: SmallWidget(entry: entry)
|
|
||||||
case .systemMedium: MediumWidget(entry: entry)
|
|
||||||
default: LargeWidget(entry: entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Shared Sub-Views
|
|
||||||
|
|
||||||
private struct DateBadge: View {
|
|
||||||
@Environment(\.colorScheme) private var cs
|
|
||||||
let size: CGFloat
|
|
||||||
|
|
||||||
private static let monthFmt: DateFormatter = {
|
|
||||||
let f = DateFormatter(); f.dateFormat = "MMM"; return f
|
|
||||||
}()
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
let day = Calendar.current.component(.day, from: Date())
|
|
||||||
VStack(spacing: 0) {
|
|
||||||
Text(Self.monthFmt.string(from: Date()).uppercased())
|
|
||||||
.font(.system(size: size * 0.18, weight: .bold, design: .monospaced))
|
|
||||||
.foregroundColor(.white)
|
|
||||||
.kerning(1)
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
.frame(height: size * 0.32)
|
|
||||||
.background(WC.accent)
|
|
||||||
Text("\(day)")
|
|
||||||
.font(.system(size: size * 0.48, weight: .bold, design: .monospaced))
|
|
||||||
.foregroundColor(WC.text(cs))
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
.frame(height: size * 0.68)
|
|
||||||
.background(WC.surface(cs))
|
|
||||||
}
|
|
||||||
.frame(width: size, height: size)
|
|
||||||
.clipShape(RoundedRectangle(cornerRadius: size * 0.22))
|
|
||||||
.overlay(
|
|
||||||
RoundedRectangle(cornerRadius: size * 0.22)
|
|
||||||
.stroke(WC.border(cs), lineWidth: 1)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct TaskRow: View {
|
|
||||||
@Environment(\.colorScheme) private var cs
|
|
||||||
let task: WidgetDataStore.WidgetTask
|
|
||||||
|
|
||||||
private static let fmt: DateFormatter = {
|
|
||||||
let f = DateFormatter(); f.dateFormat = "d MMM"; return f
|
|
||||||
}()
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
HStack(spacing: 5) {
|
|
||||||
Circle()
|
|
||||||
.stroke(task.isOverdue ? WC.accent : WC.text3(cs), lineWidth: 1.2)
|
|
||||||
.frame(width: 7, height: 7)
|
|
||||||
Text(task.title)
|
|
||||||
.font(.system(size: 11, weight: .regular, design: .default))
|
|
||||||
.foregroundColor(WC.text(cs))
|
|
||||||
.lineLimit(1)
|
|
||||||
Spacer(minLength: 0)
|
|
||||||
if let d = task.dueDate {
|
|
||||||
Text(task.isOverdue ? "Overdue" : Self.fmt.string(from: d))
|
|
||||||
.font(.system(size: 9, weight: .regular, design: .monospaced))
|
|
||||||
.foregroundColor(task.isOverdue ? WC.accent : WC.text3(cs))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct WorkoutRow: View {
|
|
||||||
@Environment(\.colorScheme) private var cs
|
|
||||||
let workout: WidgetDataStore.WidgetWorkout
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
HStack(spacing: 6) {
|
|
||||||
WorkoutSegBar(count: workout.sectionsCount)
|
|
||||||
.frame(width: 22, height: 22)
|
|
||||||
Text(workout.name)
|
|
||||||
.font(.system(size: 11, weight: .semibold, design: .default))
|
|
||||||
.foregroundColor(WC.text(cs))
|
|
||||||
.lineLimit(1)
|
|
||||||
Spacer(minLength: 0)
|
|
||||||
Text("Workout")
|
|
||||||
.font(.system(size: 9, weight: .regular, design: .monospaced))
|
|
||||||
.foregroundColor(WC.blue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct WorkoutSegBar: View {
|
|
||||||
@Environment(\.colorScheme) private var cs
|
|
||||||
let count: Int
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
let n = max(1, min(6, count))
|
|
||||||
VStack(spacing: 1.5) {
|
|
||||||
ForEach(0..<n, id: \.self) { _ in
|
|
||||||
RoundedRectangle(cornerRadius: 1)
|
|
||||||
.fill(WC.blue)
|
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.padding(4)
|
|
||||||
.background(WC.blue.opacity(0.12))
|
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 6))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Small Widget
|
|
||||||
|
|
||||||
private struct SmallWidget: View {
|
|
||||||
@Environment(\.colorScheme) private var cs
|
|
||||||
let entry: KisaniEntry
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
ZStack {
|
|
||||||
WC.bg(cs).ignoresSafeArea()
|
|
||||||
|
|
||||||
VStack(spacing: 10) {
|
|
||||||
DateBadge(size: 72)
|
|
||||||
|
|
||||||
VStack(spacing: 2) {
|
|
||||||
HStack(spacing: 0) {
|
|
||||||
Text("kisani")
|
|
||||||
.font(.system(size: 11, weight: .regular, design: .monospaced))
|
|
||||||
.foregroundColor(WC.text2(cs))
|
|
||||||
Text("CAL")
|
|
||||||
.font(.system(size: 11, weight: .bold, design: .monospaced))
|
|
||||||
.foregroundColor(WC.text(cs))
|
|
||||||
Text(".")
|
|
||||||
.font(.system(size: 11, weight: .bold, design: .monospaced))
|
|
||||||
.foregroundColor(WC.accent)
|
|
||||||
}
|
|
||||||
|
|
||||||
let todayCount = entry.todayTasks.count
|
|
||||||
let overdueCount = entry.overdueTasks.count
|
|
||||||
Group {
|
|
||||||
if overdueCount > 0 {
|
|
||||||
Text("\(overdueCount) overdue · \(todayCount) today")
|
|
||||||
.foregroundColor(WC.accent)
|
|
||||||
} else if todayCount > 0 {
|
|
||||||
Text("\(todayCount) task\(todayCount == 1 ? "" : "s") today")
|
|
||||||
.foregroundColor(WC.text2(cs))
|
|
||||||
} else {
|
|
||||||
Text("All clear")
|
|
||||||
.foregroundColor(WC.text3(cs))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.font(.system(size: 9, weight: .regular, design: .monospaced))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.padding(14)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Medium Widget
|
|
||||||
|
|
||||||
private struct MediumWidget: View {
|
|
||||||
@Environment(\.colorScheme) private var cs
|
|
||||||
let entry: KisaniEntry
|
|
||||||
|
|
||||||
private var displayTasks: [WidgetDataStore.WidgetTask] {
|
|
||||||
let all = entry.overdueTasks + entry.todayTasks
|
|
||||||
return Array(all.prefix(3))
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
ZStack {
|
|
||||||
WC.bg(cs).ignoresSafeArea()
|
|
||||||
|
|
||||||
HStack(alignment: .top, spacing: 14) {
|
|
||||||
// Left: badge + brand
|
|
||||||
VStack(spacing: 8) {
|
|
||||||
DateBadge(size: 64)
|
|
||||||
HStack(spacing: 0) {
|
|
||||||
Text("kisani")
|
|
||||||
.font(.system(size: 9, weight: .regular, design: .monospaced))
|
|
||||||
.foregroundColor(WC.text2(cs))
|
|
||||||
Text("CAL.")
|
|
||||||
.font(.system(size: 9, weight: .bold, design: .monospaced))
|
|
||||||
.foregroundColor(WC.accent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Right: tasks + workout
|
|
||||||
VStack(alignment: .leading, spacing: 5) {
|
|
||||||
if displayTasks.isEmpty && entry.workout == nil {
|
|
||||||
Spacer()
|
|
||||||
Text("Nothing scheduled")
|
|
||||||
.font(.system(size: 11, design: .monospaced))
|
|
||||||
.foregroundColor(WC.text3(cs))
|
|
||||||
Spacer()
|
|
||||||
} else {
|
|
||||||
ForEach(displayTasks) { task in
|
|
||||||
TaskRow(task: task)
|
|
||||||
}
|
|
||||||
if let workout = entry.workout, workout.hasWorkoutToday,
|
|
||||||
displayTasks.count < 3 {
|
|
||||||
if !displayTasks.isEmpty {
|
|
||||||
Divider().opacity(0.4)
|
|
||||||
}
|
|
||||||
WorkoutRow(workout: workout)
|
|
||||||
}
|
|
||||||
Spacer(minLength: 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
|
||||||
}
|
|
||||||
.padding(14)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Large Widget
|
|
||||||
|
|
||||||
private struct LargeWidget: View {
|
|
||||||
@Environment(\.colorScheme) private var cs
|
|
||||||
let entry: KisaniEntry
|
|
||||||
|
|
||||||
private static let dayFmt: DateFormatter = {
|
|
||||||
let f = DateFormatter(); f.dateFormat = "EEEE, MMM d"; return f
|
|
||||||
}()
|
|
||||||
|
|
||||||
private var allTasks: [WidgetDataStore.WidgetTask] {
|
|
||||||
Array((entry.overdueTasks + entry.todayTasks).prefix(6))
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
ZStack {
|
|
||||||
WC.bg(cs).ignoresSafeArea()
|
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
|
||||||
// Header row
|
|
||||||
HStack(spacing: 12) {
|
|
||||||
DateBadge(size: 56)
|
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 3) {
|
|
||||||
HStack(spacing: 0) {
|
|
||||||
Text("kisani")
|
|
||||||
.font(.system(size: 14, weight: .regular, design: .monospaced))
|
|
||||||
.foregroundColor(WC.text2(cs))
|
|
||||||
Text("CAL")
|
|
||||||
.font(.system(size: 14, weight: .bold, design: .monospaced))
|
|
||||||
.foregroundColor(WC.text(cs))
|
|
||||||
Text(".")
|
|
||||||
.font(.system(size: 14, weight: .bold, design: .monospaced))
|
|
||||||
.foregroundColor(WC.accent)
|
|
||||||
}
|
|
||||||
Text(Self.dayFmt.string(from: Date()))
|
|
||||||
.font(.system(size: 10, design: .monospaced))
|
|
||||||
.foregroundColor(WC.text2(cs))
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
let total = entry.todayTasks.count + entry.overdueTasks.count
|
|
||||||
VStack(alignment: .trailing, spacing: 2) {
|
|
||||||
Text("\(total)")
|
|
||||||
.font(.system(size: 22, weight: .bold, design: .monospaced))
|
|
||||||
.foregroundColor(entry.overdueTasks.isEmpty ? WC.text(cs) : WC.accent)
|
|
||||||
Text("tasks")
|
|
||||||
.font(.system(size: 9, design: .monospaced))
|
|
||||||
.foregroundColor(WC.text3(cs))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.padding(.horizontal, 14)
|
|
||||||
.padding(.top, 14)
|
|
||||||
.padding(.bottom, 12)
|
|
||||||
|
|
||||||
Divider().opacity(0.4).padding(.horizontal, 14)
|
|
||||||
|
|
||||||
// Task list
|
|
||||||
VStack(alignment: .leading, spacing: 7) {
|
|
||||||
if allTasks.isEmpty {
|
|
||||||
HStack {
|
|
||||||
Spacer()
|
|
||||||
Text("Nothing due today")
|
|
||||||
.font(.system(size: 11, design: .monospaced))
|
|
||||||
.foregroundColor(WC.text3(cs))
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
.padding(.vertical, 8)
|
|
||||||
} else {
|
|
||||||
ForEach(allTasks) { task in
|
|
||||||
TaskRow(task: task)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.padding(.horizontal, 14)
|
|
||||||
.padding(.vertical, 10)
|
|
||||||
|
|
||||||
Spacer(minLength: 0)
|
|
||||||
|
|
||||||
// Workout row
|
|
||||||
if let workout = entry.workout, workout.hasWorkoutToday {
|
|
||||||
Divider().opacity(0.4).padding(.horizontal, 14)
|
|
||||||
WorkoutRow(workout: workout)
|
|
||||||
.padding(.horizontal, 14)
|
|
||||||
.padding(.vertical, 10)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
import Foundation
|
|
||||||
|
|
||||||
// Shared between app and widget extension via App Group UserDefaults.
|
|
||||||
// Types are pure Codable — no UIKit / AppColors dependency.
|
|
||||||
|
|
||||||
struct WidgetDataStore {
|
|
||||||
static let suiteName = "group.com.kutesir.KisaniCal"
|
|
||||||
static let tasksKey = "kisani.widget.tasks"
|
|
||||||
static let workoutKey = "kisani.widget.workout"
|
|
||||||
|
|
||||||
// MARK: - Shared types
|
|
||||||
|
|
||||||
struct WidgetTask: Codable, Identifiable {
|
|
||||||
let id: UUID
|
|
||||||
let title: String
|
|
||||||
let dueDate: Date?
|
|
||||||
let isToday: Bool
|
|
||||||
let isOverdue: Bool
|
|
||||||
}
|
|
||||||
|
|
||||||
struct WidgetWorkout: Codable {
|
|
||||||
let name: String
|
|
||||||
let sectionsCount: Int
|
|
||||||
let hasWorkoutToday: Bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Write (app target)
|
|
||||||
|
|
||||||
static func saveTasks(_ tasks: [WidgetTask]) {
|
|
||||||
guard let data = try? JSONEncoder().encode(tasks),
|
|
||||||
let ud = UserDefaults(suiteName: suiteName) else { return }
|
|
||||||
ud.set(data, forKey: tasksKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func saveWorkout(_ workout: WidgetWorkout?) {
|
|
||||||
guard let ud = UserDefaults(suiteName: suiteName) else { return }
|
|
||||||
if let workout, let data = try? JSONEncoder().encode(workout) {
|
|
||||||
ud.set(data, forKey: workoutKey)
|
|
||||||
} else {
|
|
||||||
ud.removeObject(forKey: workoutKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Read (widget target)
|
|
||||||
|
|
||||||
static func loadTasks() -> [WidgetTask] {
|
|
||||||
guard let ud = UserDefaults(suiteName: suiteName),
|
|
||||||
let data = ud.data(forKey: tasksKey),
|
|
||||||
let list = try? JSONDecoder().decode([WidgetTask].self, from: data)
|
|
||||||
else { return [] }
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
static func loadWorkout() -> WidgetWorkout? {
|
|
||||||
guard let ud = UserDefaults(suiteName: suiteName),
|
|
||||||
let data = ud.data(forKey: workoutKey),
|
|
||||||
let workout = try? JSONDecoder().decode(WidgetWorkout.self, from: data)
|
|
||||||
else { return nil }
|
|
||||||
return workout
|
|
||||||
}
|
|
||||||
}
|
|
||||||
23
project.yml
23
project.yml
@@ -13,7 +13,6 @@ targets:
|
|||||||
deploymentTarget: "16.0"
|
deploymentTarget: "16.0"
|
||||||
sources:
|
sources:
|
||||||
- path: KisaniCal
|
- path: KisaniCal
|
||||||
- path: Shared
|
|
||||||
settings:
|
settings:
|
||||||
base:
|
base:
|
||||||
SWIFT_VERSION: 5.9
|
SWIFT_VERSION: 5.9
|
||||||
@@ -29,27 +28,5 @@ targets:
|
|||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME: AccentColor
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME: AccentColor
|
||||||
CODE_SIGN_STYLE: Automatic
|
CODE_SIGN_STYLE: Automatic
|
||||||
ENABLE_PREVIEWS: YES
|
ENABLE_PREVIEWS: YES
|
||||||
CODE_SIGN_ENTITLEMENTS: KisaniCal/KisaniCal.entitlements
|
|
||||||
INFOPLIST_KEY_NSCalendarsUsageDescription: "Kisani Cal shows your calendar events alongside tasks."
|
INFOPLIST_KEY_NSCalendarsUsageDescription: "Kisani Cal shows your calendar events alongside tasks."
|
||||||
INFOPLIST_KEY_NSCalendarsFullAccessUsageDescription: "Kisani Cal shows your calendar events alongside tasks."
|
INFOPLIST_KEY_NSCalendarsFullAccessUsageDescription: "Kisani Cal shows your calendar events alongside tasks."
|
||||||
dependencies:
|
|
||||||
- target: KisaniCalWidget
|
|
||||||
embed: true
|
|
||||||
|
|
||||||
KisaniCalWidget:
|
|
||||||
type: app-extension
|
|
||||||
platform: iOS
|
|
||||||
deploymentTarget: "17.0"
|
|
||||||
sources:
|
|
||||||
- path: KisaniCalWidget
|
|
||||||
- path: Shared
|
|
||||||
settings:
|
|
||||||
base:
|
|
||||||
SWIFT_VERSION: 5.9
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER: com.kutesir.KisaniCal.widget
|
|
||||||
GENERATE_INFOPLIST_FILE: YES
|
|
||||||
INFOPLIST_KEY_NSExtensionPointIdentifier: com.apple.widgetkit-extension
|
|
||||||
CODE_SIGN_STYLE: Automatic
|
|
||||||
CODE_SIGN_ENTITLEMENTS: KisaniCalWidget/KisaniCalWidget.entitlements
|
|
||||||
SKIP_INSTALL: YES
|
|
||||||
LD_RUNPATH_SEARCH_PATHS: "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"
|
|
||||||
|
|||||||
Reference in New Issue
Block a user