From 0e1ad52f896e718dab93dbf8db500c23a148527e Mon Sep 17 00:00:00 2001 From: neon443 <69979447+neon443@users.noreply.github.com> Date: Fri, 18 Apr 2025 16:14:38 +0530 Subject: [PATCH] reset date button, simplified addEvent(), refactored EventListView, reindenting --- NearFuture.xcodeproj/project.pbxproj | 4 + NearFuture/AddEventView.swift | 61 +++++---- NearFuture/ContentView.swift | 159 +--------------------- NearFuture/EditEventView.swift | 64 ++++----- NearFuture/EventListView.swift | 136 ++++++++++++++++++ NearFuture/Item.swift | 140 ++++++++++--------- NearFuture/StatsView.swift | 2 +- NearFuture/iCloudSettingsView.swift | 2 +- NearFutureWidgets/NearFutureWidgets.swift | 68 +-------- 9 files changed, 285 insertions(+), 351 deletions(-) create mode 100644 NearFuture/EventListView.swift diff --git a/NearFuture.xcodeproj/project.pbxproj b/NearFuture.xcodeproj/project.pbxproj index 4570e2c..8933b5c 100644 --- a/NearFuture.xcodeproj/project.pbxproj +++ b/NearFuture.xcodeproj/project.pbxproj @@ -25,6 +25,7 @@ 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 */; }; 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 */; }; /* End PBXBuildFile section */ @@ -87,6 +88,7 @@ A980FC302D920097006A778F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 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 = ""; }; + A985104F2DB263F00013D5FF /* EventListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventListView.swift; sourceTree = ""; }; A9C05E412D2805D7007DC497 /* NearFutureWidgetsExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NearFutureWidgetsExtension.entitlements; sourceTree = ""; }; A9FC7EE92D28238A0020D75B /* NearFutureWidgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureWidgets.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -150,6 +152,7 @@ A979F57E2D26B1300094C0B3 /* EditEventView.swift */, A920C2B72D2401A300E4F9B1 /* AddEventView.swift */, A920C2C02D2403CA00E4F9B1 /* ContentView.swift */, + A985104F2DB263F00013D5FF /* EventListView.swift */, A93BC0932D2B18A3002E8BBD /* StatsView.swift */, A920C2B42D2401A100E4F9B1 /* SettingsView.swift */, A985104D2DB256430013D5FF /* iCloudSettingsView.swift */, @@ -350,6 +353,7 @@ buildActionMask = 2147483647; files = ( A920C2BB2D2401A400E4F9B1 /* AddEventView.swift in Sources */, + A98510502DB263F00013D5FF /* EventListView.swift in Sources */, A920C2C12D2403CA00E4F9B1 /* ContentView.swift in Sources */, A920C2B82D2401A300E4F9B1 /* SettingsView.swift in Sources */, A920C28C2D24011400E4F9B1 /* Item.swift in Sources */, diff --git a/NearFuture/AddEventView.swift b/NearFuture/AddEventView.swift index 519f68c..54a2e72 100644 --- a/NearFuture/AddEventView.swift +++ b/NearFuture/AddEventView.swift @@ -16,7 +16,7 @@ struct AddEventView: View { @Binding var eventCompleteDesc: String @Binding var eventSymbol: String @Binding var eventColor: Color - @Binding var eventDescription: String + @Binding var eventNotes: String @Binding var eventDate: Date @Binding var eventTime: Bool @Binding var eventRecurrence: Event.RecurrenceType @@ -28,7 +28,7 @@ struct AddEventView: View { private enum Field { case Name, Description } - + @Environment(\.dismiss) var dismiss var body: some View { @@ -79,22 +79,33 @@ struct AddEventView: View { // dscription ZStack { - TextField("Event Description", text: $eventDescription) + TextField("Event Description", text: $eventNotes) .textFieldStyle(RoundedBorderTextFieldStyle()) - .padding(.trailing, eventDescription.isEmpty ? 0 : 30) - .animation(.spring, value: eventDescription) + .padding(.trailing, eventNotes.isEmpty ? 0 : 30) + .animation(.spring, value: eventNotes) .focused($focusedField, equals: Field.Description) .submitLabel(.done) .onSubmit { focusedField = nil } - MagicClearButton(text: $eventDescription) + MagicClearButton(text: $eventNotes) } // date picker - DatePicker("", selection: $eventDate, displayedComponents: .date) - .datePickerStyle(WheelDatePickerStyle()) + HStack { + DatePicker("", selection: $eventDate, displayedComponents: .date) + .datePickerStyle(WheelDatePickerStyle()) + Button() { + eventDate = Date() + } label: { + Image(systemName: "arrow.uturn.left") + .resizable() + .scaledToFit() + } + .buttonStyle(BorderlessButtonStyle()) + .frame(width: 20) + } Toggle("Schedule a Time", isOn: $eventTime) if eventTime { @@ -124,15 +135,17 @@ struct AddEventView: View { if adding { Button { viewModel.addEvent( - name: eventName, - complete: eventComplete, - completedDesc: eventCompleteDesc, - symbol: eventSymbol, - color: ColorCodable(eventColor), - description: eventDescription, - date: eventDate, - time: eventTime, - recurrence: eventRecurrence + newEvent: Event( + name: eventName, + complete: eventComplete, + completeDesc: eventCompleteDesc, + symbol: eventSymbol, + color: ColorCodable(eventColor), + notes: eventNotes, + date: eventDate, + time: eventTime, + recurrence: eventRecurrence + ) ) resetAddEventView() } label: { @@ -171,16 +184,8 @@ struct AddEventView: View { //reset addeventView eventName = "" eventSymbol = "star" - eventColor = [ - Color.red, - Color.orange, - Color.yellow, - Color.green, - Color.blue, - Color.indigo, - Color.purple - ].randomElement() ?? Color.red - eventDescription = "" + eventColor = randomColor() + eventNotes = "" eventDate = Date() eventRecurrence = .none dismiss() @@ -215,7 +220,7 @@ struct MagicClearButton: View { eventCompleteDesc: .constant(""), eventSymbol: .constant("star"), eventColor: .constant(Color.red), - eventDescription: .constant("A very special day"), + eventNotes: .constant("A very special day"), eventDate: .constant(Date()), eventTime: .constant(true), eventRecurrence: .constant(.monthly), diff --git a/NearFuture/ContentView.swift b/NearFuture/ContentView.swift index 8e89ebd..613c2a9 100644 --- a/NearFuture/ContentView.swift +++ b/NearFuture/ContentView.swift @@ -18,16 +18,8 @@ struct ContentView: View { @State private var eventComplete = false @State private var eventCompleteDesc = "" @State private var eventSymbol = "star" - @State private var eventColor: Color = [ - Color.red, - Color.orange, - Color.yellow, - Color.green, - Color.blue, - Color.indigo, - Color.purple - ].randomElement() ?? Color.red - @State private var eventDescription = "" + @State private var eventColor: Color = randomColor() + @State private var eventNotes = "" @State private var eventDate = Date() @State private var eventTime = false @State private var eventRecurrence: Event.RecurrenceType = .none @@ -39,7 +31,7 @@ struct ContentView: View { } else { return viewModel.events.filter { $0.name.localizedCaseInsensitiveContains(searchInput) || - $0.description.localizedCaseInsensitiveContains(searchInput) + $0.notes.localizedCaseInsensitiveContains(searchInput) } } } @@ -125,7 +117,7 @@ struct ContentView: View { eventCompleteDesc: $eventCompleteDesc, eventSymbol: $eventSymbol, eventColor: $eventColor, - eventDescription: $eventDescription, + eventNotes: $eventNotes, eventDate: $eventDate, eventTime: $eventTime, eventRecurrence: $eventRecurrence, @@ -160,128 +152,6 @@ struct ContentView: View { } } -struct EventListView: View { - @ObservedObject var viewModel: EventViewModel - @State var event: Event - - var body: some View { - NavigationLink() { - EditEventView( - viewModel: viewModel, - event: $event - ) - } label: { - HStack { - RoundedRectangle(cornerRadius: 5) - .frame(width: 5) - .foregroundStyle( - event.color.color.opacity( - event.complete ? 0.5 : 1 - ) - ) - .padding(.leading, -10) - .padding(.vertical, 5) - .animation(.spring, value: event.complete) - VStack(alignment: .leading) { - HStack { - Image(systemName: event.symbol) - .resizable() - .scaledToFit() - .frame(width: 20, height: 20) - .foregroundStyle( - event.color.color.opacity( - event.complete ? 0.5 : 1 - ) - ) - .animation(.spring, value: event.complete) - Text("\(event.name)") - .font(.headline) - .strikethrough(event.complete) - // .foregroundStyle( - // event.complete ? .gray : .primary - // ) - .animation(.spring, value: event.complete) - } - if !event.description.isEmpty { - Text(event.description) - .font(.subheadline) - .foregroundColor(.gray) - } - Text( - event.date.formatted( - date: .long, - time: event.time ? .standard : .omitted - ) - ) - .font(.subheadline) - .foregroundStyle( - event.color.color.opacity( - event.complete ? 0.5 : 1 - ) - ) - .animation(.spring, value: event.complete) - if event.recurrence != .none { - Text("Recurs \(event.recurrence.rawValue)") - .font(.subheadline) - .foregroundStyle( - .primary.opacity( - event.complete ? 0.5 : 1 - ) - ) - .animation(.spring, value: event.complete) - } - } - - Spacer() - - VStack { - Text("\(daysUntilEvent(event.date, short: false))") - .font(.subheadline) - .foregroundStyle( - event.color.color.opacity( - event.complete ? 0.5 : 1 - ) - ) - .animation(.spring, value: event.complete) - } - Button() { - withAnimation(.spring) { - event.complete.toggle() - } - let eventToModify = viewModel.events.firstIndex() { currEvent in - currEvent.id == event.id - } - if let eventToModify = eventToModify { - viewModel.events[eventToModify] = event - viewModel.saveEvents() - viewModel.loadEvents() - } - } label: { - if event.complete { - ZStack { - Circle() - .foregroundStyle(.green) - Image(systemName: "checkmark") - .resizable() - .foregroundStyle(.white) - .scaledToFit() - .frame(width: 15) - } - } else { - Image(systemName: "circle") - .resizable() - .scaledToFit() - .foregroundStyle(event.color.color) - } - } - .buttonStyle(.borderless) - .frame(maxWidth: 25, maxHeight: 25) - .animation(.spring, value: event.complete) - } - } - } -} - struct SearchHelp: View { @Binding var searchInput: String @FocusState var focusedField: Field? @@ -294,7 +164,7 @@ struct SearchHelp: View { .padding(.trailing) Text("Can't find what you're looking for?") } - Text("Tip: The Search bar searches event names and descriptions") + Text("Tip: The Search bar searches event names and notes") Button() { searchInput = "" focusedField = nil @@ -311,22 +181,3 @@ struct SearchHelp: View { #Preview { ContentView() } - -#Preview("EventListView") { - EventListView( - viewModel: EventViewModel(), - event: - Event( - name: "event", - complete: false, - completeDesc: "dofajiof", - symbol: "star", - color: ColorCodable(.orange), - description: "lksdjfakdflkasjlkjl", - date: Date(), - time: true, - recurrence: .daily -// ) - ) - ) -} diff --git a/NearFuture/EditEventView.swift b/NearFuture/EditEventView.swift index 757ec4b..81d4a32 100644 --- a/NearFuture/EditEventView.swift +++ b/NearFuture/EditEventView.swift @@ -17,7 +17,7 @@ struct EditEventView: View { @State private var eventCompleteDesc: String @State private var eventSymbol: String @State private var eventColor: Color - @State private var eventDescription: String + @State private var eventNotes: String @State private var eventDate: Date @State private var eventTime: Bool @State private var eventRecurrence: Event.RecurrenceType @@ -30,7 +30,7 @@ struct EditEventView: View { _eventCompleteDesc = State(initialValue: event.wrappedValue.completeDesc) _eventSymbol = State(initialValue: event.wrappedValue.symbol) _eventColor = State(initialValue: event.wrappedValue.color.color) - _eventDescription = State(initialValue: event.wrappedValue.description) + _eventNotes = State(initialValue: event.wrappedValue.notes) _eventDate = State(initialValue: event.wrappedValue.date) _eventTime = State(initialValue: event.wrappedValue.time) _eventRecurrence = State(initialValue: event.wrappedValue.recurrence) @@ -40,7 +40,7 @@ struct EditEventView: View { event.name = eventName event.symbol = eventSymbol event.color = ColorCodable(eventColor) - event.description = eventDescription + event.notes = eventNotes event.date = eventDate event.recurrence = eventRecurrence @@ -57,32 +57,30 @@ struct EditEventView: View { } var body: some View { -// NavigationStack { - AddEventView( - viewModel: viewModel, - eventName: $eventName, - eventComplete: $eventComplete, - eventCompleteDesc: $eventCompleteDesc, - eventSymbol: $eventSymbol, - eventColor: $eventColor, - eventDescription: $eventDescription, - eventDate: $eventDate, - eventTime: $eventTime, - eventRecurrence: $eventRecurrence, - adding: false //bc we editing existing event - ) - .navigationTitle("Edit Event") - .toolbar { - ToolbarItem(placement: .topBarTrailing) { - Button() { - saveEdits() - } label: { - Text("Done") - } - .disabled(eventName == "") + AddEventView( + viewModel: viewModel, + eventName: $eventName, + eventComplete: $eventComplete, + eventCompleteDesc: $eventCompleteDesc, + eventSymbol: $eventSymbol, + eventColor: $eventColor, + eventNotes: $eventNotes, + eventDate: $eventDate, + eventTime: $eventTime, + eventRecurrence: $eventRecurrence, + adding: false //bc we editing existing event + ) + .navigationTitle("Edit Event") + .toolbar { + ToolbarItem(placement: .topBarTrailing) { + Button() { + saveEdits() + } label: { + Text("Done") } + .disabled(eventName == "") } -// } + } } } @@ -90,17 +88,7 @@ struct EditEventView: View { EditEventView( viewModel: EventViewModel(), event: .constant( - Event( - name: "Birthday", - complete: false, - completeDesc: "", - symbol: "gear", - color: ColorCodable(.red), - description: "an event", - date: Date(), - time: true, - recurrence: .yearly - ) + EventViewModel().example ) ) } diff --git a/NearFuture/EventListView.swift b/NearFuture/EventListView.swift new file mode 100644 index 0000000..8ed9e8e --- /dev/null +++ b/NearFuture/EventListView.swift @@ -0,0 +1,136 @@ +// +// 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: { + HStack { + RoundedRectangle(cornerRadius: 5) + .frame(width: 5) + .foregroundStyle( + event.color.color.opacity( + event.complete ? 0.5 : 1 + ) + ) + .padding(.leading, -10) + .padding(.vertical, 5) + .animation(.spring, value: event.complete) + VStack(alignment: .leading) { + HStack { + Image(systemName: event.symbol) + .resizable() + .scaledToFit() + .frame(width: 20, height: 20) + .foregroundStyle( + event.color.color.opacity( + event.complete ? 0.5 : 1 + ) + ) + .animation(.spring, value: event.complete) + Text("\(event.name)") + .font(.headline) + .strikethrough(event.complete) + .animation(.spring, value: event.complete) + } + if !event.notes.isEmpty { + Text(event.notes) + .font(.subheadline) + .foregroundColor(.gray) + } + Text( + event.date.formatted( + date: .long, + time: event.time ? .standard : .omitted + ) + ) + .font(.subheadline) + .foregroundStyle( + event.color.color.opacity( + event.complete ? 0.5 : 1 + ) + ) + .animation(.spring, value: event.complete) + if event.recurrence != .none { + Text("Recurs \(event.recurrence.rawValue)") + .font(.subheadline) + .foregroundStyle( + .primary.opacity( + event.complete ? 0.5 : 1 + ) + ) + .animation(.spring, value: event.complete) + } + } + + Spacer() + + VStack { + Text("\(daysUntilEvent(event.date, short: false))") + .font(.subheadline) + .foregroundStyle( + event.color.color.opacity( + event.complete ? 0.5 : 1 + ) + ) + .animation(.spring, value: event.complete) + } + Button() { + withAnimation(.spring) { + event.complete.toggle() + } + let eventToModify = viewModel.events.firstIndex() { currEvent in + currEvent.id == event.id + } + if let eventToModify = eventToModify { + viewModel.events[eventToModify] = event + viewModel.saveEvents() + viewModel.loadEvents() + } + } label: { + if event.complete { + ZStack { + Circle() + .foregroundStyle(.green) + Image(systemName: "checkmark") + .resizable() + .foregroundStyle(.white) + .scaledToFit() + .frame(width: 15) + } + } else { + Image(systemName: "circle") + .resizable() + .scaledToFit() + .foregroundStyle(event.color.color) + } + } + .buttonStyle(.borderless) + .frame(maxWidth: 25, maxHeight: 25) + .animation(.spring, value: event.complete) + } + } + } +} + +#Preview("EventListView") { + EventListView( + viewModel: EventViewModel(), + event: + EventViewModel().example + ) +} diff --git a/NearFuture/Item.swift b/NearFuture/Item.swift index b1bbeba..f0369f6 100644 --- a/NearFuture/Item.swift +++ b/NearFuture/Item.swift @@ -26,11 +26,11 @@ struct Event: Identifiable, Codable { var completeDesc: String var symbol: String var color: ColorCodable - var description: String + var notes: String var date: Date var time: Bool var recurrence: RecurrenceType - + enum RecurrenceType: String, Codable, CaseIterable { case none, daily, weekly, monthly, yearly } @@ -44,16 +44,16 @@ struct ColorCodable: Codable { //for the brainrot kids: alpha is the opacity/transparency of the color, //alpha == 0 completely transparent //alpha == 1 completely opaque - + var color: Color { Color(red: red, green: green, blue: blue, opacity: alpha) } - + init(_ color: Color) { let uiColor = UIColor(color) var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0 uiColor.getRed(&r, green: &g, blue: &b, alpha: &a) - + self.red = Double(r) self.green = Double(g) self.blue = Double(b) @@ -92,22 +92,34 @@ func daysUntilEvent(_ eventDate: Date, short: Bool, sepLines: Bool = false) -> S class EventViewModel: ObservableObject { @Published var events: [Event] = [] @Published var icloudData: [Event] = [] - + + @Published var example: Event = Event( + name: "event", + complete: false, + completeDesc: "dofajiof", + symbol: "star", + color: ColorCodable(.orange), + notes: "lksdjfakdflkasjlkjl", + date: Date(), + time: true, + recurrence: .daily + ) + @Published var lastSync: Date? = nil @Published var icloudEventCount: Int = 0 @Published var localEventCount: Int = 0 @Published var syncStatus: String = "Not Synced" - + init() { loadEvents() } - + //appgroup or regular userdefaults let appGroupUserDefaults = UserDefaults(suiteName: "group.com.neon443.NearFuture") ?? UserDefaults.standard - + //icloud store let icloudStore = NSUbiquitousKeyValueStore.default - + // load from icloud or local func loadEvents() { //load icloud 1st @@ -118,7 +130,7 @@ class EventViewModel: ObservableObject { self.events = decodedIcEvents } } - + if events.isEmpty, let savedData = appGroupUserDefaults.data(forKey: "events") { let decoder = JSONDecoder() if let decodedEvents = try? decoder.decode([Event].self, from: savedData) { @@ -127,77 +139,55 @@ class EventViewModel: ObservableObject { } updateSyncStatus() } - + // save to local and icloud func saveEvents() { let encoder = JSONEncoder() if let encoded = try? encoder.encode(events) { appGroupUserDefaults.set(encoded, forKey: "events") - + //sync icloudStore.set(encoded, forKey: "events") icloudStore.synchronize() - + updateSyncStatus() loadEvents() WidgetCenter.shared.reloadAllTimelines()//reload all widgets when saving events } } - + private func updateSyncStatus() { lastSync = Date() icloudEventCount = icloudData.count localEventCount = events.count - + if icloudEventCount == localEventCount { syncStatus = "Successful" } else { syncStatus = "Pending" } } - - func addEvent( - name: String, - complete: Bool, - completedDesc: String, - symbol: String, - color: ColorCodable, - description: String, - date: Date, - time: Bool, - recurrence: Event.RecurrenceType - ) { - let newEvent = Event( - name: name, - complete: complete, - completeDesc: completedDesc, - symbol: symbol, - color: color, - description: description, - date: date, - time: time, - recurrence: recurrence - ) + + func addEvent(newEvent: Event) { events.append(newEvent) saveEvents() //sync with icloud } - + func removeEvent(at index: IndexSet) { events.remove(atOffsets: index) saveEvents() //sync local and icl } - + func hasUbiquitousKeyValueStore() -> Bool { let icloud = NSUbiquitousKeyValueStore.default - + let key = "com.neon443.NearFuture.testkey" let value = "testValue" - + icloud.set(value, forKey: key) icloud.synchronize() - + if icloud.string(forKey: key) != nil { -// print("has UbiquitousKeyValueStore") icloud.removeObject(forKey: key) icloud.synchronize() return true @@ -208,36 +198,36 @@ class EventViewModel: ObservableObject { return false } } - + func sync() { NSUbiquitousKeyValueStore.default.synchronize() loadEvents() } - + func replaceLocalWithiCloudData() { icloudStore.synchronize() self.events = self.icloudData saveEvents() } - + func replaceiCloudWithLocalData() { icloudStore.synchronize() self.icloudData = self.events 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 @@ -250,26 +240,26 @@ class EventViewModel: ObservableObject { 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() @@ -279,7 +269,7 @@ class EventViewModel: ObservableObject { print("Failed to decode events: \(error.localizedDescription)") } } - + //MARK: Danger Zone func dangerClearLocalData() { UserDefaults.standard.removeObject(forKey: "events") @@ -287,29 +277,29 @@ class EventViewModel: ObservableObject { events.removeAll() updateSyncStatus() } - + func dangerCleariCloudData() { icloudStore.removeObject(forKey: "events") icloudStore.synchronize() icloudData.removeAll() updateSyncStatus() } - + func dangerResetLocalData() { let userDFDict = UserDefaults.standard.dictionaryRepresentation() for key in userDFDict.keys { UserDefaults.standard.removeObject(forKey: key) } - + let appGUSDDict = appGroupUserDefaults.dictionaryRepresentation() for key in appGUSDDict.keys { appGroupUserDefaults.removeObject(forKey: key) } - + events.removeAll() updateSyncStatus() } - + func dangerResetiCloud() { let icloudDict = icloudStore.dictionaryRepresentation for key in icloudDict.keys { @@ -324,7 +314,7 @@ class EventViewModel: ObservableObject { func describeOccurrence(date: Date, recurrence: Event.RecurrenceType) -> String { let dateString = date.formatted(date: .long, time: .omitted) let recurrenceDescription: String - + switch recurrence { case .none: recurrenceDescription = "Occurs once on" @@ -337,6 +327,26 @@ func describeOccurrence(date: Date, recurrence: Event.RecurrenceType) -> String case .yearly: recurrenceDescription = "Repeats every year from" } - + return "\(recurrenceDescription) \(dateString)" } + +func randomRainbowColor() -> Color { + return [ + Color.red, + Color.orange, + Color.yellow, + Color.green, + Color.blue, + Color.indigo, + Color.purple + ].randomElement()! +} + +func randomColor() -> Color { + let r = Double.random(in: 0...1) + let g = Double.random(in: 0...1) + let b = Double.random(in: 0...1) + let a = Double.random(in: 0...1) + return Color(red: r, green: g, blue: b, opacity: a) +} diff --git a/NearFuture/StatsView.swift b/NearFuture/StatsView.swift index 07c735a..bd61ecd 100644 --- a/NearFuture/StatsView.swift +++ b/NearFuture/StatsView.swift @@ -23,7 +23,7 @@ struct StatsView: View { 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 diff --git a/NearFuture/iCloudSettingsView.swift b/NearFuture/iCloudSettingsView.swift index 42d70b7..44f8f4c 100644 --- a/NearFuture/iCloudSettingsView.swift +++ b/NearFuture/iCloudSettingsView.swift @@ -70,7 +70,7 @@ struct iCloudSettingsView: View { } message: { Text("This will replace Events stored in iCloud with Events stored locally.") } - + Button() { viewModel.sync() updateStatus() diff --git a/NearFutureWidgets/NearFutureWidgets.swift b/NearFutureWidgets/NearFutureWidgets.swift index fd87c48..63959d4 100644 --- a/NearFutureWidgets/NearFutureWidgets.swift +++ b/NearFutureWidgets/NearFutureWidgets.swift @@ -112,12 +112,6 @@ struct EventWidgetView: View { } if isLarge { - if !event.description.isEmpty { - Text(event.description) - .font(.caption2) - .foregroundColor(.gray) - .padding(.top, -5) - } Text(event.date.formatted(date: .long, time: .omitted)) .font(.caption2) .foregroundColor(event.color.color) @@ -141,8 +135,6 @@ struct EventWidgetView: View { .foregroundColor(event.color.color) .padding(.trailing, -12) } - } else { - /*@START_MENU_TOKEN@*/EmptyView()/*@END_MENU_TOKEN@*/ } } Spacer() @@ -150,7 +142,6 @@ struct EventWidgetView: View { let xMoreEvents = events.count - showedEventsNum Text("+\(xMoreEvents) more event\(xMoreEvents == 1 ? "" : "s")") .font(.caption2) -// .foregroundStyle(.gray) .padding(.top, -5) .padding(.bottom, -15) } @@ -162,61 +153,10 @@ struct EventWidgetView: View { struct Widget_Previews: PreviewProvider { static var events = [ - Event( - name: "Event Name", - complete: false, - completeDesc: "", - symbol: "gear", - color: ColorCodable(.blue), - description: "Event description", - date: Date.distantFuture, - time: false, - recurrence: .yearly - ), - Event( - name: "distant past", - complete: false, - completeDesc: "", - symbol: "star", - color: ColorCodable(.orange), - description: "description", - date: Date.distantPast, - time: false, - recurrence: .daily - ), - Event( - name: "event", - complete: false, - completeDesc: "", - symbol: "star", - color: ColorCodable(.purple), - description: "description", - date: Date(), - time: false, - recurrence: .daily - ), - Event( - name: "An event", - complete: false, - completeDesc: "", - symbol: "star", - color: ColorCodable(.green), - description: "description", - date: Date(), - time: false, - recurrence: .daily - ), - Event( - name: "time event", - complete: true, - completeDesc: "", - symbol: "clock", - color: ColorCodable(.brown), - description: "an event with a time", - date: Date(), - time: true, - recurrence: .none - ) + EventViewModel().example, + EventViewModel().example, + EventViewModel().example, + EventViewModel().example ] static var previews: some View { Group {