Thananya Phromwongsa: thphr16

Veena Balakumar: vebal13

Bitbucket Link: https://tanyaXxx@bitbucket.org/iosprogrammingsdu/lifestyleapp.git 

Project Title: LifeStyle App

Introduction

The idea behind the project is to make a lifestyle app. The report contains the background of the project and the vision and purpose behind the project. The project idea comes from a problem statement that the project tries to solve. To solve the problem stated, the requirements are specified, where it is further analyzed. After analyzing the requirement of the project, the boundary of the project is found, and the design of the product is made by having a use case diagram, navigation diagram and object diagram. Using the diagram made and the requirement defined, the app is implemented with the required functionalities. In the last section of the report, there is a discussion section to discuss the positive and negative of the design and the implementation of the app.

The idea and the background of the project

The idea is to create a lifestyle app which is inspired by Bullet journal and existing apps such as Instagram, headspace, Wunderlist etc. The app will include many aspects which will make life easier by using the app. The purpose of the app is to motivate and inspire the user to have a healthier and more productive lifestyle. This can be done by having a to do list to keep track of any possible tasks. The app will also include other tracker features which will keep your life intact and keep you stay focused. The target group of the app will be people from the age of a teenager to middle age who is busy but also want to focus on themselves and have a healthier lifestyle.

Common platform

The app is mainly inspired by bullet journaling in which the app is a digitised version. Bullet journaling is to keep track of life where you design your own calendar, write down all your tasks and goals and keep track of all your goals as well. We have taken a few essential elements from the bullet journal and applied it to our app such as habit tracker and mood tracker. Habit tracker is when you decide to change a habit of yours such as working out everyday and then you keep track and mark whether you have worked out or not. Mood tracker is to keep track of how you feel everyday. You can then look back and see how your lifestyle is and how you were feeling and evaluate your life.

The app is also inspired by Instagram since there are going to be a way of interacting with other users through uploading pictures of your day to keep yourself motivated and inspire others. For that the camera sensor will be used.

Another already existing app is Wunderlist which is a to-do-list app where you can create different to do lists for yourself.

Another similar app is the “Happiness Planner”. This app contains a calendar, to-do, schedule, meals & exercise and reflection of your day. It is very similar to this project idea compared to the vision and idea. But this project stands out in relation to tracking mood and habits similar to the bullet journal.  

Problem statement

Nowadays many people tends to focus on a healthier lifestyle, self-care, being productive and reaching their goals which can be done in several ways. There are a lot of resources out there to help them reach these goals but how can we optimize their options, and make the process of reaching these goals easier and fitting for their busy everyday life.

Methods and Materials

Brainstorm

The project being very open ended, it was discussed in the group what each member is interested in and what kind of app the group members would use themselves. Through brainstorming the group decided to make a LifeStyle App that focuses on productivity, lifestyle, tracking habits and mood.

Conceptual Design

Through brainstorming, the decided concept is a lifestyle app. The lifestyle app should help people optimize their lifestyle through defined goals and a process of tracking their everyday life and mood. They should be able to look back and evaluate on the process and the goals reached.

 

Requirements

A user should be able to:

  • view and modify their own profile (Profile)
  • take and upload pictures (Camera)
  • track habits, mood and set up a bucket list and write in a gratitude journal (Journal)
  • search and view pictures from other users (Feed) → Future Work
  • set personal information and manage their account (Settings) → Future Work

Use-Case Diagram

Simple prototyping

First prototype

As for the first prototype the overall concept is designed which is the feed and the navigation. The navigation is listed in the left side and then there is presented a feed on the right side:

Evaluation:

The first prototype has been evaluated by different people where both negative and positive feedbacks were given. The feedbacks were primarily about the app containing too much text which leads to the app being unfriendly. To develop an app, it has to be more user friendly. The feedback also pointed at the many functionalities the app contains. It should be kept more simple by reducing the functionalities.

Second prototype

https://marvelapp.com/35h84h8

