can now export events, cant import lol

This commit is contained in:
neon443
2025-02-26 18:56:25 +00:00
parent 96250e01c3
commit f556f7e4ca
12 changed files with 521 additions and 146 deletions

View File

@@ -15,6 +15,7 @@
A920C2BB2D2401A400E4F9B1 /* AddEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C2B72D2401A300E4F9B1 /* AddEventView.swift */; };
A920C2BE2D24021A00E4F9B1 /* SFSymbolsPicker in Frameworks */ = {isa = PBXBuildFile; productRef = A920C2BD2D24021A00E4F9B1 /* SFSymbolsPicker */; };
A920C2C12D2403CA00E4F9B1 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C2C02D2403CA00E4F9B1 /* ContentView.swift */; };
A93BC0942D2B18A3002E8BBD /* StatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93BC0932D2B18A3002E8BBD /* StatsView.swift */; };
A979F57F2D26B1300094C0B3 /* EditEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A979F57E2D26B1300094C0B3 /* EditEventView.swift */; };
A979F6052D270AF00094C0B3 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A979F6042D270AF00094C0B3 /* WidgetKit.framework */; };
A979F6072D270AF00094C0B3 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A979F6062D270AF00094C0B3 /* SwiftUI.framework */; };
@@ -60,6 +61,7 @@
A920C2B42D2401A100E4F9B1 /* SettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
A920C2B72D2401A300E4F9B1 /* AddEventView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddEventView.swift; sourceTree = "<group>"; };
A920C2C02D2403CA00E4F9B1 /* ContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
A93BC0932D2B18A3002E8BBD /* StatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsView.swift; sourceTree = "<group>"; };
A979F57E2D26B1300094C0B3 /* EditEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditEventView.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>"; };
@@ -124,6 +126,7 @@
A979F57E2D26B1300094C0B3 /* EditEventView.swift */,
A920C2B72D2401A300E4F9B1 /* AddEventView.swift */,
A920C2C02D2403CA00E4F9B1 /* ContentView.swift */,
A93BC0932D2B18A3002E8BBD /* StatsView.swift */,
A920C2B42D2401A100E4F9B1 /* SettingsView.swift */,
A920C2872D24011400E4F9B1 /* NearFutureApp.swift */,
A920C28B2D24011400E4F9B1 /* Item.swift */,
@@ -290,6 +293,7 @@
A920C2B82D2401A300E4F9B1 /* SettingsView.swift in Sources */,
A920C28C2D24011400E4F9B1 /* Item.swift in Sources */,
A920C2882D24011400E4F9B1 /* NearFutureApp.swift in Sources */,
A93BC0942D2B18A3002E8BBD /* StatsView.swift in Sources */,
A979F57F2D26B1300094C0B3 /* EditEventView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -438,7 +442,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = NearFuture/NearFuture.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 11;
CURRENT_PROJECT_VERSION = 16;
DEVELOPMENT_ASSET_PATHS = "\"NearFuture/Preview Content\"";
DEVELOPMENT_TEAM = P6PV2R9443;
ENABLE_HARDENED_RUNTIME = NO;
@@ -463,7 +467,9 @@
PRODUCT_BUNDLE_IDENTIFIER = dev.neon443.NearFuture;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = auto;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -478,7 +484,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = NearFuture/NearFuture.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 11;
CURRENT_PROJECT_VERSION = 16;
DEVELOPMENT_ASSET_PATHS = "\"NearFuture/Preview Content\"";
DEVELOPMENT_TEAM = P6PV2R9443;
ENABLE_HARDENED_RUNTIME = NO;
@@ -503,7 +509,9 @@
PRODUCT_BUNDLE_IDENTIFIER = dev.neon443.NearFuture;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = auto;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -517,7 +525,7 @@
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CODE_SIGN_ENTITLEMENTS = NearFutureWidgets/NearFutureWidgetsExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 11;
CURRENT_PROJECT_VERSION = 16;
DEVELOPMENT_TEAM = P6PV2R9443;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = NearFutureWidgets/Info.plist;
@@ -547,7 +555,7 @@
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CODE_SIGN_ENTITLEMENTS = NearFutureWidgets/NearFutureWidgetsExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 11;
CURRENT_PROJECT_VERSION = 16;
DEVELOPMENT_TEAM = P6PV2R9443;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = NearFutureWidgets/Info.plist;

View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1540"
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 = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "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>

View File

@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1540"
wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A979F6012D270AF00094C0B3"
BuildableName = "NearFutureWidgetsExtension.appex"
BlueprintName = "NearFutureWidgetsExtension"
ReferencedContainer = "container:NearFuture.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<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"
askForAppToLaunch = "Yes"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A920C2832D24011300E4F9B1"
BuildableName = "NearFuture.app"
BlueprintName = "NearFuture"
ReferencedContainer = "container:NearFuture.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<EnvironmentVariables>
<EnvironmentVariable
key = "_XCWidgetKind"
value = ""
isEnabled = "YES">
</EnvironmentVariable>
<EnvironmentVariable
key = "_XCWidgetDefaultView"
value = "timeline"
isEnabled = "YES">
</EnvironmentVariable>
<EnvironmentVariable
key = "_XCWidgetFamily"
value = "systemMedium"
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
askForAppToLaunch = "Yes"
launchAutomaticallySubstyle = "2">
<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>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
uuid = "81691EC5-53AC-4338-9E2E-C1A8F23D20E5"
type = "1"
version = "2.0">
<Breakpoints>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "4B7F7ADF-35FB-4F84-A9FE-98FB688F18BC"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "NearFuture/Item.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "245"
endingLineNumber = "245"
landmarkName = "importEvents(_:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>NearFuture.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>1</integer>
</dict>
<key>NearFutureWidgetsExtension.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>A920C2832D24011300E4F9B1</key>
<dict>
<key>primary</key>
<true/>
</dict>
<key>A979F6012D270AF00094C0B3</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>

BIN
NearFuture/.DS_Store vendored Normal file
View File

Binary file not shown.

View File

@@ -45,11 +45,11 @@ struct AddEventView: View {
Image(systemName: eventSymbol)
.resizable()
.scaledToFit()
.frame(width: 25, height: 25)
.frame(width: 20, height: 20)
.foregroundStyle(eventColor)
}
// .frame(width: 30)
.buttonStyle(.bordered)
.frame(width: 20)
.buttonStyle(.borderless)
.sheet(isPresented: $isSymbolPickerPresented) {
SymbolsPicker(
selection: $eventSymbol,
@@ -88,8 +88,12 @@ struct AddEventView: View {
// date picker
DatePicker("Event Date", selection: $eventDate, displayedComponents: .date)
HStack {
Spacer()
DatePicker("", selection: $eventDate, displayedComponents: .date)
.datePickerStyle(WheelDatePickerStyle())
Spacer()
}
// re-ocurrence Picker
Picker("Recurrence", selection: $eventRecurrence) {
@@ -122,7 +126,6 @@ struct AddEventView: View {
Text("Save Event")
.font(.headline)
.cornerRadius(10)
.shadow(radius: 10)
.buttonStyle(BorderedProminentButtonStyle())
}
.disabled(eventName.isEmpty)

View File

@@ -8,64 +8,6 @@
import SwiftUI
import SwiftData
//struct ContentView: View {
// @Environment(\.modelContext) private var modelContext
// @Query private var items: [Item]
//
// var body: some View {
// NavigationSplitView {
// List {
// ForEach(items) { item in
// NavigationLink {
// Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))")
// } label: {
// Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
// }
// }
// .onDelete(perform: deleteItems)
// }
//#if os(macOS)
// .navigationSplitViewColumnWidth(min: 180, ideal: 200)
//#endif
// .toolbar {
//#if os(iOS)
// ToolbarItem(placement: .navigationBarTrailing) {
// EditButton()
// }
//#endif
// ToolbarItem {
// Button(action: addItem) {
// Label("Add Item", systemImage: "plus")
// }
// }
// }
// } detail: {
// Text("Select an item")
// }
// }
//
// private func addItem() {
// withAnimation {
// let newItem = Item(timestamp: Date())
// modelContext.insert(newItem)
// }
// }
//
// private func deleteItems(offsets: IndexSet) {
// withAnimation {
// for index in offsets {
// modelContext.delete(items[index])
// }
// }
// }
//}
//
//#Preview {
// ContentView()
// .modelContainer(for: Item.self, inMemory: true)
//}
struct ContentView: View {
@StateObject private var viewModel = EventViewModel()
@State private var eventName = ""
@@ -124,7 +66,9 @@ struct ContentView: View {
private enum Field {
case Search
}
var body: some View {
TabView {
NavigationView {
ZStack {
backgroundGradient
@@ -213,6 +157,14 @@ struct ContentView: View {
}
}
}
.tabItem {
Label("Home", systemImage: "house")
}
StatsView(viewModel: viewModel)
.tabItem {
Label("Statistics", systemImage: "chart.pie")
}
}
}
}

View File

@@ -38,7 +38,7 @@ struct ColorCodable: Codable {
var green: Double
var blue: Double
var alpha: Double
//for the brainrotted: alpha is the opacity/transparency of the color,
//for the brainrot kids: alpha is the opacity/transparency of the color,
//alpha == 0 completely transparent
//alpha == 1 completely opaque
@@ -217,6 +217,60 @@ class EventViewModel: ObservableObject {
saveEvents()
}
func exportEvents() -> String? {
let encoder = JSONEncoder()
// Custom date encoding strategy to handle date formatting
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
encoder.dateEncodingStrategy = .formatted(dateFormatter)
do {
// Encode the events array to JSON data
let encodedData = try encoder.encode(events)
// Convert the JSON data to a string
if let jsonString = String(data: encodedData, encoding: .utf8) {
return jsonString
} else {
print("Failed to convert encoded data to string")
return nil
}
} catch {
print("Failed to encode events: \(error.localizedDescription)")
return nil
}
}
func importEvents(_ imp: String) {
guard let impData = imp.data(using: .utf8) else {
print("Failed to convert string to data")
return
}
// Create a JSONDecoder
let decoder = JSONDecoder()
// Add a custom date formatter for decoding the date string
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ" // Adjust this to the date format you're using
decoder.dateDecodingStrategy = .formatted(dateFormatter)
do {
// Attempt to decode the events from the provided data
let decoded = try decoder.decode([Event].self, from: impData)
print("Successfully decoded events: \(decoded)")
// Save and reload after importing events
self.events = decoded
saveEvents()
loadEvents()
} catch {
// Print error if decoding fails
print("Failed to decode events: \(error.localizedDescription)")
}
}
//MARK: Danger Zone
func dangerClearLocalData() {
UserDefaults.standard.removeObject(forKey: "events")

View File

@@ -16,6 +16,7 @@ struct SettingsView: View {
@State private var lastSyncWasNormalAgo: Bool = false
@State private var localCountEqualToiCloud: Bool = false
@State private var icloudCountEqualToLocal: Bool = false
@State private var importStr: String = ""
func updateStatus() {
let vm = viewModel
@@ -67,6 +68,48 @@ struct SettingsView: View {
updateStatus()
}
NavigationLink() {
NavigationView() {
Button() {
UIPasteboard.general.string = "\(viewModel.exportEvents())"
print(viewModel.exportEvents())
} label: {
Text("copy")
}
Text("\(viewModel.exportEvents())")
}
} label: {
Image(systemName: "list.bullet.rectangle")
Text("Export events")
}
NavigationLink() {
NavigationView() {
VStack {
TextEditor(text: $importStr)
.foregroundStyle(.foreground, .gray)
.background(.gray)
.frame(width: 200, height: 400)
.shadow(radius: 5)
Button() {
viewModel.importEvents(importStr)
} label: {
Text("import events")
}
.buttonStyle(BorderedProminentButtonStyle())
Button() {
if let pb = UIPasteboard.general.string {
print(pb)
}
} label: {
Text("print pb")
}
}
}
} label: {
Image(systemName: "square.and.arrow.down")
Text("Import events")
}
Section("Danger Zone") {
Button("Delete local data", role: .destructive) {
viewModel.dangerClearLocalData()

View File

@@ -0,0 +1,67 @@
//
// StatsView.swift
// NearFuture
//
// Created by Nihaal Sharma on 05/01/2025.
//
import SwiftUI
import Charts
struct StatsView: View {
@ObservedObject var viewModel: EventViewModel
var body: some View {
NavigationView {
List {
Section(header: Text("Upcoming Events")) {
let upcomingEvents = viewModel.events.filter { $0.date > Date() }
Text("\(upcomingEvents.count) upcoming event\(upcomingEvents.count == 1 ? "" : "s")")
.font(.headline)
.foregroundStyle(Color.accentColor)
let pastEvents = viewModel.events.filter { $0.date < Date() }
Text("\(pastEvents.count) past event\(pastEvents.count == 1 ? "" : "s")")
.foregroundStyle(.gray)
}
Section("Events by Month") {
let eventsByMonth = Dictionary(grouping: viewModel.events, by: { $0.date })
ForEach(eventsByMonth.keys.sorted(), id: \.self) { month in
let count = eventsByMonth[month]?.count ?? 0
Text("\(count) - \(month.formatted(date: .long, time: .omitted))")
}
}
Section("Event Count") {
let eventCount = viewModel.events.count
Text("\(eventCount) event\(eventCount == 1 ? "" : "s")")
.font(.headline)
.foregroundStyle(Color.accentColor)
ForEach(Event.RecurrenceType.allCases, id: \.self) { recurrence in
let count = viewModel.events.filter { $0.recurrence == recurrence }.count
let recurrenceStr = recurrence.rawValue.capitalized
var description: String {
if recurrenceStr == "None" {
return "One-Time event\(count == 1 ? "" : "s")"
} else {
return "\(recurrenceStr) event\(count == 1 ? "" : "s")"
}
}
Text("\(count) \(description)")
.font(.subheadline)
.foregroundStyle(Color.secondary)
}
}
}
.navigationTitle("Statistics")
.navigationBarTitleDisplayMode(.inline)
}
}
}
#Preview {
StatsView(
viewModel: EventViewModel()
)
}