feat: add in-app toast system with notification fallback for denied permissions
This commit is contained in:
parent
28dfa9f929
commit
a1120a56e8
26
ios/.gitignore
vendored
Normal file
26
ios/.gitignore
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
# Xcode
|
||||
*.xcodeproj/xcuserdata/
|
||||
*.xcodeproj/project.xcworkspace/xcuserdata/
|
||||
*.xcworkspace/xcuserdata/
|
||||
DerivedData/
|
||||
build/
|
||||
*.pbxuser
|
||||
*.mode1v3
|
||||
*.mode2v3
|
||||
*.perspectivev3
|
||||
*.moved-aside
|
||||
*.hmap
|
||||
*.ipa
|
||||
*.dSYM.zip
|
||||
*.dSYM
|
||||
|
||||
# Swift Package Manager
|
||||
.build/
|
||||
Packages/
|
||||
|
||||
# CocoaPods (if ever used)
|
||||
Pods/
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
*.swp
|
||||
641
ios/ChronoMind.xcodeproj/project.pbxproj
Normal file
641
ios/ChronoMind.xcodeproj/project.pbxproj
Normal file
@ -0,0 +1,641 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 77;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
006E8EA280AC7CAC5495951E /* TimerStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 089BC5A87E29D38DF3DFDFA2 /* TimerStore.swift */; };
|
||||
00BEA900EAE0226532824AE8 /* AlarmOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = F991E825657AE91E039404AD /* AlarmOverlay.swift */; };
|
||||
06789A5C995DCA4F35A4B9BD /* FormatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FACEF504403985D3BE08E29 /* FormatTests.swift */; };
|
||||
1D1DFA5585694A7BE76109E4 /* TimerEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93579D521BE5D6682B129A5C /* TimerEngine.swift */; };
|
||||
25D1EC51D100F93A735C6819 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52FDD9567F18B987402B5FF1 /* ContentView.swift */; };
|
||||
2A6837C7ACB5B9B8B632DD4D /* NotificationScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D34C1AC330B0CF41C37A771C /* NotificationScheduler.swift */; };
|
||||
33FE05A7CC65C5A251D5C686 /* CascadeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC3C28A0A106D3A02642F48 /* CascadeTests.swift */; };
|
||||
3BD65B9D32D36D682CBC5B2A /* TimerListSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1475DA4BEB57A6C1BDC13C27 /* TimerListSection.swift */; };
|
||||
3CE4B6F56C02F4962A2ECC2C /* PomodoroView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5346BBF21044F83F007D7E32 /* PomodoroView.swift */; };
|
||||
61FB6A2572B7299661705DE2 /* Format.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC158E525F3F703034E5542 /* Format.swift */; };
|
||||
6770745F2FBB9478094DC205 /* UrgencyBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AA00B60532FC72462812693 /* UrgencyBadge.swift */; };
|
||||
6F3699234F74C1DB6E71D245 /* QuickTimerSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D520D46C5759E8780334D623 /* QuickTimerSheet.swift */; };
|
||||
809719965B906AE51EA53C8B /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9019324C6A38DF943E1FF6 /* SettingsView.swift */; };
|
||||
8EF5C79BDF55D1F04851C3C0 /* TimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7C2F36FE2E4FEAD385B6860 /* TimelineView.swift */; };
|
||||
9CE528A21B258A6554DA8A46 /* ChronoMindApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD88A07063BD00F2DC6BB753 /* ChronoMindApp.swift */; };
|
||||
A77A6BFC98AD7A661CFE98DB /* FiringCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CC734D1505143775DCBDF18 /* FiringCard.swift */; };
|
||||
ABF5A4BB75D914A38A2D55CD /* TimerCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 492793555CC220F85136F2B4 /* TimerCard.swift */; };
|
||||
AE00522D3CE642B0C608E8A2 /* CountdownRing.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE814566D06D5ED5DE214765 /* CountdownRing.swift */; };
|
||||
B586A949950B02D3499C828E /* TimeBlindness.swift in Sources */ = {isa = PBXBuildFile; fileRef = D899FC687E51E9606B813E4F /* TimeBlindness.swift */; };
|
||||
C81D5D94A6F8E29C82EDD923 /* ChronoMindTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BAF2993B0DDD3D4334378B4 /* ChronoMindTheme.swift */; };
|
||||
CB7642D0D833F6D45B532AF6 /* Cascade.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE44586214BA0A4BEDA939F7 /* Cascade.swift */; };
|
||||
CFA4D8E650083161CC184D90 /* HistoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 453FAEB975BAA8307C8AED26 /* HistoryView.swift */; };
|
||||
D23D2EBC51D60E3D6C91DDAF /* TimerEngineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23F23285C9339D8EEDF95CF1 /* TimerEngineTests.swift */; };
|
||||
D488C32C9586E6BA10C17337 /* CreateTimerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33631FC9DC72BE316E763755 /* CreateTimerView.swift */; };
|
||||
DFBCDAD7322F6552D82EC73C /* HapticEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4535FFCA7608DECAFC332C5 /* HapticEngine.swift */; };
|
||||
E364FCB29C50C5780AB6BDED /* Urgency.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8775EEA5055E7416149B8384 /* Urgency.swift */; };
|
||||
EC0CEB1B4418DCD090CD431B /* CascadeProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EA0B050D86B6910385A7A7B /* CascadeProgressBar.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
5BB5DCEADCC953EE536BCB14 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = B148EC54D0D3F16627E44282 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 78243758404E574753DB494E;
|
||||
remoteInfo = ChronoMind;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
089BC5A87E29D38DF3DFDFA2 /* TimerStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerStore.swift; sourceTree = "<group>"; };
|
||||
0BAF2993B0DDD3D4334378B4 /* ChronoMindTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChronoMindTheme.swift; sourceTree = "<group>"; };
|
||||
0CC734D1505143775DCBDF18 /* FiringCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FiringCard.swift; sourceTree = "<group>"; };
|
||||
1475DA4BEB57A6C1BDC13C27 /* TimerListSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerListSection.swift; sourceTree = "<group>"; };
|
||||
1CC158E525F3F703034E5542 /* Format.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Format.swift; sourceTree = "<group>"; };
|
||||
23F23285C9339D8EEDF95CF1 /* TimerEngineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerEngineTests.swift; sourceTree = "<group>"; };
|
||||
33631FC9DC72BE316E763755 /* CreateTimerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateTimerView.swift; sourceTree = "<group>"; };
|
||||
453FAEB975BAA8307C8AED26 /* HistoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryView.swift; sourceTree = "<group>"; };
|
||||
492793555CC220F85136F2B4 /* TimerCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerCard.swift; sourceTree = "<group>"; };
|
||||
52A8E7A04EFCDCABA3F05E28 /* ChronoMind.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ChronoMind.entitlements; sourceTree = "<group>"; };
|
||||
52FDD9567F18B987402B5FF1 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||
5346BBF21044F83F007D7E32 /* PomodoroView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PomodoroView.swift; sourceTree = "<group>"; };
|
||||
6FACEF504403985D3BE08E29 /* FormatTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormatTests.swift; sourceTree = "<group>"; };
|
||||
8775EEA5055E7416149B8384 /* Urgency.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Urgency.swift; sourceTree = "<group>"; };
|
||||
93579D521BE5D6682B129A5C /* TimerEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerEngine.swift; sourceTree = "<group>"; };
|
||||
9AA00B60532FC72462812693 /* UrgencyBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UrgencyBadge.swift; sourceTree = "<group>"; };
|
||||
9EA0B050D86B6910385A7A7B /* CascadeProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CascadeProgressBar.swift; sourceTree = "<group>"; };
|
||||
A5D8865FAFACFB57899D5AF4 /* ChronoMind.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = ChronoMind.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
AE44586214BA0A4BEDA939F7 /* Cascade.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cascade.swift; sourceTree = "<group>"; };
|
||||
BD88A07063BD00F2DC6BB753 /* ChronoMindApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChronoMindApp.swift; sourceTree = "<group>"; };
|
||||
BEE32B08F25A4438A6B69FB6 /* ChronoMindTests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = ChronoMindTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
C4535FFCA7608DECAFC332C5 /* HapticEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HapticEngine.swift; sourceTree = "<group>"; };
|
||||
CEC3C28A0A106D3A02642F48 /* CascadeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CascadeTests.swift; sourceTree = "<group>"; };
|
||||
D34C1AC330B0CF41C37A771C /* NotificationScheduler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationScheduler.swift; sourceTree = "<group>"; };
|
||||
D520D46C5759E8780334D623 /* QuickTimerSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickTimerSheet.swift; sourceTree = "<group>"; };
|
||||
D899FC687E51E9606B813E4F /* TimeBlindness.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeBlindness.swift; sourceTree = "<group>"; };
|
||||
DA9019324C6A38DF943E1FF6 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
|
||||
E7C2F36FE2E4FEAD385B6860 /* TimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineView.swift; sourceTree = "<group>"; };
|
||||
EE814566D06D5ED5DE214765 /* CountdownRing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CountdownRing.swift; sourceTree = "<group>"; };
|
||||
F991E825657AE91E039404AD /* AlarmOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlarmOverlay.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
237EFEB5E79C17C58AE4B02B /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EBD394FC41C27417B6272B2B /* Components */,
|
||||
EC4D2D1AC883572D82016E7A /* CreateTimer */,
|
||||
444BD7BD82654D6A717BE39B /* Focus */,
|
||||
4DBB188595CF9B880D09EFA8 /* History */,
|
||||
2ABA85855E88EF8E5AE2C296 /* Settings */,
|
||||
583EC1D56685251E7A9410B8 /* Timeline */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2ABA85855E88EF8E5AE2C296 /* Settings */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DA9019324C6A38DF943E1FF6 /* SettingsView.swift */,
|
||||
);
|
||||
path = Settings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3C5FDEC2037E5CC602490C47 /* Store */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
089BC5A87E29D38DF3DFDFA2 /* TimerStore.swift */,
|
||||
);
|
||||
path = Store;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
444BD7BD82654D6A717BE39B /* Focus */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5346BBF21044F83F007D7E32 /* PomodoroView.swift */,
|
||||
);
|
||||
path = Focus;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
468A5761EC0508501FAF2294 /* Theme */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0BAF2993B0DDD3D4334378B4 /* ChronoMindTheme.swift */,
|
||||
);
|
||||
path = Theme;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4DBB188595CF9B880D09EFA8 /* History */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
453FAEB975BAA8307C8AED26 /* HistoryView.swift */,
|
||||
);
|
||||
path = History;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
583EC1D56685251E7A9410B8 /* Timeline */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E7C2F36FE2E4FEAD385B6860 /* TimelineView.swift */,
|
||||
);
|
||||
path = Timeline;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5AB52EC93294F076818CB0DA /* Notifications */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D34C1AC330B0CF41C37A771C /* NotificationScheduler.swift */,
|
||||
);
|
||||
path = Notifications;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
739D982BE81B9C296ED1A1C4 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ADC7E8817D3AC5CB0D19CE06 /* ChronoMind */,
|
||||
BA684DC5A43403F4E5BF4DBB /* ChronoMindTests */,
|
||||
D989A0D19D230F73B67AC744 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
889806888E26EEDFA679B318 /* Shared */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
AEBBD21D7F7F55BAA99CA1C5 /* Haptics */,
|
||||
5AB52EC93294F076818CB0DA /* Notifications */,
|
||||
3C5FDEC2037E5CC602490C47 /* Store */,
|
||||
468A5761EC0508501FAF2294 /* Theme */,
|
||||
BF15F58057A7B3864EDDE601 /* TimerEngine */,
|
||||
);
|
||||
path = Shared;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
ADC7E8817D3AC5CB0D19CE06 /* ChronoMind */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B7064A49165283316A44BD46 /* App */,
|
||||
889806888E26EEDFA679B318 /* Shared */,
|
||||
237EFEB5E79C17C58AE4B02B /* Views */,
|
||||
52A8E7A04EFCDCABA3F05E28 /* ChronoMind.entitlements */,
|
||||
);
|
||||
path = ChronoMind;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
AEBBD21D7F7F55BAA99CA1C5 /* Haptics */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C4535FFCA7608DECAFC332C5 /* HapticEngine.swift */,
|
||||
);
|
||||
path = Haptics;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B7064A49165283316A44BD46 /* App */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BD88A07063BD00F2DC6BB753 /* ChronoMindApp.swift */,
|
||||
52FDD9567F18B987402B5FF1 /* ContentView.swift */,
|
||||
);
|
||||
path = App;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
BA684DC5A43403F4E5BF4DBB /* ChronoMindTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CEC3C28A0A106D3A02642F48 /* CascadeTests.swift */,
|
||||
6FACEF504403985D3BE08E29 /* FormatTests.swift */,
|
||||
23F23285C9339D8EEDF95CF1 /* TimerEngineTests.swift */,
|
||||
);
|
||||
path = ChronoMindTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
BF15F58057A7B3864EDDE601 /* TimerEngine */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
AE44586214BA0A4BEDA939F7 /* Cascade.swift */,
|
||||
1CC158E525F3F703034E5542 /* Format.swift */,
|
||||
D899FC687E51E9606B813E4F /* TimeBlindness.swift */,
|
||||
93579D521BE5D6682B129A5C /* TimerEngine.swift */,
|
||||
8775EEA5055E7416149B8384 /* Urgency.swift */,
|
||||
);
|
||||
path = TimerEngine;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D989A0D19D230F73B67AC744 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A5D8865FAFACFB57899D5AF4 /* ChronoMind.app */,
|
||||
BEE32B08F25A4438A6B69FB6 /* ChronoMindTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EBD394FC41C27417B6272B2B /* Components */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F991E825657AE91E039404AD /* AlarmOverlay.swift */,
|
||||
9EA0B050D86B6910385A7A7B /* CascadeProgressBar.swift */,
|
||||
EE814566D06D5ED5DE214765 /* CountdownRing.swift */,
|
||||
0CC734D1505143775DCBDF18 /* FiringCard.swift */,
|
||||
492793555CC220F85136F2B4 /* TimerCard.swift */,
|
||||
1475DA4BEB57A6C1BDC13C27 /* TimerListSection.swift */,
|
||||
9AA00B60532FC72462812693 /* UrgencyBadge.swift */,
|
||||
);
|
||||
path = Components;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EC4D2D1AC883572D82016E7A /* CreateTimer */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
33631FC9DC72BE316E763755 /* CreateTimerView.swift */,
|
||||
D520D46C5759E8780334D623 /* QuickTimerSheet.swift */,
|
||||
);
|
||||
path = CreateTimer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
110092E4140109FF0073897B /* ChronoMindTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = B6C1A84B6C793EB62BA4DA19 /* Build configuration list for PBXNativeTarget "ChronoMindTests" */;
|
||||
buildPhases = (
|
||||
90C450C530D3DA144CDB7FBC /* Sources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
3630F4DD33FE96360A4DA8F4 /* PBXTargetDependency */,
|
||||
);
|
||||
name = ChronoMindTests;
|
||||
packageProductDependencies = (
|
||||
);
|
||||
productName = ChronoMindTests;
|
||||
productReference = BEE32B08F25A4438A6B69FB6 /* ChronoMindTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
78243758404E574753DB494E /* ChronoMind */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = E15654FE3118301BF65DA240 /* Build configuration list for PBXNativeTarget "ChronoMind" */;
|
||||
buildPhases = (
|
||||
30FEA9533F75E1C796E0E198 /* Sources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = ChronoMind;
|
||||
packageProductDependencies = (
|
||||
);
|
||||
productName = ChronoMind;
|
||||
productReference = A5D8865FAFACFB57899D5AF4 /* ChronoMind.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
B148EC54D0D3F16627E44282 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastUpgradeCheck = 1600;
|
||||
TargetAttributes = {
|
||||
110092E4140109FF0073897B = {
|
||||
DevelopmentTeam = 748N7QPX7J;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
78243758404E574753DB494E = {
|
||||
DevelopmentTeam = 748N7QPX7J;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 900EBDCE1F40012242E88499 /* Build configuration list for PBXProject "ChronoMind" */;
|
||||
compatibilityVersion = "Xcode 14.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
Base,
|
||||
en,
|
||||
);
|
||||
mainGroup = 739D982BE81B9C296ED1A1C4;
|
||||
minimizedProjectReferenceProxies = 1;
|
||||
preferredProjectObjectVersion = 77;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
78243758404E574753DB494E /* ChronoMind */,
|
||||
110092E4140109FF0073897B /* ChronoMindTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
30FEA9533F75E1C796E0E198 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
00BEA900EAE0226532824AE8 /* AlarmOverlay.swift in Sources */,
|
||||
CB7642D0D833F6D45B532AF6 /* Cascade.swift in Sources */,
|
||||
EC0CEB1B4418DCD090CD431B /* CascadeProgressBar.swift in Sources */,
|
||||
9CE528A21B258A6554DA8A46 /* ChronoMindApp.swift in Sources */,
|
||||
C81D5D94A6F8E29C82EDD923 /* ChronoMindTheme.swift in Sources */,
|
||||
25D1EC51D100F93A735C6819 /* ContentView.swift in Sources */,
|
||||
AE00522D3CE642B0C608E8A2 /* CountdownRing.swift in Sources */,
|
||||
D488C32C9586E6BA10C17337 /* CreateTimerView.swift in Sources */,
|
||||
A77A6BFC98AD7A661CFE98DB /* FiringCard.swift in Sources */,
|
||||
61FB6A2572B7299661705DE2 /* Format.swift in Sources */,
|
||||
DFBCDAD7322F6552D82EC73C /* HapticEngine.swift in Sources */,
|
||||
CFA4D8E650083161CC184D90 /* HistoryView.swift in Sources */,
|
||||
2A6837C7ACB5B9B8B632DD4D /* NotificationScheduler.swift in Sources */,
|
||||
3CE4B6F56C02F4962A2ECC2C /* PomodoroView.swift in Sources */,
|
||||
6F3699234F74C1DB6E71D245 /* QuickTimerSheet.swift in Sources */,
|
||||
809719965B906AE51EA53C8B /* SettingsView.swift in Sources */,
|
||||
B586A949950B02D3499C828E /* TimeBlindness.swift in Sources */,
|
||||
8EF5C79BDF55D1F04851C3C0 /* TimelineView.swift in Sources */,
|
||||
ABF5A4BB75D914A38A2D55CD /* TimerCard.swift in Sources */,
|
||||
1D1DFA5585694A7BE76109E4 /* TimerEngine.swift in Sources */,
|
||||
3BD65B9D32D36D682CBC5B2A /* TimerListSection.swift in Sources */,
|
||||
006E8EA280AC7CAC5495951E /* TimerStore.swift in Sources */,
|
||||
E364FCB29C50C5780AB6BDED /* Urgency.swift in Sources */,
|
||||
6770745F2FBB9478094DC205 /* UrgencyBadge.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
90C450C530D3DA144CDB7FBC /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
33FE05A7CC65C5A251D5C686 /* CascadeTests.swift in Sources */,
|
||||
06789A5C995DCA4F35A4B9BD /* FormatTests.swift in Sources */,
|
||||
D23D2EBC51D60E3D6C91DDAF /* TimerEngineTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
3630F4DD33FE96360A4DA8F4 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 78243758404E574753DB494E /* ChronoMind */;
|
||||
targetProxy = 5BB5DCEADCC953EE536BCB14 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
188B92F03833DCED4C79777E /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = ChronoMind/ChronoMind.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_GENERATION_MODE = GeneratedFile;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = ChronoMind;
|
||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.chronomind.app;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
1916861B34C6412F352A467C /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = ChronoMind/ChronoMind.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_GENERATION_MODE = GeneratedFile;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = ChronoMind;
|
||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.chronomind.app;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
1D8CF2BF99A3D83D8146403D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.chronomind.tests;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ChronoMind.app/ChronoMind";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
2FAE12CBA4AF17056BAF8CBD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.chronomind.tests;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ChronoMind.app/ChronoMind";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
9554092DCB210E9D537B30FC /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = 748N7QPX7J;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 14.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_VERSION = 5.9;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
WATCHOS_DEPLOYMENT_TARGET = 10.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
DF2F9E2B2834FDEE0C6C59C0 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 748N7QPX7J;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
"DEBUG=1",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 14.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.9;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
WATCHOS_DEPLOYMENT_TARGET = 10.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
900EBDCE1F40012242E88499 /* Build configuration list for PBXProject "ChronoMind" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
DF2F9E2B2834FDEE0C6C59C0 /* Debug */,
|
||||
9554092DCB210E9D537B30FC /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Debug;
|
||||
};
|
||||
B6C1A84B6C793EB62BA4DA19 /* Build configuration list for PBXNativeTarget "ChronoMindTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
1D8CF2BF99A3D83D8146403D /* Debug */,
|
||||
2FAE12CBA4AF17056BAF8CBD /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Debug;
|
||||
};
|
||||
E15654FE3118301BF65DA240 /* Build configuration list for PBXNativeTarget "ChronoMind" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
1916861B34C6412F352A467C /* Debug */,
|
||||
188B92F03833DCED4C79777E /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Debug;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = B148EC54D0D3F16627E44282 /* Project object */;
|
||||
}
|
||||
7
ios/ChronoMind.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
ios/ChronoMind.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1600"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES"
|
||||
runPostActionsOnFailure = "NO">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "78243758404E574753DB494E"
|
||||
BuildableName = "ChronoMind.app"
|
||||
BlueprintName = "ChronoMind"
|
||||
ReferencedContainer = "container:ChronoMind.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "NO"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "110092E4140109FF0073897B"
|
||||
BuildableName = "ChronoMindTests.xctest"
|
||||
BlueprintName = "ChronoMindTests"
|
||||
ReferencedContainer = "container:ChronoMind.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
onlyGenerateCoverageForSpecifiedTargets = "NO">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "78243758404E574753DB494E"
|
||||
BuildableName = "ChronoMind.app"
|
||||
BlueprintName = "ChronoMind"
|
||||
ReferencedContainer = "container:ChronoMind.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "110092E4140109FF0073897B"
|
||||
BuildableName = "ChronoMindTests.xctest"
|
||||
BlueprintName = "ChronoMindTests"
|
||||
ReferencedContainer = "container:ChronoMind.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "78243758404E574753DB494E"
|
||||
BuildableName = "ChronoMind.app"
|
||||
BlueprintName = "ChronoMind"
|
||||
ReferencedContainer = "container:ChronoMind.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "78243758404E574753DB494E"
|
||||
BuildableName = "ChronoMind.app"
|
||||
BlueprintName = "ChronoMind"
|
||||
ReferencedContainer = "container:ChronoMind.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@ -136,15 +136,12 @@ final class CMNotificationManager: ObservableObject {
|
||||
UNUserNotificationCenter.current().add(request)
|
||||
}
|
||||
|
||||
private func soundForUrgency(_ urgency: UrgencyLevel, isWarning: Bool) -> UNNotificationSound {
|
||||
private func soundForUrgency(_ urgency: UrgencyLevel, isWarning: Bool) -> UNNotificationSound? {
|
||||
let config = getUrgencyConfig(urgency)
|
||||
guard config.soundEnabled else { return .none }
|
||||
guard config.soundEnabled else { return nil }
|
||||
|
||||
if urgency == .critical && !isWarning {
|
||||
// Critical fires get the default critical alert sound
|
||||
if #available(iOS 12.0, *) {
|
||||
return .defaultCritical
|
||||
}
|
||||
return .defaultCritical
|
||||
}
|
||||
|
||||
return .default
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Inter, JetBrains_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
import { ToastContainer } from "@/components/Toast";
|
||||
|
||||
const inter = Inter({
|
||||
variable: "--font-inter",
|
||||
@ -38,6 +39,7 @@ export default function RootLayout({
|
||||
className={`${inter.variable} ${jetbrainsMono.variable} antialiased`}
|
||||
>
|
||||
{children}
|
||||
<ToastContainer />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
108
web/src/components/Toast.tsx
Normal file
108
web/src/components/Toast.tsx
Normal file
@ -0,0 +1,108 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { X, Bell, AlertTriangle, CheckCircle, Info } from 'lucide-react';
|
||||
|
||||
export interface ToastMessage {
|
||||
id: string;
|
||||
type: 'info' | 'warning' | 'success' | 'alarm';
|
||||
title: string;
|
||||
body?: string;
|
||||
duration?: number; // ms, 0 = sticky
|
||||
}
|
||||
|
||||
// Global toast state — simple pub/sub
|
||||
type Listener = (toasts: ToastMessage[]) => void;
|
||||
let toasts: ToastMessage[] = [];
|
||||
const listeners = new Set<Listener>();
|
||||
|
||||
function notify() {
|
||||
listeners.forEach((l) => l([...toasts]));
|
||||
}
|
||||
|
||||
export function showToast(toast: Omit<ToastMessage, 'id'>) {
|
||||
const id = `toast-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
|
||||
const msg: ToastMessage = { ...toast, id };
|
||||
toasts = [...toasts, msg];
|
||||
notify();
|
||||
|
||||
const duration = toast.duration ?? 5000;
|
||||
if (duration > 0) {
|
||||
setTimeout(() => dismissToast(id), duration);
|
||||
}
|
||||
}
|
||||
|
||||
export function dismissToast(id: string) {
|
||||
toasts = toasts.filter((t) => t.id !== id);
|
||||
notify();
|
||||
}
|
||||
|
||||
const ICONS = {
|
||||
info: Info,
|
||||
warning: AlertTriangle,
|
||||
success: CheckCircle,
|
||||
alarm: Bell,
|
||||
};
|
||||
|
||||
const COLORS = {
|
||||
info: { bg: 'var(--cm-accent)', text: '#fff' },
|
||||
warning: { bg: 'var(--cm-warning)', text: '#000' },
|
||||
success: { bg: 'var(--cm-success)', text: '#000' },
|
||||
alarm: { bg: 'var(--cm-critical)', text: '#fff' },
|
||||
};
|
||||
|
||||
export function ToastContainer() {
|
||||
const [items, setItems] = useState<ToastMessage[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
listeners.add(setItems);
|
||||
return () => { listeners.delete(setItems); };
|
||||
}, []);
|
||||
|
||||
const handleDismiss = useCallback((id: string) => dismissToast(id), []);
|
||||
|
||||
if (items.length === 0) return null;
|
||||
|
||||
return (
|
||||
<div className="fixed top-4 right-4 z-50 flex flex-col gap-2 max-w-sm">
|
||||
{items.map((toast) => {
|
||||
const Icon = ICONS[toast.type];
|
||||
const colors = COLORS[toast.type];
|
||||
return (
|
||||
<div
|
||||
key={toast.id}
|
||||
className="flex items-start gap-3 px-4 py-3 rounded-xl shadow-lg border animate-in slide-in-from-right"
|
||||
style={{
|
||||
backgroundColor: 'var(--cm-bg-elevated)',
|
||||
borderColor: 'var(--cm-border)',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center"
|
||||
style={{ backgroundColor: colors.bg }}
|
||||
>
|
||||
<Icon size={16} style={{ color: colors.text }} />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-semibold" style={{ color: 'var(--cm-text-primary)' }}>
|
||||
{toast.title}
|
||||
</p>
|
||||
{toast.body && (
|
||||
<p className="text-xs mt-0.5" style={{ color: 'var(--cm-text-secondary)' }}>
|
||||
{toast.body}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
onClick={() => handleDismiss(toast.id)}
|
||||
className="flex-shrink-0 p-1 rounded cursor-pointer"
|
||||
style={{ color: 'var(--cm-text-tertiary)' }}
|
||||
>
|
||||
<X size={14} />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -27,8 +27,24 @@ export function sendNotification(
|
||||
urgency: UrgencyLevel,
|
||||
options?: { tag?: string; onClick?: () => void }
|
||||
): Notification | null {
|
||||
if (typeof window === 'undefined' || !('Notification' in window)) return null;
|
||||
if (Notification.permission !== 'granted') return null;
|
||||
if (typeof window === 'undefined') return null;
|
||||
|
||||
// If notifications not available or denied, fall back to in-app toast
|
||||
if (!('Notification' in window) || Notification.permission !== 'granted') {
|
||||
// Lazy import to avoid circular deps
|
||||
import('../components/Toast').then(({ showToast }) => {
|
||||
const toastType = urgency === 'critical' ? 'alarm' as const
|
||||
: urgency === 'important' ? 'warning' as const
|
||||
: 'info' as const;
|
||||
showToast({
|
||||
type: toastType,
|
||||
title,
|
||||
body,
|
||||
duration: urgency === 'critical' ? 0 : 5000,
|
||||
});
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
const config = getUrgencyConfig(urgency);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user