After the before mentioned feedback, the navigation and layout has been changed. The app contains less text and looks more as an app after applying the navigation differently. The functionality also got limited to make the app mores simple and easy for the user to use:

Evaluation:

The feedback were more on the positive side after changes were made according to the feedback from the first prototype. The navigation is better and more manageable. It was good with less text and to include more visual components which is done by changing the layout of the user interface. Though the links between pages were a bit unclear because the missing guide for navigation of the app. It might still contain too many functionalities.

First Navigational Digital Prototype

At the first navigational digital prototype it is possible to navigate in the application and all the views were created. Beside that To-Do List and Bucketlist is also implemented without the core data:

This prototype  for the most part only contains the navigation flow and not a lot of functionality.

Evaluation:

It is now easy to navigate around in the app but the functionality and design is still missing. At this point of the project there is not a lot of feedback beside functionality missing and there is not much design.

Object Diagrams

Object diagram shows how each classes are connected. It is shown through the concept of model view controller (MVC) where there are a separation between the view, the controller to the view and the model.

Implementation

Framework

  • Foundation
    • Foundation must be imported to access basic data types, and access services to be able to define base layer of the functionalities. It can be calculations, sorting, filtering and processing data.
  • UIKit
    • UIKit is used to manage the user interface. The user interface is the view that is presented to the user. By using the UIKit it is possible to display text, image etc. It also makes the handling of interaction between the user and the view possible by having functionalities for event-handling.
  • CoreData
    • CoreData is used to manage the object in the model layer. It can be used to store and load the data of each objects. CoreData acts like a persistence layer for storing data.
  • JTAppleCalendar
    • JTAppleCalendar is an unofficial calendar library that has been used to implement calendar functionalities. The library contains range selection, boundary dates, custom cells, custom calendar view, horizontal and vertical mode and much more to design and implement a calendar.

Camera

CameraController.class:

CameraController class is responsible for the interaction with the camera and how to access and display the camera to the user. The camera class has two main responsibility which is to take pictures and get pictures from the photo library on the phone. After taking pictures or accessing the pictures from the library it is displayed to show the user which picture the user has picked.

CameraController – takePhoto method:

The method is the one responsible for show the camera to the user and make it possible for the user to take pictures. The method is triggered by clicking a button.

    //The method displays the camera when the user wants to take a picture
    @IBAction func takePhoto(_ sender: UIButton) {
        imagePickerController = UIImagePickerController()
        imagePickerController.delegate = self
        imagePickerController.sourceType = .camera
        
        imagePickerController.allowsEditing = true
        
        //presents the camera
        present(imagePickerController, animated: true ,completion: nil)
    }

The imagePickerController is used to manage the system interface for taking pictures and choosing items from photolibrary. In this context the type of the picker interface to be displayed by the controller is the camera. When taking a picture it is possible to edit the size by setting the allowsEditing to true. To display the camera, we call the present method to present the camera.

CameraController – selectPhoto method:

This method allows the user to access photos from their library on their phones. It presents access the library and presents it to the user. The user can select photos shown and use it.

   //The method displays the photolibrary when the user wants to select a photo from it
    @IBAction func selectPhoto(_ sender: UIButton) {
        
        imagePickerController = UIImagePickerController()
        imagePickerController.sourceType = .photoLibrary
        imagePickerController.allowsEditing = true
        imagePickerController.delegate = self
        
        //presents the photolibrary
        present(imagePickerController, animated: true, completion: nil)
    }

It is almost the same setting and explaination as the camera. The only difference is that the imagePickerController that is presented is displaying the photolibrary of the phone and not the camera.

Core Data

coreData.class:

The coreData class should be responsible for storing and accessing the data from the persistence layer. It saves and loads different data from the persistence. One of the object that is stored in the persistence layer is the object Photo which has an attribute image that is a binary data to be able to store pictures.

coreData – saveImage method:

The method is responsible for using the picture taken or selected by the user and convert it into a png file to store it as a Photo object in the data model.

    //Saves an image to the coredata model
    func saveImage(image: UIImage) {
        
        //defines date if wishes to sort the images
        let date : Double = NSDate().timeIntervalSince1970
        
        //converts the image to a png file
        let imageData = image.pngData()
        
        //gets an object defined in the core data model
        let entity = NSEntityDescription.entity(forEntityName: "Photo", in: self.context)
        
        //converts it to NSManagedObject
        let entityObj = NSManagedObject(entity: entity!, insertInto: self.context)
        
        //sets the value of the attributes of the object
        entityObj.setValue(imageData, forKey: "image")
        entityObj.setValue(date, forKey: "id")
        
        do{
            //save the changes of the object
            try self.context.save()
            
        }catch {
            fatalError("fail to save image!")
            
        }
        
    }

By taking an UIImage as a parameter it converts the image to an png file. After converting it, it gets the entity Photo from the data model and turns it into an object to be able to set the value of the attributes. After setting the attributes of the object, it saves the object by using the context which is used to manage an object.

coreData – loadImage method:

The method is responsible for loading the Photo object from the data model by making a fetch request to the persistence layer and access the Photo object and its attribute.

    //The method loads images from the core data model
    func loadImage() -> [UIImage] {
        
        var images: [UIImage] = []
        
        //makes a request to the persistence layer
        let fetchImage = NSFetchRequest<NSFetchRequestResult>(entityName: "Photo")
        
        do{
            
            //fetches the objects that meets the defined critaria
            let results = try self.context.fetch(fetchImage)
            
            //loops the results of it contains something
            if results.count > 0 {
                
                for result in results as! [NSManagedObject] {
                    
                    //gets an image
                    if let imageData = result.value(forKey: "image") as? Data {
                        if let image = UIImage(data: imageData){
                            
                            //adds it to the array of images
                            images.append(image)
                        }
                    }
                }
            }
            
            
        }catch{
            
            print("could not fetch image: ")
        }
        
        //returns an array of images retrieved from core data
        return images
    }

The method loads the object from the data model by making a fetch request which is then handled by the context. When the object is retrieved we get the image stored and adds it to the array of image which is used as a return value.

Calendar

JTAppleCalendar framework is used to implement the calendar for both Mood Tracker and Gratitude Journal.

setupCalenderView method: 

    override func viewDidLoad() {
        super.viewDidLoad()
        calendarView.calendarDataSource = self
        calendarView.calendarDelegate = self
        
        setupCalendarView()
        
        calendarView.scrollToDate(Date(), animateScroll: false)
        calendarView.selectDates([Date()])
    }
    
    func setupCalendarView() {
        //Setup calender spacing
        calendarView.minimumLineSpacing = 0
        calendarView.minimumInteritemSpacing = 0
        //Setup labels
        calendarView.visibleDates(){(visibileDates) in
            self.setupViewFromCalendar(from: visibileDates)
            
        }
    }

This is the visual part of the calendar. CalendarView is the collectionView added to the main storyboard. The “calendarView” is a JTAppleCalendarView UI-view in which there is added scrollToDate to make sure that the calendar starts on the current date. Furthermore the calendar spacing is being adjusted and labels are setup.

    func setupViewFromCalendar(from visibleDates: DateSegmentInfo){
        calendarView.visibleDates(){(visibileDates) in
            let date = visibileDates.monthDates.first!.date
            
            self.formatter.dateFormat = "yyyy"
            self.year.text = self.formatter.string(from: date)
            
            self.formatter.dateFormat = "MMMM"
            self.month.text = self.formatter.string(from: date)
        }
    }

The essential elements in the mood-tracker is that when a date is selected, it has to be marked either bad day(red), good day(green) or blank (white):

    func handleCellSelected(view: JTAppleCell?, cellState: CellState){
        guard let validCell = view as? CustomCell else { return }
        
        if cellState.isSelected {
            if(validCell.blankDay==true) {
                validCell.greenMarker.isHidden = false
                validCell.redMarker.isHidden = true
                validCell.goodDay = true
                validCell.blankDay = false
                validCell.badDay = false
                
            } else if  (validCell.goodDay == true) {
                
                validCell.greenMarker.isHidden = true
                validCell.redMarker.isHidden = false
                validCell.badDay = true
                validCell.goodDay = false
                validCell.blankDay = false
                
            } else if (validCell.badDay == true) {
                validCell.greenMarker.isHidden = true
                validCell.redMarker.isHidden = true
                validCell.goodDay = false
                validCell.badDay = false
                validCell.blankDay = true
            }
        }
    }

