Compare commits
40 Commits
feat-accen
...
feat-inten
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca64157923 | ||
|
|
db05da3043 | ||
|
|
940a8f4ebd | ||
|
|
48071c0791 | ||
|
|
3a94dc7675 | ||
|
|
08bf56ecbd | ||
|
|
008eecb52c | ||
|
|
c640c77600 | ||
|
|
e9d49cc137 | ||
|
|
565341c3d0 | ||
|
|
f9c50df47f | ||
|
|
bb598250a6 | ||
|
|
c7fddda601 | ||
|
|
033a01463f | ||
|
|
87209f38f3 | ||
|
|
7c852fc8ec | ||
|
|
73b3d9b234 | ||
|
|
0a17ec6292 | ||
|
|
bb67b0ce98 | ||
|
|
82341f40ef | ||
|
|
f9f030c8b3 | ||
|
|
3ca5017b61 | ||
|
|
0efcc9e183 | ||
|
|
595c2b74c5 | ||
|
|
f252359eb1 | ||
|
|
2b266e03ca | ||
|
|
c935d4b1f0 | ||
|
|
c82ce5fa17 | ||
|
|
7bef3bc4e6 | ||
|
|
025dbf22cd | ||
|
|
da65c3ac69 | ||
|
|
5f52b423db | ||
|
|
7af96834d6 | ||
|
|
17ef4f1478 | ||
|
|
785dda0e2b | ||
|
|
5f5702d958 | ||
|
|
b88bc11b36 | ||
|
|
f8f5cdde26 | ||
|
|
169d51e6b9 | ||
|
|
afd6d23838 |
@@ -12,6 +12,6 @@ TEAM_ID = 8JGND254B7
|
|||||||
BUNDLE_ID = com.neon443.NearFuture
|
BUNDLE_ID = com.neon443.NearFuture
|
||||||
BUNDLE_ID_WIDGETS = com.neon443.NearFuture.widgets
|
BUNDLE_ID_WIDGETS = com.neon443.NearFuture.widgets
|
||||||
GROUP_ID = group.NearFuture
|
GROUP_ID = group.NearFuture
|
||||||
VERSION = 3.2.1
|
VERSION = 4.4.0
|
||||||
NAME = Near Future
|
NAME = Near Future
|
||||||
BUILD_NUMBER = 5
|
BUILD_NUMBER = 1
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 13 KiB |
@@ -3,25 +3,33 @@
|
|||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 70;
|
objectVersion = 56;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
A914FA4B2DD26C6800856265 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A914FA4A2DD26C0F00856265 /* HomeView.swift */; };
|
||||||
|
A914FA4D2DD2768900856265 /* WhatsNewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A914FA4C2DD2768900856265 /* WhatsNewView.swift */; };
|
||||||
|
A914FA4F2DD276D200856265 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A914FA4E2DD276D200856265 /* AboutView.swift */; };
|
||||||
A920C2882D24011400E4F9B1 /* NearFutureApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C2872D24011400E4F9B1 /* NearFutureApp.swift */; };
|
A920C2882D24011400E4F9B1 /* NearFutureApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C2872D24011400E4F9B1 /* NearFutureApp.swift */; };
|
||||||
A920C28C2D24011400E4F9B1 /* Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C28B2D24011400E4F9B1 /* Item.swift */; };
|
A920C28C2D24011400E4F9B1 /* Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C28B2D24011400E4F9B1 /* Item.swift */; };
|
||||||
A920C28E2D24011A00E4F9B1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A920C28D2D24011A00E4F9B1 /* Assets.xcassets */; };
|
A920C28E2D24011A00E4F9B1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A920C28D2D24011A00E4F9B1 /* Assets.xcassets */; };
|
||||||
A920C2922D24011A00E4F9B1 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A920C2912D24011A00E4F9B1 /* Preview Assets.xcassets */; };
|
A920C2922D24011A00E4F9B1 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A920C2912D24011A00E4F9B1 /* Preview Assets.xcassets */; };
|
||||||
A920C2B82D2401A300E4F9B1 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C2B42D2401A100E4F9B1 /* SettingsView.swift */; };
|
|
||||||
A920C2BB2D2401A400E4F9B1 /* AddEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C2B72D2401A300E4F9B1 /* AddEventView.swift */; };
|
|
||||||
A920C2BE2D24021A00E4F9B1 /* SFSymbolsPicker in Frameworks */ = {isa = PBXBuildFile; productRef = A920C2BD2D24021A00E4F9B1 /* SFSymbolsPicker */; };
|
A920C2BE2D24021A00E4F9B1 /* SFSymbolsPicker in Frameworks */ = {isa = PBXBuildFile; productRef = A920C2BD2D24021A00E4F9B1 /* SFSymbolsPicker */; };
|
||||||
A920C2C12D2403CA00E4F9B1 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C2C02D2403CA00E4F9B1 /* ContentView.swift */; };
|
A949F8322DCAAA8A0064DCA0 /* NearFutureIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = A949F8312DCAAA8A0064DCA0 /* NearFutureIcon.png */; };
|
||||||
A93BC0942D2B18A3002E8BBD /* StatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93BC0932D2B18A3002E8BBD /* StatsView.swift */; };
|
A949F84B2DCAABE00064DCA0 /* ArchiveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F83A2DCAABE00064DCA0 /* ArchiveView.swift */; };
|
||||||
A973B26C2DC551310028F8A2 /* ImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A973B26B2DC551310028F8A2 /* ImportView.swift */; };
|
A949F84C2DCAABE00064DCA0 /* AddEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F83C2DCAABE00064DCA0 /* AddEventView.swift */; };
|
||||||
A973B2702DC552EB0028F8A2 /* ExportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A973B26F2DC552EB0028F8A2 /* ExportView.swift */; };
|
A949F84D2DCAABE00064DCA0 /* EditEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F83D2DCAABE00064DCA0 /* EditEventView.swift */; };
|
||||||
A973B2712DC553050028F8A2 /* ExportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A973B26F2DC552EB0028F8A2 /* ExportView.swift */; };
|
A949F84E2DCAABE00064DCA0 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F83F2DCAABE00064DCA0 /* ContentView.swift */; };
|
||||||
A977CC922DBBB48000DED8C0 /* ArchiveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A977CC912DBBB48000DED8C0 /* ArchiveView.swift */; };
|
A949F84F2DCAABE00064DCA0 /* EventListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8402DCAABE00064DCA0 /* EventListView.swift */; };
|
||||||
A977CC9A2DBD74FE00DED8C0 /* HelpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A977CC992DBD74FE00DED8C0 /* HelpView.swift */; };
|
A949F8502DCAABE00064DCA0 /* HelpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8412DCAABE00064DCA0 /* HelpView.swift */; };
|
||||||
A979F57F2D26B1300094C0B3 /* EditEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A979F57E2D26B1300094C0B3 /* EditEventView.swift */; };
|
A949F8512DCAABE00064DCA0 /* ExportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8432DCAABE00064DCA0 /* ExportView.swift */; };
|
||||||
|
A949F8522DCAABE00064DCA0 /* iCloudSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8442DCAABE00064DCA0 /* iCloudSettingsView.swift */; };
|
||||||
|
A949F8532DCAABE00064DCA0 /* ImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8452DCAABE00064DCA0 /* ImportView.swift */; };
|
||||||
|
A949F8542DCAABE00064DCA0 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8462DCAABE00064DCA0 /* SettingsView.swift */; };
|
||||||
|
A949F8552DCAABE00064DCA0 /* StatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8482DCAABE00064DCA0 /* StatsView.swift */; };
|
||||||
|
A949F8562DCAABE00064DCA0 /* ExportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8432DCAABE00064DCA0 /* ExportView.swift */; };
|
||||||
|
A949F8592DCAAD670064DCA0 /* NearFutureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8572DCAAD670064DCA0 /* NearFutureTests.swift */; };
|
||||||
|
A949F85F2DCABB420064DCA0 /* Buttons.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F85D2DCABB420064DCA0 /* Buttons.swift */; };
|
||||||
A979F6052D270AF00094C0B3 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A979F6042D270AF00094C0B3 /* WidgetKit.framework */; };
|
A979F6052D270AF00094C0B3 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A979F6042D270AF00094C0B3 /* WidgetKit.framework */; };
|
||||||
A979F6072D270AF00094C0B3 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A979F6062D270AF00094C0B3 /* SwiftUI.framework */; };
|
A979F6072D270AF00094C0B3 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A979F6062D270AF00094C0B3 /* SwiftUI.framework */; };
|
||||||
A979F60A2D270AF00094C0B3 /* NearFutureWidgetsBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = A979F6092D270AF00094C0B3 /* NearFutureWidgetsBundle.swift */; };
|
A979F60A2D270AF00094C0B3 /* NearFutureWidgetsBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = A979F6092D270AF00094C0B3 /* NearFutureWidgetsBundle.swift */; };
|
||||||
@@ -29,8 +37,6 @@
|
|||||||
A979F6102D270AF90094C0B3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A979F60F2D270AF80094C0B3 /* Assets.xcassets */; };
|
A979F6102D270AF90094C0B3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A979F60F2D270AF80094C0B3 /* Assets.xcassets */; };
|
||||||
A979F6142D270AF90094C0B3 /* NearFutureWidgetsExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = A979F6022D270AF00094C0B3 /* NearFutureWidgetsExtension.appex */; platformFilter = ios; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
A979F6142D270AF90094C0B3 /* NearFutureWidgetsExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = A979F6022D270AF00094C0B3 /* NearFutureWidgetsExtension.appex */; platformFilter = ios; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
A979F6182D2714310094C0B3 /* Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C28B2D24011400E4F9B1 /* Item.swift */; };
|
A979F6182D2714310094C0B3 /* Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C28B2D24011400E4F9B1 /* Item.swift */; };
|
||||||
A985104E2DB256430013D5FF /* iCloudSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A985104D2DB256430013D5FF /* iCloudSettingsView.swift */; };
|
|
||||||
A98510502DB263F00013D5FF /* EventListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A985104F2DB263F00013D5FF /* EventListView.swift */; };
|
|
||||||
A9FC7EEA2D2823920020D75B /* NearFutureWidgets.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FC7EE92D28238A0020D75B /* NearFutureWidgets.swift */; };
|
A9FC7EEA2D2823920020D75B /* NearFutureWidgets.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FC7EE92D28238A0020D75B /* NearFutureWidgets.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
@@ -67,21 +73,32 @@
|
|||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
A90FDE222DC0D4310012790C /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
|
A90FDE222DC0D4310012790C /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
|
||||||
|
A914FA4A2DD26C0F00856265 /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = "<group>"; };
|
||||||
|
A914FA4C2DD2768900856265 /* WhatsNewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WhatsNewView.swift; path = NearFuture/Views/Settings/WhatsNewView.swift; sourceTree = SOURCE_ROOT; };
|
||||||
|
A914FA4E2DD276D200856265 /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AboutView.swift; path = NearFuture/Views/Misc/AboutView.swift; sourceTree = SOURCE_ROOT; };
|
||||||
A920C2842D24011400E4F9B1 /* NearFuture.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NearFuture.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
A920C2842D24011400E4F9B1 /* NearFuture.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NearFuture.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
A920C2872D24011400E4F9B1 /* NearFutureApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureApp.swift; sourceTree = "<group>"; };
|
A920C2872D24011400E4F9B1 /* NearFutureApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureApp.swift; sourceTree = "<group>"; };
|
||||||
A920C28B2D24011400E4F9B1 /* Item.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Item.swift; sourceTree = "<group>"; };
|
A920C28B2D24011400E4F9B1 /* Item.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Item.swift; sourceTree = "<group>"; };
|
||||||
A920C28D2D24011A00E4F9B1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
A920C28D2D24011A00E4F9B1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
A920C28F2D24011A00E4F9B1 /* NearFuture.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NearFuture.entitlements; sourceTree = "<group>"; };
|
A920C28F2D24011A00E4F9B1 /* NearFuture.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NearFuture.entitlements; sourceTree = "<group>"; };
|
||||||
A920C2912D24011A00E4F9B1 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
A920C2912D24011A00E4F9B1 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
||||||
A920C2B42D2401A100E4F9B1 /* SettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
|
A949F82E2DCAAA640064DCA0 /* NearFutureIcon.pxd */ = {isa = PBXFileReference; lastKnownFileType = file; path = NearFutureIcon.pxd; sourceTree = "<group>"; };
|
||||||
A920C2B72D2401A300E4F9B1 /* AddEventView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddEventView.swift; sourceTree = "<group>"; };
|
A949F82F2DCAAA640064DCA0 /* NearFutureIconDark.pxd */ = {isa = PBXFileReference; lastKnownFileType = file; path = NearFutureIconDark.pxd; sourceTree = "<group>"; };
|
||||||
A920C2C02D2403CA00E4F9B1 /* ContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
A949F8302DCAAA640064DCA0 /* NearFutureIconTint.pxd */ = {isa = PBXFileReference; lastKnownFileType = file; path = NearFutureIconTint.pxd; sourceTree = "<group>"; };
|
||||||
A93BC0932D2B18A3002E8BBD /* StatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsView.swift; sourceTree = "<group>"; };
|
A949F8312DCAAA8A0064DCA0 /* NearFutureIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = NearFutureIcon.png; path = Assets.xcassets/AppIcon.appiconset/NearFutureIcon.png; sourceTree = "<group>"; };
|
||||||
A973B26B2DC551310028F8A2 /* ImportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportView.swift; sourceTree = "<group>"; };
|
A949F83A2DCAABE00064DCA0 /* ArchiveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArchiveView.swift; sourceTree = "<group>"; };
|
||||||
A973B26F2DC552EB0028F8A2 /* ExportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExportView.swift; sourceTree = "<group>"; };
|
A949F83C2DCAABE00064DCA0 /* AddEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddEventView.swift; sourceTree = "<group>"; };
|
||||||
A977CC912DBBB48000DED8C0 /* ArchiveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArchiveView.swift; sourceTree = "<group>"; };
|
A949F83D2DCAABE00064DCA0 /* EditEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditEventView.swift; sourceTree = "<group>"; };
|
||||||
A977CC992DBD74FE00DED8C0 /* HelpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpView.swift; sourceTree = "<group>"; };
|
A949F83F2DCAABE00064DCA0 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||||
A979F57E2D26B1300094C0B3 /* EditEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditEventView.swift; sourceTree = "<group>"; };
|
A949F8402DCAABE00064DCA0 /* EventListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventListView.swift; sourceTree = "<group>"; };
|
||||||
|
A949F8412DCAABE00064DCA0 /* HelpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpView.swift; sourceTree = "<group>"; };
|
||||||
|
A949F8432DCAABE00064DCA0 /* ExportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExportView.swift; sourceTree = "<group>"; };
|
||||||
|
A949F8442DCAABE00064DCA0 /* iCloudSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iCloudSettingsView.swift; sourceTree = "<group>"; };
|
||||||
|
A949F8452DCAABE00064DCA0 /* ImportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportView.swift; sourceTree = "<group>"; };
|
||||||
|
A949F8462DCAABE00064DCA0 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
|
||||||
|
A949F8482DCAABE00064DCA0 /* StatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsView.swift; sourceTree = "<group>"; };
|
||||||
|
A949F8572DCAAD670064DCA0 /* NearFutureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureTests.swift; sourceTree = "<group>"; };
|
||||||
|
A949F85D2DCABB420064DCA0 /* Buttons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Buttons.swift; sourceTree = "<group>"; };
|
||||||
A979F58B2D2700680094C0B3 /* NearFutureWidgetsBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureWidgetsBundle.swift; sourceTree = "<group>"; };
|
A979F58B2D2700680094C0B3 /* NearFutureWidgetsBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureWidgetsBundle.swift; sourceTree = "<group>"; };
|
||||||
A979F58D2D2700680094C0B3 /* NearFutureWidgetsLiveActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureWidgetsLiveActivity.swift; sourceTree = "<group>"; };
|
A979F58D2D2700680094C0B3 /* NearFutureWidgetsLiveActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureWidgetsLiveActivity.swift; sourceTree = "<group>"; };
|
||||||
A979F58F2D2700680094C0B3 /* NearFutureWidgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureWidgets.swift; sourceTree = "<group>"; };
|
A979F58F2D2700680094C0B3 /* NearFutureWidgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureWidgets.swift; sourceTree = "<group>"; };
|
||||||
@@ -97,16 +114,10 @@
|
|||||||
A979F6112D270AF90094C0B3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
A979F6112D270AF90094C0B3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
A980FC302D920097006A778F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
A980FC302D920097006A778F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
A980FC372D93FB2B006A778F /* NearFutureTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NearFutureTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
A980FC372D93FB2B006A778F /* NearFutureTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NearFutureTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
A985104D2DB256430013D5FF /* iCloudSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iCloudSettingsView.swift; sourceTree = "<group>"; };
|
|
||||||
A985104F2DB263F00013D5FF /* EventListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventListView.swift; sourceTree = "<group>"; };
|
|
||||||
A9C05E412D2805D7007DC497 /* NearFutureWidgetsExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NearFutureWidgetsExtension.entitlements; sourceTree = "<group>"; };
|
A9C05E412D2805D7007DC497 /* NearFutureWidgetsExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NearFutureWidgetsExtension.entitlements; sourceTree = "<group>"; };
|
||||||
A9FC7EE92D28238A0020D75B /* NearFutureWidgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureWidgets.swift; sourceTree = "<group>"; };
|
A9FC7EE92D28238A0020D75B /* NearFutureWidgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureWidgets.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
|
||||||
A980FC382D93FB2B006A778F /* NearFutureTests */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = NearFutureTests; sourceTree = "<group>"; };
|
|
||||||
/* End PBXFileSystemSynchronizedRootGroup section */
|
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
A920C2812D24011300E4F9B1 /* Frameworks */ = {
|
A920C2812D24011300E4F9B1 /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
@@ -139,9 +150,10 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
A90FDE222DC0D4310012790C /* Config.xcconfig */,
|
A90FDE222DC0D4310012790C /* Config.xcconfig */,
|
||||||
|
A949F8002DCAA0340064DCA0 /* Resources */,
|
||||||
A920C2862D24011400E4F9B1 /* NearFuture */,
|
A920C2862D24011400E4F9B1 /* NearFuture */,
|
||||||
A979F6082D270AF00094C0B3 /* NearFutureWidgets */,
|
A979F6082D270AF00094C0B3 /* NearFutureWidgets */,
|
||||||
A980FC382D93FB2B006A778F /* NearFutureTests */,
|
A949F8582DCAAD670064DCA0 /* NearFutureTests */,
|
||||||
A979F6032D270AF00094C0B3 /* Frameworks */,
|
A979F6032D270AF00094C0B3 /* Frameworks */,
|
||||||
A920C2852D24011400E4F9B1 /* Products */,
|
A920C2852D24011400E4F9B1 /* Products */,
|
||||||
);
|
);
|
||||||
@@ -162,19 +174,8 @@
|
|||||||
children = (
|
children = (
|
||||||
A920C2872D24011400E4F9B1 /* NearFutureApp.swift */,
|
A920C2872D24011400E4F9B1 /* NearFutureApp.swift */,
|
||||||
A920C28B2D24011400E4F9B1 /* Item.swift */,
|
A920C28B2D24011400E4F9B1 /* Item.swift */,
|
||||||
A920C2C02D2403CA00E4F9B1 /* ContentView.swift */,
|
A949F84A2DCAABE00064DCA0 /* Views */,
|
||||||
A985104F2DB263F00013D5FF /* EventListView.swift */,
|
|
||||||
A920C2B72D2401A300E4F9B1 /* AddEventView.swift */,
|
|
||||||
A979F57E2D26B1300094C0B3 /* EditEventView.swift */,
|
|
||||||
A977CC912DBBB48000DED8C0 /* ArchiveView.swift */,
|
|
||||||
A93BC0932D2B18A3002E8BBD /* StatsView.swift */,
|
|
||||||
A977CC992DBD74FE00DED8C0 /* HelpView.swift */,
|
|
||||||
A920C2B42D2401A100E4F9B1 /* SettingsView.swift */,
|
|
||||||
A973B26B2DC551310028F8A2 /* ImportView.swift */,
|
|
||||||
A973B26F2DC552EB0028F8A2 /* ExportView.swift */,
|
|
||||||
A985104D2DB256430013D5FF /* iCloudSettingsView.swift */,
|
|
||||||
A980FC302D920097006A778F /* Info.plist */,
|
A980FC302D920097006A778F /* Info.plist */,
|
||||||
A920C28D2D24011A00E4F9B1 /* Assets.xcassets */,
|
|
||||||
A920C28F2D24011A00E4F9B1 /* NearFuture.entitlements */,
|
A920C28F2D24011A00E4F9B1 /* NearFuture.entitlements */,
|
||||||
A920C2902D24011A00E4F9B1 /* Preview Content */,
|
A920C2902D24011A00E4F9B1 /* Preview Content */,
|
||||||
);
|
);
|
||||||
@@ -190,6 +191,96 @@
|
|||||||
path = "Preview Content";
|
path = "Preview Content";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
A949F8002DCAA0340064DCA0 /* Resources */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
A949F8312DCAAA8A0064DCA0 /* NearFutureIcon.png */,
|
||||||
|
A920C28D2D24011A00E4F9B1 /* Assets.xcassets */,
|
||||||
|
A949F82E2DCAAA640064DCA0 /* NearFutureIcon.pxd */,
|
||||||
|
A949F82F2DCAAA640064DCA0 /* NearFutureIconDark.pxd */,
|
||||||
|
A949F8302DCAAA640064DCA0 /* NearFutureIconTint.pxd */,
|
||||||
|
);
|
||||||
|
path = Resources;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
A949F83B2DCAABE00064DCA0 /* Archive */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
A949F83A2DCAABE00064DCA0 /* ArchiveView.swift */,
|
||||||
|
);
|
||||||
|
path = Archive;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
A949F83E2DCAABE00064DCA0 /* Events */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
A949F83C2DCAABE00064DCA0 /* AddEventView.swift */,
|
||||||
|
A949F83D2DCAABE00064DCA0 /* EditEventView.swift */,
|
||||||
|
);
|
||||||
|
path = Events;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
A949F8422DCAABE00064DCA0 /* Home */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
A949F83F2DCAABE00064DCA0 /* ContentView.swift */,
|
||||||
|
A949F8402DCAABE00064DCA0 /* EventListView.swift */,
|
||||||
|
A949F8412DCAABE00064DCA0 /* HelpView.swift */,
|
||||||
|
A914FA4A2DD26C0F00856265 /* HomeView.swift */,
|
||||||
|
);
|
||||||
|
path = Home;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
A949F8472DCAABE00064DCA0 /* Settings */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
A949F8462DCAABE00064DCA0 /* SettingsView.swift */,
|
||||||
|
A949F8442DCAABE00064DCA0 /* iCloudSettingsView.swift */,
|
||||||
|
A914FA4C2DD2768900856265 /* WhatsNewView.swift */,
|
||||||
|
A949F8452DCAABE00064DCA0 /* ImportView.swift */,
|
||||||
|
A949F8432DCAABE00064DCA0 /* ExportView.swift */,
|
||||||
|
);
|
||||||
|
path = Settings;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
A949F8492DCAABE00064DCA0 /* Stats */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
A949F8482DCAABE00064DCA0 /* StatsView.swift */,
|
||||||
|
);
|
||||||
|
path = Stats;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
A949F84A2DCAABE00064DCA0 /* Views */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
A949F8422DCAABE00064DCA0 /* Home */,
|
||||||
|
A949F83E2DCAABE00064DCA0 /* Events */,
|
||||||
|
A949F83B2DCAABE00064DCA0 /* Archive */,
|
||||||
|
A949F85E2DCABB420064DCA0 /* Misc */,
|
||||||
|
A949F8492DCAABE00064DCA0 /* Stats */,
|
||||||
|
A949F8472DCAABE00064DCA0 /* Settings */,
|
||||||
|
);
|
||||||
|
path = Views;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
A949F8582DCAAD670064DCA0 /* NearFutureTests */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
A949F8572DCAAD670064DCA0 /* NearFutureTests.swift */,
|
||||||
|
);
|
||||||
|
path = NearFutureTests;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
A949F85E2DCABB420064DCA0 /* Misc */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
A949F85D2DCABB420064DCA0 /* Buttons.swift */,
|
||||||
|
A914FA4E2DD276D200856265 /* AboutView.swift */,
|
||||||
|
);
|
||||||
|
path = Misc;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
A979F58A2D2700680094C0B3 /* NearFutureWidgets */ = {
|
A979F58A2D2700680094C0B3 /* NearFutureWidgets */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -280,9 +371,6 @@
|
|||||||
dependencies = (
|
dependencies = (
|
||||||
A980FC3C2D93FB2B006A778F /* PBXTargetDependency */,
|
A980FC3C2D93FB2B006A778F /* PBXTargetDependency */,
|
||||||
);
|
);
|
||||||
fileSystemSynchronizedGroups = (
|
|
||||||
A980FC382D93FB2B006A778F /* NearFutureTests */,
|
|
||||||
);
|
|
||||||
name = NearFutureTests;
|
name = NearFutureTests;
|
||||||
packageProductDependencies = (
|
packageProductDependencies = (
|
||||||
);
|
);
|
||||||
@@ -341,6 +429,7 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
A920C2922D24011A00E4F9B1 /* Preview Assets.xcassets in Resources */,
|
A920C2922D24011A00E4F9B1 /* Preview Assets.xcassets in Resources */,
|
||||||
|
A949F8322DCAAA8A0064DCA0 /* NearFutureIcon.png in Resources */,
|
||||||
A920C28E2D24011A00E4F9B1 /* Assets.xcassets in Resources */,
|
A920C28E2D24011A00E4F9B1 /* Assets.xcassets in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -367,19 +456,23 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
A920C2BB2D2401A400E4F9B1 /* AddEventView.swift in Sources */,
|
|
||||||
A973B26C2DC551310028F8A2 /* ImportView.swift in Sources */,
|
|
||||||
A98510502DB263F00013D5FF /* EventListView.swift in Sources */,
|
|
||||||
A920C2C12D2403CA00E4F9B1 /* ContentView.swift in Sources */,
|
|
||||||
A973B2712DC553050028F8A2 /* ExportView.swift in Sources */,
|
|
||||||
A920C2B82D2401A300E4F9B1 /* SettingsView.swift in Sources */,
|
|
||||||
A977CC9A2DBD74FE00DED8C0 /* HelpView.swift in Sources */,
|
|
||||||
A920C28C2D24011400E4F9B1 /* Item.swift in Sources */,
|
A920C28C2D24011400E4F9B1 /* Item.swift in Sources */,
|
||||||
|
A949F84B2DCAABE00064DCA0 /* ArchiveView.swift in Sources */,
|
||||||
|
A914FA4F2DD276D200856265 /* AboutView.swift in Sources */,
|
||||||
|
A949F84C2DCAABE00064DCA0 /* AddEventView.swift in Sources */,
|
||||||
|
A914FA4B2DD26C6800856265 /* HomeView.swift in Sources */,
|
||||||
|
A949F84D2DCAABE00064DCA0 /* EditEventView.swift in Sources */,
|
||||||
|
A949F84E2DCAABE00064DCA0 /* ContentView.swift in Sources */,
|
||||||
|
A949F84F2DCAABE00064DCA0 /* EventListView.swift in Sources */,
|
||||||
|
A949F8502DCAABE00064DCA0 /* HelpView.swift in Sources */,
|
||||||
|
A949F85F2DCABB420064DCA0 /* Buttons.swift in Sources */,
|
||||||
|
A914FA4D2DD2768900856265 /* WhatsNewView.swift in Sources */,
|
||||||
|
A949F8512DCAABE00064DCA0 /* ExportView.swift in Sources */,
|
||||||
|
A949F8522DCAABE00064DCA0 /* iCloudSettingsView.swift in Sources */,
|
||||||
|
A949F8532DCAABE00064DCA0 /* ImportView.swift in Sources */,
|
||||||
|
A949F8542DCAABE00064DCA0 /* SettingsView.swift in Sources */,
|
||||||
|
A949F8552DCAABE00064DCA0 /* StatsView.swift in Sources */,
|
||||||
A920C2882D24011400E4F9B1 /* NearFutureApp.swift in Sources */,
|
A920C2882D24011400E4F9B1 /* NearFutureApp.swift in Sources */,
|
||||||
A93BC0942D2B18A3002E8BBD /* StatsView.swift in Sources */,
|
|
||||||
A977CC922DBBB48000DED8C0 /* ArchiveView.swift in Sources */,
|
|
||||||
A979F57F2D26B1300094C0B3 /* EditEventView.swift in Sources */,
|
|
||||||
A985104E2DB256430013D5FF /* iCloudSettingsView.swift in Sources */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -398,7 +491,8 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
A973B2702DC552EB0028F8A2 /* ExportView.swift in Sources */,
|
A949F8592DCAAD670064DCA0 /* NearFutureTests.swift in Sources */,
|
||||||
|
A949F8562DCAABE00064DCA0 /* ExportView.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -423,7 +517,10 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "Bloo Blue Green Pink Purple Red Yellow";
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
@@ -483,7 +580,7 @@
|
|||||||
);
|
);
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 6.0;
|
SWIFT_VERSION = 5.0;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
@@ -491,7 +588,10 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "Bloo Blue Green Pink Purple Red Yellow";
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
@@ -539,7 +639,7 @@
|
|||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
SWIFT_COMPILATION_MODE = wholemodule;
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
SWIFT_VERSION = 6.0;
|
SWIFT_VERSION = 5.0;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
@@ -547,8 +647,10 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = A90FDE222DC0D4310012790C /* Config.xcconfig */;
|
baseConfigurationReference = A90FDE222DC0D4310012790C /* Config.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "bloo blue green pink purple red yellow";
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
CLANG_USE_OPTIMIZATION_PROFILE = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = NearFuture/NearFuture.entitlements;
|
CODE_SIGN_ENTITLEMENTS = NearFuture/NearFuture.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = "$(BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(BUILD_NUMBER)";
|
||||||
@@ -582,10 +684,10 @@
|
|||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID)";
|
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID)";
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
REGISTER_APP_GROUPS = NO;
|
REGISTER_APP_GROUPS = YES;
|
||||||
SDKROOT = auto;
|
SDKROOT = auto;
|
||||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
SUPPORTS_MACCATALYST = NO;
|
SUPPORTS_MACCATALYST = YES;
|
||||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
|
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
|
||||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES;
|
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES;
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
@@ -598,8 +700,10 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = A90FDE222DC0D4310012790C /* Config.xcconfig */;
|
baseConfigurationReference = A90FDE222DC0D4310012790C /* Config.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "bloo blue green pink purple red yellow";
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
CLANG_USE_OPTIMIZATION_PROFILE = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = NearFuture/NearFuture.entitlements;
|
CODE_SIGN_ENTITLEMENTS = NearFuture/NearFuture.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = "$(BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(BUILD_NUMBER)";
|
||||||
@@ -630,10 +734,10 @@
|
|||||||
OTHER_LDFLAGS = "";
|
OTHER_LDFLAGS = "";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID)";
|
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID)";
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
REGISTER_APP_GROUPS = NO;
|
REGISTER_APP_GROUPS = YES;
|
||||||
SDKROOT = auto;
|
SDKROOT = auto;
|
||||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
SUPPORTS_MACCATALYST = NO;
|
SUPPORTS_MACCATALYST = YES;
|
||||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
|
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
|
||||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES;
|
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES;
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
@@ -648,6 +752,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||||
|
CLANG_USE_OPTIMIZATION_PROFILE = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = NearFutureWidgets/NearFutureWidgetsExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = NearFutureWidgets/NearFutureWidgetsExtension.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = "$(BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(BUILD_NUMBER)";
|
||||||
@@ -662,6 +767,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 14;
|
||||||
MARKETING_VERSION = "$(VERSION)";
|
MARKETING_VERSION = "$(VERSION)";
|
||||||
OTHER_LDFLAGS = (
|
OTHER_LDFLAGS = (
|
||||||
"-Xlinker",
|
"-Xlinker",
|
||||||
@@ -669,10 +775,11 @@
|
|||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_WIDGETS)";
|
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_WIDGETS)";
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
REGISTER_APP_GROUPS = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
SUPPORTS_MACCATALYST = NO;
|
SUPPORTS_MACCATALYST = YES;
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
@@ -686,6 +793,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||||
|
CLANG_USE_OPTIMIZATION_PROFILE = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = NearFutureWidgets/NearFutureWidgetsExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = NearFutureWidgets/NearFutureWidgetsExtension.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = "$(BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(BUILD_NUMBER)";
|
||||||
@@ -700,13 +808,15 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 14;
|
||||||
MARKETING_VERSION = "$(VERSION)";
|
MARKETING_VERSION = "$(VERSION)";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_WIDGETS)";
|
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_WIDGETS)";
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
REGISTER_APP_GROUPS = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
SUPPORTS_MACCATALYST = NO;
|
SUPPORTS_MACCATALYST = YES;
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Scheme
|
|
||||||
LastUpgradeVersion = "1630"
|
|
||||||
version = "1.7">
|
|
||||||
<BuildAction
|
|
||||||
parallelizeBuildables = "YES"
|
|
||||||
buildImplicitDependencies = "YES"
|
|
||||||
buildArchitectures = "Automatic">
|
|
||||||
<BuildActionEntries>
|
|
||||||
<BuildActionEntry
|
|
||||||
buildForTesting = "YES"
|
|
||||||
buildForRunning = "YES"
|
|
||||||
buildForProfiling = "YES"
|
|
||||||
buildForArchiving = "YES"
|
|
||||||
buildForAnalyzing = "YES">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "A920C2832D24011300E4F9B1"
|
|
||||||
BuildableName = "NearFuture.app"
|
|
||||||
BlueprintName = "NearFuture"
|
|
||||||
ReferencedContainer = "container:NearFuture.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildActionEntry>
|
|
||||||
</BuildActionEntries>
|
|
||||||
</BuildAction>
|
|
||||||
<TestAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
||||||
shouldAutocreateTestPlan = "YES">
|
|
||||||
</TestAction>
|
|
||||||
<LaunchAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = ""
|
|
||||||
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
|
||||||
launchStyle = "0"
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
|
||||||
debugDocumentVersioning = "YES"
|
|
||||||
debugServiceExtension = "internal"
|
|
||||||
allowLocationSimulation = "YES">
|
|
||||||
<BuildableProductRunnable
|
|
||||||
runnableDebuggingMode = "0">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "A920C2832D24011300E4F9B1"
|
|
||||||
BuildableName = "NearFuture.app"
|
|
||||||
BlueprintName = "NearFuture"
|
|
||||||
ReferencedContainer = "container:NearFuture.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildableProductRunnable>
|
|
||||||
</LaunchAction>
|
|
||||||
<ProfileAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
||||||
savedToolIdentifier = ""
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
debugDocumentVersioning = "YES">
|
|
||||||
<BuildableProductRunnable
|
|
||||||
runnableDebuggingMode = "0">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "A920C2832D24011300E4F9B1"
|
|
||||||
BuildableName = "NearFuture.app"
|
|
||||||
BlueprintName = "NearFuture"
|
|
||||||
ReferencedContainer = "container:NearFuture.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildableProductRunnable>
|
|
||||||
</ProfileAction>
|
|
||||||
<AnalyzeAction
|
|
||||||
buildConfiguration = "Debug">
|
|
||||||
</AnalyzeAction>
|
|
||||||
<ArchiveAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
revealArchiveInOrganizer = "YES">
|
|
||||||
</ArchiveAction>
|
|
||||||
</Scheme>
|
|
||||||
@@ -4,11 +4,6 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>SchemeUserState</key>
|
<key>SchemeUserState</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NearFuture nodebug.xcscheme_^#shared#^_</key>
|
|
||||||
<dict>
|
|
||||||
<key>orderHint</key>
|
|
||||||
<integer>2</integer>
|
|
||||||
</dict>
|
|
||||||
<key>NearFuture.xcscheme_^#shared#^_</key>
|
<key>NearFuture.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
|
|||||||
@@ -1,262 +0,0 @@
|
|||||||
//
|
|
||||||
// AddEventView.swift
|
|
||||||
// NearFuture
|
|
||||||
//
|
|
||||||
// Created by Nihaal Sharma on 25/12/2024.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
import SFSymbolsPicker
|
|
||||||
|
|
||||||
struct AddEventView: View {
|
|
||||||
@ObservedObject var viewModel: EventViewModel
|
|
||||||
|
|
||||||
@Binding var eventName: String
|
|
||||||
@Binding var eventComplete: Bool
|
|
||||||
@Binding var eventCompleteDesc: String
|
|
||||||
@Binding var eventSymbol: String
|
|
||||||
@Binding var eventColor: Color
|
|
||||||
@Binding var eventNotes: String
|
|
||||||
@Binding var eventDate: Date
|
|
||||||
@Binding var eventRecurrence: Event.RecurrenceType
|
|
||||||
|
|
||||||
@State var adding: Bool
|
|
||||||
@State var showNeedsNameAlert: Bool = false
|
|
||||||
@State var isSymbolPickerPresented = false
|
|
||||||
|
|
||||||
@FocusState private var focusedField: Field?
|
|
||||||
private enum Field {
|
|
||||||
case Name, Notes
|
|
||||||
}
|
|
||||||
|
|
||||||
@Environment(\.dismiss) var dismiss
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
NavigationStack {
|
|
||||||
Form {
|
|
||||||
Section(
|
|
||||||
header:
|
|
||||||
Text("Event Details")
|
|
||||||
.font(.headline)
|
|
||||||
.foregroundColor(.accentColor)
|
|
||||||
) {
|
|
||||||
// name & symbol
|
|
||||||
HStack(spacing: 5) {
|
|
||||||
Button() {
|
|
||||||
isSymbolPickerPresented.toggle()
|
|
||||||
} label: {
|
|
||||||
Image(systemName: eventSymbol)
|
|
||||||
.resizable()
|
|
||||||
.scaledToFit()
|
|
||||||
.frame(width: 20, height: 20)
|
|
||||||
.foregroundStyle(eventColor)
|
|
||||||
}
|
|
||||||
.frame(width: 20)
|
|
||||||
.buttonStyle(.borderless)
|
|
||||||
.sheet(isPresented: $isSymbolPickerPresented) {
|
|
||||||
SymbolsPicker(
|
|
||||||
selection: $eventSymbol,
|
|
||||||
title: "Choose a Symbol",
|
|
||||||
searchLabel: "Search...",
|
|
||||||
autoDismiss: true)
|
|
||||||
.apply {
|
|
||||||
if #available(iOS 16.4, *) {
|
|
||||||
$0.presentationBackground(.ultraThinMaterial)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ColorPicker("", selection: $eventColor, supportsOpacity: false)
|
|
||||||
.fixedSize()
|
|
||||||
ZStack {
|
|
||||||
TextField("Event Name", text: $eventName)
|
|
||||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
|
||||||
.padding(.trailing, eventName.isEmpty ? 0 : 30)
|
|
||||||
.animation(.spring, value: eventName)
|
|
||||||
.focused($focusedField, equals: Field.Name)
|
|
||||||
.submitLabel(.next)
|
|
||||||
.onSubmit {
|
|
||||||
focusedField = .Notes
|
|
||||||
}
|
|
||||||
MagicClearButton(text: $eventName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// dscription
|
|
||||||
ZStack {
|
|
||||||
TextField("Event Notes", text: $eventNotes)
|
|
||||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
|
||||||
.padding(.trailing, eventNotes.isEmpty ? 0 : 30)
|
|
||||||
.animation(.spring, value: eventNotes)
|
|
||||||
.focused($focusedField, equals: Field.Notes)
|
|
||||||
.submitLabel(.done)
|
|
||||||
.onSubmit {
|
|
||||||
focusedField = nil
|
|
||||||
}
|
|
||||||
MagicClearButton(text: $eventNotes)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// date picker
|
|
||||||
HStack {
|
|
||||||
Spacer()
|
|
||||||
DatePicker("", selection: $eventDate, displayedComponents: .date)
|
|
||||||
.datePickerStyle(WheelDatePickerStyle())
|
|
||||||
Spacer()
|
|
||||||
Button() {
|
|
||||||
eventDate = Date()
|
|
||||||
} label: {
|
|
||||||
Image(systemName: "arrow.uturn.left")
|
|
||||||
.resizable()
|
|
||||||
.scaledToFit()
|
|
||||||
}
|
|
||||||
.buttonStyle(BorderlessButtonStyle())
|
|
||||||
.frame(width: 20)
|
|
||||||
}
|
|
||||||
|
|
||||||
DatePicker(
|
|
||||||
"",
|
|
||||||
selection: $eventDate,
|
|
||||||
displayedComponents: .hourAndMinute
|
|
||||||
)
|
|
||||||
|
|
||||||
// re-ocurrence Picker
|
|
||||||
Picker("Recurrence", selection: $eventRecurrence) {
|
|
||||||
ForEach(Event.RecurrenceType.allCases, id: \.self) { recurrence in
|
|
||||||
Text(recurrence.rawValue.capitalized)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.pickerStyle(SegmentedPickerStyle())
|
|
||||||
Text(
|
|
||||||
describeOccurrence(
|
|
||||||
date: eventDate,
|
|
||||||
recurrence: eventRecurrence
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.scrollContentBackground(.hidden)
|
|
||||||
.navigationTitle("\(adding ? "Add Event" : "")")
|
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
|
||||||
.toolbar {
|
|
||||||
ToolbarItem(placement: .topBarLeading) {
|
|
||||||
if adding {
|
|
||||||
Button() {
|
|
||||||
resetAddEventView()
|
|
||||||
dismiss()
|
|
||||||
} label: {
|
|
||||||
Image(systemName: "xmark.circle.fill")
|
|
||||||
.symbolRenderingMode(.hierarchical)
|
|
||||||
.resizable()
|
|
||||||
.scaledToFit()
|
|
||||||
.frame(width: 30)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ToolbarItem(placement: .topBarTrailing) {
|
|
||||||
if adding {
|
|
||||||
Button {
|
|
||||||
viewModel.addEvent(
|
|
||||||
newEvent: Event(
|
|
||||||
name: eventName,
|
|
||||||
complete: eventComplete,
|
|
||||||
completeDesc: eventCompleteDesc,
|
|
||||||
symbol: eventSymbol,
|
|
||||||
color: ColorCodable(eventColor),
|
|
||||||
notes: eventNotes,
|
|
||||||
date: eventDate,
|
|
||||||
recurrence: eventRecurrence
|
|
||||||
)
|
|
||||||
)
|
|
||||||
resetAddEventView()
|
|
||||||
} label: {
|
|
||||||
Text("Save")
|
|
||||||
.font(.headline)
|
|
||||||
.cornerRadius(10)
|
|
||||||
.buttonStyle(BorderedProminentButtonStyle())
|
|
||||||
}
|
|
||||||
.disabled(eventName.isEmpty)
|
|
||||||
.onTapGesture {
|
|
||||||
if eventName.isEmpty {
|
|
||||||
showNeedsNameAlert.toggle()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.alert("Missing Name", isPresented: $showNeedsNameAlert) {
|
|
||||||
Button("OK", role: .cancel) {
|
|
||||||
showNeedsNameAlert.toggle()
|
|
||||||
focusedField = .Name
|
|
||||||
}
|
|
||||||
} message: {
|
|
||||||
Text("Give your Event a name before saving.")
|
|
||||||
}
|
|
||||||
if eventName.isEmpty {
|
|
||||||
HStack {
|
|
||||||
Image(systemName: "exclamationmark")
|
|
||||||
.foregroundStyle(.red)
|
|
||||||
Text("Give your event a name.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func resetAddEventView() {
|
|
||||||
//reset addeventView
|
|
||||||
eventName = viewModel.template.name
|
|
||||||
eventComplete = viewModel.template.complete
|
|
||||||
eventCompleteDesc = viewModel.template.completeDesc
|
|
||||||
eventSymbol = viewModel.template.symbol
|
|
||||||
eventColor = randomColor()
|
|
||||||
eventNotes = viewModel.template.notes
|
|
||||||
eventDate = viewModel.template.date
|
|
||||||
eventRecurrence = viewModel.template.recurrence
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
struct MagicClearButton: View {
|
|
||||||
@Binding var text: String
|
|
||||||
var body: some View {
|
|
||||||
HStack {
|
|
||||||
Spacer()
|
|
||||||
Button {
|
|
||||||
text = ""
|
|
||||||
} label: {
|
|
||||||
Image(systemName: "xmark.circle.fill")
|
|
||||||
.resizable()
|
|
||||||
.scaledToFit()
|
|
||||||
.frame(width: text.isEmpty ? 0 : 25)
|
|
||||||
.symbolRenderingMode(.hierarchical)
|
|
||||||
.padding(.trailing, -5)
|
|
||||||
.animation(.spring, value: text.isEmpty)
|
|
||||||
}
|
|
||||||
.buttonStyle(.borderless)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#Preview {
|
|
||||||
let vm = dummyEventViewModel()
|
|
||||||
Color.orange
|
|
||||||
.ignoresSafeArea(.all)
|
|
||||||
.sheet(isPresented: .constant(true)) {
|
|
||||||
AddEventView(
|
|
||||||
viewModel: vm,
|
|
||||||
eventName: .constant(vm.template.notes),
|
|
||||||
eventComplete: .constant(vm.template.complete),
|
|
||||||
eventCompleteDesc: .constant(vm.template.completeDesc),
|
|
||||||
eventSymbol: .constant(vm.template.symbol),
|
|
||||||
eventColor: .constant(vm.template.color.color),
|
|
||||||
eventNotes: .constant(vm.template.notes),
|
|
||||||
eventDate: .constant(vm.template.date),
|
|
||||||
eventRecurrence: .constant(vm.template.recurrence),
|
|
||||||
adding: true
|
|
||||||
)
|
|
||||||
.presentationDragIndicator(.visible)
|
|
||||||
.apply {
|
|
||||||
if #available(iOS 16.4, *) {
|
|
||||||
$0.presentationBackground(.ultraThinMaterial)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"colors" : [
|
|
||||||
{
|
|
||||||
"color" : {
|
|
||||||
"color-space" : "display-p3",
|
|
||||||
"components" : {
|
|
||||||
"alpha" : "1.000",
|
|
||||||
"blue" : "0.000",
|
|
||||||
"green" : "0.000",
|
|
||||||
"red" : "0.000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"idiom" : "universal"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"appearances" : [
|
|
||||||
{
|
|
||||||
"appearance" : "luminosity",
|
|
||||||
"value" : "dark"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"color" : {
|
|
||||||
"color-space" : "display-p3",
|
|
||||||
"components" : {
|
|
||||||
"alpha" : "1.000",
|
|
||||||
"blue" : "1.000",
|
|
||||||
"green" : "1.000",
|
|
||||||
"red" : "1.000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"idiom" : "universal"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,216 +0,0 @@
|
|||||||
//
|
|
||||||
// ContentView.swift
|
|
||||||
// NearFuture
|
|
||||||
//
|
|
||||||
// Created by Nihaal Sharma on 24/12/2024.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
import SwiftData
|
|
||||||
|
|
||||||
enum Field {
|
|
||||||
case Search
|
|
||||||
}
|
|
||||||
enum Tab {
|
|
||||||
case Home
|
|
||||||
case Archive
|
|
||||||
case Statistics
|
|
||||||
case Settings
|
|
||||||
case Gradient
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ContentView: View {
|
|
||||||
@StateObject var viewModel: EventViewModel
|
|
||||||
@StateObject var settingsModel: SettingsViewModel
|
|
||||||
@State private var eventName = ""
|
|
||||||
@State private var eventComplete = false
|
|
||||||
@State private var eventCompleteDesc = ""
|
|
||||||
@State private var eventSymbol = "star"
|
|
||||||
@State private var eventColor: Color = randomColor()
|
|
||||||
@State private var eventNotes = ""
|
|
||||||
@State private var eventDate = Date()
|
|
||||||
@State private var eventRecurrence: Event.RecurrenceType = .none
|
|
||||||
@State var hey: UUID = UUID()
|
|
||||||
@State private var showingAddEventView = false
|
|
||||||
@State private var searchInput: String = ""
|
|
||||||
var filteredEvents: [Event] {
|
|
||||||
if searchInput.isEmpty {
|
|
||||||
return viewModel.events.filter() {!$0.complete}
|
|
||||||
} else {
|
|
||||||
return viewModel.events.filter {
|
|
||||||
$0.name.localizedCaseInsensitiveContains(searchInput) ||
|
|
||||||
$0.notes.localizedCaseInsensitiveContains(searchInput)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var noEvents: Bool {
|
|
||||||
if viewModel.events.count == 0 {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@FocusState private var focusedField: Field?
|
|
||||||
@FocusState private var focusedTab: Tab?
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
TabView {
|
|
||||||
NavigationStack {
|
|
||||||
ZStack {
|
|
||||||
backgroundGradient
|
|
||||||
VStack {
|
|
||||||
ZStack {
|
|
||||||
SearchBar(searchInput: $searchInput)
|
|
||||||
.focused($focusedField, equals: Field.Search)
|
|
||||||
.onSubmit {
|
|
||||||
focusedField = nil
|
|
||||||
}
|
|
||||||
MagicClearButton(text: $searchInput)
|
|
||||||
.onTapGesture {
|
|
||||||
focusedField = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.padding(.horizontal)
|
|
||||||
if filteredEvents.isEmpty && !searchInput.isEmpty {
|
|
||||||
HelpView(searchInput: $searchInput, focusedField: focusedField)
|
|
||||||
} else {
|
|
||||||
ScrollView {
|
|
||||||
ForEach(filteredEvents) { event in
|
|
||||||
EventListView(viewModel: viewModel, event: event)
|
|
||||||
}
|
|
||||||
.onDelete(perform: viewModel.removeEvent)
|
|
||||||
.id(hey)
|
|
||||||
.onReceive(viewModel.objectWillChange) {
|
|
||||||
hey = UUID()
|
|
||||||
}
|
|
||||||
.padding(.horizontal)
|
|
||||||
if /*!searchInput.isEmpty && */filteredEvents.isEmpty {
|
|
||||||
HelpView(
|
|
||||||
searchInput: $searchInput,
|
|
||||||
focusedField: focusedField
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.navigationTitle("Near Future")
|
|
||||||
.apply {
|
|
||||||
if #available(iOS 17, *) {
|
|
||||||
$0.toolbarTitleDisplayMode(.inlineLarge)
|
|
||||||
} else {
|
|
||||||
$0.navigationBarTitleDisplayMode(.inline)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.sheet(isPresented: $showingAddEventView) {
|
|
||||||
AddEventView(
|
|
||||||
viewModel: viewModel,
|
|
||||||
eventName: $eventName,
|
|
||||||
eventComplete: $eventComplete,
|
|
||||||
eventCompleteDesc: $eventCompleteDesc,
|
|
||||||
eventSymbol: $eventSymbol,
|
|
||||||
eventColor: $eventColor,
|
|
||||||
eventNotes: $eventNotes,
|
|
||||||
eventDate: $eventDate,
|
|
||||||
eventRecurrence: $eventRecurrence,
|
|
||||||
adding: true //adding event
|
|
||||||
)
|
|
||||||
.presentationDragIndicator(.visible)
|
|
||||||
.apply {
|
|
||||||
if #available(iOS 16.4, *) {
|
|
||||||
$0.presentationBackground(.ultraThinMaterial)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.toolbar {
|
|
||||||
ToolbarItem(placement: .topBarTrailing) {
|
|
||||||
AddEventButton(showingAddEventView: $showingAddEventView)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.tabItem {
|
|
||||||
Label("Home", systemImage: "house")
|
|
||||||
}
|
|
||||||
.focused($focusedTab, equals: Tab.Home)
|
|
||||||
ArchiveView(viewModel: viewModel)
|
|
||||||
.tabItem() {
|
|
||||||
Label("Archive", systemImage: "tray.full")
|
|
||||||
}
|
|
||||||
.focused($focusedTab, equals: Tab.Archive)
|
|
||||||
StatsView(viewModel: viewModel)
|
|
||||||
.tabItem {
|
|
||||||
Label("Statistics", systemImage: "chart.pie")
|
|
||||||
}
|
|
||||||
.focused($focusedTab, equals: Tab.Statistics)
|
|
||||||
SettingsView(viewModel: viewModel, settingsModel: settingsModel)
|
|
||||||
.tabItem {
|
|
||||||
Label("Settings", systemImage: "gear")
|
|
||||||
}
|
|
||||||
.focused($focusedTab, equals: Tab.Settings)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#Preview {
|
|
||||||
ContentView(
|
|
||||||
viewModel: dummyEventViewModel(),
|
|
||||||
settingsModel: dummySettingsViewModel()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SearchBar: View {
|
|
||||||
@Binding var searchInput: String
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
TextField(
|
|
||||||
"\(Image(systemName: "magnifyingglass")) Search",
|
|
||||||
text: $searchInput
|
|
||||||
)
|
|
||||||
.padding(.trailing, searchInput.isEmpty ? 0 : 30)
|
|
||||||
.animation(.spring, value: searchInput)
|
|
||||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
|
||||||
.submitLabel(.done)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AddEventButton: View {
|
|
||||||
@Binding var showingAddEventView: Bool
|
|
||||||
var body: some View {
|
|
||||||
Button() {
|
|
||||||
showingAddEventView.toggle()
|
|
||||||
} label: {
|
|
||||||
ZStack {
|
|
||||||
Circle()
|
|
||||||
.frame(width: 33)
|
|
||||||
.foregroundStyle(.one)
|
|
||||||
Image(systemName: "plus")
|
|
||||||
.resizable()
|
|
||||||
.scaledToFit()
|
|
||||||
.frame(width: 15)
|
|
||||||
.bold()
|
|
||||||
.foregroundStyle(.two)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension View {
|
|
||||||
var appearance: ColorScheme {
|
|
||||||
return UITraitCollection.current.userInterfaceStyle == .dark ? .dark : .light
|
|
||||||
}
|
|
||||||
var backgroundGradient: some View {
|
|
||||||
return LinearGradient(
|
|
||||||
gradient: Gradient(colors: [.bgTop, .two]),
|
|
||||||
startPoint: .top,
|
|
||||||
endPoint: .bottom
|
|
||||||
)
|
|
||||||
.ignoresSafeArea(.all)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension View {
|
|
||||||
func apply<V: View>(@ViewBuilder _ block: (Self) -> V) -> V { block(self) }
|
|
||||||
}
|
|
||||||
@@ -126,6 +126,7 @@ struct EventListView: View {
|
|||||||
)
|
)
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
}
|
}
|
||||||
|
.transition(.opacity)
|
||||||
.contextMenu() {
|
.contextMenu() {
|
||||||
Button(role: .destructive) {
|
Button(role: .destructive) {
|
||||||
let eventToModify = viewModel.events.firstIndex() { currEvent in
|
let eventToModify = viewModel.events.firstIndex() { currEvent in
|
||||||
@@ -1,5 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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">
|
<!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>AppIntents</key>
|
||||||
|
<array>
|
||||||
|
<string>com.neon443.NearFuture.CompleteEvent</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -2,13 +2,15 @@
|
|||||||
// Item.swift
|
// Item.swift
|
||||||
// NearFuture
|
// NearFuture
|
||||||
//
|
//
|
||||||
// Created by Nihaal Sharma on 24/12/2024.
|
// Created by neon443 on 24/12/2024.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import SwiftData
|
import SwiftData
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import WidgetKit
|
import WidgetKit
|
||||||
|
import UserNotifications
|
||||||
|
import AppIntents
|
||||||
|
|
||||||
//@Model
|
//@Model
|
||||||
//final class Item {
|
//final class Item {
|
||||||
@@ -19,7 +21,7 @@ import WidgetKit
|
|||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
struct Event: Identifiable, Codable {
|
struct Event: Identifiable, Codable, Equatable, Animatable {
|
||||||
var id = UUID()
|
var id = UUID()
|
||||||
var name: String
|
var name: String
|
||||||
var complete: Bool
|
var complete: Bool
|
||||||
@@ -106,27 +108,66 @@ func daysUntilEvent(_ eventDate: Date) -> (long: String, short: String) {
|
|||||||
struct Settings: Codable, Equatable {
|
struct Settings: Codable, Equatable {
|
||||||
var showCompletedInHome: Bool
|
var showCompletedInHome: Bool
|
||||||
var tint: ColorCodable
|
var tint: ColorCodable
|
||||||
|
var showWhatsNew: Bool
|
||||||
|
var prevAppVersion: String
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AccentIcon {
|
||||||
|
var icon: UIImage
|
||||||
|
var color: Color
|
||||||
|
var name: String
|
||||||
|
init(_ colorName: String) {
|
||||||
|
if colorName == "orange" {
|
||||||
|
self.icon = UIImage(named: "AppIcon")!
|
||||||
|
} else {
|
||||||
|
self.icon = UIImage(named: colorName)!
|
||||||
|
}
|
||||||
|
self.color = Color(uiColor: UIColor(named: "uiColors/\(colorName)")!)
|
||||||
|
self.name = colorName
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SettingsViewModel: ObservableObject {
|
class SettingsViewModel: ObservableObject {
|
||||||
@Published var settings: Settings = Settings(
|
@Published var settings: Settings = Settings(
|
||||||
showCompletedInHome: false,
|
showCompletedInHome: false,
|
||||||
tint: ColorCodable(uiColor: UIColor(named: "AccentColor")!)
|
tint: ColorCodable(uiColor: UIColor(named: "AccentColor")!),
|
||||||
|
showWhatsNew: true,
|
||||||
|
prevAppVersion: getVersion()+getBuildID()
|
||||||
)
|
)
|
||||||
|
@Published var notifsGranted: Bool = false
|
||||||
|
|
||||||
@Published var accentChoices: [Color] = [
|
@Published var colorChoices: [AccentIcon] = []
|
||||||
Color(UIColor(named: "uiColors/red")!),
|
|
||||||
Color(UIColor(named: "uiColors/orange")!),
|
let accentChoices: [String] = [
|
||||||
Color(UIColor(named: "uiColors/yellow")!),
|
"red",
|
||||||
Color(UIColor(named: "uiColors/green")!),
|
"orange",
|
||||||
Color(UIColor(named: "uiColors/blue")!),
|
"yellow",
|
||||||
Color(UIColor(named: "uiColors/indigo")!),
|
"green",
|
||||||
Color(UIColor(named: "uiColors/basic")!)
|
"blue",
|
||||||
|
"bloo",
|
||||||
|
"purple",
|
||||||
|
"pink"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@Published var device: (sf: String, label: String)
|
||||||
|
|
||||||
init(load: Bool = true) {
|
init(load: Bool = true) {
|
||||||
|
self.device = getDevice()
|
||||||
if load {
|
if load {
|
||||||
loadSettings()
|
loadSettings()
|
||||||
|
Task {
|
||||||
|
let requestResult = await requestNotifs()
|
||||||
|
await MainActor.run {
|
||||||
|
self.notifsGranted = requestResult
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func changeTint(to: String) {
|
||||||
|
if let uicolor = UIColor(named: "uiColors/\(to)") {
|
||||||
|
self.settings.tint = ColorCodable(uiColor: uicolor)
|
||||||
|
saveSettings()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,6 +185,9 @@ class SettingsViewModel: ObservableObject {
|
|||||||
self.settings = decodedSetts
|
self.settings = decodedSetts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if self.settings.prevAppVersion != getVersion()+getBuildID() {
|
||||||
|
self.settings.showWhatsNew = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveSettings() {
|
func saveSettings() {
|
||||||
@@ -157,7 +201,7 @@ class SettingsViewModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EventViewModel: ObservableObject {
|
class EventViewModel: ObservableObject, @unchecked Sendable {
|
||||||
@Published var events: [Event] = []
|
@Published var events: [Event] = []
|
||||||
@Published var icloudData: [Event] = []
|
@Published var icloudData: [Event] = []
|
||||||
|
|
||||||
@@ -219,6 +263,44 @@ class EventViewModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateSyncStatus()
|
updateSyncStatus()
|
||||||
|
self.events.sort() {$0.date < $1.date}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNotifs() async -> [UNNotificationRequest] {
|
||||||
|
return await UNUserNotificationCenter.current().pendingNotificationRequests()
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkPendingNotifs(_ pending: [UNNotificationRequest]) {
|
||||||
|
var eventUUIDs = events.map({$0.id.uuidString})
|
||||||
|
for req in pending {
|
||||||
|
//match the notif to an event
|
||||||
|
if let index = events.firstIndex(where: {$0.id.uuidString == req.identifier}) {
|
||||||
|
if let remove = eventUUIDs.firstIndex(where: {$0 == req.identifier}) {
|
||||||
|
eventUUIDs.remove(at: remove)
|
||||||
|
}
|
||||||
|
let components = getDateComponents(events[index].date)
|
||||||
|
//check the notif matches event details
|
||||||
|
if req.content.title == events[index].name,
|
||||||
|
req.content.subtitle == events[index].notes,
|
||||||
|
req.trigger == UNCalendarNotificationTrigger(dateMatching: components, repeats: false) {
|
||||||
|
//if it does, make sure the notif delets if u complete the veent
|
||||||
|
if events[index].complete {
|
||||||
|
cancelNotif(req.identifier)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cancelNotif(req.identifier)
|
||||||
|
scheduleEventNotif(events[index])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//cancel if the event is deleted
|
||||||
|
cancelNotif(req.identifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for uuid in eventUUIDs {
|
||||||
|
if let event = events.first(where: {$0.id.uuidString == uuid}) {
|
||||||
|
scheduleEventNotif(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// save to local and icloud
|
// save to local and icloud
|
||||||
@@ -233,6 +315,9 @@ class EventViewModel: ObservableObject {
|
|||||||
|
|
||||||
updateSyncStatus()
|
updateSyncStatus()
|
||||||
loadEvents()
|
loadEvents()
|
||||||
|
Task {
|
||||||
|
await checkPendingNotifs(getNotifs())
|
||||||
|
}
|
||||||
WidgetCenter.shared.reloadAllTimelines()//reload all widgets when saving events
|
WidgetCenter.shared.reloadAllTimelines()//reload all widgets when saving events
|
||||||
objectWillChange.send()
|
objectWillChange.send()
|
||||||
}
|
}
|
||||||
@@ -252,6 +337,7 @@ class EventViewModel: ObservableObject {
|
|||||||
|
|
||||||
func addEvent(newEvent: Event) {
|
func addEvent(newEvent: Event) {
|
||||||
events.append(newEvent)
|
events.append(newEvent)
|
||||||
|
scheduleEventNotif(newEvent)
|
||||||
saveEvents() //sync with icloud
|
saveEvents() //sync with icloud
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,6 +411,7 @@ class EventViewModel: ObservableObject {
|
|||||||
UserDefaults.standard.removeObject(forKey: "events")
|
UserDefaults.standard.removeObject(forKey: "events")
|
||||||
appGroupUserDefaults.removeObject(forKey: "events")
|
appGroupUserDefaults.removeObject(forKey: "events")
|
||||||
events.removeAll()
|
events.removeAll()
|
||||||
|
cancelAllNotifs()
|
||||||
updateSyncStatus()
|
updateSyncStatus()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,6 +419,7 @@ class EventViewModel: ObservableObject {
|
|||||||
icloudStore.removeObject(forKey: "events")
|
icloudStore.removeObject(forKey: "events")
|
||||||
icloudStore.synchronize()
|
icloudStore.synchronize()
|
||||||
icloudData.removeAll()
|
icloudData.removeAll()
|
||||||
|
cancelAllNotifs()
|
||||||
updateSyncStatus()
|
updateSyncStatus()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,6 +435,7 @@ class EventViewModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
events.removeAll()
|
events.removeAll()
|
||||||
|
cancelAllNotifs()
|
||||||
updateSyncStatus()
|
updateSyncStatus()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,14 +446,26 @@ class EventViewModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
icloudStore.synchronize()
|
icloudStore.synchronize()
|
||||||
icloudData.removeAll()
|
icloudData.removeAll()
|
||||||
|
cancelAllNotifs()
|
||||||
updateSyncStatus()
|
updateSyncStatus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class dummyEventViewModel: EventViewModel {
|
class dummyEventViewModel: EventViewModel, @unchecked Sendable {
|
||||||
|
var template2: Event
|
||||||
override init(load: Bool = false) {
|
override init(load: Bool = false) {
|
||||||
|
self.template2 = Event(
|
||||||
|
name: "template2",
|
||||||
|
complete: false,
|
||||||
|
completeDesc: "",
|
||||||
|
symbol: "hammer",
|
||||||
|
color: ColorCodable(randomColor()),
|
||||||
|
notes: "notes",
|
||||||
|
date: Date(),
|
||||||
|
recurrence: .none
|
||||||
|
)
|
||||||
super.init(load: false)
|
super.init(load: false)
|
||||||
self.events = [self.example, self.template, self.example, self.template]
|
self.events = [self.example, self.template, self.template2]
|
||||||
self.events[0].complete.toggle()
|
self.events[0].complete.toggle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -423,3 +524,124 @@ func plu(_ inp: Int) -> String {
|
|||||||
public enum importError: Error {
|
public enum importError: Error {
|
||||||
case invalidB64
|
case invalidB64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func requestNotifs() async -> Bool {
|
||||||
|
let result = try? await UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .carPlay, .sound])
|
||||||
|
return result ?? false
|
||||||
|
}
|
||||||
|
|
||||||
|
func scheduleNotif(title: String, sub: String, date: Date, id: String = UUID().uuidString) {
|
||||||
|
let content = UNMutableNotificationContent()
|
||||||
|
content.title = title
|
||||||
|
content.subtitle = sub
|
||||||
|
content.sound = .default
|
||||||
|
|
||||||
|
let identifier = id
|
||||||
|
let dateComponents = getDateComponents(date)
|
||||||
|
|
||||||
|
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
|
||||||
|
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)
|
||||||
|
UNUserNotificationCenter.current().add(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
func scheduleEventNotif(_ event: Event) {
|
||||||
|
scheduleNotif(
|
||||||
|
title: event.name,
|
||||||
|
sub: event.notes,
|
||||||
|
date: event.date,
|
||||||
|
id: event.id.uuidString
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDateComponents(_ date: Date) -> DateComponents {
|
||||||
|
return Calendar.current.dateComponents([.year, .month, .day, .hour, .minute], from: date)
|
||||||
|
}
|
||||||
|
|
||||||
|
func cancelNotif(_ id: String) {
|
||||||
|
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [id])
|
||||||
|
}
|
||||||
|
|
||||||
|
func cancelAllNotifs() {
|
||||||
|
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getVersion() -> String {
|
||||||
|
guard let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] else {
|
||||||
|
fatalError("no bundle id wtf lol")
|
||||||
|
}
|
||||||
|
return "\(version)"
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBuildID() -> String {
|
||||||
|
guard let build = Bundle.main.infoDictionary?["CFBundleVersion"] else {
|
||||||
|
fatalError("wtf did u do w the build number")
|
||||||
|
}
|
||||||
|
return "\(build)"
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDevice() -> (sf: String, label: String) {
|
||||||
|
let asi = ProcessInfo().isiOSAppOnMac
|
||||||
|
let model = UIDevice().model
|
||||||
|
if asi {
|
||||||
|
return (sf: "laptopcomputer", label: "Computer")
|
||||||
|
} else if model == "iPhone" {
|
||||||
|
return (sf: model.lowercased(), label: model)
|
||||||
|
} else if model == "iPad" {
|
||||||
|
return (sf: model.lowercased(), label: model)
|
||||||
|
}
|
||||||
|
return (sf: "iphone", label: "iPhone")
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Event: AppEntity {
|
||||||
|
static let defaultQuery = EventQuery()
|
||||||
|
|
||||||
|
static var typeDisplayRepresentation: TypeDisplayRepresentation {
|
||||||
|
TypeDisplayRepresentation("skdfj")
|
||||||
|
}
|
||||||
|
|
||||||
|
var displayRepresentation: DisplayRepresentation {
|
||||||
|
DisplayRepresentation("eventsss")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct EventQuery: EntityQuery, DynamicOptionsProvider {
|
||||||
|
typealias Entity = Event
|
||||||
|
@Dependency var vm: EventViewModel
|
||||||
|
func results() async throws -> some ResultsCollection {
|
||||||
|
return vm.events
|
||||||
|
}
|
||||||
|
// func defaultResult() async -> DefaultValue? {
|
||||||
|
// return vm.events[0]
|
||||||
|
// }
|
||||||
|
func entities(for identifiers: [Entity.ID]) async throws -> [Entity] {
|
||||||
|
return vm.events
|
||||||
|
}
|
||||||
|
func suggestedEntities() async throws -> some ResultsCollection {
|
||||||
|
return vm.events //lol cba
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CompleteEvent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "Complete An Event"
|
||||||
|
static var description = IntentDescription("Mark an Event as complete.")
|
||||||
|
|
||||||
|
@Parameter(title: "Event ID")
|
||||||
|
var eventID: String
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult {
|
||||||
|
print("s")
|
||||||
|
let viewModel = EventViewModel()
|
||||||
|
print("hip")
|
||||||
|
guard let eventUUID = UUID(uuidString: eventID) else {
|
||||||
|
print(":sdklfajk")
|
||||||
|
return .result()
|
||||||
|
}
|
||||||
|
print("hii")
|
||||||
|
if let eventToModify = viewModel.events.firstIndex(where: { $0.id == eventUUID }) {
|
||||||
|
print("hiii")
|
||||||
|
viewModel.events[eventToModify].complete = true
|
||||||
|
viewModel.saveEvents()
|
||||||
|
}
|
||||||
|
return .result()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
<!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>aps-environment</key>
|
||||||
|
<string>development</string>
|
||||||
|
<key>com.apple.developer.aps-environment</key>
|
||||||
|
<string>development</string>
|
||||||
<key>com.apple.developer.icloud-container-identifiers</key>
|
<key>com.apple.developer.icloud-container-identifiers</key>
|
||||||
<array/>
|
<array/>
|
||||||
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
|
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// NearFutureApp.swift
|
// NearFutureApp.swift
|
||||||
// NearFuture
|
// NearFuture
|
||||||
//
|
//
|
||||||
// Created by Nihaal Sharma on 24/12/2024.
|
// Created by neon443 on 24/12/2024.
|
||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// AppIntent.swift
|
// AppIntent.swift
|
||||||
// NearFutureWidgets
|
// NearFutureWidgets
|
||||||
//
|
//
|
||||||
// Created by Nihaal Sharma on 02/01/2025.
|
// Created by neon443 on 02/01/2025.
|
||||||
//
|
//
|
||||||
|
|
||||||
import WidgetKit
|
import WidgetKit
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// NearFutureWidgets.swift
|
// NearFutureWidgets.swift
|
||||||
// NearFutureWidgets
|
// NearFutureWidgets
|
||||||
//
|
//
|
||||||
// Created by Nihaal Sharma on 02/01/2025.
|
// Created by neon443 on 02/01/2025.
|
||||||
//
|
//
|
||||||
|
|
||||||
import WidgetKit
|
import WidgetKit
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// NearFutureWidgetsBundle.swift
|
// NearFutureWidgetsBundle.swift
|
||||||
// NearFutureWidgets
|
// NearFutureWidgets
|
||||||
//
|
//
|
||||||
// Created by Nihaal Sharma on 02/01/2025.
|
// Created by neon443 on 02/01/2025.
|
||||||
//
|
//
|
||||||
|
|
||||||
import WidgetKit
|
import WidgetKit
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// NearFutureWidgetsLiveActivity.swift
|
// NearFutureWidgetsLiveActivity.swift
|
||||||
// NearFutureWidgets
|
// NearFutureWidgets
|
||||||
//
|
//
|
||||||
// Created by Nihaal Sharma on 02/01/2025.
|
// Created by neon443 on 02/01/2025.
|
||||||
//
|
//
|
||||||
|
|
||||||
import ActivityKit
|
import ActivityKit
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ import SwiftUI
|
|||||||
struct ArchiveView: View {
|
struct ArchiveView: View {
|
||||||
@ObservedObject var viewModel: EventViewModel
|
@ObservedObject var viewModel: EventViewModel
|
||||||
@State var showAddEvent: Bool = false
|
@State var showAddEvent: Bool = false
|
||||||
@State var hey: UUID = UUID()
|
var filteredEvents: [Event] {
|
||||||
|
return viewModel.events.filter() {$0.complete}
|
||||||
|
}
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
ZStack {
|
ZStack {
|
||||||
@@ -19,15 +21,14 @@ struct ArchiveView: View {
|
|||||||
HelpView(showAddEvent: $showAddEvent)
|
HelpView(showAddEvent: $showAddEvent)
|
||||||
} else {
|
} else {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
ForEach(viewModel.events.filter({$0.complete})) { event in
|
ForEach(filteredEvents) { event in
|
||||||
EventListView(viewModel: viewModel, event: event)
|
EventListView(viewModel: viewModel, event: event)
|
||||||
|
.transition(.moveAndFadeReversed)
|
||||||
|
.id(event.complete)
|
||||||
}
|
}
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
.id(hey)
|
|
||||||
.onReceive(viewModel.objectWillChange) {
|
|
||||||
hey = UUID()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
.animation(.default, value: filteredEvents)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.scrollContentBackground(.hidden)
|
.scrollContentBackground(.hidden)
|
||||||
@@ -58,12 +59,6 @@ struct ArchiveView: View {
|
|||||||
eventRecurrence: $viewModel.editableTemplate.recurrence,
|
eventRecurrence: $viewModel.editableTemplate.recurrence,
|
||||||
adding: true
|
adding: true
|
||||||
)
|
)
|
||||||
.presentationDragIndicator(.visible)
|
|
||||||
.apply {
|
|
||||||
if #available(iOS 16.4, *) {
|
|
||||||
$0.presentationBackground(.ultraThinMaterial)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,5 +66,3 @@ struct ArchiveView: View {
|
|||||||
#Preview {
|
#Preview {
|
||||||
ArchiveView(viewModel: dummyEventViewModel())
|
ArchiveView(viewModel: dummyEventViewModel())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
257
NearFuture/Views/Events/AddEventView.swift
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
//
|
||||||
|
// AddEventView.swift
|
||||||
|
// NearFuture
|
||||||
|
//
|
||||||
|
// Created by neon443 on 25/12/2024.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import SFSymbolsPicker
|
||||||
|
|
||||||
|
struct AddEventView: View {
|
||||||
|
@ObservedObject var viewModel: EventViewModel
|
||||||
|
|
||||||
|
@Binding var eventName: String
|
||||||
|
@Binding var eventComplete: Bool
|
||||||
|
@Binding var eventCompleteDesc: String
|
||||||
|
@Binding var eventSymbol: String
|
||||||
|
@Binding var eventColor: Color
|
||||||
|
@Binding var eventNotes: String
|
||||||
|
@Binding var eventDate: Date
|
||||||
|
@Binding var eventRecurrence: Event.RecurrenceType
|
||||||
|
|
||||||
|
@State var adding: Bool
|
||||||
|
@State var showNeedsNameAlert: Bool = false
|
||||||
|
@State var isSymbolPickerPresented = false
|
||||||
|
|
||||||
|
@State private var bye: Bool = false
|
||||||
|
|
||||||
|
@FocusState private var focusedField: Field?
|
||||||
|
private enum Field {
|
||||||
|
case Name, Notes
|
||||||
|
}
|
||||||
|
|
||||||
|
@Environment(\.dismiss) var dismiss
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
ZStack {
|
||||||
|
if !adding {
|
||||||
|
backgroundGradient
|
||||||
|
}
|
||||||
|
NavigationStack {
|
||||||
|
Form {
|
||||||
|
Section(
|
||||||
|
header:
|
||||||
|
Text("Event Details")
|
||||||
|
.font(.headline)
|
||||||
|
.foregroundColor(.accentColor)
|
||||||
|
) {
|
||||||
|
// name & symbol
|
||||||
|
HStack(spacing: 5) {
|
||||||
|
Button() {
|
||||||
|
isSymbolPickerPresented.toggle()
|
||||||
|
} label: {
|
||||||
|
Image(systemName: eventSymbol)
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: 20, height: 20)
|
||||||
|
.foregroundStyle(eventColor)
|
||||||
|
}
|
||||||
|
.frame(width: 20)
|
||||||
|
.buttonStyle(.borderless)
|
||||||
|
.sheet(isPresented: $isSymbolPickerPresented) {
|
||||||
|
SymbolsPicker(
|
||||||
|
selection: $eventSymbol,
|
||||||
|
title: "Choose a Symbol",
|
||||||
|
searchLabel: "Search...",
|
||||||
|
autoDismiss: true)
|
||||||
|
.presentationDetents([.medium])
|
||||||
|
.apply {
|
||||||
|
if #available(iOS 16.4, *) {
|
||||||
|
$0.presentationBackground(.ultraThinMaterial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ColorPicker("", selection: $eventColor, supportsOpacity: false)
|
||||||
|
.fixedSize()
|
||||||
|
ZStack {
|
||||||
|
TextField("Event Name", text: $eventName)
|
||||||
|
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||||
|
.padding(.trailing, eventName.isEmpty ? 0 : 30)
|
||||||
|
.animation(.spring, value: eventName)
|
||||||
|
.focused($focusedField, equals: Field.Name)
|
||||||
|
.submitLabel(.next)
|
||||||
|
.onSubmit {
|
||||||
|
focusedField = .Notes
|
||||||
|
}
|
||||||
|
MagicClearButton(text: $eventName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dscription
|
||||||
|
ZStack {
|
||||||
|
TextField("Event Notes", text: $eventNotes)
|
||||||
|
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||||
|
.padding(.trailing, eventNotes.isEmpty ? 0 : 30)
|
||||||
|
.animation(.spring, value: eventNotes)
|
||||||
|
.focused($focusedField, equals: Field.Notes)
|
||||||
|
.submitLabel(.done)
|
||||||
|
.onSubmit {
|
||||||
|
focusedField = nil
|
||||||
|
}
|
||||||
|
MagicClearButton(text: $eventNotes)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// date picker
|
||||||
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
DatePicker("", selection: $eventDate, displayedComponents: .date)
|
||||||
|
.datePickerStyle(WheelDatePickerStyle())
|
||||||
|
Spacer()
|
||||||
|
Button() {
|
||||||
|
eventDate = Date()
|
||||||
|
} label: {
|
||||||
|
Image(systemName: "arrow.uturn.left")
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
}
|
||||||
|
.buttonStyle(BorderlessButtonStyle())
|
||||||
|
.frame(width: 20)
|
||||||
|
}
|
||||||
|
|
||||||
|
DatePicker(
|
||||||
|
"",
|
||||||
|
selection: $eventDate,
|
||||||
|
displayedComponents: .hourAndMinute
|
||||||
|
)
|
||||||
|
|
||||||
|
// re-ocurrence Picker
|
||||||
|
Picker("Recurrence", selection: $eventRecurrence) {
|
||||||
|
ForEach(Event.RecurrenceType.allCases, id: \.self) { recurrence in
|
||||||
|
Text(recurrence.rawValue.capitalized)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.pickerStyle(SegmentedPickerStyle())
|
||||||
|
Text(
|
||||||
|
describeOccurrence(
|
||||||
|
date: eventDate,
|
||||||
|
recurrence: eventRecurrence
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.scrollContentBackground(.hidden)
|
||||||
|
.navigationTitle("\(adding ? "Add Event" : "")")
|
||||||
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
.toolbar {
|
||||||
|
ToolbarItem(placement: .topBarLeading) {
|
||||||
|
if adding {
|
||||||
|
Button() {
|
||||||
|
resetAddEventView()
|
||||||
|
dismiss()
|
||||||
|
} label: {
|
||||||
|
Image(systemName: "xmark.circle.fill")
|
||||||
|
.symbolRenderingMode(.hierarchical)
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: 30)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ToolbarItem(placement: .topBarTrailing) {
|
||||||
|
if adding {
|
||||||
|
Button {
|
||||||
|
viewModel.addEvent(
|
||||||
|
newEvent: Event(
|
||||||
|
name: eventName,
|
||||||
|
complete: eventComplete,
|
||||||
|
completeDesc: eventCompleteDesc,
|
||||||
|
symbol: eventSymbol,
|
||||||
|
color: ColorCodable(eventColor),
|
||||||
|
notes: eventNotes,
|
||||||
|
date: eventDate,
|
||||||
|
recurrence: eventRecurrence
|
||||||
|
)
|
||||||
|
)
|
||||||
|
bye.toggle()
|
||||||
|
resetAddEventView()
|
||||||
|
} label: {
|
||||||
|
Text("Save")
|
||||||
|
.font(.headline)
|
||||||
|
.cornerRadius(10)
|
||||||
|
.buttonStyle(BorderedProminentButtonStyle())
|
||||||
|
}
|
||||||
|
.apply {
|
||||||
|
if #available(iOS 17, *) {
|
||||||
|
$0.sensoryFeedback(.success, trigger: bye)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.disabled(eventName.isEmpty)
|
||||||
|
.onTapGesture {
|
||||||
|
if eventName.isEmpty {
|
||||||
|
showNeedsNameAlert.toggle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.alert("Missing Name", isPresented: $showNeedsNameAlert) {
|
||||||
|
Button("OK", role: .cancel) {
|
||||||
|
showNeedsNameAlert.toggle()
|
||||||
|
focusedField = .Name
|
||||||
|
}
|
||||||
|
} message: {
|
||||||
|
Text("Give your Event a name before saving.")
|
||||||
|
}
|
||||||
|
if eventName.isEmpty {
|
||||||
|
HStack {
|
||||||
|
Image(systemName: "exclamationmark")
|
||||||
|
.foregroundStyle(.red)
|
||||||
|
Text("Give your event a name.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.presentationDragIndicator(.visible)
|
||||||
|
.scrollContentBackground(.hidden)
|
||||||
|
}
|
||||||
|
.apply {
|
||||||
|
if #available(iOS 16.4, *) {
|
||||||
|
$0.presentationBackground(.ultraThinMaterial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func resetAddEventView() {
|
||||||
|
//reset addeventView
|
||||||
|
eventName = viewModel.template.name
|
||||||
|
eventComplete = viewModel.template.complete
|
||||||
|
eventCompleteDesc = viewModel.template.completeDesc
|
||||||
|
eventSymbol = viewModel.template.symbol
|
||||||
|
eventColor = randomColor()
|
||||||
|
eventNotes = viewModel.template.notes
|
||||||
|
eventDate = viewModel.template.date
|
||||||
|
eventRecurrence = viewModel.template.recurrence
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
let vm = dummyEventViewModel()
|
||||||
|
Color.orange
|
||||||
|
.ignoresSafeArea(.all)
|
||||||
|
.sheet(isPresented: .constant(true)) {
|
||||||
|
AddEventView(
|
||||||
|
viewModel: vm,
|
||||||
|
eventName: .constant(vm.template.notes),
|
||||||
|
eventComplete: .constant(vm.template.complete),
|
||||||
|
eventCompleteDesc: .constant(vm.template.completeDesc),
|
||||||
|
eventSymbol: .constant(vm.template.symbol),
|
||||||
|
eventColor: .constant(vm.template.color.color),
|
||||||
|
eventNotes: .constant(vm.template.notes),
|
||||||
|
eventDate: .constant(vm.template.date),
|
||||||
|
eventRecurrence: .constant(vm.template.recurrence),
|
||||||
|
adding: true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
// EditEventView.swift
|
// EditEventView.swift
|
||||||
// NearFuture
|
// NearFuture
|
||||||
//
|
//
|
||||||
// Created by Nihaal Sharma on 02/01/2025.
|
// Created by neon443 on 02/01/2025.
|
||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
96
NearFuture/Views/Home/ContentView.swift
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
//
|
||||||
|
// ContentView.swift
|
||||||
|
// NearFuture
|
||||||
|
//
|
||||||
|
// Created by neon443 on 24/12/2024.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import UserNotifications
|
||||||
|
import SwiftData
|
||||||
|
|
||||||
|
enum Field {
|
||||||
|
case Search
|
||||||
|
}
|
||||||
|
enum Tab {
|
||||||
|
case home
|
||||||
|
case archive
|
||||||
|
case stats
|
||||||
|
case settings
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ContentView: View {
|
||||||
|
@StateObject var viewModel: EventViewModel
|
||||||
|
@StateObject var settingsModel: SettingsViewModel
|
||||||
|
@State var selection: Tab = .home
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
TabView(selection: $selection) {
|
||||||
|
HomeView(viewModel: viewModel, settingsModel: settingsModel)
|
||||||
|
.tabItem {
|
||||||
|
Label("Home", systemImage: "house")
|
||||||
|
}
|
||||||
|
.tag(Tab.home)
|
||||||
|
ArchiveView(viewModel: viewModel)
|
||||||
|
.tabItem() {
|
||||||
|
Label("Archive", systemImage: "tray.full")
|
||||||
|
}
|
||||||
|
.tag(Tab.archive)
|
||||||
|
StatsView(viewModel: viewModel)
|
||||||
|
.tabItem {
|
||||||
|
Label("Statistics", systemImage: "chart.pie")
|
||||||
|
}
|
||||||
|
.tag(Tab.stats)
|
||||||
|
SettingsView(viewModel: viewModel, settingsModel: settingsModel)
|
||||||
|
.tabItem {
|
||||||
|
Label("Settings", systemImage: "gear")
|
||||||
|
}
|
||||||
|
.tag(Tab.settings)
|
||||||
|
}
|
||||||
|
.apply {
|
||||||
|
if #available(iOS 17, *) {
|
||||||
|
$0.sensoryFeedback(.impact(weight: .heavy, intensity: 1), trigger: selection)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sheet(isPresented: $settingsModel.settings.showWhatsNew) {
|
||||||
|
WhatsNewView(settingsModel: settingsModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
ContentView(
|
||||||
|
viewModel: dummyEventViewModel(),
|
||||||
|
settingsModel: dummySettingsViewModel()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
extension View {
|
||||||
|
var backgroundGradient: some View {
|
||||||
|
return LinearGradient(
|
||||||
|
gradient: Gradient(colors: [.bgTop, .two]),
|
||||||
|
startPoint: .top,
|
||||||
|
endPoint: .bottom
|
||||||
|
)
|
||||||
|
.ignoresSafeArea(.all)
|
||||||
|
}
|
||||||
|
|
||||||
|
func apply<V: View>(@ViewBuilder _ block: (Self) -> V) -> V { block(self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AnyTransition {
|
||||||
|
static var moveAndFade: AnyTransition {
|
||||||
|
.asymmetric(
|
||||||
|
insertion: .move(edge: .leading),
|
||||||
|
removal: .move(edge: .trailing)
|
||||||
|
)
|
||||||
|
.combined(with: .opacity)
|
||||||
|
}
|
||||||
|
static var moveAndFadeReversed: AnyTransition {
|
||||||
|
.asymmetric(
|
||||||
|
insertion: .move(edge: .trailing),
|
||||||
|
removal: .move(edge: .leading)
|
||||||
|
)
|
||||||
|
.combined(with: .opacity)
|
||||||
|
}
|
||||||
|
}
|
||||||
175
NearFuture/Views/Home/EventListView.swift
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
//
|
||||||
|
// EventListView.swift
|
||||||
|
// NearFuture
|
||||||
|
//
|
||||||
|
// Created by neon443 on 18/04/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import SwiftData
|
||||||
|
|
||||||
|
struct EventListView: View {
|
||||||
|
@ObservedObject var viewModel: EventViewModel
|
||||||
|
@State var event: Event
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
NavigationLink() {
|
||||||
|
EditEventView(
|
||||||
|
viewModel: viewModel,
|
||||||
|
event: $event
|
||||||
|
)
|
||||||
|
} label: {
|
||||||
|
ZStack {
|
||||||
|
HStack {
|
||||||
|
RoundedRectangle(cornerRadius: 5)
|
||||||
|
.frame(width: 7)
|
||||||
|
.foregroundStyle(
|
||||||
|
event.color.color.opacity(
|
||||||
|
event.complete ? 0.5 : 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
HStack {
|
||||||
|
Image(systemName: event.symbol)
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: 20, height: 20)
|
||||||
|
.shadow(radius: 5)
|
||||||
|
.foregroundStyle(
|
||||||
|
.one.opacity(
|
||||||
|
event.complete ? 0.5 : 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Text("\(event.name)")
|
||||||
|
.font(.headline)
|
||||||
|
.foregroundStyle(.one)
|
||||||
|
.strikethrough(event.complete)
|
||||||
|
.multilineTextAlignment(.leading)
|
||||||
|
}
|
||||||
|
if !event.notes.isEmpty {
|
||||||
|
Text(event.notes)
|
||||||
|
.font(.subheadline)
|
||||||
|
.foregroundStyle(.one.opacity(0.8))
|
||||||
|
.multilineTextAlignment(.leading)
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
event.date.formatted(
|
||||||
|
date: .long,
|
||||||
|
time: .shortened
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.font(.subheadline)
|
||||||
|
.foregroundStyle(
|
||||||
|
.one.opacity(
|
||||||
|
event.complete ? 0.5 : 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if event.recurrence != .none {
|
||||||
|
Text("Occurs \(event.recurrence.rawValue)")
|
||||||
|
.font(.subheadline)
|
||||||
|
.foregroundStyle(
|
||||||
|
.one.opacity(event.complete ? 0.5 : 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
VStack {
|
||||||
|
Text("\(daysUntilEvent(event.date).long)")
|
||||||
|
.font(.subheadline)
|
||||||
|
.foregroundStyle(event.date.timeIntervalSinceNow < 0 ? .red : .one)
|
||||||
|
}
|
||||||
|
Button() {
|
||||||
|
withAnimation {
|
||||||
|
event.complete.toggle()
|
||||||
|
}
|
||||||
|
let eventToModify = viewModel.events.firstIndex() { currEvent in
|
||||||
|
currEvent.id == event.id
|
||||||
|
}
|
||||||
|
if let eventToModify = eventToModify {
|
||||||
|
viewModel.events[eventToModify] = event
|
||||||
|
viewModel.saveEvents()
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
if event.complete {
|
||||||
|
ZStack {
|
||||||
|
Circle()
|
||||||
|
.foregroundStyle(.green)
|
||||||
|
Image(systemName: "checkmark")
|
||||||
|
.resizable()
|
||||||
|
.foregroundStyle(.white)
|
||||||
|
.scaledToFit()
|
||||||
|
.bold()
|
||||||
|
.frame(width: 15)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Image(systemName: "circle")
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.foregroundStyle(event.color.color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.buttonStyle(.borderless)
|
||||||
|
.frame(maxWidth: 25, maxHeight: 25)
|
||||||
|
.shadow(radius: 5)
|
||||||
|
.padding(.trailing, 5)
|
||||||
|
.apply {
|
||||||
|
if #available(iOS 17, *) {
|
||||||
|
$0.sensoryFeedback(.success, trigger: event.complete)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.transition(.opacity)
|
||||||
|
.padding(.vertical, 5)
|
||||||
|
.background(.ultraThinMaterial)
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 10)
|
||||||
|
.stroke(
|
||||||
|
.one.opacity(0.5),
|
||||||
|
lineWidth: 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.clipShape(
|
||||||
|
RoundedRectangle(cornerRadius: 10)
|
||||||
|
)
|
||||||
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
|
}
|
||||||
|
.contextMenu() {
|
||||||
|
Button(role: .destructive) {
|
||||||
|
let eventToModify = viewModel.events.firstIndex() { currEvent in
|
||||||
|
currEvent.id == event.id
|
||||||
|
}
|
||||||
|
if let eventToModify = eventToModify {
|
||||||
|
viewModel.events.remove(at: eventToModify)
|
||||||
|
viewModel.saveEvents()
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
Label("Delete", systemImage: "trash")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview("EventListView") {
|
||||||
|
let vm = dummyEventViewModel()
|
||||||
|
ZStack {
|
||||||
|
Color.black
|
||||||
|
VStack {
|
||||||
|
ForEach(0..<50) { _ in
|
||||||
|
Rectangle()
|
||||||
|
.foregroundStyle(randomColor().opacity(0.5))
|
||||||
|
.padding(-10)
|
||||||
|
}
|
||||||
|
.ignoresSafeArea(.all)
|
||||||
|
.blur(radius: 5)
|
||||||
|
}
|
||||||
|
VStack {
|
||||||
|
ForEach(vm.events) { event in
|
||||||
|
EventListView(
|
||||||
|
viewModel: vm,
|
||||||
|
event: event
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.horizontal, 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
112
NearFuture/Views/Home/HelpView.swift
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
//
|
||||||
|
// ArchiveHelp.swift
|
||||||
|
// NearFuture
|
||||||
|
//
|
||||||
|
// Created by neon443 on 26/04/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
enum HelpType {
|
||||||
|
case Search
|
||||||
|
case Archive
|
||||||
|
}
|
||||||
|
|
||||||
|
struct HelpView: View {
|
||||||
|
/// initialises a Search HelpView
|
||||||
|
///
|
||||||
|
init(searchInput: Binding<String>, focusedField: Field?) {
|
||||||
|
_searchInput = searchInput
|
||||||
|
self.helpType = .Search
|
||||||
|
_showAddEvent = .constant(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// initialises an Archive HelpView
|
||||||
|
///
|
||||||
|
init(showAddEvent: Binding<Bool>) {
|
||||||
|
_showAddEvent = showAddEvent
|
||||||
|
self.helpType = .Archive
|
||||||
|
_searchInput = .constant("")
|
||||||
|
self.focusedField = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
@Binding var searchInput: String
|
||||||
|
@FocusState var focusedField: Field?
|
||||||
|
|
||||||
|
@Binding var showAddEvent: Bool
|
||||||
|
|
||||||
|
var helpType: HelpType
|
||||||
|
var details: (
|
||||||
|
symbol: String,
|
||||||
|
title: String,
|
||||||
|
body: String,
|
||||||
|
buttonAction: () -> (),
|
||||||
|
buttonSymbol: String,
|
||||||
|
buttonText: String
|
||||||
|
) {
|
||||||
|
switch helpType {
|
||||||
|
case .Search:
|
||||||
|
return (
|
||||||
|
symbol: "questionmark.app.dashed",
|
||||||
|
title: "Looking for something?",
|
||||||
|
body: "Tip: The Search bar searches event names and notes.",
|
||||||
|
buttonAction: {
|
||||||
|
searchInput = ""
|
||||||
|
focusedField = nil
|
||||||
|
},
|
||||||
|
buttonSymbol: "xmark",
|
||||||
|
buttonText: "Clear Filters"
|
||||||
|
)
|
||||||
|
case .Archive:
|
||||||
|
return (
|
||||||
|
symbol: "eyes",
|
||||||
|
title: "Nothing to see here...",
|
||||||
|
body: "The Archive contains events that have been marked as complete.",
|
||||||
|
buttonAction: {
|
||||||
|
showAddEvent.toggle()
|
||||||
|
},
|
||||||
|
buttonSymbol: "plus",
|
||||||
|
buttonText: "Create an event"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var body: some View {
|
||||||
|
List {
|
||||||
|
ZStack {
|
||||||
|
Color(.tintColor)
|
||||||
|
.opacity(0.4)
|
||||||
|
.padding(.horizontal, -15)
|
||||||
|
.blur(radius: 5)
|
||||||
|
HStack {
|
||||||
|
Image(systemName: details.symbol)
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: 30, height: 30)
|
||||||
|
.padding(.trailing)
|
||||||
|
Text(details.title)
|
||||||
|
.bold()
|
||||||
|
.font(.title2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.listRowSeparator(.hidden)
|
||||||
|
Text(details.body)
|
||||||
|
Button() {
|
||||||
|
details.buttonAction()
|
||||||
|
} label: {
|
||||||
|
HStack {
|
||||||
|
Image(systemName: details.buttonSymbol)
|
||||||
|
.bold()
|
||||||
|
Text(details.buttonText)
|
||||||
|
}
|
||||||
|
.foregroundStyle(Color.accentColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.scrollContentBackground(.hidden)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
HelpView(searchInput: .constant(""), focusedField: nil)
|
||||||
|
HelpView(showAddEvent: .constant(false))
|
||||||
|
}
|
||||||
129
NearFuture/Views/Home/HomeView.swift
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
//
|
||||||
|
// HomeView.swift
|
||||||
|
// NearFuture
|
||||||
|
//
|
||||||
|
// Created by neon443 on 12/05/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI;import AppIntents
|
||||||
|
|
||||||
|
struct HomeView: View {
|
||||||
|
@ObservedObject var viewModel: EventViewModel
|
||||||
|
@ObservedObject var settingsModel: SettingsViewModel
|
||||||
|
@State private var eventName = ""
|
||||||
|
@State private var eventComplete = false
|
||||||
|
@State private var eventCompleteDesc = ""
|
||||||
|
@State private var eventSymbol = "star"
|
||||||
|
@State private var eventColor: Color = randomColor()
|
||||||
|
@State private var eventNotes = ""
|
||||||
|
@State private var eventDate = Date()
|
||||||
|
@State private var eventRecurrence: Event.RecurrenceType = .none
|
||||||
|
@State private var showingAddEventView = false
|
||||||
|
@State private var searchInput: String = ""
|
||||||
|
@Environment(\.colorScheme) var appearance
|
||||||
|
var darkMode: Bool {
|
||||||
|
return appearance == .dark
|
||||||
|
}
|
||||||
|
var filteredEvents: [Event] {
|
||||||
|
if searchInput.isEmpty {
|
||||||
|
if settingsModel.settings.showCompletedInHome {
|
||||||
|
return viewModel.events
|
||||||
|
} else {
|
||||||
|
return viewModel.events.filter() {!$0.complete}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return viewModel.events.filter {
|
||||||
|
$0.name.localizedCaseInsensitiveContains(searchInput) ||
|
||||||
|
$0.notes.localizedCaseInsensitiveContains(searchInput)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@State private var focusedTab: Tab = .home
|
||||||
|
|
||||||
|
@FocusState private var focusedField: Field?
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
NavigationStack {
|
||||||
|
ZStack {
|
||||||
|
backgroundGradient
|
||||||
|
VStack {
|
||||||
|
ZStack {
|
||||||
|
TextField(
|
||||||
|
"\(Image(systemName: "magnifyingglass")) Search",
|
||||||
|
text: $searchInput
|
||||||
|
)
|
||||||
|
.padding(.trailing, searchInput.isEmpty ? 0 : 30)
|
||||||
|
.animation(.spring, value: searchInput)
|
||||||
|
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||||
|
.submitLabel(.done)
|
||||||
|
.focused($focusedField, equals: Field.Search)
|
||||||
|
.onSubmit {
|
||||||
|
focusedField = nil
|
||||||
|
}
|
||||||
|
MagicClearButton(text: $searchInput)
|
||||||
|
.onTapGesture {
|
||||||
|
focusedField = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.horizontal)
|
||||||
|
|
||||||
|
if filteredEvents.isEmpty && !searchInput.isEmpty {
|
||||||
|
HelpView(searchInput: $searchInput, focusedField: focusedField)
|
||||||
|
} else {
|
||||||
|
ScrollView {
|
||||||
|
ForEach(filteredEvents) { event in
|
||||||
|
EventListView(viewModel: viewModel, event: event)
|
||||||
|
.transition(.moveAndFade)
|
||||||
|
.id(event.complete)
|
||||||
|
}
|
||||||
|
.padding(.horizontal)
|
||||||
|
if filteredEvents.isEmpty {
|
||||||
|
HelpView(
|
||||||
|
searchInput: $searchInput,
|
||||||
|
focusedField: focusedField
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
.animation(.default, value: filteredEvents)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.navigationTitle("Near Future")
|
||||||
|
.apply {
|
||||||
|
if #available(iOS 17, *) {
|
||||||
|
$0.toolbarTitleDisplayMode(.inlineLarge)
|
||||||
|
} else {
|
||||||
|
$0.navigationBarTitleDisplayMode(.inline)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sheet(isPresented: $showingAddEventView) {
|
||||||
|
AddEventView(
|
||||||
|
viewModel: viewModel,
|
||||||
|
eventName: $eventName,
|
||||||
|
eventComplete: $eventComplete,
|
||||||
|
eventCompleteDesc: $eventCompleteDesc,
|
||||||
|
eventSymbol: $eventSymbol,
|
||||||
|
eventColor: $eventColor,
|
||||||
|
eventNotes: $eventNotes,
|
||||||
|
eventDate: $eventDate,
|
||||||
|
eventRecurrence: $eventRecurrence,
|
||||||
|
adding: true //adding event
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.toolbar {
|
||||||
|
ToolbarItem(placement: .topBarTrailing) {
|
||||||
|
AddEventButton(showingAddEventView: $showingAddEventView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
HomeView(
|
||||||
|
viewModel: dummyEventViewModel(),
|
||||||
|
settingsModel: dummySettingsViewModel()
|
||||||
|
)
|
||||||
|
}
|
||||||
31
NearFuture/Views/Misc/AboutView.swift
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// AboutView.swift
|
||||||
|
// NearFuture
|
||||||
|
//
|
||||||
|
// Created by neon443 on 12/05/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct AboutView: View {
|
||||||
|
var body: some View {
|
||||||
|
VStack {
|
||||||
|
Image(uiImage: #imageLiteral(resourceName: "NearFutureIcon.png"))
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: 100)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 25))
|
||||||
|
Text("Near Future")
|
||||||
|
.bold()
|
||||||
|
.monospaced()
|
||||||
|
.font(.title)
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
Text("Version " + getVersion() + " (\(getBuildID()))")
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
AboutView()
|
||||||
|
}
|
||||||
58
NearFuture/Views/Misc/Buttons.swift
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
//
|
||||||
|
// MagicClearButton.swift
|
||||||
|
// NearFuture
|
||||||
|
//
|
||||||
|
// Created by neon443 on 06/05/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct MagicClearButton: View {
|
||||||
|
@Binding var text: String
|
||||||
|
var body: some View {
|
||||||
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
Button {
|
||||||
|
text = ""
|
||||||
|
} label: {
|
||||||
|
Image(systemName: "xmark.circle.fill")
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: text.isEmpty ? 0 : 25)
|
||||||
|
.symbolRenderingMode(.hierarchical)
|
||||||
|
.padding(.trailing, -5)
|
||||||
|
.animation(.spring, value: text.isEmpty)
|
||||||
|
}
|
||||||
|
.buttonStyle(.borderless)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AddEventButton: View {
|
||||||
|
@Binding var showingAddEventView: Bool
|
||||||
|
var body: some View {
|
||||||
|
Button() {
|
||||||
|
showingAddEventView.toggle()
|
||||||
|
} label: {
|
||||||
|
ZStack {
|
||||||
|
Circle()
|
||||||
|
.frame(width: 33)
|
||||||
|
.foregroundStyle(.one)
|
||||||
|
Image(systemName: "plus")
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: 15)
|
||||||
|
.bold()
|
||||||
|
.foregroundStyle(.two)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
MagicClearButton(text: .constant("s"))
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
AddEventButton(showingAddEventView: .constant(false))
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
// SettingsView.swift
|
// SettingsView.swift
|
||||||
// NearFuture
|
// NearFuture
|
||||||
//
|
//
|
||||||
// Created by Nihaal Sharma on 29/12/2024.
|
// Created by neon443 on 29/12/2024.
|
||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
@@ -40,6 +40,22 @@ struct SettingsView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func changeIcon(to: String) {
|
||||||
|
guard UIApplication.shared.supportsAlternateIcons else {
|
||||||
|
print("doesnt tsupport alternate icons")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard to != "orange" else {
|
||||||
|
UIApplication.shared.setAlternateIconName(nil) { error in
|
||||||
|
print(error as Any)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
UIApplication.shared.setAlternateIconName(to) { error in
|
||||||
|
print(error as Any)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
ZStack {
|
ZStack {
|
||||||
@@ -47,11 +63,12 @@ struct SettingsView: View {
|
|||||||
List {
|
List {
|
||||||
ScrollView(.horizontal) {
|
ScrollView(.horizontal) {
|
||||||
HStack {
|
HStack {
|
||||||
ForEach(settingsModel.accentChoices, id: \.self) { color in
|
ForEach(settingsModel.accentChoices, id: \.self) { choice in
|
||||||
|
let color = Color(uiColor: UIColor(named: "uiColors/\(choice)")!)
|
||||||
ZStack {
|
ZStack {
|
||||||
Button() {
|
Button() {
|
||||||
settingsModel.settings.tint.colorBind = color
|
settingsModel.changeTint(to: choice)
|
||||||
settingsModel.saveSettings()
|
changeIcon(to: choice)
|
||||||
} label: {
|
} label: {
|
||||||
Circle()
|
Circle()
|
||||||
.foregroundStyle(color)
|
.foregroundStyle(color)
|
||||||
@@ -67,9 +84,36 @@ struct SettingsView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Button("Show What's New") {
|
||||||
|
settingsModel.settings.showWhatsNew = true
|
||||||
|
}
|
||||||
|
Toggle("Show completed Events in Home", isOn: $settingsModel.settings.showCompletedInHome)
|
||||||
|
.onChange(of: settingsModel.settings.showCompletedInHome) { _ in
|
||||||
|
settingsModel.saveSettings()
|
||||||
|
}
|
||||||
|
NavigationLink() {
|
||||||
|
List {
|
||||||
|
if !settingsModel.notifsGranted {
|
||||||
|
Button("Request Notifications") {
|
||||||
|
Task {
|
||||||
|
settingsModel.notifsGranted = await requestNotifs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Text("\(Image(systemName: "xmark")) Notifications disabled for Near Future")
|
||||||
|
.foregroundStyle(.red)
|
||||||
|
} else {
|
||||||
|
Text("\(Image(systemName: "checkmark")) Notifications enabled for Near Future")
|
||||||
|
.foregroundStyle(.green)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
Image(systemName: "bell.badge.fill")
|
||||||
|
Text("Notifications")
|
||||||
|
}
|
||||||
NavigationLink() {
|
NavigationLink() {
|
||||||
iCloudSettingsView(
|
iCloudSettingsView(
|
||||||
viewModel: viewModel,
|
viewModel: viewModel,
|
||||||
|
settingsModel: settingsModel,
|
||||||
hasUbiquitous: $hasUbiquitous,
|
hasUbiquitous: $hasUbiquitous,
|
||||||
lastSyncWasSuccessful: $lastSyncWasSuccessful,
|
lastSyncWasSuccessful: $lastSyncWasSuccessful,
|
||||||
lastSyncWasNormalAgo: $lastSyncWasNormalAgo,
|
lastSyncWasNormalAgo: $lastSyncWasNormalAgo,
|
||||||
@@ -129,22 +173,7 @@ struct SettingsView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Section("About") {
|
Section("About") {
|
||||||
VStack {
|
AboutView()
|
||||||
if let image = UIImage(named: getAppIcon()) {
|
|
||||||
Image(uiImage: image)
|
|
||||||
.resizable()
|
|
||||||
.scaledToFit()
|
|
||||||
.frame(width: 100)
|
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 25))
|
|
||||||
}
|
|
||||||
Text("Near Future")
|
|
||||||
.bold()
|
|
||||||
.monospaced()
|
|
||||||
.font(.title)
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
Text("Version " + getVersion() + " (\(getBuildID()))")
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,28 +196,3 @@ struct SettingsView: View {
|
|||||||
settingsModel: dummySettingsViewModel()
|
settingsModel: dummySettingsViewModel()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAppIcon() -> String {
|
|
||||||
let bundle = Bundle.main
|
|
||||||
guard let icons = bundle.object(forInfoDictionaryKey: "CFBundleIcons") as? [String: Any],
|
|
||||||
let primaryIcon = icons["CFBundlePrimaryIcon"] as? [String: Any],
|
|
||||||
let iconFiles = primaryIcon["CFBundleIconFiles"] as? [String],
|
|
||||||
let iconFileName = iconFiles.last else {
|
|
||||||
fatalError("hell na where ur icon")
|
|
||||||
}
|
|
||||||
return iconFileName
|
|
||||||
}
|
|
||||||
|
|
||||||
func getVersion() -> String {
|
|
||||||
guard let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] else {
|
|
||||||
fatalError("no bundle id wtf lol")
|
|
||||||
}
|
|
||||||
return "\(version)"
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBuildID() -> String {
|
|
||||||
guard let build = Bundle.main.infoDictionary?["CFBundleVersion"] else {
|
|
||||||
fatalError("wtf did u do w the build number")
|
|
||||||
}
|
|
||||||
return "\(build)"
|
|
||||||
}
|
|
||||||
138
NearFuture/Views/Settings/WhatsNewView.swift
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
//
|
||||||
|
// WhatsNewView.swift
|
||||||
|
// NearFuture
|
||||||
|
//
|
||||||
|
// Created by neon443 on 12/05/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct WhatsNewView: View {
|
||||||
|
@ObservedObject var settingsModel: SettingsViewModel
|
||||||
|
@Environment(\.dismiss) var dismiss
|
||||||
|
struct WhatsNewChunk: Identifiable {
|
||||||
|
var id: UUID = UUID()
|
||||||
|
var symbol: String
|
||||||
|
var title: String
|
||||||
|
var subtitle: String
|
||||||
|
}
|
||||||
|
@State var bye = false
|
||||||
|
var whatsNewChunks: [WhatsNewChunk] {
|
||||||
|
return [
|
||||||
|
WhatsNewChunk(
|
||||||
|
symbol: "iphone.radiowaves.left.and.right",
|
||||||
|
title: "Haptic Feedback",
|
||||||
|
subtitle: "Lovely haptic feedback when completing and adding events, and selecting tabs"
|
||||||
|
),
|
||||||
|
WhatsNewChunk(
|
||||||
|
symbol: "app",
|
||||||
|
title: "App Icons",
|
||||||
|
subtitle: "You now get a special app icon that matches the color you choose in settings!"
|
||||||
|
),
|
||||||
|
WhatsNewChunk(
|
||||||
|
symbol: "apps.iphone",
|
||||||
|
title: "Widgets Day Count Fix",
|
||||||
|
subtitle: "The day count for widgets are now red for overdue events, just like the app, and are now more readable"
|
||||||
|
),
|
||||||
|
WhatsNewChunk(
|
||||||
|
symbol: settingsModel.device.sf,
|
||||||
|
title: "This Screen",
|
||||||
|
subtitle: "This update add a Whats New page that will tell you (suprise!) What's New"
|
||||||
|
),
|
||||||
|
WhatsNewChunk(
|
||||||
|
symbol: "bell.badge.fill",
|
||||||
|
title: "Notifications",
|
||||||
|
subtitle: "Events now have notifications, reminding you to complete them!"
|
||||||
|
),
|
||||||
|
WhatsNewChunk(
|
||||||
|
symbol: "list.bullet.indent",
|
||||||
|
title: "Animations!",
|
||||||
|
subtitle: "I added animations for adding, removing and ticking events - animations are definitely the most important change"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
var body: some View {
|
||||||
|
NavigationStack {
|
||||||
|
List {
|
||||||
|
VStack {
|
||||||
|
Text("What's New")
|
||||||
|
.font(.largeTitle)
|
||||||
|
.bold()
|
||||||
|
AboutView()
|
||||||
|
Divider()
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
ForEach(whatsNewChunks) { new in
|
||||||
|
WhatsNewChunkView(
|
||||||
|
symbol: new.symbol,
|
||||||
|
title: new.title,
|
||||||
|
subtitle: new.subtitle
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button() {
|
||||||
|
bye.toggle()
|
||||||
|
dismiss()
|
||||||
|
} label: {
|
||||||
|
Text("Continue")
|
||||||
|
.font(.headline)
|
||||||
|
.frame(height: 40)
|
||||||
|
.bold()
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
}
|
||||||
|
.buttonStyle(BorderedProminentButtonStyle())
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 15))
|
||||||
|
.padding().padding()
|
||||||
|
.apply {
|
||||||
|
if #available(iOS 17, *) {
|
||||||
|
$0.sensoryFeedback(.impact(weight: .heavy, intensity: 1), trigger: bye)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.scrollContentBackground(.hidden)
|
||||||
|
.presentationDragIndicator(.visible)
|
||||||
|
.apply {
|
||||||
|
if #available(iOS 16.4, *) {
|
||||||
|
$0.presentationBackground(.ultraThinMaterial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onDisappear {
|
||||||
|
settingsModel.settings.prevAppVersion = getVersion()+getBuildID()
|
||||||
|
settingsModel.saveSettings()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
Color.accent
|
||||||
|
.ignoresSafeArea(.all)
|
||||||
|
.sheet(isPresented: .constant(true)) {
|
||||||
|
WhatsNewView(settingsModel: dummySettingsViewModel())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WhatsNewChunkView: View {
|
||||||
|
@State var symbol: String
|
||||||
|
@State var title: String
|
||||||
|
@State var subtitle: String
|
||||||
|
var body: some View {
|
||||||
|
HStack {
|
||||||
|
Image(systemName: symbol)
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: 30, height: 30)
|
||||||
|
.foregroundStyle(Color.accentColor)
|
||||||
|
.padding(.trailing, 15)
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Text(title)
|
||||||
|
.font(.headline)
|
||||||
|
.bold()
|
||||||
|
Text(subtitle)
|
||||||
|
.foregroundStyle(.gray)
|
||||||
|
.font(.subheadline)
|
||||||
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,8 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct iCloudSettingsView: View {
|
struct iCloudSettingsView: View {
|
||||||
@State var viewModel: EventViewModel
|
@ObservedObject var viewModel: EventViewModel
|
||||||
|
@ObservedObject var settingsModel: SettingsViewModel
|
||||||
@State var showPushAlert: Bool = false
|
@State var showPushAlert: Bool = false
|
||||||
@State var showPullAlert: Bool = false
|
@State var showPullAlert: Bool = false
|
||||||
|
|
||||||
@@ -18,19 +19,6 @@ struct iCloudSettingsView: View {
|
|||||||
@Binding var localCountEqualToiCloud: Bool
|
@Binding var localCountEqualToiCloud: Bool
|
||||||
@Binding var icloudCountEqualToLocal: Bool
|
@Binding var icloudCountEqualToLocal: Bool
|
||||||
|
|
||||||
let asi = ProcessInfo().isiOSAppOnMac
|
|
||||||
let model = UIDevice().model
|
|
||||||
var device: (sf: String, label: String) {
|
|
||||||
if asi {
|
|
||||||
return (sf: "laptopcomputer", label: "Computer")
|
|
||||||
} else if model == "iPhone" {
|
|
||||||
return (sf: model.lowercased(), label: model)
|
|
||||||
} else if model == "iPad" {
|
|
||||||
return (sf: model.lowercased(), label: model)
|
|
||||||
}
|
|
||||||
return (sf: "iphone", label: "iPhone")
|
|
||||||
}
|
|
||||||
|
|
||||||
var updateStatus: () -> Void
|
var updateStatus: () -> Void
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@@ -107,7 +95,7 @@ struct iCloudSettingsView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ZStack {
|
ZStack {
|
||||||
Image(systemName: device.sf)
|
Image(systemName: settingsModel.device.sf)
|
||||||
.resizable()
|
.resizable()
|
||||||
.scaledToFit()
|
.scaledToFit()
|
||||||
.frame(width: 75, height: 75)
|
.frame(width: 75, height: 75)
|
||||||
@@ -117,7 +105,7 @@ struct iCloudSettingsView: View {
|
|||||||
.monospaced()
|
.monospaced()
|
||||||
.bold()
|
.bold()
|
||||||
}
|
}
|
||||||
Text(device.label)
|
Text(settingsModel.device.label)
|
||||||
}
|
}
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
@@ -196,6 +184,7 @@ struct iCloudSettingsView: View {
|
|||||||
#Preview("iCloudSettingsView") {
|
#Preview("iCloudSettingsView") {
|
||||||
iCloudSettingsView(
|
iCloudSettingsView(
|
||||||
viewModel: dummyEventViewModel(),
|
viewModel: dummyEventViewModel(),
|
||||||
|
settingsModel: dummySettingsViewModel(),
|
||||||
hasUbiquitous: .constant(true),
|
hasUbiquitous: .constant(true),
|
||||||
lastSyncWasSuccessful: .constant(true),
|
lastSyncWasSuccessful: .constant(true),
|
||||||
lastSyncWasNormalAgo: .constant(true),
|
lastSyncWasNormalAgo: .constant(true),
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
// StatsView.swift
|
// StatsView.swift
|
||||||
// NearFuture
|
// NearFuture
|
||||||
//
|
//
|
||||||
// Created by Nihaal Sharma on 05/01/2025.
|
// Created by neon443 on 05/01/2025.
|
||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
@@ -2,11 +2,12 @@
|
|||||||
// NearFutureWidgets.swift
|
// NearFutureWidgets.swift
|
||||||
// NearFutureWidgets
|
// NearFutureWidgets
|
||||||
//
|
//
|
||||||
// Created by Nihaal Sharma on 02/01/2025.
|
// Created by neon443 on 02/01/2025.
|
||||||
//
|
//
|
||||||
|
|
||||||
import WidgetKit
|
import WidgetKit
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import AppIntents
|
||||||
|
|
||||||
// Timeline Entry for Widget
|
// Timeline Entry for Widget
|
||||||
struct EventWidgetEntry: TimelineEntry {
|
struct EventWidgetEntry: TimelineEntry {
|
||||||
@@ -46,6 +47,24 @@ struct EventWidgetProvider: TimelineProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Event Widget View
|
// Event Widget View
|
||||||
struct EventWidgetView: View {
|
struct EventWidgetView: View {
|
||||||
var entry: EventWidgetEntry
|
var entry: EventWidgetEntry
|
||||||
@@ -128,17 +147,36 @@ struct EventWidgetView: View {
|
|||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
//short days till if not large widget
|
//short days till if not large widget
|
||||||
if isLarge {
|
if !isLarge {
|
||||||
Text(daysUntilEvent(event.date).long)
|
|
||||||
.font(.caption)
|
|
||||||
.multilineTextAlignment(.trailing)
|
|
||||||
.foregroundColor(event.color.color)
|
|
||||||
.padding(.trailing, -12)
|
|
||||||
} else {
|
|
||||||
Text(daysUntilEvent(event.date).short)
|
Text(daysUntilEvent(event.date).short)
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
.multilineTextAlignment(.trailing)
|
.multilineTextAlignment(.trailing)
|
||||||
.foregroundColor(event.color.color)
|
.foregroundColor(event.date < Date() ? .red : .primary)
|
||||||
|
.padding(.trailing, -12)
|
||||||
|
} else {
|
||||||
|
Button(
|
||||||
|
intent: CompleteEvent(
|
||||||
|
eventID: IntentParameter(
|
||||||
|
title: LocalizedStringResource(
|
||||||
|
stringLiteral: event.id.uuidString
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
if event.complete {
|
||||||
|
Circle()
|
||||||
|
.frame(width: 10)
|
||||||
|
.foregroundStyle(.green)
|
||||||
|
} else {
|
||||||
|
Circle()
|
||||||
|
.frame(width: 10)
|
||||||
|
.foregroundStyle(.gray)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Text(daysUntilEvent(event.date).long)
|
||||||
|
.font(.caption)
|
||||||
|
.multilineTextAlignment(.trailing)
|
||||||
|
.foregroundColor(event.date < Date() ? .red : .primary)
|
||||||
.padding(.trailing, -12)
|
.padding(.trailing, -12)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// NearFutureWidgetsBundle.swift
|
// NearFutureWidgetsBundle.swift
|
||||||
// NearFutureWidgets
|
// NearFutureWidgets
|
||||||
//
|
//
|
||||||
// Created by Nihaal Sharma on 02/01/2025.
|
// Created by neon443 on 02/01/2025.
|
||||||
//
|
//
|
||||||
|
|
||||||
import WidgetKit
|
import WidgetKit
|
||||||
|
|||||||
@@ -2,79 +2,79 @@
|
|||||||
// NearFutureWidgetsLiveActivity.swift
|
// NearFutureWidgetsLiveActivity.swift
|
||||||
// NearFutureWidgets
|
// NearFutureWidgets
|
||||||
//
|
//
|
||||||
// Created by Nihaal Sharma on 02/01/2025.
|
// Created by neon443 on 02/01/2025.
|
||||||
//
|
//
|
||||||
|
|
||||||
import ActivityKit
|
//import ActivityKit
|
||||||
import WidgetKit
|
import WidgetKit
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct NearFutureWidgetsAttributes: ActivityAttributes {
|
//struct NearFutureWidgetsAttributes: ActivityAttributes {
|
||||||
public struct ContentState: Codable, Hashable {
|
// public struct ContentState: Codable, Hashable {
|
||||||
// Dynamic stateful properties about your activity go here!
|
// // Dynamic stateful properties about your activity go here!
|
||||||
var emoji: String
|
// var emoji: String
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
// // Fixed non-changing properties about your activity go here!
|
||||||
|
// var name: String
|
||||||
|
//}
|
||||||
|
|
||||||
// Fixed non-changing properties about your activity go here!
|
//struct NearFutureWidgetsLiveActivity: Widget {
|
||||||
var name: String
|
// var body: some WidgetConfiguration {
|
||||||
}
|
// ActivityConfiguration(for: NearFutureWidgetsAttributes.self) { context in
|
||||||
|
// // Lock screen/banner UI goes here
|
||||||
|
// VStack {
|
||||||
|
// Text("Hello \(context.state.emoji)")
|
||||||
|
// }
|
||||||
|
// .activityBackgroundTint(Color.cyan)
|
||||||
|
// .activitySystemActionForegroundColor(Color.black)
|
||||||
|
//
|
||||||
|
// } dynamicIsland: { context in
|
||||||
|
// DynamicIsland {
|
||||||
|
// // Expanded UI goes here. Compose the expanded UI through
|
||||||
|
// // various regions, like leading/trailing/center/bottom
|
||||||
|
// DynamicIslandExpandedRegion(.leading) {
|
||||||
|
// Text("Leading")
|
||||||
|
// }
|
||||||
|
// DynamicIslandExpandedRegion(.trailing) {
|
||||||
|
// Text("Trailing")
|
||||||
|
// }
|
||||||
|
// DynamicIslandExpandedRegion(.bottom) {
|
||||||
|
// Text("Bottom \(context.state.emoji)")
|
||||||
|
// // more content
|
||||||
|
// }
|
||||||
|
// } compactLeading: {
|
||||||
|
// Text("L")
|
||||||
|
// } compactTrailing: {
|
||||||
|
// Text("T \(context.state.emoji)")
|
||||||
|
// } minimal: {
|
||||||
|
// Text(context.state.emoji)
|
||||||
|
// }
|
||||||
|
// .widgetURL(URL(string: "http://www.apple.com"))
|
||||||
|
// .keylineTint(Color.red)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//extension NearFutureWidgetsAttributes {
|
||||||
|
// fileprivate static var preview: NearFutureWidgetsAttributes {
|
||||||
|
// NearFutureWidgetsAttributes(name: "World")
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
struct NearFutureWidgetsLiveActivity: Widget {
|
//extension NearFutureWidgetsAttributes.ContentState {
|
||||||
var body: some WidgetConfiguration {
|
// fileprivate static var smiley: NearFutureWidgetsAttributes.ContentState {
|
||||||
ActivityConfiguration(for: NearFutureWidgetsAttributes.self) { context in
|
// NearFutureWidgetsAttributes.ContentState(emoji: "😀")
|
||||||
// Lock screen/banner UI goes here
|
// }
|
||||||
VStack {
|
//
|
||||||
Text("Hello \(context.state.emoji)")
|
// fileprivate static var starEyes: NearFutureWidgetsAttributes.ContentState {
|
||||||
}
|
// NearFutureWidgetsAttributes.ContentState(emoji: "🤩")
|
||||||
.activityBackgroundTint(Color.cyan)
|
// }
|
||||||
.activitySystemActionForegroundColor(Color.black)
|
//}
|
||||||
|
//
|
||||||
} dynamicIsland: { context in
|
//#Preview("Notification", as: .content, using: NearFutureWidgetsAttributes.preview) {
|
||||||
DynamicIsland {
|
// NearFutureWidgetsLiveActivity()
|
||||||
// Expanded UI goes here. Compose the expanded UI through
|
//} contentStates: {
|
||||||
// various regions, like leading/trailing/center/bottom
|
// NearFutureWidgetsAttributes.ContentState.smiley
|
||||||
DynamicIslandExpandedRegion(.leading) {
|
// NearFutureWidgetsAttributes.ContentState.starEyes
|
||||||
Text("Leading")
|
//}
|
||||||
}
|
|
||||||
DynamicIslandExpandedRegion(.trailing) {
|
|
||||||
Text("Trailing")
|
|
||||||
}
|
|
||||||
DynamicIslandExpandedRegion(.bottom) {
|
|
||||||
Text("Bottom \(context.state.emoji)")
|
|
||||||
// more content
|
|
||||||
}
|
|
||||||
} compactLeading: {
|
|
||||||
Text("L")
|
|
||||||
} compactTrailing: {
|
|
||||||
Text("T \(context.state.emoji)")
|
|
||||||
} minimal: {
|
|
||||||
Text(context.state.emoji)
|
|
||||||
}
|
|
||||||
.widgetURL(URL(string: "http://www.apple.com"))
|
|
||||||
.keylineTint(Color.red)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension NearFutureWidgetsAttributes {
|
|
||||||
fileprivate static var preview: NearFutureWidgetsAttributes {
|
|
||||||
NearFutureWidgetsAttributes(name: "World")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension NearFutureWidgetsAttributes.ContentState {
|
|
||||||
fileprivate static var smiley: NearFutureWidgetsAttributes.ContentState {
|
|
||||||
NearFutureWidgetsAttributes.ContentState(emoji: "😀")
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate static var starEyes: NearFutureWidgetsAttributes.ContentState {
|
|
||||||
NearFutureWidgetsAttributes.ContentState(emoji: "🤩")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#Preview("Notification", as: .content, using: NearFutureWidgetsAttributes.preview) {
|
|
||||||
NearFutureWidgetsLiveActivity()
|
|
||||||
} contentStates: {
|
|
||||||
NearFutureWidgetsAttributes.ContentState.smiley
|
|
||||||
NearFutureWidgetsAttributes.ContentState.starEyes
|
|
||||||
}
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 729 KiB After Width: | Height: | Size: 729 KiB |
|
Before Width: | Height: | Size: 632 KiB After Width: | Height: | Size: 632 KiB |
38
Resources/Assets.xcassets/bloo.appiconset/Contents.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "bloo.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filename" : "blooDark.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "tinted"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filename" : "NearFutureIconTint.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Resources/Assets.xcassets/bloo.appiconset/NearFutureIconTint.png
Normal file
|
After Width: | Height: | Size: 632 KiB |
BIN
Resources/Assets.xcassets/bloo.appiconset/bloo.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
Resources/Assets.xcassets/bloo.appiconset/blooDark.png
Normal file
|
After Width: | Height: | Size: 712 KiB |
38
Resources/Assets.xcassets/blue.appiconset/Contents.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "blue.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filename" : "blueDark.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "tinted"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filename" : "NearFutureIconTint.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Resources/Assets.xcassets/blue.appiconset/NearFutureIconTint.png
Normal file
|
After Width: | Height: | Size: 632 KiB |
BIN
Resources/Assets.xcassets/blue.appiconset/blue.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
Resources/Assets.xcassets/blue.appiconset/blueDark.png
Normal file
|
After Width: | Height: | Size: 743 KiB |
38
Resources/Assets.xcassets/green.appiconset/Contents.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "green.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filename" : "greenDark.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "tinted"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filename" : "NearFutureIconTint.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 632 KiB |
BIN
Resources/Assets.xcassets/green.appiconset/green.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
Resources/Assets.xcassets/green.appiconset/greenDark.png
Normal file
|
After Width: | Height: | Size: 734 KiB |
38
Resources/Assets.xcassets/pink.appiconset/Contents.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "pink.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filename" : "pinkDark.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "tinted"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filename" : "NearFutureIconTint.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Resources/Assets.xcassets/pink.appiconset/NearFutureIconTint.png
Normal file
|
After Width: | Height: | Size: 632 KiB |
BIN
Resources/Assets.xcassets/pink.appiconset/pink.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
Resources/Assets.xcassets/pink.appiconset/pinkDark.png
Normal file
|
After Width: | Height: | Size: 728 KiB |
38
Resources/Assets.xcassets/purple.appiconset/Contents.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "purple.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filename" : "purpleDark.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "tinted"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filename" : "NearFutureIconTint.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 632 KiB |
BIN
Resources/Assets.xcassets/purple.appiconset/purple.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
Resources/Assets.xcassets/purple.appiconset/purpleDark.png
Normal file
|
After Width: | Height: | Size: 746 KiB |
38
Resources/Assets.xcassets/red.appiconset/Contents.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "red.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filename" : "redDark.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "tinted"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filename" : "NearFutureIconTint.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Resources/Assets.xcassets/red.appiconset/NearFutureIconTint.png
Normal file
|
After Width: | Height: | Size: 632 KiB |
BIN
Resources/Assets.xcassets/red.appiconset/red.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
Resources/Assets.xcassets/red.appiconset/redDark.png
Normal file
|
After Width: | Height: | Size: 751 KiB |
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "display-p3",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0.341",
|
||||||
|
"green" : "0.286",
|
||||||
|
"red" : "0.114"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
38
Resources/Assets.xcassets/yellow.appiconset/Contents.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "yellow.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filename" : "yellowDark.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "tinted"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filename" : "NearFutureIconTint.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 632 KiB |
BIN
Resources/Assets.xcassets/yellow.appiconset/yellow.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
Resources/Assets.xcassets/yellow.appiconset/yellowDark.png
Normal file
|
After Width: | Height: | Size: 743 KiB |