Challenge yourself in every aspect.

by: Diana Ismail, deism16; Dune Zerna, duzer17; Pernille Madsen, pemad17

Introduction

Most people have multiple personal goals they have thought about accomplishing, but never actually gotten done. This could be a result of forgetfulness, lack of motivation or not having the reminder to get it done.

Many applications focus on setting personal goals, but they are all topic related. There are applications related to improve mental health, by meditating every day, or applications related to improve psychical health, by going for a run every day. There are even applications related to reducing stress, by switching off your phone for a given period of time every day – but they are all separate applications, and most of them only have premade goals. The idea of Challenger is to combine multiple of the already made applications, and allow users to create their own challenge to reach a personal goal. 

So how can we create an application, that disable people to make excuses, and motivate them to complete personal challenges? 

The application needs to be easily accessible and easy to navigate. It must both have preset challenges, that the users can choose from, but also the option of creating their own. To make the usage and completion more motivating, a gallery is added to the application, so the user can take pictures at any given moment during the challenge and look back upon it sometime. QR may also be scanned in order to find popular running routes.

The functionalities of the application, all contribute towards a personal development tool, that helps the users to make personal goals and reach them. The application itself is not what creates the success, but it helps to keep track of the goals, and making it easier to accomplish.

Reevaluated introduction

The idea described in the previous chapter, was the initial idea for the application. We tried executing this, but it was much too difficult and time-time consuming. To be able to create a full-functioning application, the idea was cut down, to mainly contain step-tracking and goal setting in this matter – the user of the application can set personal goals with regards to steps, and complete these goals. The camera function is still implemented, as well as the gallery.

The application is now, instead of a personal goal challenger, a step-counter with personal goals and a gallery implementation – further development would be to implement more challenges, so the main function of the application, was no longer just steps.

Methods & materials

For the project, we started out brainstorming for ideas that fell under the criteria for the project: a health-related topic. Every group member did this, and after discussing them in the group, we decided to go with the challenger application. After choosing the idea, the group started looking for application similar to the idea – from this we gathered inspiration of both design and content. 

After considering who the main end-user was, the development started. Anyone with an iPhone should be able to use the application, which was also thought of throughout the implementations. The application should be running on a phone, as this is a platform where the screen is large enough to view and read from, but also a mobile device that the user carries around.

We then started brainstorming how to implement different sensors from the device, and created a low-fidelity prototype, by drawing the views in a sketching application. These sketches were evaluated, by letting potential users look at the sketches whilst being explained the functions of the application. The feedback they gave concerning the main functionality of the application, was then taken into consideration for further development. 

After the evaluation, the high-fidelity prototype was started. This was where the implementation of the actual functionality happened and created the full-functional application. For the implementation, a use case diagram was created, to give a better overview of the functions of the application. 

The application was then divided into a model-view-controller design pattern, to separate the different functionalities. This prototype was once again evaluated, based on the use, functionality and design. 

The application was not running full-functional and changes to the idea and execution were made. The prototype was once again evaluated, based on over-all usability and design.

Results

The entire project can be found on the link: https://bitbucket.org/pernillemadsen/challenger-v2.0/src/LocalStorage/

From the completed brainstorm, we were left with 3 different ideas: the challenger application, a fitness application and a sustainability application. From these three, the challenger app was chosen. When looking at the similar applications to Challenger, there are a few coming into play, such as Endomondo, that allows tracking progress of a physical activity, Forest that enables the user to set a meditation goal of the day and many other, that support setting goals and challenges for oneself. 

Brainstorming of ideas and similar applications

These applications helped decide the functionality of the application, and what things the user would be allowed to do, such as the setting personal challenges and viewing previously completed ones. 

Use case diagram for application

In the use-case diagram, it is clear that there are 4 things, the user can do in the application. Create challenge, where they can create a challenge of their choice; View challenge, where they can view both running and completed challenges; take pictures, that will be stored in the application and on their phone; and view gallery, which is where they can see the pictures taken in the application.

When looking at the different sensors that could be incorporated into the application, we went with two of the many: the accelerometer, to track steps, and the camera, to take pictures. The accelerometer is not directly accessed but is implemented by using the HealthKit available for iOS devices. The HealthKit gives access to multiple features, where step count is one of them. 

