Passing data in PreviewProvider SwiftUI, ObservableObject class, ObservedObject - swift

I guys, I have a class with some properties (class ReservationInfo). In my first screen (ReservationFormView) I create an instance of the class(myReservationInfo).
I pass the data with a NavigationLink to the second view (ReservationRecapView). It works all right, but I have a problem with the SwiftUI preview. How can I pass some example data to the preview provider?
class ReservationInfo: ObservableObject {
#Published var customerName: String = ""
#Published var surname : String = ""
#Published var nPeople : Int = 1
#Published var date = Date()
}
struct ReservationFormView: View {
#StateObject var myReservationInfo = ReservationInfo()
#State private var showSecondView = false
init() {
UIStepper.appearance().setDecrementImage(UIImage(systemName: "minus"), for: .normal)
UIStepper.appearance().setIncrementImage(UIImage(systemName: "plus"), for: .normal)
}
var body: some View {
NavigationView{
VStack(alignment: .center) {
Text("Little lemon")
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color.gray)
.multilineTextAlignment(.center)
.padding(.bottom, 10.0)
Label("Reservation Form", systemImage: "fork.knife")
.foregroundColor(Color.gray)
.padding(.bottom, 30)
VStack(alignment: .center, spacing: 30.0){
TextField("Type your name", text: $myReservationInfo.customerName, onEditingChanged: {print($0)})
.onChange(of: myReservationInfo.customerName, perform: { newValue in print(newValue)})
.onSubmit {
print("submitted")
}
.underlineTextField()
TextField("Type your surname", text: $myReservationInfo.surname)
.underlineTextField()
HStack(alignment: .center, spacing: 30.0){
Label("\(myReservationInfo.nPeople)", systemImage: "person.fill")
.font(.title2)
Stepper("N di persone", value: $myReservationInfo.nPeople , in: 1...20)
.labelsHidden()
.accentColor(.blue)
}
.padding(.top)
DatePicker(
"Select date",
selection: $myReservationInfo.date,
in: Date.now...,
displayedComponents: [.date, .hourAndMinute]
)
.onChange(of: myReservationInfo.date, perform: {date in print(date)})
.padding(.bottom, 20.0)
}
NavigationLink{
ReservationRecapView(myReservationInfo: myReservationInfo)
} label: {
Text("Avanti")
.padding(.horizontal, 70.0)
}
.padding(.vertical, 10)
.background(Color.blue)
.cornerRadius(10)
.foregroundColor(.white)
}
.padding(.horizontal, 30.0)
.padding(.bottom, 100.0)
.environmentObject(myReservationInfo)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ReservationFormView()
}
}
}
extension Color {
static let darkPink = Color(red: 208 / 255, green: 45 / 255, blue: 208 / 255)
}
extension View {
func underlineTextField() -> some View {
self
.autocorrectionDisabled(true)
.overlay(Rectangle().frame(height: 2).padding(.top, 40))
.foregroundColor(.blue)
}
}
struct ReservationRecapView: View {
#ObservedObject var myReservationInfo : ReservationInfo
var body: some View {
VStack(alignment: .leading, spacing: 10.0){
Text(myReservationInfo.customerName)
Text(myReservationInfo.surname)
Text("Number of people \(myReservationInfo.nPeople)")
Text(myReservationInfo.date, style: .date)
Text(myReservationInfo.date, style: .time)
}.font(.title2)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ReservationRecapView(myReservationInfo: ReservationInfo())
}
}
I don't know how to pass date in the PreviewProvider

Related

How to save the answers of a specific user to his profile in the questionnaire app (SwiftUI)?

