New: custom alert for merge/replace imported events

This commit is contained in:
neon443
2025-05-28 14:47:05 +01:00
parent 1902c5102c
commit 0f3b86fe8c
3 changed files with 92 additions and 40 deletions

View File

@@ -55,7 +55,6 @@
A98C20CE2DE7308E0008D61C /* ArchiveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98C20CD2DE7308E0008D61C /* ArchiveView.swift */; }; A98C20CE2DE7308E0008D61C /* ArchiveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98C20CD2DE7308E0008D61C /* ArchiveView.swift */; };
A98C20D02DE731BD0008D61C /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98C20CF2DE731BD0008D61C /* HomeView.swift */; }; A98C20D02DE731BD0008D61C /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98C20CF2DE731BD0008D61C /* HomeView.swift */; };
A98C20D42DE7339E0008D61C /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98C20D32DE7339E0008D61C /* AboutView.swift */; }; A98C20D42DE7339E0008D61C /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98C20D32DE7339E0008D61C /* AboutView.swift */; };
A98C20D52DE7339E0008D61C /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98C20D32DE7339E0008D61C /* AboutView.swift */; };
A9FC7EEA2D2823920020D75B /* NearFutureWidgets.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FC7EE92D28238A0020D75B /* NearFutureWidgets.swift */; }; A9FC7EEA2D2823920020D75B /* NearFutureWidgets.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FC7EE92D28238A0020D75B /* NearFutureWidgets.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
@@ -526,7 +525,6 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
A920C28C2D24011400E4F9B1 /* Events.swift in Sources */, A920C28C2D24011400E4F9B1 /* Events.swift in Sources */,
A98C20D52DE7339E0008D61C /* AboutView.swift in Sources */,
A949F84B2DCAABE00064DCA0 /* ArchiveView.swift in Sources */, A949F84B2DCAABE00064DCA0 /* ArchiveView.swift in Sources */,
A914FA4F2DD276D200856265 /* AboutView.swift in Sources */, A914FA4F2DD276D200856265 /* AboutView.swift in Sources */,
A949F84C2DCAABE00064DCA0 /* AddEventView.swift in Sources */, A949F84C2DCAABE00064DCA0 /* AddEventView.swift in Sources */,

View File

@@ -15,7 +15,12 @@ struct ImportView: View {
@State private var text: String = "Ready..." @State private var text: String = "Ready..."
@State private var fgColor: Color = .yellow @State private var fgColor: Color = .yellow
@State private var showAlert: Bool = false
@State private var replaceCurrentEvents: Bool = false
var body: some View { var body: some View {
ZStack(alignment: .center) {
List { List {
Section("Status") { Section("Status") {
Label(text, systemImage: image) Label(text, systemImage: image)
@@ -24,8 +29,52 @@ struct ImportView: View {
} }
TextField("", text: $importStr) TextField("", text: $importStr)
Button() { Button() {
withAnimation {
showAlert.toggle()
}
} label: {
Label("Import", systemImage: "tray.and.arrow.down.fill")
}
.disabled(importStr.isEmpty)
.onAppear() {
importStr = ""
image = "clock.fill"
text = "Ready..."
fgColor = .yellow
}
}
.blur(radius: showAlert ? 2 : 0)
Group {
Rectangle()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.foregroundStyle(replaceCurrentEvents ? .red.opacity(0.3) : .black.opacity(0.2))
.animation(.default, value: replaceCurrentEvents)
.ignoresSafeArea()
ZStack {
RoundedRectangle(cornerRadius: 30)
.foregroundStyle(.one.opacity(0.8))
.blur(radius: 1)
VStack(alignment: .center) {
Text("Are you sure?")
.font(.largeTitle)
.bold()
.foregroundStyle(replaceCurrentEvents ? .red : .two)
.animation(.default, value: replaceCurrentEvents)
Text("This will replace your current events!")
.lineLimit(nil)
.multilineTextAlignment(.center)
.opacity(replaceCurrentEvents ? 1 : 0)
.animation(.default, value: replaceCurrentEvents)
.foregroundStyle(.two)
Toggle("Replace Events", isOn: $replaceCurrentEvents)
.foregroundStyle(.two)
Spacer()
Button() {
withAnimation {
showAlert.toggle()
}
do throws { do throws {
try viewModel.importEvents(importStr) try viewModel.importEvents(importStr, replace: replaceCurrentEvents)
withAnimation { withAnimation {
image = "checkmark.circle.fill" image = "checkmark.circle.fill"
text = "Complete" text = "Complete"
@@ -45,17 +94,18 @@ struct ImportView: View {
} }
} }
} label: { } label: {
Label("Import", systemImage: "tray.and.arrow.down.fill") Text("yes")
.font(.title2)
.bold()
} }
.disabled(importStr.isEmpty) .buttonStyle(BorderedProminentButtonStyle())
.onAppear() {
importStr = ""
image = "clock.fill"
text = "Ready..."
fgColor = .yellow
} }
.padding()
}
.frame(maxWidth: 250, maxHeight: 250)
}
.opacity(showAlert ? 1 : 0)
} }
} }
} }

View File

@@ -325,14 +325,18 @@ class EventViewModel: ObservableObject, @unchecked Sendable {
return "" return ""
} }
func importEvents(_ imported: String) throws { func importEvents(_ imported: String, replace: Bool) throws {
guard let data = Data(base64Encoded: imported) else { guard let data = Data(base64Encoded: imported) else {
throw importError.invalidB64 throw importError.invalidB64
} }
let decoder = JSONDecoder() let decoder = JSONDecoder()
do { do {
let decoded = try decoder.decode([Event].self, from: data) let decoded = try decoder.decode([Event].self, from: data)
if replace {
self.events = decoded self.events = decoded
} else {
self.events = self.events + decoded
}
saveEvents() saveEvents()
} catch { } catch {
throw error throw error