The reason why we have chosen to use the accelerometer is because it tracks movement at a low cost; by only tracking when the smartphone is in acceleration, rather than pinpointing GPS position. This requires only a small amount of software and relies more on the hardware, which is less energy consuming.

Using the camera as a sensor came into play as a pseudo-unit. While this sensor doesn’t contribute to the app in health-oriented manner, it does contribute to user functionality. Taking a picture to highlight a specific event, or scanning a QR code to find an activity route does have a positive effect on the user experience.

An implementation of the HealthKit can be seen below. In the code, the different attributes of the HealthKit is implemented, and the steps are printed on a label.

let healthStore = HKHealthStore()
    
    func getSteps(completion: @escaping (Double) -> Void){
        let stepsQuantityType = HKQuantityType.quantityType(forIdentifier: .stepCount)!
        
        let now = Date()
        let startOfDay = Calendar.current.startOfDay(for: now)
        var interval = DateComponents()
        interval.day = 1
        
        let query = HKStatisticsCollectionQuery(
            quantityType: stepsQuantityType, quantitySamplePredicate: nil, options: [.cumulativeSum], anchorDate: startOfDay, intervalComponents: interval)
        
        query.initialResultsHandler = {_, result, error in
            var resultCount = 0.0
            result!.enumerateStatistics(from: startOfDay, to: now) {
                statistics, _ in
                if let sum = statistics.sumQuantity(){
                        resultCount = sum.doubleValue(for: HKUnit.count())
                }
            }
            
            DispatchQueue.main.async {
                completion(resultCount)
            }
        }
        
        query.statisticsUpdateHandler = {
            query, statistics, statisticsCollection, error in
            
            if let sum = statistics?.sumQuantity(){
                let resultCount = sum.doubleValue(for: HKUnit.count())
                
                DispatchQueue.main.async {
                    completion(resultCount)
                }
            }
        }
        healthStore.execute(query)
    }
        
        let allTypes = Set([HKObjectType.workoutType(),
                            HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!,
                            HKObjectType.quantityType(forIdentifier: .stepCount)!,
                            HKObjectType.quantityType(forIdentifier: .distanceWalkingRunning)!])

        healthStore.requestAuthorization(toShare: allTypes, read: allTypes) { (success, error) in
            if (success){
                self.getSteps {(result) in
                    
                    DispatchQueue.main.async {
                        let stepCount = Int(result)
                        self.stepsLabel.text = String(stepCount) + (" / 10.000 steps")
                        
                    }
                    
                }
            }
        }

Before going into making the high-fidelity prototype, the application started out being visualized in a sketch-up program. 

The feedback given on the low-fidelity prototype, was muchly concerning the functionality of the application. It was here stated, that this would stand out, if the user would be able to create their own challenge, instead of choosing pre-made ones. It was also made clear, that the application needed to be easy to use, and not as confusing as some of the other. 

With this feedback in mind, the main implementation of the application begun. The application was slowly being created in XCode, and build up using a navigation controller and multiple view controllers. Inside the application, a table view was created for holding the previously completed challenges, and a collection view was created as a gallery for the photos taken. The design pattern used to develop the app was based on MVC design pattern.

A simple MVC overview

The hi-fi prototype did not quite end up as the lo-fi prototype. As the development progressed, difficulties rose up to be more challenging than initially expected. In the hi-fi prototype, we strayed from creating a view with a Google Maps implementation, because this was the least important factor in the app and we prioritized other sections of the app.

The watch/timer on the active challenge view was not implemented either, since it would require logic to define when it should be used as a timer, stopwatch or just a regular clock. We deemed it a nice-to-have feature.

The video below shows the application we had created, when the deadline hit. It was not full-functioning and lacked both design and functionality.

Use of application

It was decided to switch our focus to the step counting function in the application, whilst still having the ability to create and complete challenges (purely step-based now). The code for the previous result, will not be implemented in this post.

The data we’re saving in the application, is stored in the User Default class, provided by Apple, which allows us to save smaller amounts.

In order for the user to be able to login, the user can register with a username, password, name and e-mail address, which will then be saved and used as the login. This login is only stored locally, and will not be able to be used on any other device.