I am creating an app for parents or guardians of autistic children. In the app, you can create profiles for several kids and then click on the "Start Questionnaire" button in the personal card of each child. When the questionnaire page opens, there the parent answers several questions in several categories, where the questions from each category have a different weight (1, 2, 3, 4). At the end of the questionnaire, these answers are recorded in the profile of a particular kid in order to display a graph of his progress based on the answers on his personal page.
My question is that I can't figure out how to save answers to a specific kid's profile. To store profiles of children, I use CoreData, where there are four attributes: name, birthdate, dateCreated and answers. I assigned the Binary Data type to the latter. I created a #State variable in the QuestionnairePageView file and specified its type as [[String:Int]] to store a question category as a String (1, 2, 3 or 4) and an answer as an Int (yes = 1 or no = 0). Also in that file I created a saveAnswers function that assigns questionnaire answers to that #State variable when the user taps End Questionnaire button.
However, it didn't work. Please help me to understand the issue.
My data manager:
import SwiftUI
import CoreData
class CoreDataManager {
let container: NSPersistentContainer
static let shared: CoreDataManager = CoreDataManager()
private init() {
container = NSPersistentContainer(name: "PersonModel")
container.loadPersistentStores { description, error in
if let error = error {
fatalError("Unable to initialize Core Data \(error)")
}
}
}
}
My QuestinarrieApp file:
import SwiftUI
#main
struct QuestinarrieApp: App {
let controller = CoreDataManager.shared.container
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.managedObjectContext, controller.viewContext)
}
}
}
My ContentView:
import SwiftUI
import CoreData
struct ContentView: View {
#State private var isShowingAddPersonPage: Bool = false
#Environment(\.managedObjectContext) private var viewContext
#FetchRequest(fetchRequest: Person.ownFetchRequest)
var persons: FetchedResults<Person>
var body: some View {
NavigationView {
ScrollView(.vertical, showsIndicators: false) {
VStack(spacing: 10) {
ForEach(persons) { person in
let age = "\(calculateAge(fromDate: person.birthdate ?? Date()))"
NavigationLink {
PersonalPageView(person: person, name: person.name ?? "Noname", age: age)
} label: {
HStack {
Text(person.name ?? "Noname").font(.title2.bold())
Spacer()
Text(age + " years old").font(.body.bold())
}
.foregroundColor(.black)
.padding()
.background(
RoundedRectangle(cornerRadius: 15, style: .continuous)
.fill(Color(UIColor.secondarySystemBackground))
)
.padding(.horizontal)
}
}
}
}
.navigationTitle("Persons")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: {
isShowingAddPersonPage = true
}) {
Image(systemName: "plus.circle")
} //: BUTTON
.sheet(isPresented: $isShowingAddPersonPage) {
AddPersonView()
}
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
let container = CoreDataManager.shared.container
ContentView()
.environment(\.managedObjectContext, container.viewContext)
}
}
My AddPersonView file:
import SwiftUI
struct AddPersonView: View {
#Environment(\.presentationMode) var presentationMode
#Environment(\.managedObjectContext) private var viewContext
#State private var name: String = ""
#State private var birthdate: Date = Date()
var body: some View {
NavigationView {
VStack(spacing: 10) {
// MARK: - NAME
HStack(spacing: 12) {
Image(systemName: "person.text.rectangle")
.resizable()
.renderingMode(.template)
.scaledToFit()
.frame(width: 25, height: 25)
TextField("Name", text: $name)
} //: HSTACK
.padding(.horizontal)
.frame(height: 60)
.background(
RoundedRectangle(cornerRadius: 15, style: .continuous)
.fill(Color(UIColor.secondarySystemBackground))
)
// MARK: - BIRTH DATE
HStack(spacing: 12) {
Image(systemName: "calendar")
.resizable()
.renderingMode(.template)
.scaledToFit()
.frame(width: 25, height: 25)
DatePicker(
"Birth date",
selection: $birthdate,
in: ...Date(),
displayedComponents: .date
)
.accentColor(.black)
} //: HSTACK
.padding(.horizontal)
.frame(height: 60)
.background(
RoundedRectangle(cornerRadius: 15, style: .continuous)
.fill(Color(UIColor.secondarySystemBackground))
)
Spacer()
// MARK: - SAVE BUTTON
Button {
if name != "" {
savePerson()
presentationMode.wrappedValue.dismiss()
}
} label: {
Text("Save")
.font(.body.bold())
.frame(maxWidth: .infinity)
.frame(height: 60)
.background(
RoundedRectangle(cornerRadius: 15, style: .continuous)
.fill(Color(UIColor.secondarySystemBackground))
)
} //: BUTTON
}
.navigationTitle("Add Person")
.padding()
}
}
private func savePerson() {
let newPerson = Person(context: viewContext)
do {
newPerson.name = name
newPerson.birthdate = birthdate
newPerson.dateCreated = Date()
try viewContext.save()
} catch {
print(error.localizedDescription)
}
}
}
struct AddPersonView_Previews: PreviewProvider {
static var previews: some View {
let container = CoreDataManager.shared.container
AddPersonView()
.environment(\.managedObjectContext, container.viewContext)
}
}
My PersonalPageView:
import SwiftUI
struct PersonalPageView: View {
#Environment(\.managedObjectContext) private var viewContext
var person: Person
var name: String
var age: String
var body: some View {
VStack(spacing: 20) {
HStack {
Text(name).font(.largeTitle.bold())
Spacer()
Text(age + " years old").font(.title2.bold()).foregroundColor(.secondary)
}
RoundedRectangle(cornerRadius: 10)
.fill(.ultraThinMaterial)
.frame(height: 300)
VStack {
ForEach(person.answers) { answer in // <- This ForEach doesn't work for now
Text("\(answer)")
}
}
Spacer()
NavigationLink {
QuestinarriePageView(person: person, name: "Jack")
} label: {
Text("Start Questinarrie")
.font(.title2.bold())
.frame(maxWidth: .infinity)
.frame(height: 60)
.background(
RoundedRectangle(cornerRadius: 15, style: .continuous)
.fill(Color(UIColor.secondarySystemBackground))
)
}
}
.navigationBarTitleDisplayMode(.inline)
.padding()
}
}
struct PersonalPageView_Previews: PreviewProvider {
static var previews: some View {
PersonalPageView(person: Person(), name: "Igor", age: "28")
}
}
And finally QuestinarriePageView:
import SwiftUI
struct QuestinarriePageView: View {
#Environment(\.managedObjectContext) private var viewContext
#State private var answers: [[String:Int]] = [[:]]
var person: Person
var name: String
var body: some View {
VStack(spacing: 40) {
HStack {
Spacer()
Button {} label: {
Text("Quit").font(.title2)
}
.tint(.black)
}
VStack {
Text("Does \(name) like to play with other kids?")
HStack(spacing: 100) {
Button {
answers += [["1":1]]
} label: {
Text("Yes")
.foregroundColor(.black)
.padding()
.background(
RoundedRectangle(cornerRadius: 10)
.fill(.secondary)
)
}
Button {
answers += [["1":0]]
} label: {
Text("No")
.foregroundColor(.black)
.padding()
.background(
RoundedRectangle(cornerRadius: 10)
.fill(.secondary)
)
}
}
}
VStack {
Text("Does \(name) like to speak?")
HStack(spacing: 100) {
Button {
answers += [["2":1]]
} label: {
Text("Yes")
.foregroundColor(.black)
.padding()
.background(
RoundedRectangle(cornerRadius: 10)
.fill(.secondary)
)
}
Button {
answers += [["2":0]]
} label: {
Text("No")
.foregroundColor(.black)
.padding()
.background(
RoundedRectangle(cornerRadius: 10)
.fill(.secondary)
)
}
}
}
VStack {
Text("Does \(name) like to play dance?")
HStack(spacing: 100) {
Button {
answers += [["3":1]]
} label: {
Text("Yes")
.foregroundColor(.black)
.padding()
.background(
RoundedRectangle(cornerRadius: 10)
.fill(.secondary)
)
}
Button {
answers += [["3":0]]
} label: {
Text("No")
.foregroundColor(.black)
.padding()
.background(
RoundedRectangle(cornerRadius: 10)
.fill(.secondary)
)
}
}
}
Spacer()
Button {
saveAnswers()
} label: {
Text("End Questionnaire")
.font(.body.bold())
.frame(maxWidth: .infinity)
.frame(height: 60)
.background(
RoundedRectangle(cornerRadius: 15, style: .continuous)
.fill(Color(UIColor.secondarySystemBackground))
)
}
}
.toolbar(.hidden)
.padding()
}
private func saveAnswers() {
let thisPerson = person
do {
thisPerson.answers = answers as? Data
try viewContext.save()
} catch {
print(error.localizedDescription)
}
}
}
struct QuestinarriePageView_Previews: PreviewProvider {
static var previews: some View {
QuestinarriePageView(person: Person(), name: "Igor")
}
}
Also I have a file with some helpers:
import SwiftUI
import CoreData
func calculateAge(fromDate: Date) -> Int {
let now = Date()
let calendar = Calendar.current
let ageComponents = calendar.dateComponents([.year], from: fromDate, to: now)
let age = ageComponents.year!
return age
}
extension Person {
static var ownFetchRequest: NSFetchRequest<Person> {
let request: NSFetchRequest<Person> = Person.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(key: "dateCreated", ascending: false)]
return request
}
}
I've been struggling with this problem for a month now. I hope this is solvable🙏

