fix "new edit event window" on mac not working

- it would save events with the same id and modify the previous one if u opened another one
add symbols to ios
date picker looks better mac
This commit is contained in:
neon443
2025-06-15 15:34:08 +01:00
parent 5dd25f1ede
commit 5c667679d5
10 changed files with 45 additions and 228 deletions

View File

@@ -32,23 +32,30 @@ struct NearFutureApp: App {
} }
WindowGroup("Edit Event", for: Event.ID.self) { $eventID in WindowGroup("Edit Event", for: Event.ID.self) { $eventID in
EditEventView( if viewModel.events.first(where: {$0.id == eventID}) == nil {
viewModel: viewModel, AddEventView(
event: Binding( viewModel: viewModel
get: {
viewModel.events.first(where: {$0.id == eventID}) ?? viewModel.template
},
set: { newValue in
if let eventIndex = viewModel.events.firstIndex(where: {
$0.id == eventID
}) {
viewModel.events[eventIndex] = newValue
}
viewModel.saveEvents()
}
) )
) } else {
EditEventView(
viewModel: viewModel,
event: Binding(
get: {
viewModel.events.first(where: {$0.id == eventID}) ?? viewModel.template
},
set: { newValue in
if let eventIndex = viewModel.events.firstIndex(where: {
$0.id == eventID
}) {
viewModel.events[eventIndex] = newValue
}
viewModel.saveEvents()
}
)
)
}
} }
.defaultSize(width: 480, height: 550)
.windowIdealSize(.fitToContent) .windowIdealSize(.fitToContent)
.restorationBehavior(.disabled) .restorationBehavior(.disabled)

View File

@@ -65,9 +65,7 @@ struct ContentView: View {
} }
.sheet(isPresented: $showAddEventView) { .sheet(isPresented: $showAddEventView) {
AddEventView( AddEventView(
viewModel: viewModel, viewModel: viewModel
event: $viewModel.editableTemplate,
adding: true
) )
.presentationSizing(.page) .presentationSizing(.page)
} }
@@ -75,8 +73,7 @@ struct ContentView: View {
Button() { Button() {
showAddEventView.toggle() showAddEventView.toggle()
} label: { } label: {
Image(systemName: "plus") Label("New", systemImage: "plus")
Text("New")
} }
} }
} }

View File

@@ -1,193 +0,0 @@
//
// EventListView.swift
// MacNearFuture
//
// Created by neon443 on 21/05/2025.
//
import SwiftUI
struct EventListView: View {
@ObservedObject var viewModel: EventViewModel
@State var event: Event
@State var largeTick: Bool = false
@State var hovering: Bool = false
@State var completeInProgress: Bool = false
@State var completeStartTime: Date = .now
@State var progress: Double = 0
@State var timer: Timer?
private let completeDuration: TimeInterval = 3.0
@Environment(\.openWindow) var openWindow
func startCompleting() {
NSHapticFeedbackManager.defaultPerformer.perform(.generic, performanceTime: .now)
completeInProgress = true
progress = 0
completeStartTime = .now
timer = Timer(timeInterval: 0.05, repeats: true) { timer in
let elapsed = Date().timeIntervalSince(completeStartTime)
progress = min(elapsed, 1.0)
if progress >= 1.0 {
timer.invalidate()
viewModel.completeEvent(&event)
completeInProgress = false
}
}
RunLoop.main.add(timer!, forMode: .common)
}
var body: some View {
ZStack {
Color.black.opacity(hovering ? 0.5 : 0.0)
HStack {
RoundedRectangle(cornerRadius: 5)
.frame(width: 7)
.foregroundStyle(
event.color.color.opacity(
event.complete ? 0.5 : 1
)
)
VStack(alignment: .leading) {
HStack {
Image(systemName: event.symbol)
.resizable()
.scaledToFit()
.frame(width: 20, height: 20)
.shadow(radius: 5)
.foregroundStyle(
.one.opacity(
event.complete ? 0.5 : 1
)
)
Text("\(event.name)")
.bold()
.foregroundStyle(.one)
.strikethrough(event.complete)
.multilineTextAlignment(.leading)
}
if !event.notes.isEmpty {
Text(event.notes)
.foregroundStyle(.one.opacity(0.8))
.multilineTextAlignment(.leading)
}
Text(
event.date.formatted(
date: .long,
time: .shortened
)
)
.foregroundStyle(
.one.opacity(
event.complete ? 0.5 : 1
)
)
if event.recurrence != .none {
Text("Occurs \(event.recurrence.rawValue)")
.font(.subheadline)
.foregroundStyle(
.one.opacity(event.complete ? 0.5 : 1))
}
}
Spacer()
VStack {
Text("\(daysUntilEvent(event.date).long)")
.multilineTextAlignment(.trailing)
.foregroundStyle(event.date.timeIntervalSinceNow < 0 ? .red : .one)
}
Button() {
startCompleting()
} label: {
if completeInProgress {
ZStack {
ProgressView(value: progress)
.progressViewStyle(.circular)
Image(systemName: "xmark")
.bold()
}
} else {
Image(systemName: event.complete ? "checkmark.circle.fill" : "circle")
.resizable().scaledToFit()
.foregroundStyle(event.complete ? .green : event.color.color)
.bold()
}
}
.onHover() { hovering in
withAnimation {
largeTick.toggle()
}
}
.buttonStyle(.borderless)
.scaleEffect(
completeInProgress ? 1 :
largeTick ? 1.5 : 1
)
.frame(maxWidth: 20)
.shadow(radius: 5)
.padding(.trailing, 15)
.animation(
.spring(response: 0.2, dampingFraction: 0.75, blendDuration: 2),
value: largeTick
)
}
.transition(.opacity)
.fixedSize(horizontal: false, vertical: true)
}
.onHover { isHovering in
withAnimation {
hovering.toggle()
}
}
.onTapGesture {
openWindow(value: event.id)
}
.contextMenu() {
Button(role: .destructive) {
let eventToModify = viewModel.events.firstIndex() { currEvent in
currEvent.id == event.id
}
if let eventToModify = eventToModify {
viewModel.events.remove(at: eventToModify)
viewModel.saveEvents()
}
} label: {
Label("Delete", systemImage: "trash")
}
}
}
}
#Preview("EventListView") {
let vm = dummyEventViewModel()
ZStack {
Color.black
VStack {
ForEach(0..<50) { _ in
Rectangle()
.foregroundStyle(randomColor().opacity(0.5))
.padding(-10)
}
.ignoresSafeArea(.all)
.blur(radius: 5)
}
VStack {
ForEach(vm.events) { event in
EventListView(
viewModel: vm,
event: event
)
}
}
.padding(.horizontal, 10)
}
}
#Preview {
EventListView(
viewModel: dummyEventViewModel(),
event: dummyEventViewModel().template
)
}