This part shows that when a cell is selected once it will be marked as a good day (green). If it then is selected again it will change to bad day (red) and at last when selecting the same cell again it will be a blank day.

There has been used extensions to add new functionality from JTAppleCalendarViewDataSource and JTAppleCalendarViewDelegate. In the JTAppleCalendarViewDataSource contains the format-part of the calendar in relation to date format and time zone . For now we only use the two parameters start date and end date:

extension CalendarMoodController: JTAppleCalendarViewDataSource {
    
    
    func configureCalendar(_ calendar: JTAppleCalendarView) -> ConfigurationParameters {
        formatter.dateFormat = "yyyy MM dd"
        formatter.timeZone = Calendar.current.timeZone
        formatter.locale = Calendar.current.locale
        
        let startDate = formatter.date(from: "2018 01 01")!
        let endDate = formatter.date(from: "2050 12 31")!
        
        let parameters = ConfigurationParameters(startDate: startDate, endDate: endDate)
        return parameters
    }
}

In the exension-part with JTAppleCalendarViewDelegate the implementation is about how the cell is being displayed on the calendar. In this part the date label is being defined as the class CustomCell. This function also calls the methods “handleCellSelected” and “handleCellTextColor” which are two methods that defined how the cells should look compared to current date and the other dates. And the second method defined how to act when a cell is selected. The methods used in this part is willDisplay, cellForItemAt, didSelectDate and didScollToDateSegment. These functions define what to display in general and for each cell, and how to act when a cell is selected and to be able to scroll to the current date and then automatically scroll around in the calendar. cellForItemAt method also makes sure that the dates are only selected when the user selects the date or the current date and that there is not selected any dates randomly otherwise.

extension CalendarMoodController: JTAppleCalendarViewDelegate {
    //Display the cell
    
    func calendar(_ calendar: JTAppleCalendarView, willDisplay cell: JTAppleCell, forItemAt date: Date, cellState: CellState, indexPath: IndexPath) {
        let myCustomCell = cell as! CustomCell
        sharedFunctionToConfigureCell(myCustomCell: myCustomCell, cellState: cellState, date: date)
    }
    
    func calendar(_ calendar: JTAppleCalendarView, cellForItemAt date: Date, cellState: CellState, indexPath: IndexPath) -> JTAppleCell {
        let myCustomCell = calendar.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
        sharedFunctionToConfigureCell(myCustomCell: myCustomCell, cellState: cellState, date: date)
        handleCellSelected(view: myCustomCell, cellState: cellState)
        handleCellTextColor(view: myCustomCell, cellState: cellState)
        
        
        if cellState.isSelected {
            myCustomCell.greenMarker.isHidden = false
            myCustomCell.redMarker.isHidden = false
        } else {
            myCustomCell.greenMarker.isHidden = true
            myCustomCell.redMarker.isHidden = true
        }
        
        return myCustomCell
    }
    
    func sharedFunctionToConfigureCell(myCustomCell: CustomCell, cellState: CellState, date: Date) {
        myCustomCell.dateLabel.text = cellState.text
        // more code configurations
    }
    
    func calendar(_ calendar: JTAppleCalendarView, didSelectDate date: Date, cell: JTAppleCell?, cellState: CellState) {
        handleCellSelected(view: cell, cellState: cellState)
        handleCellTextColor(view: cell, cellState: cellState)
    }
    
    func calendar(_ calendar: JTAppleCalendarView, didScrollToDateSegmentWith visibleDates: DateSegmentInfo) {
        setupViewFromCalendar(from: visibleDates)
    }
}

