Compare commits
31 Commits
feat-notif
...
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 |
@@ -12,6 +12,6 @@ TEAM_ID = 8JGND254B7
|
||||
BUNDLE_ID = com.neon443.NearFuture
|
||||
BUNDLE_ID_WIDGETS = com.neon443.NearFuture.widgets
|
||||
GROUP_ID = group.NearFuture
|
||||
VERSION = 4.0.0
|
||||
VERSION = 4.4.0
|
||||
NAME = Near Future
|
||||
BUILD_NUMBER = 0
|
||||
BUILD_NUMBER = 1
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
objects = {
|
||||
|
||||
/* 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 */; };
|
||||
A920C28C2D24011400E4F9B1 /* Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C28B2D24011400E4F9B1 /* Item.swift */; };
|
||||
A920C28E2D24011A00E4F9B1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A920C28D2D24011A00E4F9B1 /* Assets.xcassets */; };
|
||||
@@ -70,6 +73,9 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
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; };
|
||||
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>"; };
|
||||
@@ -220,6 +226,7 @@
|
||||
A949F83F2DCAABE00064DCA0 /* ContentView.swift */,
|
||||
A949F8402DCAABE00064DCA0 /* EventListView.swift */,
|
||||
A949F8412DCAABE00064DCA0 /* HelpView.swift */,
|
||||
A914FA4A2DD26C0F00856265 /* HomeView.swift */,
|
||||
);
|
||||
path = Home;
|
||||
sourceTree = "<group>";
|
||||
@@ -227,10 +234,11 @@
|
||||
A949F8472DCAABE00064DCA0 /* Settings */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A949F8432DCAABE00064DCA0 /* ExportView.swift */,
|
||||
A949F8442DCAABE00064DCA0 /* iCloudSettingsView.swift */,
|
||||
A949F8452DCAABE00064DCA0 /* ImportView.swift */,
|
||||
A949F8462DCAABE00064DCA0 /* SettingsView.swift */,
|
||||
A949F8442DCAABE00064DCA0 /* iCloudSettingsView.swift */,
|
||||
A914FA4C2DD2768900856265 /* WhatsNewView.swift */,
|
||||
A949F8452DCAABE00064DCA0 /* ImportView.swift */,
|
||||
A949F8432DCAABE00064DCA0 /* ExportView.swift */,
|
||||
);
|
||||
path = Settings;
|
||||
sourceTree = "<group>";
|
||||
@@ -246,12 +254,12 @@
|
||||
A949F84A2DCAABE00064DCA0 /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A949F83B2DCAABE00064DCA0 /* Archive */,
|
||||
A949F83E2DCAABE00064DCA0 /* Events */,
|
||||
A949F8422DCAABE00064DCA0 /* Home */,
|
||||
A949F8472DCAABE00064DCA0 /* Settings */,
|
||||
A949F8492DCAABE00064DCA0 /* Stats */,
|
||||
A949F83E2DCAABE00064DCA0 /* Events */,
|
||||
A949F83B2DCAABE00064DCA0 /* Archive */,
|
||||
A949F85E2DCABB420064DCA0 /* Misc */,
|
||||
A949F8492DCAABE00064DCA0 /* Stats */,
|
||||
A949F8472DCAABE00064DCA0 /* Settings */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
@@ -268,6 +276,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A949F85D2DCABB420064DCA0 /* Buttons.swift */,
|
||||
A914FA4E2DD276D200856265 /* AboutView.swift */,
|
||||
);
|
||||
path = Misc;
|
||||
sourceTree = "<group>";
|
||||
@@ -449,12 +458,15 @@
|
||||
files = (
|
||||
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 */,
|
||||
@@ -505,7 +517,10 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
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_INCLUDE_ALL_APPICON_ASSETS = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
@@ -565,7 +580,7 @@
|
||||
);
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 6.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -573,7 +588,10 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
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_INCLUDE_ALL_APPICON_ASSETS = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
@@ -621,7 +639,7 @@
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_VERSION = 6.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -629,8 +647,10 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = A90FDE222DC0D4310012790C /* Config.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "bloo blue green pink purple red yellow";
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_USE_OPTIMIZATION_PROFILE = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = NearFuture/NearFuture.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(BUILD_NUMBER)";
|
||||
@@ -680,8 +700,10 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = A90FDE222DC0D4310012790C /* Config.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "bloo blue green pink purple red yellow";
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_USE_OPTIMIZATION_PROFILE = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = NearFuture/NearFuture.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(BUILD_NUMBER)";
|
||||
@@ -730,6 +752,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||
CLANG_USE_OPTIMIZATION_PROFILE = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = NearFutureWidgets/NearFutureWidgetsExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(BUILD_NUMBER)";
|
||||
@@ -770,6 +793,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||
CLANG_USE_OPTIMIZATION_PROFILE = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = NearFutureWidgets/NearFutureWidgetsExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(BUILD_NUMBER)";
|
||||
|
||||
@@ -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>
|
||||
<key>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>NearFuture nodebug.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>2</integer>
|
||||
</dict>
|
||||
<key>NearFuture.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
|
||||
@@ -126,6 +126,7 @@ struct EventListView: View {
|
||||
)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
.transition(.opacity)
|
||||
.contextMenu() {
|
||||
Button(role: .destructive) {
|
||||
let eventToModify = viewModel.events.firstIndex() { currEvent in
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict/>
|
||||
<dict>
|
||||
<key>AppIntents</key>
|
||||
<array>
|
||||
<string>com.neon443.NearFuture.CompleteEvent</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Item.swift
|
||||
// NearFuture
|
||||
//
|
||||
// Created by Nihaal Sharma on 24/12/2024.
|
||||
// Created by neon443 on 24/12/2024.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@@ -10,6 +10,7 @@ import SwiftData
|
||||
import SwiftUI
|
||||
import WidgetKit
|
||||
import UserNotifications
|
||||
import AppIntents
|
||||
|
||||
//@Model
|
||||
//final class Item {
|
||||
@@ -20,7 +21,7 @@ import UserNotifications
|
||||
// }
|
||||
//}
|
||||
|
||||
struct Event: Identifiable, Codable {
|
||||
struct Event: Identifiable, Codable, Equatable, Animatable {
|
||||
var id = UUID()
|
||||
var name: String
|
||||
var complete: Bool
|
||||
@@ -107,26 +108,51 @@ func daysUntilEvent(_ eventDate: Date) -> (long: String, short: String) {
|
||||
struct Settings: Codable, Equatable {
|
||||
var showCompletedInHome: Bool
|
||||
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 {
|
||||
@Published var settings: Settings = Settings(
|
||||
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] = [
|
||||
Color(UIColor(named: "uiColors/red")!),
|
||||
Color(UIColor(named: "uiColors/orange")!),
|
||||
Color(UIColor(named: "uiColors/yellow")!),
|
||||
Color(UIColor(named: "uiColors/green")!),
|
||||
Color(UIColor(named: "uiColors/blue")!),
|
||||
Color(UIColor(named: "uiColors/indigo")!),
|
||||
Color(UIColor(named: "uiColors/basic")!)
|
||||
@Published var colorChoices: [AccentIcon] = []
|
||||
|
||||
let accentChoices: [String] = [
|
||||
"red",
|
||||
"orange",
|
||||
"yellow",
|
||||
"green",
|
||||
"blue",
|
||||
"bloo",
|
||||
"purple",
|
||||
"pink"
|
||||
]
|
||||
|
||||
@Published var device: (sf: String, label: String)
|
||||
|
||||
init(load: Bool = true) {
|
||||
self.device = getDevice()
|
||||
if load {
|
||||
loadSettings()
|
||||
Task {
|
||||
@@ -138,6 +164,13 @@ class SettingsViewModel: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
func changeTint(to: String) {
|
||||
if let uicolor = UIColor(named: "uiColors/\(to)") {
|
||||
self.settings.tint = ColorCodable(uiColor: uicolor)
|
||||
saveSettings()
|
||||
}
|
||||
}
|
||||
|
||||
let appGroupSettingsStore = UserDefaults(suiteName: "group.NearFuture") ?? UserDefaults.standard
|
||||
let icSettStore = NSUbiquitousKeyValueStore.default
|
||||
|
||||
@@ -152,6 +185,9 @@ class SettingsViewModel: ObservableObject {
|
||||
self.settings = decodedSetts
|
||||
}
|
||||
}
|
||||
if self.settings.prevAppVersion != getVersion()+getBuildID() {
|
||||
self.settings.showWhatsNew = true
|
||||
}
|
||||
}
|
||||
|
||||
func saveSettings() {
|
||||
@@ -165,7 +201,7 @@ class SettingsViewModel: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
class EventViewModel: ObservableObject {
|
||||
class EventViewModel: ObservableObject, @unchecked Sendable {
|
||||
@Published var events: [Event] = []
|
||||
@Published var icloudData: [Event] = []
|
||||
|
||||
@@ -227,6 +263,7 @@ class EventViewModel: ObservableObject {
|
||||
}
|
||||
}
|
||||
updateSyncStatus()
|
||||
self.events.sort() {$0.date < $1.date}
|
||||
}
|
||||
|
||||
func getNotifs() async -> [UNNotificationRequest] {
|
||||
@@ -414,10 +451,21 @@ class EventViewModel: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
class dummyEventViewModel: EventViewModel {
|
||||
class dummyEventViewModel: EventViewModel, @unchecked Sendable {
|
||||
var template2: Event
|
||||
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)
|
||||
self.events = [self.example, self.template, self.example, self.template]
|
||||
self.events = [self.example, self.template, self.template2]
|
||||
self.events[0].complete.toggle()
|
||||
}
|
||||
}
|
||||
@@ -516,3 +564,84 @@ func cancelNotif(_ id: String) {
|
||||
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,7 +2,7 @@
|
||||
// NearFutureApp.swift
|
||||
// NearFuture
|
||||
//
|
||||
// Created by Nihaal Sharma on 24/12/2024.
|
||||
// Created by neon443 on 24/12/2024.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// AppIntent.swift
|
||||
// NearFutureWidgets
|
||||
//
|
||||
// Created by Nihaal Sharma on 02/01/2025.
|
||||
// Created by neon443 on 02/01/2025.
|
||||
//
|
||||
|
||||
import WidgetKit
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// NearFutureWidgets.swift
|
||||
// NearFutureWidgets
|
||||
//
|
||||
// Created by Nihaal Sharma on 02/01/2025.
|
||||
// Created by neon443 on 02/01/2025.
|
||||
//
|
||||
|
||||
import WidgetKit
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// NearFutureWidgetsBundle.swift
|
||||
// NearFutureWidgets
|
||||
//
|
||||
// Created by Nihaal Sharma on 02/01/2025.
|
||||
// Created by neon443 on 02/01/2025.
|
||||
//
|
||||
|
||||
import WidgetKit
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// NearFutureWidgetsLiveActivity.swift
|
||||
// NearFutureWidgets
|
||||
//
|
||||
// Created by Nihaal Sharma on 02/01/2025.
|
||||
// Created by neon443 on 02/01/2025.
|
||||
//
|
||||
|
||||
import ActivityKit
|
||||
|
||||
@@ -10,7 +10,9 @@ import SwiftUI
|
||||
struct ArchiveView: View {
|
||||
@ObservedObject var viewModel: EventViewModel
|
||||
@State var showAddEvent: Bool = false
|
||||
@State var hey: UUID = UUID()
|
||||
var filteredEvents: [Event] {
|
||||
return viewModel.events.filter() {$0.complete}
|
||||
}
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
ZStack {
|
||||
@@ -19,15 +21,14 @@ struct ArchiveView: View {
|
||||
HelpView(showAddEvent: $showAddEvent)
|
||||
} else {
|
||||
ScrollView {
|
||||
ForEach(viewModel.events.filter({$0.complete})) { event in
|
||||
ForEach(filteredEvents) { event in
|
||||
EventListView(viewModel: viewModel, event: event)
|
||||
.transition(.moveAndFadeReversed)
|
||||
.id(event.complete)
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.id(hey)
|
||||
.onReceive(viewModel.objectWillChange) {
|
||||
hey = UUID()
|
||||
}
|
||||
}
|
||||
.animation(.default, value: filteredEvents)
|
||||
}
|
||||
}
|
||||
.scrollContentBackground(.hidden)
|
||||
@@ -58,12 +59,6 @@ struct ArchiveView: View {
|
||||
eventRecurrence: $viewModel.editableTemplate.recurrence,
|
||||
adding: true
|
||||
)
|
||||
.presentationDragIndicator(.visible)
|
||||
.apply {
|
||||
if #available(iOS 16.4, *) {
|
||||
$0.presentationBackground(.ultraThinMaterial)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,5 +66,3 @@ struct ArchiveView: View {
|
||||
#Preview {
|
||||
ArchiveView(viewModel: dummyEventViewModel())
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// AddEventView.swift
|
||||
// NearFuture
|
||||
//
|
||||
// Created by Nihaal Sharma on 25/12/2024.
|
||||
// Created by neon443 on 25/12/2024.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
@@ -24,6 +24,8 @@ struct AddEventView: View {
|
||||
@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
|
||||
@@ -32,172 +34,190 @@ struct AddEventView: View {
|
||||
@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)
|
||||
.presentationDetents([.medium])
|
||||
.apply {
|
||||
if #available(iOS 16.4, *) {
|
||||
$0.presentationBackground(.ultraThinMaterial)
|
||||
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)
|
||||
}
|
||||
}
|
||||
ColorPicker("", selection: $eventColor, supportsOpacity: false)
|
||||
.fixedSize()
|
||||
|
||||
// dscription
|
||||
ZStack {
|
||||
TextField("Event Name", text: $eventName)
|
||||
TextField("Event Notes", text: $eventNotes)
|
||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||
.padding(.trailing, eventName.isEmpty ? 0 : 30)
|
||||
.animation(.spring, value: eventName)
|
||||
.focused($focusedField, equals: Field.Name)
|
||||
.submitLabel(.next)
|
||||
.padding(.trailing, eventNotes.isEmpty ? 0 : 30)
|
||||
.animation(.spring, value: eventNotes)
|
||||
.focused($focusedField, equals: Field.Notes)
|
||||
.submitLabel(.done)
|
||||
.onSubmit {
|
||||
focusedField = .Notes
|
||||
focusedField = nil
|
||||
}
|
||||
MagicClearButton(text: $eventName)
|
||||
MagicClearButton(text: $eventNotes)
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
|
||||
// date picker
|
||||
HStack {
|
||||
Spacer()
|
||||
DatePicker("", selection: $eventDate, displayedComponents: .date)
|
||||
.datePickerStyle(WheelDatePickerStyle())
|
||||
Spacer()
|
||||
Button() {
|
||||
eventDate = Date()
|
||||
} label: {
|
||||
Image(systemName: "arrow.uturn.left")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
}
|
||||
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)
|
||||
}
|
||||
.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)
|
||||
|
||||
// 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.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.pickerStyle(SegmentedPickerStyle())
|
||||
Text(
|
||||
describeOccurrence(
|
||||
date: eventDate,
|
||||
recurrence: eventRecurrence
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
.presentationDragIndicator(.visible)
|
||||
.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.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.apply {
|
||||
if #available(iOS 16.4, *) {
|
||||
$0.presentationBackground(.ultraThinMaterial)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -233,11 +253,5 @@ struct AddEventView: View {
|
||||
eventRecurrence: .constant(vm.template.recurrence),
|
||||
adding: true
|
||||
)
|
||||
.presentationDragIndicator(.visible)
|
||||
.apply {
|
||||
if #available(iOS 16.4, *) {
|
||||
$0.presentationBackground(.ultraThinMaterial)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// EditEventView.swift
|
||||
// NearFuture
|
||||
//
|
||||
// Created by Nihaal Sharma on 02/01/2025.
|
||||
// Created by neon443 on 02/01/2025.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// ContentView.swift
|
||||
// NearFuture
|
||||
//
|
||||
// Created by Nihaal Sharma on 24/12/2024.
|
||||
// Created by neon443 on 24/12/2024.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
@@ -13,152 +13,47 @@ enum Field {
|
||||
case Search
|
||||
}
|
||||
enum Tab {
|
||||
case Home
|
||||
case Archive
|
||||
case Statistics
|
||||
case Settings
|
||||
case Gradient
|
||||
case home
|
||||
case archive
|
||||
case stats
|
||||
case settings
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@State var selection: Tab = .home
|
||||
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
.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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TabView(selection: $selection) {
|
||||
HomeView(viewModel: viewModel, settingsModel: settingsModel)
|
||||
.tabItem {
|
||||
Label("Home", systemImage: "house")
|
||||
}
|
||||
.focused($focusedTab, equals: Tab.Home)
|
||||
.tag(Tab.home)
|
||||
ArchiveView(viewModel: viewModel)
|
||||
.tabItem() {
|
||||
Label("Archive", systemImage: "tray.full")
|
||||
}
|
||||
.focused($focusedTab, equals: Tab.Archive)
|
||||
.tag(Tab.archive)
|
||||
StatsView(viewModel: viewModel)
|
||||
.tabItem {
|
||||
Label("Statistics", systemImage: "chart.pie")
|
||||
}
|
||||
.focused($focusedTab, equals: Tab.Statistics)
|
||||
.tag(Tab.stats)
|
||||
SettingsView(viewModel: viewModel, settingsModel: settingsModel)
|
||||
.tabItem {
|
||||
Label("Settings", systemImage: "gear")
|
||||
}
|
||||
.focused($focusedTab, equals: Tab.Settings)
|
||||
.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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,9 +66,6 @@ struct ContentView: View {
|
||||
}
|
||||
|
||||
extension View {
|
||||
var appearance: ColorScheme {
|
||||
return UITraitCollection.current.userInterfaceStyle == .dark ? .dark : .light
|
||||
}
|
||||
var backgroundGradient: some View {
|
||||
return LinearGradient(
|
||||
gradient: Gradient(colors: [.bgTop, .two]),
|
||||
@@ -182,8 +74,23 @@ extension View {
|
||||
)
|
||||
.ignoresSafeArea(.all)
|
||||
}
|
||||
}
|
||||
|
||||
extension View {
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ struct EventListView: View {
|
||||
VStack {
|
||||
Text("\(daysUntilEvent(event.date).long)")
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(.one)
|
||||
.foregroundStyle(event.date.timeIntervalSinceNow < 0 ? .red : .one)
|
||||
}
|
||||
Button() {
|
||||
withAnimation {
|
||||
@@ -111,13 +111,19 @@ struct EventListView: View {
|
||||
.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(appearance == .dark ? 0.5 : 1),
|
||||
.one.opacity(0.5),
|
||||
lineWidth: 1
|
||||
)
|
||||
)
|
||||
|
||||
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()
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// SettingsView.swift
|
||||
// NearFuture
|
||||
//
|
||||
// Created by Nihaal Sharma on 29/12/2024.
|
||||
// Created by neon443 on 29/12/2024.
|
||||
//
|
||||
|
||||
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 {
|
||||
NavigationStack {
|
||||
ZStack {
|
||||
@@ -47,11 +63,12 @@ struct SettingsView: View {
|
||||
List {
|
||||
ScrollView(.horizontal) {
|
||||
HStack {
|
||||
ForEach(settingsModel.accentChoices, id: \.self) { color in
|
||||
ForEach(settingsModel.accentChoices, id: \.self) { choice in
|
||||
let color = Color(uiColor: UIColor(named: "uiColors/\(choice)")!)
|
||||
ZStack {
|
||||
Button() {
|
||||
settingsModel.settings.tint.colorBind = color
|
||||
settingsModel.saveSettings()
|
||||
settingsModel.changeTint(to: choice)
|
||||
changeIcon(to: choice)
|
||||
} label: {
|
||||
Circle()
|
||||
.foregroundStyle(color)
|
||||
@@ -67,6 +84,13 @@ 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 {
|
||||
@@ -89,6 +113,7 @@ struct SettingsView: View {
|
||||
NavigationLink() {
|
||||
iCloudSettingsView(
|
||||
viewModel: viewModel,
|
||||
settingsModel: settingsModel,
|
||||
hasUbiquitous: $hasUbiquitous,
|
||||
lastSyncWasSuccessful: $lastSyncWasSuccessful,
|
||||
lastSyncWasNormalAgo: $lastSyncWasNormalAgo,
|
||||
@@ -148,20 +173,7 @@ struct SettingsView: View {
|
||||
}
|
||||
}
|
||||
Section("About") {
|
||||
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)
|
||||
}
|
||||
AboutView()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,17 +196,3 @@ struct SettingsView: View {
|
||||
settingsModel: dummySettingsViewModel()
|
||||
)
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
struct iCloudSettingsView: View {
|
||||
@State var viewModel: EventViewModel
|
||||
@ObservedObject var viewModel: EventViewModel
|
||||
@ObservedObject var settingsModel: SettingsViewModel
|
||||
@State var showPushAlert: Bool = false
|
||||
@State var showPullAlert: Bool = false
|
||||
|
||||
@@ -18,19 +19,6 @@ struct iCloudSettingsView: View {
|
||||
@Binding var localCountEqualToiCloud: 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 body: some View {
|
||||
@@ -107,7 +95,7 @@ struct iCloudSettingsView: View {
|
||||
}
|
||||
}
|
||||
ZStack {
|
||||
Image(systemName: device.sf)
|
||||
Image(systemName: settingsModel.device.sf)
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 75, height: 75)
|
||||
@@ -117,7 +105,7 @@ struct iCloudSettingsView: View {
|
||||
.monospaced()
|
||||
.bold()
|
||||
}
|
||||
Text(device.label)
|
||||
Text(settingsModel.device.label)
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
@@ -196,6 +184,7 @@ struct iCloudSettingsView: View {
|
||||
#Preview("iCloudSettingsView") {
|
||||
iCloudSettingsView(
|
||||
viewModel: dummyEventViewModel(),
|
||||
settingsModel: dummySettingsViewModel(),
|
||||
hasUbiquitous: .constant(true),
|
||||
lastSyncWasSuccessful: .constant(true),
|
||||
lastSyncWasNormalAgo: .constant(true),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// StatsView.swift
|
||||
// NearFuture
|
||||
//
|
||||
// Created by Nihaal Sharma on 05/01/2025.
|
||||
// Created by neon443 on 05/01/2025.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
// NearFutureWidgets.swift
|
||||
// NearFutureWidgets
|
||||
//
|
||||
// Created by Nihaal Sharma on 02/01/2025.
|
||||
// Created by neon443 on 02/01/2025.
|
||||
//
|
||||
|
||||
import WidgetKit
|
||||
import SwiftUI
|
||||
import AppIntents
|
||||
|
||||
// Timeline Entry for Widget
|
||||
struct EventWidgetEntry: TimelineEntry {
|
||||
@@ -46,6 +47,24 @@ struct EventWidgetProvider: TimelineProvider {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Event Widget View
|
||||
struct EventWidgetView: View {
|
||||
var entry: EventWidgetEntry
|
||||
@@ -128,17 +147,36 @@ struct EventWidgetView: View {
|
||||
Spacer()
|
||||
|
||||
//short days till if not large widget
|
||||
if isLarge {
|
||||
Text(daysUntilEvent(event.date).long)
|
||||
.font(.caption)
|
||||
.multilineTextAlignment(.trailing)
|
||||
.foregroundColor(event.color.color)
|
||||
.padding(.trailing, -12)
|
||||
} else {
|
||||
if !isLarge {
|
||||
Text(daysUntilEvent(event.date).short)
|
||||
.font(.caption)
|
||||
.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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// NearFutureWidgetsBundle.swift
|
||||
// NearFutureWidgets
|
||||
//
|
||||
// Created by Nihaal Sharma on 02/01/2025.
|
||||
// Created by neon443 on 02/01/2025.
|
||||
//
|
||||
|
||||
import WidgetKit
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// NearFutureWidgetsLiveActivity.swift
|
||||
// NearFutureWidgets
|
||||
//
|
||||
// Created by Nihaal Sharma on 02/01/2025.
|
||||
// Created by neon443 on 02/01/2025.
|
||||
//
|
||||
|
||||
//import ActivityKit
|
||||
|
||||
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 |
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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 |