Why ViewModel function is throwing error in SwiftUI? - ios

I am trying to call ViewModel method in the view but getting error as Thread 1: Fatal error: No ObservableObject of type AuthViewModel found. A View.environmentObject(_:) for AuthViewModel may be missing as an ancestor of this view. I don't have any idea why it is happening.
AuthViewModel
import SwiftUI
class AuthViewModel: ObservableObject {
func login() {
print("Hello")
}
}
My View File
//
// RegistrationView.swift
// TwitterSwiftUI
//
// Created by developer on 11/06/21.
//
import SwiftUI
struct RegistrationView: View {
#State var text = ""
#State var fullName = ""
#State var userName = ""
#State var password = ""
#State var isImagePickerDisplay = false
#State var selectedImage:UIImage?
#Environment(\.presentationMode) var mode: Binding<PresentationMode>
#EnvironmentObject var viewModel: AuthViewModel
var body: some View {
ZStack {
Color(#colorLiteral(red: 0.2203325033, green: 0.6315936446, blue: 0.955042541, alpha: 1))
.ignoresSafeArea()
VStack {
Button(action: {
isImagePickerDisplay = true
}, label: {
if selectedImage != nil {
Image(uiImage: selectedImage!)
.resizable()
.scaledToFit()
.frame(width: 140, height: 140)
.padding(.top, 0)
} else {
Image("plus_photo")
.resizable()
.renderingMode(/*#START_MENU_TOKEN#*/.template/*#END_MENU_TOKEN#*/)
.foregroundColor(.white)
.scaledToFit()
.frame(width: 140, height: 140)
.padding(.top, 0)
}
})
VStack {
CustomTextField(text: $fullName, placeholder: Text("Full name"), icon: Image(systemName: "person"))
.foregroundColor(.white)
.padding()
.background(Color(.init(white: 1, alpha: 0.15)))
.cornerRadius(10)
CustomTextField(text: $fullName, placeholder: Text("Email"), icon: Image(systemName: "envelope"))
.foregroundColor(.white)
.padding()
.background(Color(.init(white: 1, alpha: 0.15)))
.cornerRadius(10)
CustomTextField(text: $userName, placeholder: Text("Username"), icon: Image(systemName: "person"))
.foregroundColor(.white)
.padding()
.background(Color(.init(white: 1, alpha: 0.15)))
.cornerRadius(10)
CustomSecureField(password: $password)
.foregroundColor(.white)
.padding()
.background(Color(.init(white: 1, alpha: 0.15)))
.cornerRadius(10)
Spacer()
.frame(height: 30)
GeometryReader { geometry in
Button(action: {
//viewModel.registerUser(email: "userName", password: "password", userName: "userName", fullName: "fullName", profileImage: selectedImage)
viewModel.login()
}, label: {
Text("Sign up")
})
.frame(width: (geometry.size.width*1), height: 50)
.background(Color.white)
.clipShape(Capsule())
.padding(.vertical)
}
}.padding()
Spacer()
HStack {
Text("Already have account? Login in")
.foregroundColor(.white)
}.onTapGesture {
mode.wrappedValue.dismiss()
}.padding(.bottom, 28)
}
}.sheet(isPresented: self.$isImagePickerDisplay) {
ImagePickerViewHelper(selectedImage: self.$selectedImage, sourceType: .photoLibrary)
}
}
}

The error message clearly says that the #EnvironmentObject property wrapper requires the associated object to be added to the environment somewhere on a higher level of the view hierarchy with the environmentObject() modifier.
To access the view model directly you have to use #Stateobject to create an instance of the observed class
#Stateobject var viewModel = AuthViewModel()

Related

How to close sheet view with buttons

I'm currently running into a problem with a sheet not closing when the close button is pushed or the save button has completed transferring the data from the form to the list in homeview. Below is the code for a custom tab bar that when "New Survey" is pushed it will open the formView. The formView has two buttons closed and save. I would like it that when either one of these buttons are selected that it closes the formView.
struct FormView: View {
#Binding var surveys: [Survey]
#State var customerName = ""
#State var city = ""
#State var state = ""
#State var lineName = ""
#State var date = Date()
#Binding var isPresented: Bool
#State var showingFormView = false
var body: some View {
VStack{
ZStack {
NavigationView {
VStack {
ZStack {
Form {
Section(header: Text("Survey Info").font(.custom("Roboto-Light", size: 24)).foregroundColor(Color(red: 0.00, green: 0.188, blue: 0.42)).offset(x: -20)) { TextField("Customer Name", text: $customerName)
.padding(.vertical, 10.0)
.font(.custom("Roboto-Light", size: 18))
TextField("Customer City", text: $city)
.padding(.vertical, 10.0)
.font(.custom("Roboto-Light", size: 18))
TextField("State", text: $state)
.padding(.vertical, 10.0)
.font(.custom("Roboto-Light", size: 18))
TextField("Line Name", text: $lineName)
.padding(.vertical, 10.0)
.font(.custom("Roboto-Light", size: 18))
DatePicker("Date", selection: $date, displayedComponents: .date)
.padding(.vertical, 10.0)
.font(.custom("Roboto-Light", size: 18))
}
}
VStack (alignment: .center){
Spacer()
HStack {
**Button(action: {
self.showingFormView = false
self.isPresented = false
}, label: {
Text("Close")
.font(.custom("Roboto-Light", size: 23))
.foregroundColor(Color.white)
.frame(width: 150.0, height: 50.0, alignment: .center)
.background(Color(hue: 0.001, saturation: 0.768, brightness: 0.975))
.cornerRadius(3)
})
Button(action: {
// Save survey data to UserDefaults or any other means
let survey = Survey(customerName: customerName, city: city, state: state, lineName: lineName, date: date)
self.surveys.append(survey)
// Clear text fields
self.customerName = ""
self.city = ""
self.state = ""
self.lineName = ""
self.date = Date()
// Close FormView
self.showingFormView = false
self.isPresented = false
}, label: {
Text("Save")
.font(.custom("Roboto-Light", size: 23))
.foregroundColor(Color.white)
.frame(width: 150.0, height: 50.0, alignment: .center)
.background(Color(red: 0.451, green: 0.729, blue: 0.251))
.cornerRadius(3)
})**
}
}
}
}
.navigationBarHidden(true)
}
}
}
}
}
Custom Tab Bar
struct CustomTabBar: View {
#Binding var surveys: [Survey]
#Binding var isPresented : Bool
#State var showingFormView = false
var body: some View {
NavigationView{
VStack {
Spacer()
HStack (alignment: .bottom) {
Button {
} label: {
GeometryReader { geo in
VStack (alignment: .center, spacing: 4) {
Image(systemName: "magnifyingglass")
.resizable()
.scaledToFit()
.frame(width: 32, height: 32)
Text("Search")
.font(.custom("Roboto-Light", size: 14))
}
.frame(width: geo.size.width,height: geo.size.height)
}
}
.tint(Color(red: 0.0, green: 0.188, blue: 0.42))
**Button(action: {
showingFormView = true
}) {
GeometryReader { geo in
VStack(alignment: .center, spacing: 4) {
Image("PSIcon")
.resizable()
.scaledToFit()
.frame(width: 38, height: 38)
Text("New Survey")
.font(.custom("Roboto-Light", size: 14))
.tint(Color(red: 0.0, green: 0.188, blue: 0.42))
}
.frame(width: geo.size.width, height: geo.size.height)
}
}
.sheet(isPresented: $showingFormView) {
FormView(surveys: $surveys, isPresented: $isPresented) }
//code allows you to call up a specific view so long as a var is indicated
**
Button {
} label: {
GeometryReader { geo in
VStack (alignment: .center, spacing: 4) {
Image(systemName: "arrow.up.arrow.down")
.resizable()
.scaledToFit()
.frame(width: 35, height: 35)
Text("Sort")
.font(.custom("Roboto-Light", size: 14))
}
.frame(width: geo.size.width,height: geo.size.height)
}
}
.tint(Color(red: 0.0, green: 0.188, blue: 0.42))
}
.frame(height: 50.0)
}
}
}
}
The save button saves and creates a new item in the dynamic list but it does not close the formView. The only way for me to close the view is by swiping down on the screen.

Array is not updating swiftUI [duplicate]

This question already has answers here:
What is the difference between ObservedObject and StateObject in SwiftUI
(6 answers)
Saving Date/Time to UserDefaults through didSet on #Published var (from TimePicker component of SwiftUI)
(1 answer)
Closed 8 months ago.
I trying to update the array when the user change the input.
Here is the viewModel
struct Person: Identifiable {
var id = UUID()
var name : String
var age : String
}
class PersonViewModel : ObservableObject{
#Published var PersonArray = [Person]()
func emptyPersonArray() {
self.PersonArray.append(Person(name: "", age: ""))
}
}
struct ContentView: View {
#ObservedObject var personViewModel = PersonViewModel()
var body: some View {
VStack{
Button(action: {
personViewModel.emptyPersonArray()
}) {
HStack {
Text("Add")
.font(.title3)
.bold()
}
}
.padding()
.foregroundColor(Color.black)
.frame(width: 150.72, height: 40)
.background(RoundedRectangle(cornerRadius: 6).stroke(Color(red: 0.463, green: 0.483, blue: 1.034), lineWidth: 2))
List{
ForEach(personViewModel.PersonArray) {person in
PersonView(person: person,name: person.name, age: person.age)
}.padding(.leading, -150)
}
Button(action: {
for person in personViewModel.PersonArray{
print("Person Name: \(person.name)")
print("Person Age: \(person.age)")
}
}) {
HStack {
Text("Show data")
.font(.title3)
.bold()
}
}
}
}
}
here is PersonView:
struct PersonView: View {
#State var person: Person
#State var name = ""
#State var age = ""
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 9)
.fill(Color.white)
.frame(width: 650, height: 180)
VStack (alignment: .center) {
Text("Person")
.font(.title3)
.fontWeight(.bold)
VStack{
Text("Enter Name:")
TextField("", text: $name)
.onChange(of: name, perform: { newValue in
person.name = newValue
})
.frame(width: 289, height: 40.0)
.background(RoundedRectangle(cornerRadius: 6).stroke(Color.black))
Text("Enter Age:")
TextField("", text: $age).padding()
.onChange(of: age, perform: { newValue in
person.age = newValue
})
.frame(width: 289, height: 40.0)
.background(RoundedRectangle(cornerRadius: 6).stroke(Color.black))
} .padding(.leading)
}
}
}
}
when I tried to print it shows empty and did not update:
The problem have be solved
by changing the #State to #Binding in PersonView
struct PersonView: View {
#Binding var person: Person
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 9)
.fill(Color.white)
.frame(width: 650, height: 180)
VStack (alignment: .center) {
Text("Person")
.font(.title3)
.fontWeight(.bold)
VStack{
Text("Enter Name:")
TextField("", text: $person.name)
.onChange(of: person.name, perform: { newValue in
person.name = newValue
})
.frame(width: 289, height: 40.0)
.background(RoundedRectangle(cornerRadius: 6).stroke(Color.black))
Text("Enter Age:")
TextField("", text: $person.age).padding()
.onChange(of: person.age, perform: { newValue in
person.age = newValue
})
.frame(width: 289, height: 40.0)
.background(RoundedRectangle(cornerRadius: 6).stroke(Color.black))
} .padding(.leading)
}
}
}
}