navigationLink to tag in another view

Here's an edited version of the question. I'm working in Swiftui and I have two views. The first has two NavigationLinks. The second link is where I get stuck. I would like that link to go to 'tabTwo' on PageTwo. Getting to PageTwo isn't an issue... it's getting to tabTwo as a view on that page.
Here's an edited down contentView file:
import SwiftUI
struct ContentView: View {
#State var isNavigationBarHidden: Bool = true
#State private var selectedTab = ""
var body: some View {
NavigationView {
ZStack {
VStack(spacing: 0) {
VStack(spacing: 0) {
NavigationLink("Link One", destination: PageTwo()).padding(10)
.foregroundColor(Color.gray)
.background(Color.white)
Divider().frame(width: 300,height: 1).background(Color.black)
}
VStack(spacing: 0) {
NavigationLink("Link Two", destination: PageTwo())
.padding(10)
.foregroundColor(Color.gray)
.background(Color.white)
}
// If you remove the below VStack everything works.
VStack(spacing: 0) {
NavigationLink("Page Two tabTwo", destination: PageTwo(), tag: "tabTwo", selection: $selectedTab?)
.padding(10)
.foregroundColor(Color.gray)
.background(Color.white)
}
}
}
}
.navigationBarTitle("Hidden Title")
.navigationBarHidden(self.isNavigationBarHidden)
.onAppear {self.isNavigationBarHidden = true}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
and here's an edited down PageTwo:
import SwiftUI
struct PageTwo: View {
#Environment(\.presentationMode) var mode: Binding<PresentationMode>
#State var isNavigationBarHidden: Bool = true
#State private var selectedTab = ""
var body: some View {
ZStack() {
TabView(selection: $selectedTab) {
//---> Tab One
VStack(spacing: 0) {
VStack{
Text("PAGE ONE")
.padding(.bottom, 20)
}
Button(action: {
self.mode.wrappedValue.dismiss()})
{ Text("BACK") }
.font(Font.system(size:14, weight: .bold, design: .default))
}
.navigationBarTitle("Hidden Title")
.navigationBarHidden(self.isNavigationBarHidden)
.onAppear {self.isNavigationBarHidden = true}
.tabItem {Label("ONE", systemImage: "circle.fill")}
.tag("tabOne")
//---> Tab Two
VStack(spacing: 0) {
VStack{
Text("PAGE TWO")
.padding(.bottom, 20)
}
Button(action: {
self.mode.wrappedValue.dismiss()})
{ Text("BACK") }
.font(Font.system(size:14, weight: .bold, design: .default))
}
.navigationBarTitle("Hidden Title")
.navigationBarHidden(self.isNavigationBarHidden)
.onAppear {self.isNavigationBarHidden = true}
.tabItem {Label("TWO", systemImage: "circle.fill")}
.tag("tabTwo")
}
.tabViewStyle(PageTabViewStyle())
.indexViewStyle(.page(backgroundDisplayMode: .never))
.onAppear {self.isNavigationBarHidden = true}
}
.navigationBarTitle("Hidden Title")
.navigationBarHidden(self.isNavigationBarHidden)
.onAppear {self.isNavigationBarHidden = true}
.background(Color.gray)
.opacity(0.75)
.indexViewStyle(.page(backgroundDisplayMode: .never))
}
}
struct PageTwo_Previews: PreviewProvider {
static var previews: some View {
PageTwo()
}
}
This throws an error at the 'some view' level of:
Failed to produce diagnostic for expression; please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the project
I've submitted the report, but can't figure out how to do what I'd like. Any help is much appreciated.

How to append something to a list?

I'm new to Swift at the moment and I'm having trouble appending to a to-do list. I am not receiving an error, so I don't know what's wrong. I hope this isn't too much code to go through, but I don't even know where the problem is.
There is a sheet modal that opens and closes fine. The only issue is that when I press the save button, the information I typed in doesn't add to the list.
I've add the ViewModel, NewTaskView(sheet), TaskView(customizes list), and a bit of code of the DetailView where the list should be.
import Foundation
import SwiftUI
class TaskViewModel : Identifiable , ObservableObject {
#Published var tasks : [Task] = [
Task(taskName: "Lab", taskDate: Date(), taskCompleted: false),
Task(taskName: "Assignment 4.02", taskDate: Date(), taskCompleted: false)
]
#Published var sortType : SortType = .alphabetical
#Published var isPresented = false
#Published var searched = ""
func addTask(task : Task){
tasks.append(task)
}
func removeTask(indexAt : IndexSet){
tasks.remove(atOffsets: indexAt)
}
func sort(){
switch sortType {
case .alphabetical :
tasks.sort(by: { $0.taskName < $1.taskName })
case .date :
tasks.sort(by: { $0.taskDate > $1.taskDate })
}
}
}
struct Task : Identifiable , Equatable {
var id : String = UUID().uuidString
let taskName : String
let taskDate : Date
var taskCompleted: Bool
}
enum SortType : String , Identifiable , CaseIterable {
var id : String { rawValue }
case alphabetical
case date
}
struct NewTaskView: View {
#Environment(\.presentationMode) var presentationMode
#ObservedObject var taskVM : TaskViewModel
#State var taskName = ""
#State var taskCompleted = Bool()
#State var taskDate = Date()
var body: some View {
NavigationView {
VStack(spacing: 14) {
Spacer()
TextField("Assignment Name",text: $taskName)
.padding()
.background(Color("tan"))
.cornerRadius(5)
.font(Font.custom(FontNameManager.Montserrat.semibold, size: 15))
.padding(.bottom, 20)
HStack{
Text("Due Date")
.font(Font.custom(FontNameManager.Montserrat.semibold, size: 15))
Image(systemName: "bell.badge")
.foregroundColor(.gray)
.frame(width: 30, height: 30, alignment: .leading)
VStack{
DatePicker("Select Date", selection: $taskDate, displayedComponents: .date)
.labelsHidden()
}
}
HStack{
Text("Mark as Completed")
.font(Font.custom(FontNameManager.Montserrat.semibold, size: 15))
Button(action : {
taskCompleted.toggle()
}){
if taskCompleted == true {
Image(systemName: "checkmark.circle.fill")
.foregroundColor(Color("orange"))
.font(.title2)
}
else {
Image(systemName: "circle")
.foregroundColor(Color("lightorange"))
.font(.title2)
}
}
}
Spacer()
Button(action:{taskVM.addTask(task: .init(taskName: taskName, taskDate: taskDate, taskCompleted: taskCompleted))
presentationMode.wrappedValue.dismiss()},
label:{
Text("Save")
})
}.padding()
.navigationBarItems(trailing: Button(action: {
presentationMode.wrappedValue.dismiss()
}) {
HStack{
Image(systemName: "xmark")
.foregroundColor(Color("orange"))
}
})
}
}
}
struct NewTaskView_Previews: PreviewProvider {
static var previews: some View {
NewTaskView(taskVM: TaskViewModel())
}
}
struct TaskView: View {
var task : Task
#Environment(\.managedObjectContext) var moc
#State var currentDate: Date = Date()
#State var taskCompleted = false
func getDateFormatString(date:Date) -> String
{
var dateString = ""
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM. dd"
dateString = dateFormatter.string(from: date)
return dateString
}
var body: some View {
HStack {
Button(action : {
self.taskCompleted.toggle()
try? self.moc.save()
}){
if self.taskCompleted {
Image(systemName: "checkmark.circle.fill")
.foregroundColor(Color("orange"))
.font(.title2)
}
else {
Image(systemName: "circle")
.foregroundColor(Color("lightorange"))
.font(.title2)
}
}.padding()
VStack (alignment: .leading, spacing: 2){
Text("\(task.taskName)")
.font(Font.custom(FontNameManager.Montserrat.bold, size: 18))
.foregroundColor(Color("dark"))
.padding([.leading, .trailing], 1)
if self.taskCompleted {
Text("Completed")
.font(Font.custom(FontNameManager.Montserrat.bold, size: 12))
.foregroundColor(Color("burntorange"))
.frame(width: 95, height: 20)
.background(Color("lightorange"))
.cornerRadius(4)
}
else if currentDate > task.taskDate {
Text("Late")
.font(Font.custom(FontNameManager.Montserrat.semibold, size: 12))
.foregroundColor(.white)
.frame(width: 95, height: 18)
.background(Color("lightbrown"))
.cornerRadius(4)
}
else {
let diffs = Calendar.current.dateComponents([.day], from: currentDate, to: task.taskDate )
Text("\(diffs.day!) days left")
.font(Font.custom(FontNameManager.Montserrat.semibold, size: 12))
.foregroundColor(Color("burntorange"))
.frame(width: 95, height: 20)
.background(Color("lightorange"))
.cornerRadius(4)
}
}
Spacer()
Text(getDateFormatString(date: task.taskDate ))
.font(Font.custom(FontNameManager.Montserrat.medium, size: 12))
.padding()
}
.padding(10)
.cornerRadius(10)
.background(
RoundedRectangle(cornerRadius: 10 , style: .continuous)
.foregroundColor(.white))
}
}
struct TaskView_Previews: PreviewProvider {
static var previews: some View {
TaskView(task: Task(id: "", taskName: "Task Name", taskDate: Date(), taskCompleted: false))
}
}
struct DetailsView: View {
#Environment(\.managedObjectContext) var moc
#ObservedObject var developers : Developer
#ObservedObject var taskVM : TaskViewModel
#Environment(\.presentationMode) var presen
#Environment(\.editMode) var editButton
#State var taskCompleted = false
#State var show = false
#State var showSearch = false
#State var txt = ""
#State var currentDate: Date = Date()
#State var image : Data = .init(count: 0)
#State var indices : [Int] = []
func getDateFormatString(date:Date) -> String
{
var dateString = ""
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM. dd"
dateString = dateFormatter.string(from: date)
return dateString
}
var body: some View {
NavigationView {
ZStack {
ZStack{
VStack{
Color("lightorange")
.clipShape(CustomCorners(corners: [.bottomLeft, .bottomRight], size: 70))
.ignoresSafeArea(.all, edges: .top)
.frame(width: 420, height: 175)
Spacer()
}
VStack{
HStack {
if !self.showSearch{
Button(action: {
withAnimation(.spring()){
self.presen.wrappedValue.dismiss()
}
}) {
Image(systemName: "chevron.left")
.font(.title2)
.foregroundColor(Color("dark"))
.padding(10)
}
}
Spacer(minLength: 0)
HStack {
if self.showSearch{
Image(systemName: "magnifyingglass")
.font(.title2)
.foregroundColor(Color("dark"))
.padding(.horizontal, 8)
TextField("Search", text: $taskVM.searched , onEditingChanged: { (isBegin) in
if isBegin {
showSearch = true
} else {
showSearch = false
}
})
Button(action: {
withAnimation{
self.showSearch.toggle()
}
}) {
Image(systemName: "xmark").foregroundColor(.black).padding(.horizontal, 8)
}
}
else {
Button(action: {
withAnimation {
self.showSearch.toggle()
}
}) {
Image(systemName: "magnifyingglass")
.font(.title2)
.foregroundColor(Color("dark"))
.padding(10)
}
}
}.padding(self.showSearch ? 10 : 0)
.background(Color("lightorange"))
.cornerRadius(20)
}
ZStack{
RoundedRectangle(cornerRadius: 25)
.foregroundColor(Color("tan"))
.frame(width: 335, height: 130)
HStack {
VStack (alignment: .leading){
// Image(uiImage: UIImage(data: developers.imageD ?? self.image)!)
// .resizable()
// .frame(width: 70, height: 70)
// .clipShape(RoundedRectangle(cornerRadius: 20))
Text("\(developers.username ?? "")")
.font(Font.custom(FontNameManager.Montserrat.bold, size: 24))
.foregroundColor(Color("dark"))
Text("\(developers.descriptions ?? "")")
.font(Font.custom(FontNameManager.Montserrat.semibold, size: 18))
.foregroundColor(.gray)
}
.padding([.leading, .trailing], 70)
.padding(.bottom, 80)
Spacer()
}
}
HStack{
Text("Assignments")
.font(Font.custom(FontNameManager.Montserrat.bold, size: 20))
Spacer(minLength: 0)
EditButton()
}
.padding([.leading, .trailing], 20)
Spacer()
List {
ForEach (taskVM.tasks.filter {
self.taskVM.searched.isEmpty ? true : $0.taskName.localizedCapitalized.contains(self.taskVM.searched)} ){ task in
TaskView(task: task)
.listRowSeparator(.hidden)
}
.onDelete(perform: {
taskVM.removeTask(indexAt: $0)
})
}
.listStyle(InsetListStyle())
}
}
VStack {
Spacer()
HStack {
Spacer()
ExpandableFAB(taskVM: TaskViewModel(), show: $show)
}
}
}.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
}
}
}
struct DetailsView_Previews: PreviewProvider {
static let persistenceController = PersistenceController.shared
static var developers: Developer = {
let context = persistenceController.container.viewContext
let developers = Developer(context: context)
developers.username = "Math"
developers.descriptions = "Calculus"
return developers
}()
static var previews: some View {
DetailsView(developers: developers, taskVM: TaskViewModel()).environment(\.managedObjectContext, persistenceController.container.viewContext)
}
}
struct ExpandableFAB: View {
#Environment(\.managedObjectContext) var moc
#ObservedObject var taskVM : TaskViewModel
#Binding var show: Bool
var body: some View{
VStack(spacing: 20){
if self.show{
Button(action: {
taskVM.isPresented.toggle()
}) {
Image(systemName: "list.bullet.rectangle.portrait").resizable().frame(width: 25, height: 25).padding()
}
.foregroundColor(.white)
.background(Color("orange"))
.clipShape(Circle())
Button(action: {
self.show.toggle()
}) {
Image(systemName: "doc.badge.plus").resizable().frame(width: 25, height: 25).padding()
}.foregroundColor(.white)
.background(Color("orange"))
.clipShape(Circle())
}
Button(action: {
self.show.toggle()
}) {
Image(systemName: "plus").resizable().frame(width: 25, height: 25).padding()
}.foregroundColor(.white)
.background(Color("orange"))
.clipShape(RoundedRectangle(cornerRadius: 20))
.padding()
.rotationEffect(.init(degrees: self.show ? 180 : 0))
}.fullScreenCover(isPresented: $taskVM.isPresented, content: {
NewTaskView(taskVM: taskVM)
})
}
}
#burnsi I don't think I have that anywhere. Where should there be one?
Of course you have one and you need one:
ExpandableFAB(taskVM: TaskViewModel(), show: $show)
This line is causing the issue.
You are somehow injecting a TaskViewModel in your DetailsView (You are not showing where), but not using it. Try:
ExpandableFAB(taskVM: taskVM, show: $show)
And the place you create your ViewModel ('TaskViewModel()') should have a #StateObject wrapper.
Explanation:
As you add something to your ViewModel the views depending on the ViewModel get rebuild. So your TaskViewModel ends up beeing recreated and you still have your 2 initial values in your array.

CoreData data not showing up in my list view

I have a problem with CoreData...I've managed to get it to work, but it won't show my title property (which is the task name). I'm pretty new at this, I hope someone can help me out.
MainUI <--this is a pic of what the UI looks like and where the problem is.
This is the main ViewController
import SwiftUI
struct ContentView: View {
#Environment(\.managedObjectContext) var moc
#FetchRequest(entity: Task.entity(), sortDescriptors: []) var tasks: FetchedResults<Task>
#State var isPresented = false
var body: some View {
VStack {
NavigationView {
ZStack {
List{
ForEach(tasks, id: \.id){ task in
CellView(completionState: task.completionState, title: task.title!)
}
}
Button(action: {
self.isPresented.toggle()
print(isPresented)
}) {
CircleView()
}.offset(x: 158, y: 250)
}
.navigationBarTitle("Infinito")
.sheet(isPresented: $isPresented, content: {
EditView()
.environment(\.managedObjectContext, self.moc)
})
}
HStack(alignment: .center, spacing: 97) {
Button(action: {}) {
Image(systemName: "highlighter")
.resizable()
.frame(width: 45, height: 45)
.padding()
.foregroundColor(.orange)
}.offset(x: 10)
Button(action: {}){
Image(systemName: "timelapse")
.resizable()
.frame(width: 45, height: 45)
.offset(x: 4, y: 0)
.padding()
.foregroundColor(.green)
}.offset(x: -7)
.padding(.trailing, 20.0)
Button(action: {}){
Image(systemName: "alarm")
.resizable()
.frame(width: 45, height: 45)
.foregroundColor(.red)
}.offset(x: -24)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
return ContentView().environment(\.managedObjectContext, context)
}
}
}
struct CellView: View {
#Environment(\.managedObjectContext) var moc
#FetchRequest(entity: Task.entity(), sortDescriptors: []) var tasks: FetchedResults<Task>
var completionState: Bool
var title: String
var body: some View {
HStack{
switch completionState{
case false:
Image(systemName: "square")
case true:
Image(systemName: "checkmark.square")
.foregroundColor(.green)
Text(title)
.foregroundColor(.black)
}
}
}
}
And this is the code for the sheet view
//
// EditView.swift
// Infinito
//
// Created by Armando Visini on 28/10/2020.
//
import SwiftUI
struct EditView: View{
#Environment(\.managedObjectContext) var moc
#FetchRequest(entity: Task.entity(), sortDescriptors: []) var tasks: FetchedResults<Task>
#State var titleOfTask: String = ""
var body: some View {
NavigationView {
VStack(alignment: .leading){
Text("Title of task")
.font(.title)
.fontWeight(.bold)
HStack {
TextField("Enter name of task here...", text: $titleOfTask)
.textFieldStyle(RoundedBorderTextFieldStyle())
Button(action: {
let task = Task(context: self.moc)
task.id = UUID()
task.title = titleOfTask
task.completionState = false
try? self.moc.save()
UIApplication.shared.endEditing()
}) {
Text("Confirm")
.foregroundColor(.white)
.fontWeight(.medium)
.background(Color(.blue))
.cornerRadius(6.0)
}
}
}
.padding()
.offset(y: -200.0)
}
}
struct EditView_Previews: PreviewProvider {
static var previews: some View {
EditView()
}
}
}
extension UIApplication{
func endEditing() {
sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
//
// EditView.swift
// Infinito
//
// Created by Armando Visini on 28/10/2020.
//
import SwiftUI
struct EditView: View{
#Environment(\.managedObjectContext) var moc
#FetchRequest(entity: Task.entity(), sortDescriptors: []) var tasks: FetchedResults<Task>
#State var titleOfTask: String = ""
var body: some View {
NavigationView {
VStack(alignment: .leading){
Text("Title of task")
.font(.title)
.fontWeight(.bold)
HStack {
TextField("Enter name of task here...", text: $titleOfTask)
.textFieldStyle(RoundedBorderTextFieldStyle())
Button(action: {
let task = Task(context: self.moc)
task.id = UUID()
task.title = titleOfTask
task.completionState = false
try? self.moc.save()
UIApplication.shared.endEditing()
}) {
Text("Confirm")
.foregroundColor(.white)
.fontWeight(.medium)
.background(Color(.blue))
.cornerRadius(6.0)
}
}
}
.padding()
.offset(y: -200.0)
}
}
struct EditView_Previews: PreviewProvider {
static var previews: some View {
EditView()
}
}
}
extension UIApplication{
func endEditing() {
sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
It looks like inside your CellView your not closing the switch statement, this will probably cause that your Text is only displayed when the checkbox ist checked. (completionState is true) Place your Text that contains your title outside the switch statement:
HStack {
switch completionState {
case false:
Image(systemName: "square")
case true:
Image(systemName: "checkmark.square")
.foregroundColor(.green)
}
Text(title)
.foregroundColor(.black)
}

SwiftUI passing a saved value to parent view

I am fairly new to SwiftUI I am trying to figure out the best way to pass data from a child view to parent?
Thanks for the help I come from a Javascript (React) background so this is a little different for me
The way my child view works is the user clicks on an image to select that image.
I have #State binding that saves the imgUrl which is a String referring to name in Assets.
I am just not sure about the best way to pass that value to the parent component.
Here is the child view (imageSelector)
struct ImageSelector: View {
#State private var windowImgs = ["1", "2", "3","4","5","6","7","8","9","10","11","12","13", "14","15","16","17","18"]
#State private var imgPicked = ""
var body: some View{
ScrollView(Axis.Set.horizontal, showsIndicators: true){
HStack{
ForEach(0..<18){num in
Button(action:{
self.imgPicked = self.windowImgs[num]
print(self.imgPicked)
}){
Image("\(self.windowImgs[num])")
.renderingMode(.original)
.resizable()
.cornerRadius(4)
.frame(width: 100, height: 100)
}
}
}
}
}
}
Here is the parent view (AddCounterForm)
struct AddCounterForm: View {
#Environment(\.presentationMode) var presentationMode
#State private var pickedImg: String = "defaultImg"
#State private var price: String = "0.0"
#State private var qty: String = "0"
var body: some View {
VStack (spacing: 40){
HStack {
Button("Cancel"){
self.presentationMode.wrappedValue.dismiss()
}
.foregroundColor(.red)
Spacer()
Button("Save"){
}
}
HStack {
VStack (spacing: 20){
TextField("Window type", text: /*#START_MENU_TOKEN#*//*#PLACEHOLDER=Value#*/.constant("")/*#END_MENU_TOKEN#*/)
TextField("Window location", text: /*#START_MENU_TOKEN#*//*#PLACEHOLDER=Value#*/.constant("")/*#END_MENU_TOKEN#*/)
}
.textFieldStyle(RoundedBorderTextFieldStyle())
Image(pickedImg)
.resizable()
.cornerRadius(4)
.frame(width: 90, height: 90)
.padding(.leading)
}
HStack {
Text("Price")
TextField("", text:$price)
.frame(width: 70)
.textFieldStyle(RoundedBorderTextFieldStyle())
.keyboardType(.numberPad)
Spacer()
Text("Qty")
TextField("", text:$qty)
.frame(width: 70)
.textFieldStyle(RoundedBorderTextFieldStyle())
.keyboardType(.numberPad)
}
VStack {
Text("Select an image")
.foregroundColor(.blue)
ImageSelector()
.padding(.bottom)
Button("Use your own image"){
//method
}
.frame(width: 180, height: 40)
.background(Color.blue)
.clipShape(Capsule())
.foregroundColor(.white)
.padding(.top)
}
}
.padding()
}
}
Solution for preview thanks for the help from #Asperi & #neverwinterMoon
struct ImageSelector_Previews: PreviewProvider {
static var previews: some View {
PreviewWrapper()
}
}
struct PreviewWrapper: View {
#State(initialValue: "") var imgPicked: String
var body: some View {
ImageSelector(imgPicked: $imgPicked)
}
}
In this case Binding is most appropriate
struct ImageSelector: View {
#Binding var imgPicked: String
and use
ImageSelector(imgPicked: $pickedImg)
.padding(.bottom)