Search code examples
swiftuiuipickerviewswift5swiftui-listsections

Check selection in pickerView SwiftUi


I am a noob and I learning Swift and SwiftUI. I want to create an application for organize the notes. I have 2 problems.

  1. I would like to control when user had selected category in picker view before pressed button. And hide button save if category is not selected.
  2. Sort notes in list by category in ListView.

//
//  NewNoteView.swift
//  List&Notes
//
//  Created by Yoan on 18/04/2021.
//

import SwiftUI

    struct NewNoteView: View {
        let coreDM: CoreDataManger
        
        @State var category: [Category] = [Category]()
        @State private var categorySelected = Category()
        @State private var categoryField = String()
        @State private var noteField: String = "Your note here"
        @State private var noteTitleField = String()
        @State private var showButton = false
        
        private func emptyField() {
            categoryField = ""
            noteField = ""
            noteTitleField = ""
        }
        
          var body: some View {
          
            VStack{
                Form {
                    Picker("Select your category", selection: $categorySelected) {
                            ForEach(category, id: \.self) { categorize in
                                Text(categorize.title ?? "no value")
                            }
                        }
                    TextField("titleNote", text: $noteTitleField)
                        .font(.title2)
                        .background(Color.white)
                        .cornerRadius(5)
                        .shadow(radius: 5)
                    
                        TextEditor(text: $noteField)
                            .padding(.bottom)
                      .font(.body)
                      .background(Color.white)
                      .shadow(radius: 5)
                      .cornerRadius(8)
                    }
               
                    Button(action: {
                        guard !noteTitleField.isEmpty && !noteField.isEmpty && categorySelected != nil else {
                            print("Error")
                            return
                        }
                        coreDM.saveNote(noteData: noteField, noteTitle: noteTitleField,
                                          noteDate: Date(), noteCategory: categorySelected)
                          emptyField()
                          }, label: {
                              Text("Save")
                            }
                    )
                        .frame(maxWidth: .infinity, maxHeight: 40.0 )
                        .background(Color.yellow)
                        .shadow(radius: 10)
                        .cornerRadius(10)
            }
            .navigationTitle("Create new note")
                .onAppear(perform: {
                category = coreDM.getAllCategory()
                })
    }
}

struct NewNoteView_Previews: PreviewProvider {
    static var previews: some View {
        NavigationView{
            NewNoteView(coreDM: CoreDataManger())
        }
    }
}

//
//  ListView.swift
//  List&Notes
//
//  Created by Yoan on 18/04/2021.
//

import SwiftUI

struct ListView: View {
    let coreDM: CoreDataManger
    @State var notes: [Note] = [Note]()
    @State var needsRefresh: Bool = false
    @State var category: [Category] = [Category]()
    
    
    private func updateListNote() {
        notes = coreDM.getAllNotes()
        category = coreDM.getAllCategory()
    }
    var body: some View {
        
        List {
                        ForEach(notes, id: \.self) { notes in
                        NavigationLink(
                            destination: NoteDetailView(coreDM: coreDM, note: notes, needsRefresh: $needsRefresh),
                            label: {
                                HStack{
                                    VStack{
                                        Text(notes.title ?? "no value")
                                            .font(.title2)
                                            .multilineTextAlignment(.leading)
                                            .lineLimit(1)
                                        Text(notes.dataNote ?? "No description")
                                            .font(.subheadline)
                                            .foregroundColor(.gray)
                                            .multilineTextAlignment(.leading)
                                            .lineLimit(2)
                                    }
                                    Spacer()
                                    VStack{
                                        Text(notes.date!, style: .date)
                                        Text(notes.date!, style: .time)
                                    }
                                   
                                }
                            })
                        }
                        .onDelete(perform: { indexSet in
                            indexSet.forEach { index in
                                let note = notes[index]
                                coreDM.deleteNote(note: note)
                                updateListNote()
                                }
                        })
        }
        .listStyle(PlainListStyle())
        .accentColor(needsRefresh ? .red: .blue)
        
        .navigationTitle("Your notes")
        .onAppear(perform: {
            updateListNote()
        })
    }
}

struct ListView_Previews: PreviewProvider {
    static var previews: some View {
        ListView(coreDM: CoreDataManger())
    }
}

You can find my project in my GitHub if you need. https://github.com/yoan8306/List-Notes.git