View File

@@ -154,7 +154,6 @@
A979F6092D270AF00094C0B3 /* NearFutureWidgetsBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureWidgetsBundle.swift; sourceTree = "<group>"; }; A979F6092D270AF00094C0B3 /* NearFutureWidgetsBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureWidgetsBundle.swift; sourceTree = "<group>"; };
A979F60B2D270AF00094C0B3 /* NearFutureWidgetsLiveActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureWidgetsLiveActivity.swift; sourceTree = "<group>"; }; A979F60B2D270AF00094C0B3 /* NearFutureWidgetsLiveActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureWidgetsLiveActivity.swift; sourceTree = "<group>"; };
A979F60F2D270AF80094C0B3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; A979F60F2D270AF80094C0B3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
A98C20CA2DE730740008D61C /* EventListViewMac.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventListViewMac.swift; sourceTree = "<group>"; };
A98C20CD2DE7308E0008D61C /* ArchiveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArchiveView.swift; sourceTree = "<group>"; }; A98C20CD2DE7308E0008D61C /* ArchiveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArchiveView.swift; sourceTree = "<group>"; };
A98C20CF2DE731BD0008D61C /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = "<group>"; }; A98C20CF2DE731BD0008D61C /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = "<group>"; };
A98C20D32DE7339E0008D61C /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = "<group>"; }; A98C20D32DE7339E0008D61C /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = "<group>"; };
@@ -215,7 +214,6 @@
children = ( children = (
A90D49332DDE0FAF00781124 /* ContentViewMac.swift */, A90D49332DDE0FAF00781124 /* ContentViewMac.swift */,
A98C20CF2DE731BD0008D61C /* HomeView.swift */, A98C20CF2DE731BD0008D61C /* HomeView.swift */,
A98C20CA2DE730740008D61C /* EventListViewMac.swift */,
A98C20CD2DE7308E0008D61C /* ArchiveView.swift */, A98C20CD2DE7308E0008D61C /* ArchiveView.swift */,
A91EF80F2DFCB66C00B8463D /* SettingsView.swift */, A91EF80F2DFCB66C00B8463D /* SettingsView.swift */,
); );

View File

@@ -43,9 +43,7 @@ struct ArchiveView: View {
} }
.sheet(isPresented: $showAddEvent) { .sheet(isPresented: $showAddEvent) {
AddEventView( AddEventView(
viewModel: viewModel, viewModel: viewModel
event: $viewModel.editableTemplate,
adding: true
) )
} }
} }

View File

