mirror of
https://github.com/neon443/NearFuture.git
synced 2026-03-11 06:49:12 +00:00
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:
@@ -32,6 +32,11 @@ struct NearFutureApp: App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
WindowGroup("Edit Event", for: Event.ID.self) { $eventID in
|
WindowGroup("Edit Event", for: Event.ID.self) { $eventID in
|
||||||
|
if viewModel.events.first(where: {$0.id == eventID}) == nil {
|
||||||
|
AddEventView(
|
||||||
|
viewModel: viewModel
|
||||||
|
)
|
||||||
|
} else {
|
||||||
EditEventView(
|
EditEventView(
|
||||||
viewModel: viewModel,
|
viewModel: viewModel,
|
||||||
event: Binding(
|
event: Binding(
|
||||||
@@ -49,6 +54,8 @@ struct NearFutureApp: App {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
.defaultSize(width: 480, height: 550)
|
||||||
.windowIdealSize(.fitToContent)
|
.windowIdealSize(.fitToContent)
|
||||||
.restorationBehavior(.disabled)
|
.restorationBehavior(.disabled)
|
||||||
|
|
||||||
|
|||||||
@@ -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")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -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 */,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -43,9 +43,7 @@ struct ArchiveView: View {
|
|||||||
}
|
}
|
||||||
.sheet(isPresented: $showAddEvent) {
|
.sheet(isPresented: $showAddEvent) {
|
||||||
AddEventView(
|
AddEventView(
|
||||||
viewModel: viewModel,
|
viewModel: viewModel
|
||||||
event: $viewModel.editableTemplate,
|
|
||||||
adding: true
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 == "")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user