iOS: How to switch views from Login to Main Content SwiftUi

firstly I am really new to iOS development and Swift (2 weeks coming here from PHP :))
I am build a simple application, when the user Logs (Is confirmed) the view switched to the main content.
So currently I have a LoginView() and that is what loads first. I am wondering how when I click the Login button in LoginView() then the view switches to the MainContentView()
Any help would be appreciated. Thanks
LoginView()
'''
import SwiftUI
struct LoginView: View {
#State private var email: String = ""
#State private var password: String = ""
let verticalPaddingForForm = 40
#State private var willMoveToNextScreen = true
var body: some View {
ZStack {
Color(red: 20/225.0 ,green: 22/225.0 , blue: 25/225.0)
VStack(alignment: .leading, spacing: 0) {
Image("logo")
.resizable()
.scaledToFit()
.padding(.top, 150)
.padding()
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)
.ignoresSafeArea(.all)
VStack(spacing: CGFloat(verticalPaddingForForm)) {
VStack {
TextField("Email", text: $email)
.padding(.horizontal, 15).padding(.top, 50)
Divider()
.padding(.horizontal, 15)
SecureField("Password", text: $password)
.padding(.horizontal, 15).padding(.top, 20)
Divider()
.padding(.horizontal, 15)
}
.background(Color(.white))
Link("Forgotten Password",
destination: URL(string: "https://www.google.co.uk")!)
.foregroundColor(.blue)
.font(.system(size: 15))
Button(action: {
//Do login stuff here and if true switch view to to MainContentView
}) {
Text("Login")
.padding()
.font(.system(size: 20))
}
.background(Color.black)
.foregroundColor(Color.white)
.cornerRadius(10)
.padding(.top, 0)
.padding(.bottom, 20)
}
.padding(.horizontal, CGFloat(verticalPaddingForForm))
.background(Color(.white))
VStack{
Spacer()
Button(action: /*#START_MENU_TOKEN#*/{}/*#END_MENU_TOKEN#*/) {
Text("Register")
.padding()
.font(.system(size: 40))
}
.background(Color(red: 20/225.0 ,green: 22/225.0 , blue: 25/225.0))
.foregroundColor(Color.white)
.cornerRadius(10)
.padding()
}
}.ignoresSafeArea()
};
}
'''
Below is the content view, the LoginView loads firsts and when the login button is click from above then should switch to the MainContentView() which is commented out below
ContentView:
'''
import SwiftUI
struct ContentView: View {
var body: some View {
LoginView()
//After login is confirmed in the login view, then switch from
// LoginView to
//MainContentView()
}
}
'''
You can have a State in the ContentView, which decides wheather your User is logged in.
struct ContentView: View {
#State var isLoggedIn: Bool = false
var body: some View {
if !isLoggedIn {
LoginView(isLoggedIn: $isLoggedIn)
} else {
MainContentView()
}
}
}
Then in the logging View add a Binding, and when the users successfully logged in, change that binding.
struct LoginView: View {
#State private var email: String = ""
#State private var password: String = ""
let verticalPaddingForForm = 40
#Binding var isLoggedIn: Bool // here is the Binding
Then in the Action, toggle that Binding
Button(action: {
//Do login stuff here and if true switch view to to MainContentView
isLoggedIn = true
You could also think using some kind of Navigation Pattern and pushing to the next view.
The code above is not tested, just out of my mind

How to bind an image to the next view in SwiftUI?

trying to create an onboarding flow of views with text fields to capture profile data and in the last view I will store the data in Firestore. However, need to pass all the data down to the last view to register the user with this data.
View 0 has Username, email, and password
View 1 has first name, last name and image
View 2 has Job title, company name
I am able to pass the username, email, and password to view 1 and first name, last name, and image to view 2.
I am NOT able to pass the image to view 3 because it is now binding and is asking for an argument in the "Preview" that I can't figure out.
The String bindings I pass with .constant("") BUT what do I do to pass the image see code below.
```
import SwiftUI
struct Step1: View {
#State var firstname = ""
#State var lastname = ""
#Binding var email: String
#Binding var password:String
#Binding var username: String
#State var image: Image?
#State var showImagePicker = false
#State private var selectedImage: UIImage?
var body: some View {
VStack{
HStack{
VStack(alignment: .leading, spacing: 4) {
Text("Create profile")
.font(.system(size: 30))
.fontWeight(.bold)
Text("Basic profile information")
.font(.system(size: 18))
}
.padding(.horizontal, 32)
.padding(.bottom, 50)
.padding(.top, 50)
Spacer()
}
VStack(spacing: 20){
HStack{
if image != nil {
image?
.resizable()
.scaledToFill()
.frame(width: 80, height: 80)
.clipShape(RoundedRectangle(cornerRadius: 10.0))
} else {
Image("upload")
.resizable()
.scaledToFill()
.frame(width: 80, height: 80)
.clipShape(RoundedRectangle(cornerRadius: 10.0))
}
Spacer()
}
.onTapGesture {
self.showImagePicker = true
}
CustomTextField(text: $firstname, placeholder: Text("First name"), ImageName: "person")
.padding()
.background(Color(#colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 0.2611568921)))
.cornerRadius(10)
CustomTextField(text: $lastname, placeholder: Text("Last name"), ImageName: "person")
.padding()
.background(Color(#colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 0.2611568921)))
.cornerRadius(10)
}
.padding(.horizontal, 32)
Spacer()
NavigationLink(
destination: Step2(firstname: $email, lastname: $password, email: $username, password: $firstname, username: $lastname, image: $image)
.navigationBarBackButtonHidden(true)
.navigationTitle("")
.navigationBarHidden(true),
label: {
Text("Sign Up")
.font(.headline)
.foregroundColor(.white)
.frame(width:360, height: 50)
.background(Color(#colorLiteral(red: 0.03573478386, green: 0.4008729458, blue: 0.7616711259, alpha: 1)))
.cornerRadius(10)
.padding()
Spacer()
})
.navigationTitle("")
.navigationBarHidden(true)
}.sheet(isPresented: $showImagePicker, onDismiss: loadImage) {
ImagePicker(image: self.$selectedImage)
}
}
func loadImage() {
guard let selectedImage = selectedImage else { return }
image = Image(uiImage: selectedImage)
}
}
struct Step1_Previews: PreviewProvider {
static var previews: some View {
Step1(email: .constant(""), password: .constant(""), username: .constant(""))
}
}
```
```
import SwiftUI
struct Step2: View {
#Binding var firstname: String
#Binding var lastname: String
#Binding var email: String
#Binding var password:String
#Binding var username: String
#Binding var image: Image?
var body: some View {
VStack{
HStack{
VStack(alignment: .leading, spacing: 4) {
Text("Create profile")
.font(.system(size: 30))
.fontWeight(.bold)
Text("Basic profile information")
.font(.system(size: 18))
}
.padding(.horizontal, 32)
.padding(.bottom, 50)
.padding(.top, 50)
Spacer()
}
VStack(spacing: 20){
CustomTextField(text: $firstname, placeholder: Text("First name"), ImageName: "person")
.padding()
.background(Color(#colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 0.2611568921)))
.cornerRadius(10)
CustomTextField(text: $lastname, placeholder: Text("Last name"), ImageName: "person")
.padding()
.background(Color(#colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 0.2611568921)))
.cornerRadius(10)
}
.padding(.horizontal, 32)
Spacer()
.navigationTitle("")
.navigationBarHidden(true)
}
}
}
struct Step2_Previews: PreviewProvider {
static var previews: some View {
Step2(firstname: .constant(""), lastname: .constant(""), email: .constant(""), password: .constant(""), username: .constant(""), image: WHAT TO PUT HERE????)
}
}
```
You can use .constant(Image(uiImage: UIImage())) or set any static image like this .constant(Image("image_name")))

Removing items from a child view generated by For Each loop causes Fatal Error

I hope you are having a more pleasant evening than mine!
So as I mentioned in the title, my for each loop crashes whenever I try to remove an item from the original list with a binding. I did some research and the problem is that for each generates a view with an id but when you delete the item in your child view it can't find the contents and crashes. Returns 'Thread 1: Fatal error: Index out of range'. I can fix the issue by declaring a #State var instead of #Binding, which really works! However, I have more than a delete button in my child view and if I don't use a binding declaration, changes made don't reflect on the main view. I don't wanna give up on neither the delete button nor buttons. Is there way to keep all of them in my childview?
Mainview declarations;
struct ContentView: View {
#ObservedObject var superReminders = SuperReminders()
#State var superReminder = SuperReminder()}
My list View;
List{
ForEach(superReminders.reminderlist.indices, id: \.self) { index in
NavigationLink(destination: DetailedRemView(superReminder : self.$superReminders.reminderlist[index] ).environmentObject(superReminders)) {
squareImageView(superReminder : self.$superReminders.reminderlist[index]).environmentObject(superReminders).environmentObject(superReminders)
}.listRowBackground(Color.clear)
}.onDelete { indexSet in
superReminders.reminderlist.remove(atOffsets: indexSet)}
}
Childview declarations;
import SwiftUI
struct DetailedRemView: View {
var dateFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.dateFormat = "EE, MMM d, YYYY"
return formatter
}
#State public var showingDetail = false
#Environment(\.colorScheme) var colorScheme: ColorScheme
#State private var deleteReminderAlert = false
#EnvironmentObject var superReminders : SuperReminders
#Environment(\.presentationMode) var presentationMode
#Binding var superReminder : SuperReminder
#State private var showDialog = false
#State var animate = false
var body: some View {
VStack{
HStack(alignment: .center){
Text(superReminder.remdate)
.font(.title)
.multilineTextAlignment(.leading)
.padding(.leading)
.frame(minWidth: 100,maxWidth: .infinity, maxHeight: 50)
Spacer()
Button(action: {
self.showDialog.toggle()
}, label: {
ZStack{
RoundedRectangle(cornerRadius: 10)
.fill(Color.blue)
.frame(width: 80, height: 35)
HStack{
Text("Edit")
.foregroundColor(.white)
.multilineTextAlignment(.center)
.cornerRadius(8)
Image(systemName: "pencil")
.foregroundColor(.white)
}
}
.shadow(color:Color.gray.opacity(0.3), radius: 3, x: 3, y: 3)
.padding(.leading)
.alert(isPresented: $showDialog,
TextAlert(title: "Edit reminder title",
message: "Enter a new title or dissmis.", placeholder: superReminder.remdate,
keyboardType: .default) { result in
if let text = result {
if text != "" {
superReminder.remdate = text }
else{}
} else {
}
})
})
.padding(.leading)
}
.frame(minWidth: 100, maxWidth: /*#START_MENU_TOKEN#*/.infinity/*#END_MENU_TOKEN#*/, maxHeight: 50, alignment: /*#START_MENU_TOKEN#*/.center/*#END_MENU_TOKEN#*/)
.padding(.vertical, -10)
ZStack(alignment: .topTrailing){
Image(superReminder.image)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(minWidth: 0,maxWidth: .infinity,minHeight: 200,maxHeight: .infinity)
.saturation(superReminder.pastreminder ? 0.1 : 1)
.clipShape(Rectangle())
.cornerRadius(10)
.padding(.all)
.pinchToZoom()
HStack{
Text(superReminder.dateactual, formatter: dateFormatter)
.foregroundColor(.white)
.frame(width: 180, height: 30, alignment: /*#START_MENU_TOKEN#*/.center/*#END_MENU_TOKEN#*/)
.background( superReminder.pastreminder ? Color.gray : Color.lightlygreen)
.cornerRadius(8)
.animation(/*#START_MENU_TOKEN#*/.easeIn/*#END_MENU_TOKEN#*/)
if superReminder.pastreminder == true {
ZStack{
RoundedRectangle(cornerRadius: 8)
.fill(Color.black)
.frame(width: 30, height: 30)
Image(systemName: "moon.zzz")
.foregroundColor(.white)
}.offset(x: animate ? -3 : 0)
.onAppear(perform: {
shake()
})
}
else{}
}
.zIndex(0)
.offset(x: -10, y: 10)
.padding()
}
.zIndex(1)
.shadow(color: Color.gray.opacity(0.4), radius: 3, x: 1, y: 2)
HStack{
Button(action: {
self.showingDetail.toggle()
}){
ZStack{
RoundedRectangle(cornerRadius: 10)
.fill(Color.lightlygreen)
.frame(width: 140, height: 40)
HStack{
Text("Reschedule")
.foregroundColor(.white)
.multilineTextAlignment(.center)
.cornerRadius(8)
Image(systemName: "calendar")
.foregroundColor(.white)
}
}
.shadow(color:Color.gray.opacity(0.3), radius: 3, x: 3, y: 3)
.padding(.all, 4.0)
}
.sheet(isPresented: $showingDetail, content :{
remdatepicker(isPresented: self.$showingDetail, superReminder: $superReminder)})
Button(action: {
if superReminder.pastreminder == true {
superReminder.pastreminder = false
}
else if superReminder.pastreminder == false{
superReminder.pastreminder = true
}
}, label: {
ZStack{
RoundedRectangle(cornerRadius: 10)
.fill(superReminder.pastreminder == true ? Color.lightlyblue : Color.gray)
.frame(width: 100, height: 40)
HStack{
Text(superReminder.pastreminder == true ? "Activate" : "Silence")
.foregroundColor(.white)
.multilineTextAlignment(.center)
.cornerRadius(8)
Image(systemName: superReminder.pastreminder == true ? "checkmark.circle" : "moon.zzz")
.foregroundColor(.white)
}
}
.shadow(color:Color.gray.opacity(0.3), radius: 3, x: 3, y: 3)
.padding(.all, 4.0)
})
Button(action: {
self.deleteReminderAlert.toggle()
}, label: {
ZStack{
RoundedRectangle(cornerRadius: 10)
.fill(Color(.red))
.frame(width: 40, height: 40)
HStack{
Image(systemName: "trash")
.foregroundColor(.white)
}
}
.shadow(color:Color.gray.opacity(0.3), radius: 3, x: 3, y: 3)
.padding(.all, 4.0)
})
}.padding(.bottom, 20)
.alert(isPresented: $deleteReminderAlert){
Alert(
title: Text("Are you sure?"),
message: Text("Do you want to delete this reminder?"),
primaryButton: .destructive(Text("Yes"), action: {
superReminders.remove(superReminder: superReminder)
self.presentationMode.wrappedValue.dismiss()
}),
secondaryButton: .cancel(Text("No"))
)
}
}
}
func shake() {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
withAnimation(Animation.default.repeatCount(6).speed(7)){
animate.toggle()}}}
}
Class and List;
import SwiftUI
struct SuperReminder: Identifiable, Codable, Equatable {
var id = UUID()
var remdate = ""
var dateactual = Date.init()
var image = "New1"
var pastreminder = false
}
class SuperReminders: ObservableObject {
#Published var reminderlist: [SuperReminder]
init() {
self.reminderlist = [
]
}
func add(superReminder: SuperReminder) {
reminderlist.append(superReminder)
}
func remove(superReminder: SuperReminder) {
if let index = reminderlist.firstIndex(of: superReminder) {
reminderlist.remove(at: index)
}
}
}
This answer is similar to
Accessing and manipulating array item in an EnvironmentObject
Loop over superReminders.reminderlist since SuperReminder: Identifiable, Codable, Equatable.
ForEach(superReminders.reminderlist) { superReminder in
NavigationLink(destination: DetailedRemView(superReminders: superReminders,
superReminder: superReminder)) {
-----
}
}
In DetailedRemView, do the following:
struct DetailedRemView: View {
#ObservedObject var superReminders : SuperReminders
var superReminder : SuperReminder
// find index of current superReminder
var indexOfReminder: Int? {
superReminders.reminderlist.firstIndex {$0 == superReminder}
}
var body: some View {
// Unwrap indexOfReminder
if let index = indexOfReminder {
VStack {
------
}
}
}
----
}
Use superReminders.reminderlist[index] in DetailRemView whereever you need to update superReminder.
superReminders.reminderlist[index].pastreminder = false

Resources