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.
I am new to coding and am trying to make a notes app come to life, the issue is I have no idea how to make separate text editors in my for loops.
This is my code. When you run the project and create a green sticky note and type on it, it works fine, but if you do a second one of the same color, they have the same text. How do I fix this in a way that doesn't take hours of tedious work?
I have tried to use different ways to make a for loop. I have made one with normal lists and with a struct list that has different ids, both come up with the same text editor.
(Text editors don't copy over color, which makes me think it's the for loop because when I tried to use different variables for the bindings it didn't work either.)
//
// ContentView.swift
// Notesapp
//
//
import SwiftUI
import Foundation
struct newBoy: Identifiable {
let id = UUID()
let number: Int
}
class NewBoys: ObservableObject {
#Published var numbs = [newBoy]()
}
struct ContentView: View {
#StateObject var numbers1 = NewBoys()
#State var buttonoff = true
#State var recaddor: [GridItem] = [
GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible()),
]
#State var glist = [Int]()
#State var i = -1
#State var gtext = "This be me"
#State var blist = [Int]()
#State var bman = -1000
#State var btext = "Enter your notes here!"
#State var bklist = [Int]()
#State var bkman = -2000
#State var bktext = "Enter your notes here!"
#State var ylist = [Int]()
#State var yman = -3000
#State var ytext = "Enter your notes here!"
#State var olist = [Int]()
#State var oman = -4000
#State var otext = "Enter your notes here!"
#State var plist = [Int]()
#State var pman = -5000
#State var ptext = "Enter your notes here!"
var body: some View {
HStack{
VStack {
Text("Make new note!").padding().foregroundColor(Color.black)
Button {
withAnimation(.easeIn) {
self.buttonoff.toggle()
}
} label: {
Image(systemName: "plus")
.font(.title2)
.foregroundColor(.white)
.rotationEffect(.init(degrees: buttonoff ? 0 : 45))
.scaleEffect(buttonoff ? 1 : 1.3)
.padding()
}.buttonStyle(PlainButtonStyle())
.background(Color.black)
.clipShape(Circle())
.padding()
if buttonoff {
}
else {
Group {
Button {
recGreen()
} label: {
RoundedRectangle(cornerRadius: 25)
.fill(Color.green)
.frame(width: 30, height: 30)
}.buttonStyle(PlainButtonStyle())
Button {
recBlue()
} label: {
RoundedRectangle(cornerRadius: 25)
.fill(Color.blue)
.frame(width: 30, height: 30)
}.buttonStyle(PlainButtonStyle())
Button {
recBlack()
} label: {
RoundedRectangle(cornerRadius: 25)
.fill(Color.black)
.frame(width: 30, height: 30)
}.buttonStyle(PlainButtonStyle())
Button {
recYellow()
} label: {
RoundedRectangle(cornerRadius: 25)
.fill(Color.yellow)
.frame(width: 30, height: 30)
}.buttonStyle(PlainButtonStyle())
Button {
recOrange()
} label: {
RoundedRectangle(cornerRadius: 25)
.fill(Color.orange)
.frame(width: 30, height: 30)
}.buttonStyle(PlainButtonStyle())
Button {
recPurple()
} label: {
RoundedRectangle(cornerRadius: 25)
.fill(Color.purple)
.frame(width: 30, height: 30)
}.buttonStyle(PlainButtonStyle())
}.padding(20)
.scaleEffect(1.5)
}
}.frame(width: 100, height: 700, alignment: .top)
.background(Color.white)
.border(Color.gray, width: 2)
VStack {
ScrollView{
LazyVGrid(columns: recaddor){
ForEach(numbers1.numbs, id: \.id) {o in
ZStack{
RoundedRectangle(cornerRadius: 25)
.fill(Color.green)
.frame(width: 250, height: 200)
.padding()
VStack{
HStack{
Spacer()
Button {
print("hi")
} label: {
Image(systemName: "minus")
}
.padding(.top, 25.0)
.padding(.trailing, 30.0)
.frame(alignment:.trailing)
}
TextEditor(text: $gtext)
.frame(width: 225, height: 150, alignment: .center)
.cornerRadius(3.0)
.colorMultiply(.green)
Spacer()
}
}
}
ForEach(blist, id: \.self) {blueman in
ZStack{
RoundedRectangle(cornerRadius: 25)
.fill(Color.blue)
.frame(width: 250, height: 200)
.padding()
VStack{
HStack{
Spacer()
Button {
blist = blist.filter({ Int in
return Int != blueman
})
} label: {
Image(systemName: "minus")
}
.padding(.top, 25.0)
.padding(.trailing, 30.0)
.frame(alignment:.trailing)
}
TextEditor(text: $btext)
Spacer()
}
}
}
ForEach(bklist, id: \.self) {bklueman in
ZStack{
RoundedRectangle(cornerRadius: 25)
.fill(Color.black)
.frame(width: 250, height: 200)
.padding()
VStack{
HStack{
Spacer()
Button {
bklist = bklist.filter({ Int in
return Int != bklueman
})
} label: {
Image(systemName: "minus")
}
.padding(.top, 25.0)
.padding(.trailing, 30.0)
.frame(alignment:.trailing)
}
TextEditor(text: $bktext)
Spacer()
}
}
}
ForEach(ylist, id: \.self) {ylueman in
ZStack{
RoundedRectangle(cornerRadius: 25)
.fill(Color.yellow)
.frame(width: 250, height: 200)
.padding()
VStack{
HStack{
Spacer()
Button {
ylist = ylist.filter({ Int in
return Int != ylueman
})
} label: {
Image(systemName: "minus")
}
.padding(.top, 25.0)
.padding(.trailing, 30.0)
.frame(alignment:.trailing)
}
TextEditor(text: $ytext)
Spacer()
}
}
}
ForEach(olist, id: \.self) {olueman in
ZStack{
RoundedRectangle(cornerRadius: 25)
.fill(Color.orange)
.frame(width: 250, height: 200)
.padding()
VStack{
HStack{
Spacer()
Button {
olist = olist.filter({ Int in
return Int != olueman
})
} label: {
Image(systemName: "minus")
}
.padding(.top, 25.0)
.padding(.trailing, 30.0)
.frame(alignment:.trailing)
}
TextEditor(text: $otext)
Spacer()
}
}
}
ForEach(plist, id: \.self) {plueman in
ZStack{
RoundedRectangle(cornerRadius: 25)
.fill(Color.purple)
.frame(width: 250, height: 200)
.padding()
VStack{
HStack{
Spacer()
Button {
plist = plist.filter({ Int in
return Int != plueman
})
} label: {
Image(systemName: "minus")
}
.padding(.top, 25.0)
.padding(.trailing, 30.0)
.frame(alignment:.trailing)
}
TextEditor(text: $ptext)
Spacer()
}
}
}
}
}
}.frame(width: 1100)
}
}
func recGreen() {
let i = newBoy(number: 0)
numbers1.numbs.append(i)
print(numbers1.numbs)
}
func recBlue() {
bman += 1
blist.append(bman)
}
func recBlack() {
bkman += 1
bklist.append(bkman)
}
func recYellow() {
yman += 1
ylist.append(yman)
}
func recOrange() {
oman += 1
olist.append(oman)
}
func recPurple() {
pman += 1
plist.append(pman)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
It's because you are using the same binding.
In your ForEach, you are creating multiple TextEditors but they are editing the same variable like $otext. You need to create a struct that holds the text, and the array you use in the ForEach should be of type YourStruct. Then you pass the text to TextEditors.
struct Note: Identifiable {
var id: Int //your current array type, i.e if your array is [Int] use Int.
var text: String //this is the text to pass to the editors
}
I have three Views exchanging information, ContentView, TimerView and TaskView. I used #Binding in TaskView to bring data from TaskView to ContentView, now I want to use that data to pass into TimerView.
I created a #State variable in ContentView to store the data from TaskView, but when I try to use that #State variable to pass data to TimerView it isn't giving me any desirable results.
Now if you see the TasksView call in ContentView, I get the output for the print statement, but in the main TimerView, it doesn't change from the default I set as #State variable in timerInfo.
Any help is appreciated, thank you.
Code for ContentView ->
//
// ContentView.swift
// ProDActivity
//
// Created by Vivek Pattanaik on 5/27/21.
//
import SwiftUI
struct TimerInfo : Identifiable {
let id = UUID()
// let taskIndex : Int
// let taskProjectName : String
var timerTaskName : String
var timerMinutes : Float
let timerIntervals : Int
var timerPriority : String
var timerShortbreakMinute : Float
var timerLongbreakMinute : Float
var timerLongbreakInterval : Int
}
struct ContentView: View {
init() {
UITabBar.appearance().backgroundColor = UIColor.init(Color("TabBar "))
}
// #State var selection: Tab = .dasboard
#State var timerInfo = TimerInfo(timerTaskName: "Sample Task 1", timerMinutes: 30, timerIntervals: 10, timerPriority: "High Priority", timerShortbreakMinute: 5, timerLongbreakMinute: 15, timerLongbreakInterval: 3)
var body: some View {
TabView {
TimerView(defaultTimeRemaining: self.timerInfo.timerMinutes * 60, timeRemaining: self.timerInfo.timerMinutes * 60)
.tabItem {
Image(systemName: "clock.fill")
Text("Timer")
}.tag(0)
TasksView(didClickTimer: { info in
self.timerInfo.timerTaskName = info.timerTaskName
self.timerInfo.timerMinutes = info.timerMinutes
self.timerInfo.timerPriority = info.timerPriority
self.timerInfo.timerShortbreakMinute = info.timerShortbreakMinute
self.timerInfo.timerLongbreakMinute = info.timerLongbreakMinute
self.timerInfo.timerLongbreakInterval = info.timerLongbreakInterval
print("\(self.timerInfo.timerMinutes)ContentView")
})
.tabItem {
Image(systemName: "doc.plaintext.fill")
Text("Tasks")
}.tag(1)
StatisticsView()
.tabItem {
Image(systemName: "chart.pie.fill")
Text("Statistics")
}.tag(3)
SettingsView()
.tabItem {
Image(systemName: "gearshape.fill")
Text("Settings")
}.tag(4)
}
.font(.headline)
.accentColor(Color("AccentColor"))
.environment(\.colorScheme, .dark)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Code for TasksView ->
//
// TasksView.swift
// ProDActivity
//
// Created by Vivek Pattanaik on 5/30/21.
//
import SwiftUI
struct TaskLabels : Identifiable {
let id = UUID()
// let taskIndex : Int
// let taskProjectName : String
let taskName : String
let taskPriority : String
let taskIntervals : String
let taskMinutes : String
let shortBreakMinutes : String
let longBreakMinutes : String
let longBreakIntervals : String
}
struct TaskRow: View {
let tasks : TaskLabels
var body: some View {
HStack(alignment: .center, spacing: 10) {
Image(tasks.taskPriority)
.frame(width: 40, height: 40, alignment: .center)
VStack(alignment: .leading, spacing:4){
Text(tasks.taskName)
.font(.system(size: 15))
Text("\(tasks.shortBreakMinutes) Min Breaks")
.font(.system(size: 13))
}
.frame(width: 100, height: 20, alignment: .leading)
Spacer()
VStack(alignment: .trailing, spacing:4){
Text("0/\(tasks.taskIntervals)")
Text("\(tasks.taskMinutes) Min Tasks")
.font(.system(size: 13))
}
.frame(width: 90, height: 20, alignment: .trailing)
.padding()
}
}
}
struct TasksView: View {
// #Binding var timeSelected : Float
#State var addTasksModalView: Bool = false
#State var taskLabels : [TaskLabels] = []
var didClickTimer : (TimerInfo) -> ()
var body: some View {
NavigationView{
if taskLabels.count != 0 {
List{
ForEach(taskLabels) { task in
HStack {
Button(action: {
self.didClickTimer(.init(timerTaskName: task.taskName, timerMinutes: Float(task.taskMinutes)!, timerIntervals: Int(task.taskIntervals)!, timerPriority: task.taskPriority, timerShortbreakMinute: Float(task.shortBreakMinutes)!, timerLongbreakMinute: Float(task.longBreakMinutes)!, timerLongbreakInterval: Int(task.longBreakIntervals)!))
print(task.taskMinutes)
}, label: {
TaskRow(tasks: task)
})
}
}
.onDelete(perform: self.deleteRow)
}
.navigationBarTitle("Tasks")
.navigationBarItems(trailing: Button(action: {
self.addTasksModalView = true
}, label: {
Image(systemName: "plus.square.on.square")
.resizable()
.frame(width: 26, height: 26, alignment: .leading)
.foregroundColor(Color.accentColor)
}))
.sheet(isPresented: $addTasksModalView, content: {
AddTasks(addTaskPresented: $addTasksModalView) { tasks in
taskLabels.append(tasks)
}
})
} else {
Text("")
.navigationTitle("Tasks")
.navigationBarTitle("Tasks")
.navigationBarItems(trailing: Button(action: {
self.addTasksModalView = true
}, label: {
Image(systemName: "plus.square.on.square")
.resizable()
.frame(width: 26, height: 26, alignment: .leading)
.foregroundColor(Color.accentColor)
}))
.sheet(isPresented: $addTasksModalView, content: {
AddTasks(addTaskPresented: $addTasksModalView) { tasks in
taskLabels.append(tasks)
}
})
}
}
.environment(\.colorScheme, .dark)
}
private func deleteRow(at indexSet: IndexSet){
self.taskLabels.remove(atOffsets: indexSet)
}
}
//struct TasksView_Previews: PreviewProvider {
// static var previews: some View {
// TasksView()
// }
//}
TimerView Code ->
//
// TimerView.swift
// ProDActivity
//
// Created by Vivek Pattanaik on 5/27/21.
//
import SwiftUI
struct TimerView: View {
let lineWidth : CGFloat = 11
let radius : CGFloat = 150
// to pass into the struct
// #State var taskTime = 300
#State var defaultTimeRemaining : Float
#State var timeRemaining : Float
#State private var isActive = false
#State private var showButtons = false
#State private var stopAlert = false
#State private var pausePressed = false
#State private var stopPressed = false
// #State private var timeRemainingSeconds : CGFloat = 25
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
// self.defaultTimeRemaining = timerInfo.timerMinutes
VStack(spacing : 60) {
ZStack{
RoundedRectangle(cornerRadius: 7)
.frame(width: 300, height: 70)
.foregroundColor(Color("TabBar "))
}
ZStack(alignment: Alignment(horizontal: .center, vertical: .center)) {
Circle()
.stroke(Color.gray, style: StrokeStyle(lineWidth: lineWidth, lineCap: .round))
.opacity(0.2)
Circle()
.trim(from: 1 - CGFloat(((defaultTimeRemaining-timeRemaining)/defaultTimeRemaining)), to: 1 )
.stroke(Color.accentColor, style: StrokeStyle(lineWidth: lineWidth, lineCap: .round))
.rotationEffect( .degrees(-90))
.animation(.easeInOut)
// VStack for the timer and seesions
VStack {
// Text("\(Int(timeRemaining)):\(Int(timeRemainingSeconds))")
Text("\(timeString(time: Int(timeRemaining)))")
.font(.system(size: 50)).fontWeight(.medium)
Text("0 of 5 Sessions")
.font(.system(size: 20)).fontWeight(.medium)
}
}.frame(width: radius*2, height: radius*2)
// BEGIN, STOP, PAUSE BUTTONS
HStack(spacing: 25){
if showButtons == false {
Button(action: {
}, label: {
ZStack {
Rectangle()
.frame(width: 176, height: 55, alignment: .center)
.foregroundColor(Color.accentColor)
.cornerRadius(5)
Button(action: {
self.showButtons.toggle()
isActive.toggle()
}, label: {
Text("BEGIN")
.foregroundColor(Color.white)
.font(.system(size: 23).weight(.medium))
.frame(width: 176, height: 55, alignment: .center)
})
}
})
} else if showButtons == true {
HStack {
ZStack {
Rectangle()
.frame(width: 152, height: 55, alignment: .center)
.foregroundColor(Color("LightDark"))
.cornerRadius(5)
.border(Color.accentColor, width: 2)
Button(action: {
self.stopPressed.toggle()
self.pausePressed = true
if isActive == true {
isActive.toggle()
self.stopAlert = true
} else {
self.stopAlert = true
}
}, label: {
Text("STOP")
.foregroundColor(Color.accentColor)
.font(.system(size: 23).weight(.medium))
.frame(width: 152, height: 55, alignment: .center)
})
.alert(isPresented: $stopAlert) {
Alert(title: Text("Are you sure you want to stop?"),
message: Text("This will stop the timer and task associated with it."),
primaryButton: .destructive(Text("Yes"), action: {
self.showButtons = false
timeRemaining = defaultTimeRemaining
}),
secondaryButton: .cancel({
isActive = false
pausePressed = true
})
)
}
}
ZStack {
Rectangle()
.frame(width: 152, height: 55, alignment: .center)
.foregroundColor(pausePressed ? Color.accentColor : Color("LightDark"))
.cornerRadius(5)
.border(pausePressed ? Color.accentColor : Color.accentColor, width: 2)
Button(action: {
pausePressed.toggle()
if pausePressed == true {
isActive = false
} else {
isActive = true
}
}, label: {
Text("\(pausePressed ? "RESUME" : "PAUSE")")
.foregroundColor(pausePressed ? Color("TabBar ") : Color.accentColor)
.font(.system(size: 23).weight(.medium))
.frame(width: 152, height: 55, alignment: .center)
})
}
}
}
}
}.onReceive(timer, perform: { _ in
guard isActive else {return}
if timeRemaining > 0 {
timeRemaining -= 1
} else {
isActive = false
showButtons = false
self.timer.upstream.connect().cancel()
}
})
}
func timeString(time: Int) -> String {
let minutes = Int(time) / 60 % 60
let seconds = Int(time) % 60
return String(format:"%02i:%02i", minutes, seconds)
}
}
//struct TimerView_Previews: PreviewProvider {
// static var previews: some View {
// TimerView()
// }
//}
//func buttonChange(){
//
//}
I'm trying to create my own PhoneTextField in and I have found a tutorial in here it's working fine if don't call it inside ZStack let's see the code example as below
countryCode View
struct CountryCodes: View {
#Binding var countryCode : String
#Binding var countryFlag : String
#Binding var y : CGFloat
var body: some View {
GeometryReader { geo in
List(self.countryDictionary.sorted(by: <), id: \.key) { key , value in
HStack {
Text("\(self.flag(country: key))")
Text("\(self.countryName(countryCode: key) ?? key)")
Spacer()
Text("+\(value)").foregroundColor(.secondary)
}.background(Color.white)
.font(.system(size: 20))
.onTapGesture {
self.countryCode = value
self.countryFlag = self.flag(country: key)
withAnimation(.spring()) {
self.y = 350
}
}
}
.padding(.bottom)
.frame(width: geo.size.width, height: 500)
.position(x: geo.frame(in: .global).midX, y: geo.frame(in: .global).maxY - -200)
}
}
let countryDictionary = ["AF":"93","AL":"355","DZ":"213","US":"1",
"AD":"376","AO":"244","AI":"1","AG":"1","AR":"54",
"AM":"374","AW":"297","AU":"61","AT":"43","AZ":"994",
"BS":"1","BH":"973","BD":"880","BB":"1","BY":"375",
"BE":"32","BZ":"501","BJ":"229","BM":"1","BT":"975",
"BA":"387","BW":"267","BR":"55","IO":"246","BG":"359",
"BF":"226","BI":"257","KH":"855","CM":"237","CA":"1",
"CV":"238","KY":"345","CF":"236","TD":"235","CL":"56","CN":"86",
"CX":"61","CO":"57","KM":"269","CG":"242","CK":"682","CR":"506",
"HR":"385","CU":"53","CY":"537","CZ":"420","DK":"45","DJ":"253",
"DM":"1","DO":"1","EC":"593","EG":"20","SV":"503","GQ":"240",
"ER":"291","EE":"372","ET":"251","FO":"298","FJ":"679","FI":"358",
"FR":"33","GF":"594","PF":"689","GA":"241","GM":"220","GE":"995",
"DE":"49","GH":"233","GI":"350","GR":"30","GL":"299","GD":"1",
"GP":"590","GU":"1","GT":"502","GN":"224","GW":"245","GY":"595","HT":"509",
"HN":"504","HU":"36","IS":"354","IN":"91","ID":"62","IQ":"964",
"IE":"353","IL":"972","IT":"39","JM":"1","JP":"81","JO":"962",
"KZ":"77","KE":"254","KI":"686","KW":"965","KG":"996","LV":"371",
"LB":"961","LS":"266","LR":"231","LI":"423","LT":"370","LU":"352",
"MG":"261","MW":"265","MY":"60","MV":"960","ML":"223",
"MT":"356","MH":"692","MQ":"596","MR":"222","MU":"230","YT":"262",
"MX":"52","MC":"377","MN":"976", "ME":"382","MS":"1","MA":"212",
"MM":"95","NA":"264","NR":"674","NP":"977","NL":"31","NC":"687",
"NZ":"64","NI":"505","NE":"227","NG":"234","NU":"683",
"NF":"672","MP":"1","NO":"47","OM":"968","PK":"92","PW":"680",
"PA":"507","PG":"675","PY":"595","PE":"51","PH":"63","PL":"48",
"PT":"351","PR":"1","QA":"974","RO":"40","RW":"250","WS":"685",
"SM":"378","SA":"966","SN":"221","RS":"381","SC":"248",
"SL":"232","SG":"65","SK":"421","SI":"386","SB":"677",
"ZA":"27","GS":"500","ES":"34","LK":"94","SD":"249","SR":"597",
"SZ":"268","SE":"46","CH":"41","TJ":"992","TH":"66","TG":"228",
"TK":"690","TO":"676","TT":"1","TN":"216","TR":"90",
"TM":"993","TC":"1","TV":"688","UG":"256","UA":"380",
"AE":"971","GB":"44","AS":"1","UY":"598","UZ":"998",
"VU":"678","WF":"681","YE":"967","ZM":"260",
"ZW":"263","BO":"591","BN":"673","CC":"61",
"CD":"243","CI":"225","FK":"500","GG":"44",
"VA":"379","HK":"852","IR":"98","IM":"44",
"JE":"44","KP":"850","KR":"82","LA":"856",
"LY":"218","MO":"853","MK":"389","FM":"691",
"MD":"373","MZ":"258","PS":"970","PN":"872",
"RE":"262","RU":"7","BL":"590","SH":"290","KN":"1",
"LC":"1","MF":"590","PM":"508","VC":"1","ST":"239",
"SO":"252","SJ":"47","SY":"963","TW":"886","TZ":"255",
"TL":"670","VE":"58","VN":"84","VG":"284","VI":"340"]
func countryName(countryCode: String) -> String? {
let current = Locale(identifier: "en_US")
return current.localizedString(forRegionCode: countryCode)
}
func flag(country:String) -> String {
let base : UInt32 = 127397
var flag = ""
for v in country.unicodeScalars {
flag.unicodeScalars.append(UnicodeScalar(base + v.value)!)
}
return flag
}
}
RegistrationView
//
// RegisterView.swift
// Instagram
//
// Created by Admin on 4/4/21.
//
import SwiftUI
import Combine
struct RegistrationView: View {
#State var isEditing: Bool = false
// navigate to verification view
#State private var selection: String? = nil
#State private var email:String = ""
#State private var phone:String = ""
#State private var fullname = ""
#State private var username = ""
#State private var password = ""
#State private var selectedImage:UIImage?
#State private var image:Image?
#Environment(\.presentationMode) var mode
#State var imagePickerPresented = false
#EnvironmentObject var viewModel: AuthViewModel
#State var isVerification = false
#State var phoneNumber = ""
#State var y : CGFloat = 350
#State var countryCode = ""
#State var countryFlag = ""
#State var isInputPhoneNumber = true
#State var isInputEmail = false
#State var tempData = DataTempo()
#State var isShowSignInButton = true
// var successClosure: (Bool) -> Void {
//
// }
#EnvironmentObject var mobileVerificationViewModel: MobileVerificationNvm
var body: some View {
ZStack {
LinearGradient(gradient: Gradient(colors: [Color.purple, Color("PrimaryColor")]), startPoint: .top, endPoint: .bottom)
.ignoresSafeArea()
VStack{
// Spacer()
VStack(spacing:20){
VStack(alignment:.leading){
Text("Sign Up")
.font(.largeTitle)
.bold()
.foregroundColor(.white)
}.padding(.horizontal,32).frame(width: UIScreen.main.bounds.width, alignment: .leading)
Toggle( isInputEmail ? "Use Email" : "Use Phone Number", isOn: $isInputEmail)
.foregroundColor(.white)
.toggleStyle(SwitchToggleStyle(tint: Color(#colorLiteral(red: 0.5568627715, green: 0.3529411852, blue: 0.9686274529, alpha: 1))))
.padding(.horizontal,32)
if isInputEmail == true {
CustomTextField(text: $email, placeholder: Text("Email"), imageName: "envelope")
.padding()
.background(Color(.init(white: 1, alpha: 0.15)))
.cornerRadius(10)
.foregroundColor(.white)
.padding(.horizontal,32)
.onChange(of: email) {
// self.autocomplete($0) // like this
if viewModel.isValidEmail(testStr: $0){
print("email")
//phone number
}
}
}
if isInputEmail == false{
ZStack(alignment:.center) {
HStack (spacing: 0) {
Text(countryCode.isEmpty ? "🇹🇠+66" : "\(countryFlag) +\(countryCode)")
.frame(width: 100, height: 50)
// .background(Color.secondary.opacity(0.2))
.background(Color(.init(white: 1, alpha: 0.15)))
.cornerRadius(10)
// .foregroundColor(countryCode.isEmpty ? .secondary : .black)
.foregroundColor(.white)
.onTapGesture {
isShowSignInButton = false
withAnimation (.spring()) {
self.y = 0
}
}
TextField("Phone Number", text: $phone)
.onChange(of: phone) { newValue in
if !phone.isEmpty {
self.isShowSignInButton = true
if viewModel.validatePhoneNumber(value:newValue){
print("phone")
//phone number
self.isInputPhoneNumber = true
self.isInputEmail = false
}
}
else{
self.isShowSignInButton = false
}
}
.frame(width: 250, height: 50)
.keyboardType(.phonePad)
.background(Color(.init(white: 1, alpha: 0.15)))
.foregroundColor(.white)
}
CountryCodes(countryCode: $countryCode, countryFlag: $countryFlag, y: $y)
.offset(y: y)
RoundedRectangle(cornerRadius: 10).stroke()
.frame(width: 350, height: 50)
.foregroundColor(.white)
} .zIndex(1).frame( height: 50, alignment: .center)
}
CustomTextField(text: $username, placeholder: Text("Username"), imageName: "person")
.padding()
.background(Color(.init(white: 1, alpha: 0.15)))
.cornerRadius(10)
.foregroundColor(.white)
.padding(.horizontal,32)
CustomTextField(text: $fullname, placeholder: Text("Full Name"), imageName: "person")
.padding()
.background(Color(.init(white: 1, alpha: 0.15)))
.cornerRadius(10)
.foregroundColor(.white)
.padding(.horizontal,32)
CustomSecureField(text: $password, placeholder: Text("Password"))
.padding()
.background(Color(.init(white: 1, alpha: 0.15)))
.cornerRadius(10)
.foregroundColor(.white)
.padding(.horizontal,32)
}
.alert(isPresented: $isInputPhoneNumber, content: {
Alert(title: Text("Message"), message: Text("you're using phone number to register"), dismissButton: .default(Text("Bye alert!"), action: {
isInputPhoneNumber = true
}))
})
.alert(isPresented: mobileVerificationViewModel.alertBinding) {
Alert(title: Text(mobileVerificationViewModel.errorMessage ?? "(unknown)"), message: nil, dismissButton: .cancel())
}
HStack{
Spacer()
Button(action: /*#START_MENU_TOKEN#*/{}/*#END_MENU_TOKEN#*/, label: {
Text("Forgot Password")
})
.font(.system(size: 13, weight: .semibold))
.foregroundColor(.white)
.padding(.top)
.padding(.trailing,28)
}
ZStack{
NavigationLink(destination:VerificationView { (pin, successClosure) in
print(pin)
mobileVerificationViewModel.codeVerification(phoneNumber: isInputEmail ? tempData.email : tempData.phone, pinCode: pin, email: email, password: password, fullname: fullname, username: username)
//navigation back
self.mode.wrappedValue.dismiss()
// print(successClosure)
}, tag: "verification", selection: $selection) { EmptyView() }
Button(action: {
self.selection = "verification"
var phoneWithCountryCode = ""
// if countryCode == "" {
// phoneWithCountryCode = "+66\(phone)"
// }
// if countryCode != ""{
// phoneWithCountryCode = "+\(countryCode)\(phone)"
// }
//
// // "+\(countryCode == "" ? "66" : countryCode + phone)"
// if (!email.isEmpty || !phone.isEmpty) && !password.isEmpty{
//
// if isInputEmail {
// MobileVerificationNvm.shared.sendVerification(phoneNumber:email)
// isVerification = true
// tempData.email = email
// }
//
// else{
// DispatchQueue.main.async {
// // print("phone:\(phoneWithCountryCode)")
// MobileVerificationNvm.shared.sendVerification(phoneNumber: phoneWithCountryCode)
// isVerification = true
// tempData.phone = phone
// }
//
// }
//
// }
// viewModel.register(withEmail: email, password: password,image: selectedImage,fullname: fullname,username: username)
}, label: {
Text("Sign Up")
}).zIndex(0)
// Spacer()
}
.font(.headline)
.frame(width: 360, height: 50)
.foregroundColor(.white)
.background(Color(#colorLiteral(red: 0.5568627715, green: 0.3529411852, blue: 0.9686274529, alpha: 1)))
// .clipShape(Capsule())
.clipShape(RoundedRectangle(cornerRadius: 16, style: .continuous))
.padding()
.alert(isPresented: $isInputEmail, content: {
Alert(title: Text("Message"), message: Text("Now! you're using Email to register but you also register with email just swtich on togle button"), dismissButton: .default(Text("Bye alert!"), action: {
isInputEmail = true
}))
})
Button(action: {
mode.wrappedValue.dismiss()
// isVerification = true
}, label: {
Text("Already have an account? ")
.font(.system(size: 14))
+ Text("Sign In")
.font(.system(size: 14, weight: .bold))
})
.foregroundColor(.white)
.padding(.bottom,32)
}
}
.ignoresSafeArea()
}
}
extension RegistrationView{
func loadImage() {
guard let selectedImage = selectedImage else {
return
}
image = Image(uiImage: selectedImage)
}
}
//
struct RegistrationView_Previews: PreviewProvider {
static var previews: some View {
RegistrationView()
}
}
this is my issue when I tap on country code to choose the country code you will see the button sign in over countries code list
you also can check from [here]:github.com/PhanithNoch/SwiftUIPhoneTextField this is the repo that I tried to separate code from my real project as an example
I stuck with this a few days ago hope anyone can help, please.