Sunday, May 24, 2020

Todo app using SwiftUI

It's time again and I started learning the iOS programming again as SwiftUI looks cool.

I spent couple of weeks going through the swift programming documentation and watched the WWDC videos. 

Note: This is an ongoing blog, which I update as I add more features to my TodoApp.

Learning


Follow along the Swift documentation. Try to code along the examples. Just go through the documentation even if you don't understand the whole thing just try to read all the documentation and get yourself aware with the concepts. This is will help later while reading the code of some
open source project. 

And.. read the documentation again. This is what I am doing now, this time try to understand and repeat until it becomes muscle memory. this is ongoing process.

SwiftUI


Follow the SwiftUI tutorials and try to recreate them. 

Videos


One of my colleague suggested WWDC videos and watch them in the order. 


Blogs

After going through all those videos and tutorials, I have decided to start creating something. So what is first app everyone build, it's Todo app. 

iOS-TodosApp


Download the Github repo to follow along and try the completed features.

Features


  • Create a new Todo
  • Context menu to Complete or Delete a Todo
  • Show completed tasks
  • Add Priority
  • Add Date

Upcoming


  • Edit 
  • Persist the data
  • Add Notification
  • Add Location
  • Login functionality

Learnings while doing TodoApp

SF Symbols


There are system image which can be used in the app and easier way to find them is to install the SF Symbols app on your Mac. Here is the link to the SF Symbols.

https://developer.apple.com/design/human-interface-guidelines/sf-symbols/overview/

Use it in the code like 

Image(systemName: "checkmark.seal.fill")


Layout


TodoRow has 3 elements in the row. The task description, priority and Due date. So I had the description set to fixed width of 200 to show the description. But it does not feel correct. 

So the better option is to use the layoutPriority modifier and set it to 1 for task description to take what ever space it needs and let the rest of the elements trimmed.


Adding a ContextMenu


Adding a context menu is simple as using the contextMenu modifier. 

.contextMenu(menuItems: {

                    TodoContextMenu(todo: todo)

                })


that provider takes viewBuilder so we can use a separate view to create those context menu options

HStack{

            Button(action: {

                self.userData.todos[self.todoIndex].isCompleted.toggle()

            }, label: {

                HStack{

                    Text("Complete")

                        .foregroundColor(.green)

                    Image(systemName: "checkmark.circle.fill")

                        .foregroundColor(.green)

                }

            })

            Button(action: {

                self.userData.todos.remove(at: self.todoIndex)

            }, label: {

                    HStack{

                        Text("Delete")

                            .foregroundColor(.red)

                        Image(systemName: "trash")

                            .foregroundColor(.red)

                    }

            })

        }



Note: I believe there is a bug in swiftUI and the context menu shows text only in black and ignores the styling. 

@Environment


Environment is a wrapper object to provide environment values to the view. EnvironmentValues has list of environment values you can access. 

I have used the Presentation to dismiss the view and go back to the list page. 

@Environment(\.presentationMode) var presentationMode


So, after the todo is created successfully, use is navigated back to list page. 

.alert(isPresented: self.$saved, content: {

                Alert(title: Text("Success"), message: Text("Todo created successfully with \(self.todo.priority.name) and due by \(self.todo.dueDate.ShortDate)"), dismissButton: .cancel(Text("Ok"), action: {

                    self.presentationMode.wrappedValue.dismiss()

                }))

            })



Extensions


Existing types can be extended with extensions. I have created a extension ShortDate for Date to provide short date string for display purposes

extension Date {

    var ShortDate: String {

        let dateFormatter: DateFormatter = DateFormatter()

        dateFormatter.dateStyle = .medium

        dateFormatter.timeStyle = .none

        return dateFormatter.string(from: self)

    }

}


this can now be used in the code like other Date properties

Text(todo.dueDate.ShortDate)



Core Data


Alright, now we have the basic structure in place and our code is working with adding and deleting the Todos.Now, need to learn how to persist data. There may be different ways to persist the data and Core 
Data is one of them and will try that. 

Setting up Core Data Stack


When I created the project I did not choose to add Core data. So, to add core data model to the existing project follow the steps in documentation.

So first thing we always need to do while get the list of data. That is done using the @FetchRequest and then we need to filter the content of that list. This can be done by passing the NS Predicate to the fetch request. 

I would suggest follow the Predicate Programming Guide 

The repo is updated with using the core data. 

CRUD operations with CoreData


Local Notifications




Preparing iOS app for Release


App Icons

Use the Icon Set Creator app to set of icons for the app.





No comments:

Post a Comment