@@ -12,6 +12,7 @@ import SwiftData
enum Tab { enum Tab {
case home case home
case archive case archive
case symbols
case stats case stats
case settings case settings
} }
@@ -33,6 +34,13 @@ struct ContentView: View {
Label("Archive", systemImage: "tray.full") Label("Archive", systemImage: "tray.full")
} }
.tag(Tab.archive) .tag(Tab.archive)
SymbolsPicker(
selection: .constant("")
)
.tabItem {
Label("Symbols", systemImage: "star.circle")
}
.tag(Tab.symbols)
StatsView(viewModel: viewModel) StatsView(viewModel: viewModel)
// SymbolsPickerStoryboardUIViewRepresentable() // SymbolsPickerStoryboardUIViewRepresentable()
.tabItem { .tabItem {

View File

@@ -10,9 +10,9 @@ import SwiftUI
struct AddEventView: View { struct AddEventView: View {
@ObservedObject var viewModel: EventViewModel @ObservedObject var viewModel: EventViewModel
@Binding var event: Event @State var event: Event = dummyEventViewModel().template
@State var adding: Bool @State var adding: Bool = true
@State var showNeedsNameAlert: Bool = false @State var showNeedsNameAlert: Bool = false
@State var isSymbolPickerPresented: Bool = false @State var isSymbolPickerPresented: Bool = false
@@ -93,6 +93,8 @@ struct AddEventView: View {
DatePicker("", selection: $event.date, displayedComponents: .date) DatePicker("", selection: $event.date, displayedComponents: .date)
#if os(iOS) #if os(iOS)
.datePickerStyle(.wheel) .datePickerStyle(.wheel)
#else
.datePickerStyle(.graphical)
#endif #endif
Spacer() Spacer()
Button() { Button() {
@@ -111,6 +113,9 @@ struct AddEventView: View {
selection: $event.date, selection: $event.date,
displayedComponents: .hourAndMinute displayedComponents: .hourAndMinute
) )
#if os(macOS)
.datePickerStyle(.stepperField)
#endif
// re-ocurrence Picker // re-ocurrence Picker
Picker("Recurrence", selection: $event.recurrence) { Picker("Recurrence", selection: $event.recurrence) {
@@ -197,7 +202,6 @@ struct AddEventView: View {
.sheet(isPresented: .constant(true)) { .sheet(isPresented: .constant(true)) {
AddEventView( AddEventView(
viewModel: vm, viewModel: vm,
event: .constant(vm.template),
adding: true adding: true
) )
} }

View File

@@ -28,17 +28,18 @@ struct EditEventView: View {
var body: some View { var body: some View {
AddEventView( AddEventView(
viewModel: viewModel, viewModel: viewModel,
event: $event, event: event,
adding: false //bc we editing existing event adding: false //bc we editing existing event
) )
.navigationTitle("Edit Event") .navigationTitle("Edit Event")
.toolbar { .toolbar {
ToolbarItem(/*placement: .topBarTrailing*/) { ToolbarItem(placement: .confirmationAction) {
Button() { Button() {
saveEdits() saveEdits()
} label: { } label: {
Text("Done") Text("Done")
.bold() .bold()
.foregroundStyle(.blue)
} }
.disabled(event.name == "") .disabled(event.name == "")
} }

View File

@@ -138,7 +138,7 @@ struct EventListView: View {
} }
} }
.frame(maxWidth: 20) .frame(maxWidth: 20)
.shadow(radius: 5) .shadow(color: .one.opacity(0.2), radius: 2.5)
.padding(.trailing, 15) .padding(.trailing, 15)
.animation( .animation(
.spring(response: 0.2, dampingFraction: 0.75, blendDuration: 2), .spring(response: 0.2, dampingFraction: 0.75, blendDuration: 2),

View File

@@ -12,7 +12,6 @@ struct HomeView: View {
@ObservedObject var viewModel: EventViewModel @ObservedObject var viewModel: EventViewModel
@ObservedObject var settingsModel: SettingsViewModel @ObservedObject var settingsModel: SettingsViewModel
@State private var event: Event = dummyEventViewModel().template
@State private var showingAddEventView: Bool = false @State private var showingAddEventView: Bool = false
@State private var searchInput: String = "" @State private var searchInput: String = ""
@Environment(\.colorScheme) var appearance @Environment(\.colorScheme) var appearance
@@ -70,9 +69,7 @@ struct HomeView: View {
.modifier(navigationInlineLarge()) .modifier(navigationInlineLarge())
.sheet(isPresented: $showingAddEventView) { .sheet(isPresented: $showingAddEventView) {
AddEventView( AddEventView(
viewModel: viewModel, viewModel: viewModel
event: $event,
adding: true //adding event
) )
} }
.toolbar { .toolbar {