A challenge class was created, used to create and store challenges made. In this class, the predefined challenges were also initialized. The challenges created, with a belonging description, was also stored in the User Default class. A code snippet of the challenge class is seen below:

class Challenge {
    
        // Dune: Predefined challenge array
        static var predefinedChallenges = [" ","Run 5KM","Walk 10K steps", "Walk backwards"]
        static var challenges: [String] = []
    
        // Dune: Predefined descriptions
        static var description: [String] = [" ","Running is good for you. Let's try to run for 5KM", "Walking is essential to reduce cardiac arrests and other health issues. Let's try to walk 10.000 steps", "Well, walking backwards can be a challenge"]
    
        // Dune: Array for saved challenges, persists through sessions
    static var savedChallenges: [String] = UserDefaults.standard.stringArray(forKey: "savedChallenges") ?? [""]
    // Dune: Array for saved descriptions, persists through sessions
    static var savedDescriptions: [String] = UserDefaults.standard.stringArray(forKey: "savedDescriptions") ?? [""]
        static var totalSteps: String = ""
    
    //Pernille: declared array of activeChallenges - this is set based on the steps registered on device vs the Challenge goal. If steps walked are less than Challenge goal, they're on the active list
    static var activeChallenges: [String] = UserDefaults.standard.stringArray(forKey: "savedActiveChallenges") ?? [""]
    
    // Dune: Method for saving new challenges
    static func saveChallenge(newChallenge: String) -> Void{
        Challenge.savedChallenges.append(newChallenge)
        UserDefaults.standard.set(Challenge.savedChallenges, forKey: "savedChallenges")
    }
    
    // Dune: Method for saving new descriptions
    static func saveDescription(newDescription: String) -> Void{
        Challenge.savedDescriptions.append(newDescription)
        UserDefaults.standard.set(Challenge.savedDescriptions, forKey: "savedDescriptions")
    }
    
    // Dune: Method for saving active challenges
    static func saveActiveChallenge(activeChallenge: String) -> Void{
        Challenge.activeChallenges.append(activeChallenge)
        UserDefaults.standard.set(Challenge.activeChallenges, forKey: "savedActiveChallenges")
    }

}

When the user creates a new challenge, the challenge is stored in the array ‘savedChallenges’, which is also connected to the User Default, which stores the data, even when the application is closed. When the user creates a new challenge, it is also added to the ‘activeChallenges’ array, which checks if the user has completed the challenge; if they have taken more steps than the challenge goal, the challenge is removed from this array, but still stored in ‘savedChallenges’.

A code snippet of saving the challenge is shown below. As seen, if the user types in the text field, the input is evaluated. If its purely numbers used, the challenge is created and appended to the ‘savedChallenges’ array, using a custom made function ‘saveChallenge’.

//Pernille: if you wrote only numbers in the textField, your challenge was created
        if challengeInt != 0 {
            let alert = UIAlertController(title: "Success", message: "Your challenge was created!", preferredStyle: .alert)
            let okAction = UIAlertAction(title: "Okay", style: .default, handler: nil)
            alert.addAction(okAction)
            self.present(alert, animated: true, completion: nil)
          
            
            // Dune: Method for saving new challenges & descriptions
            Challenge.saveChallenge(newChallenge: textField.text!)
            Challenge.saveDescription(newDescription: "")
            print(Challenge.savedChallenges)
            
        }
        
            //Pernille: if you wrote letters in the textField, error occurs
        else {
            let alert = UIAlertController(title: "Error!", message: "You may only use numbers", preferredStyle: .alert)
            let okAction = UIAlertAction(title: "Okay", style: .default, handler: nil)
            alert.addAction(okAction)
            self.present(alert, animated: true, completion: nil)
            
        }
    }

The custom made function can be seen below:

// Dune: Method for saving new challenges
    func saveChallenge(newChallenge: String) -> Void{
        Challenge.savedChallenges.append(newChallenge)
        UserDefaults.standard.set(Challenge.savedChallenges, forKey: "savedChallenges")

In the same ViewController as the creation of a challenge (ChallengeViewController), the user is also able to see the active challenges, as previously described. In order for the user to see the completed challenges, the ViewController, HistoryViewController, must be opened. In this ViewController, a tableView with all challenges is created.

The user is able to click on the different challenges, and it expands into further detail. When expanded, it shows the title of the challenge, the description of the challenge (if this is not yet present, the user is given the opportunity to create a description), and the option of taking a picture for the challenge – this is then stored on the device itself, and is also transferred to the CollectionViewController, which is a gallery of the pictures.

Below is a code snippet of the creation of the tableView from HistoryViewController:

//Pernille: creation of tableView in history
     func numberOfSections(in tableView: UITableView) -> Int
    {
        return 1
    }
    
     func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        
        return challenges.count
    }
    
     func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCell(withIdentifier: "HistoryCell") as! HistoryTableCell
        
        cell.tableCell?.text = challenges[indexPath.row]
        return cell
    }
    
     func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        indexNr = indexPath.row
        tappedView.isHidden = false
        print("Touched")
        
        
        //Pernille: using title and description for each challenge
        tappedTitleLabel.text = Challenge.savedChallenges[indexNr]
        
        
        //Pernille: checking if challenge has no description
        if Challenge.savedDecriptions[indexNr] == "No description yet.." {
            
            tappedDescView.isHidden = true
            
            
            //Pernille: if has description, print description on label
        } else {
            
            tappedDescView.isHidden = false
            tappedDescLabel.text = Challenge.savedDecriptions[indexNr]
            
        }
    }
    
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        cell.backgroundColor = UIColor.clear
    }

In the video, the application running is shown:

The application was evaluated on 3 people in total (more people would have been ideal). They were given a phone with the application on it, and were asked to play around with it, and think out loud. As the application is something that would take a longer time to test, it was mainly the design and way of creating and viewing the challenges. The feedback given was:

There was a general need of more feedback and respons when using the application. The use was not intuitive enough to use without trial and error, or an introduction. The applications functions were also not very versatile and are very constrained around steps.

This feedback is something the group had already known, and had in mind to implement. Unfortunately time ran out, and we chose to focus on creating a functional.

Discussion

The first version of the application created, was lacking in multiple areas. The user could create a challenge, but it was not saved and there was no way of completing the challenge. The user-interface was lacking in both design and functionality.

After reevaluating the functionality of the idea, and settling on one topic instead of multiple, it was easier for us to make it fully functional, adding the ability to create and complete challenges. The challenges are only stored locally, and this is not ideal for further development of the application – a cloud based database would be ideal, as the data could be passed between different devices.

The user can choose a challenge and view progress and completion. The user can take pictures from the application or choose an already existing picture from their device gallery, but the pictures they take in the application, cannot be stored in their gallery, for unknown reasons. It has been tried multiple times, and it has been debugged to find the error with no luck. The step-counter works with no problems. 

It must be admitted, that the application have been more difficult to put together as first planned, as a lot of the things needed implementation, also needed access to a database and a lot of work and time, which the group did not have the most of, needed to be put into this, in order for it to work as intended. Even though not all functions of the application are running as wished, the things that are not, are simulated in a realistic way. 

The idea was to implement a database using Firebase as the handler. After implementing this on one computer and trying in on a different, it gave a lot of problems when downloading the needed files. Since this was the case, and Firebase could not run without these files, a local storage was used. This is not optimal, and does not have the potential of Firebase, but it simulates nicely how the database would work. 

Evaluation

The application Challenger has been created with the intention of creation a new app, that could motivate the users to make a change in their life, whether this would be a health change, a practical change or any change at all – and the idea is good! The first implementation of the idea was not as intended and was lacking in multiple functionalities. Reevaluating the project and choosing to focus mainly on the steps, helped us spend time more efficiently.

It is possible to create multiple challenges, complete them and view them in the History section. Currently there is a full connection between the challenges and their description, but the user cannot take pictures and save the, dependent on the challenge itself. The user is able to take photos, save them to their device, BUT they are not stored in the challenges.

Looking at the simulator in Xcode, the application is responsive to size and rotation, but running it on a device is a different story. It is not as smooth in the design and use, and will need a lot of tweaking before it becomes nice.

Leave a Reply