The implementation for both gratitude-journal and mood-tracker are similar to some extend. The gratitude-calendar is a little different since it does not contain color coding in the calendar  when selecting a date. It contains three text fields where the user can write what the user is grateful for and then click on the add-button. Then the date will be marked as the user gives the date some input:

    
    @IBAction func addGratitude(_ sender: UIButton) {
       

        if((gratitudeTxtfield1!.text != "") && gratitudeTxtfield2!.text != "" && gratitudeTxtfield3!.text != ""){
            currentCell.gratitude1 = gratitudeTxtfield1.text!
            currentCell.gratitude2 = gratitudeTxtfield2.text!
            currentCell.gratitude3 = gratitudeTxtfield3.text!
            
            gratitudeTxtfield1.resignFirstResponder()
            gratitudeTxtfield2.resignFirstResponder()
            gratitudeTxtfield3.resignFirstResponder()
            currentCell.greenMarker.isHidden = false
            
        } else {
            
            let alertController = UIAlertController(title: "Error", message: "Please fill in the three fields", preferredStyle: UIAlertController.Style.alert)
            alertController.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
            present(alertController, animated: true, completion: nil)
        }
    }

If the user does not fill all three fields it is not possible to save the text to the date and the user will get an alert.

Results

Profile, Feed and Journal:

 

Profile page contains information about the user and then a personal to-do list and a portfolio which contains the images the user has uploaded from the camera or photo library. 

Feed is where you can see other users pictures. This is for future work since this prototype is not distributed yet. The third screenshot is the Journal navigation where the user have four different options.

Mood Tracker:

The mood tracker is a blank calendar where the user can color code the calendar whether the user has had a good day or bad day. If the user has not marked anything the date will be blank.

Gratitude Journal:

In the gratitude journal, the user can add three things the user is grateful for and then click save. When clicking save and afterwards if you click on the same date again you can see what the user wrote for that day. When the user has filled in three things and saved it the date will be marked with green. If the user does not fill in one or more of the three fields, the user will get an alert as shown above. 

To-Do:

The to-do list and bucket list is implemented similarly, but the purpose of them are different. You can add something to the list and then delete it by swiping left.

Camera & Portfolio:

The sensor decided to use in this project is the camera. The user is able to take a photo with a camera or select a photo from the user’s photo library. Then the user can upload it to their portfolio-view which is a collectionview with all the photos chosen to be uploaded.

Habit tracker:

The purpose of the habit tracker is to change the users lifestyle habits. The user can create a habit and choose the amount of days the user wants to keep track of. When writing the title of the habit and the amount of days and clicking the “add habit” button it will be added to a list. If you then click on the habit you will get a new view where the title of the habit and checkboxes for the amount of days you decided you wanted. Then you can cross off whenever you kept the habit. This will give the user an overview and also motivate the user to stick to his new lifestyle habits.

Discussion

MVC:

What could have been done better is the design of the app. If it should be made using good practice, the app should be divided better according to the MVC princip. The object diagram only shows one class in the model layer which could be optimized. The way that it can be optimized is by dividing the code in the controller layer and take the logic into the model layer. It is about keeping the responsibility of each class at minimal. The model layer should not worry about how things are presented in the GUI and the controller should not worry about the logic of the app.

DUPLICATE CODE:

Another improvement for this project would be reusing code properly. For this prototype there has been duplicated code of the calendar implementation and the bucket list and to do list implementation repeatingly. But to improve the implementation it would be better to reuse the code instead of writing the same code several places.

GENERAL:

The last improvement would be to improve the layout and adjust the constraints more properly so it fits all iPhone sizes. Another future improvement that the group have not taken into consideration is autolayout when you for example rotate the screen, the app is not responsive. 

Conclusion

The goal of this project is to develop a lifestyle app that contains a calendar, camera, portfolio,  habit tracker, to-do list, bucket list, mood tracker and gratitude journal. The group succeeded in developing an app with the above mentioned features according to the defined requirements and the scope of the project. Due to the time limit the group was not able to store all data of every feature as expected and also decided to not make the app distributed which can be a future work instead.

Appendix

Leave a Reply