Sorry I'm French and my English is not very well. I hope it's my problem it's clear.


Solution

  • I fix my 1 query. Like say udbhateja make categorySelected as optional @State private var categorySelected: Category? = nil For fix selection in pickerView we need add .tag((categorize as Category?)) the code is

    import SwiftUI
    
        struct NewNoteView: View {
            let coreDM: CoreDataManger
            
            @State var category: [Category] = [Category]()
            @State private var categorySelected : Category? = nil
            @State private var categoryField = String()
            @State private var noteField: String = "Your note here"
            @State private var noteTitleField = String()
            @State private var showButton = false
            @State private var presentAlert = false
            @State private var saveSuccess = false
            @State private var selection = Category()
            
            private func emptyField() {
                categoryField = ""
                noteField = ""
                noteTitleField = ""
            }
            private func checkNoteIsOk() -> Bool{
                if !noteTitleField.isEmpty && !noteField.isEmpty && categorySelected != nil {
                  return true
                } else {
                    presentAlert = true
                    return false
                }
            }
            
              var body: some View {
              
                VStack{
                    Form {
                        Picker("Select your category", selection: $categorySelected ) {
                                ForEach(category, id: \.self) { categorize in
                                Text(categorize.title ?? "no value").tag((categorize as Category?))
                                }
                            }
                        TextField("titleNote", text: $noteTitleField)
                            .font(.title2)
                            .background(Color.white)
                            .cornerRadius(5)
                            .shadow(radius: 5)
                        
                            TextEditor(text: $noteField)
                              .font(.body)
                              .background(Color.white)
                              .shadow(radius: 5)
                              .cornerRadius(8)
                                .padding(.bottom)
                        }
                    if let category = categorySelected {
                        Button(action: {
                           
                            guard checkNoteIsOk() else {
                                return
                            }
                            coreDM.saveNote(noteData: noteField, noteTitle: noteTitleField,
                                            noteDate: Date(), noteCategory: categorySelected!)
                            emptyField()
                            saveSuccess = true
                              },
                                label: {
                                  Text("Save")
                                }
                        )
                            .frame(maxWidth: .infinity, maxHeight: 40.0 )
                            .background(Color.yellow)
                            .shadow(radius: 10)
                            .cornerRadius(10)
                    }
                }
                .navigationTitle("Create new note")
                .onAppear(perform: {category = coreDM.getAllCategory()})
                
                .alert(isPresented: $presentAlert) {
                    Alert(title: Text("Error !"), message: Text("Not saved"),
                    dismissButton: .default(Text("OK"))) }
                
                .alert(isPresented: $saveSuccess) {
                    Alert(title: Text("Success !"), message: Text("Insert with success !"),
                    dismissButton: .default(Text("OK"))) }
        }
    }
    
    struct NewNoteView_Previews: PreviewProvider {
        static var previews: some View {
            NavigationView{
                NewNoteView(coreDM: CoreDataManger())
            }
        }
    }

    But I have new problem. I think it's simple. I would like make 2 alerts messages. The first it's when save is success and the second is when they are problem like one field is empty or category is empty.

    private func checkNoteIsOk() -> Bool{
            if !noteTitleField.isEmpty && !noteField.isEmpty && categorySelected != nil {
              return true
            } else {
                presentAlert = true
                return false
            }
        }
    

    .

    Button(action: {
                            guard checkNoteIsOk() else {
                            // present alert here
                                return
                            }
                            coreDM.saveNote(noteData: noteField, noteTitle: noteTitleField,
                                              noteDate: Date(), noteCategory: categorySelected!)
                            emptyField()
                            ( ..present saveSuccess alert here..)
                            saveSuccess = true
                              },
                                label: {
                                  Text("Save")
                                }
                        ) //end button
                        
                      code .... 
    
    
        } //end Vstak
          .navigationTitle("Create new note")
         .alert(isPresented: $presentAlert) {
                    Alert(title: Text("Error !"), message: Text("Not saved"),
                    dismissButton: .default(Text("OK"))) }
                
        .alert(isPresented: $saveSuccess) {
            Alert(title: Text("Success !"), message: Text("Insert with success !"),
            dismissButton: .default(Text("OK"))) }
    

    I think it's because they are two alerts messages. And only the last message alert can display. Thank you for your answer and your help.