SnapChallenge

Andreas Grøntved Jeppesen – ajepp09

Emil Nedergaard Jensen – emije14

Nicolai Hedegaard Jensen – nije214

1. Introduction

The video showcasing the app can be seen here:

The project is developed as a part of the iOS programming course (OK-IOS-U1) taking place in the fall semester of 2018. The emphasis of the project is promoting welfare technology or physical play though the use of at least one sensor technology. The final product of the project should be a prototype of the developed software and this report outlining the process, design and results.

1.1 What is your basic idea?

The project we created is called SnapChallenge. SnapChallenge is an application for iOS devices which utilizes the camera and gps sensors to enable physical play.

SnapChallenge allows the user to take a picture of anything they want, write a caption and send it to their friends. The caption for the attached image should present the receiver with a challenge. Once the challenge has been completed by the recipient they send it back to the challenger, who then either accepts the challenge as completed or rejects it making the challenge incomplete.

The camera sensor will be used to capture the images which can be sent for the challenges. The gps will allow the sender and recipient to see where the image was taken. This combination has the ability to promote physical play by making the users go out in search of good ways to solve the challenges.

1.2 Why is this subject important?

The subject of the project is primarily consisting of the health benefits that physical play provides. We are currently seeing a rise in obesity rates both worldwide [1] and in Denmark specifically [2], for this reason we need to encourage more physical play especially to prevent childhood obesity as obese children have a high risk of becoming obese in adulthood [3].

We are attempting to battle this epidemic by making physical play fun and engaging, furthermore the added benefit of playing with friends can help to decrease involuntary loneliness which in turn can improve the mental health of the users [4].

1.3 Related apps

The most closely related application to SnapChallenge would be SnapChat [5]. SnapChat allows the users to send images of their current environment to their friends, which disappear after they have been viewed, these images can be edited with facial filters, text and clipart.

1.4 Common platform

The platforms that must be described to give a better understanding of the application, are the iOS development platform and the Firebase Realtime Database.

The iOS application development is done using the Xcode IDE created by Apple. Xcode can be downloaded through the App Store and run on macOS devices. The available programming languages for iOS development are Objective-C and Swift. SnapChallenge was developed using Swift.

Since the application is a distributed application with multiple users interacting through the functionality of the application, the persistence of data is done using Google Firebase. Firebase enables us to use a cloud based Realtime Database giving the application seamless persistence updates.

1.5 Problem statement

The problem we attempt to solve is the emergence of serious health issues related to lack of physical exercise, and mental health issues that arise as a consequence of feeling isolated from other people. As described in section 1.2 these issues are currently plaguing society and currently are not slowing down in terms of their growth rate.

1.6 Aim

We aim to create an application that will allow the users to communicate with their friends while also providing incentive to go out and pursue new experiences, thereby providing connectivity between peers and physical play which in return improves the overall health of the users.

2. Methods and Materials

2.1 Materials

During the design phase we brainstormed ideas for which application to make, getting inspiration from existing applications on the App Store. Once we settled on SnapChallenge we used draw.io to create the paper prototype of the possible designs which we presented to other people for improvements before making the final design of the application which uses metaphors for describing the navigation and functionality presented to the user.

In order to produce the application we used Xcode with Swift. Testing the prototype was done using an iPad 2018. The artwork used in the application was found using Google images. Data persistence was handled using Google Firebase enabling the distributed nature of the application and allowing us to mock data for testing the functionality.

2.2 Methods

In the initial idea generation phase we used brainstorming and searched for inspiration by looking for ways to improve upon existing applications.

Once the idea was settled, we did some simple design paper prototypes using draw.io.

We presented the paper prototypes to some potential users and received feedback consisting of the following points:

  • The amount of text is too excessive.
  • The challenges should be viewable after they are completed.
  • There should be a score for how well the challenge was completed.
  • More ways to issue challenges would be entertaining.

From this feedback we refactored the design to use a much more image based approach which was an improvement according to the potential users.

The implementation of the application follows the MVC design pattern using the Firebase Realtime Database for persisting data.

3. Results

3.1 Design

Using the feedback we received from the potential users we generated a final paper prototype from which the design of the application was based. The first part of the application is a login page where the user either logs into their account or registers a new account. Once the user is logged in, the application opens the first page which has a view of the camera as the background and four buttons. The button in the lower left of the screen creates a challenge by snapping a picture using the camera and transitioning to another view where the user can write a small caption, before choosing who to send the challenge to from a table view.

The design process has been happening iteratively, an example of this is the below images showing how the design of the table, used to send challenges, has changed as we realised there was a better solution. The first image shows how the first version of sending challenges worked by having to send each challenge separately, updating the Firebase database with operation.

The improved solution allows the user to highlight each of the friends they wish to send their challenge to and handles the update of the database all at once with the use of a single button instead.

Returning to the main screen, the button in the lower right side of the screen is the friend list button. Pressing this button will redirect the user to a screen with a table view where each friend associated with the account is stored. The purpose of the friends list is to give the user an overview of the users associated  with the account. The friends list has an “Add Friend” button allowing the user to expand his circle of friends.

The top right of the initial screen with the camera shows pending challenges to be accepted or rejected by the user. The middle of the button will display a number representing how many challenges are pending judgement. If no challenges are pending, the button will be blue and show a “0” in the middle, while a red button represents pending challenges.

The top left corner button represents existing conversations. Pressing this button opens a tableview showing each challenge the user has received or sent. Pressing an item in the table view shows the post and allows the user to vote on it. Furthermore the user can press the “See On Map” button to open a map showcasing where the image was taken.

To show how the application is navigated we have created a UML flow diagram.

3.2 Implementation

The source code can be found here: https://bitbucket.org/iosprogrammingsdu/snapchallenge

 

The implementation of SnapChallenge as mentioned in section 2.2 uses MVC. This made it quite straight forward to separate the data and the business logic in the application.

The layout of the application was designed for the iPad used for testing the application. This means it may not look optimal on all devices and simulators that run it, though most screens should.

3.2.1 View

The views in the application are made using the storyboard feature of Xcode, which is a drag and drop user interface builder. The storyboard allows for components such as buttons, labels, textfields and many more to be created using XML. We used this to design the application GUI. These views work very well with the controllers as buttons, labels and more can be defined in Xcode using the drag and drop feature to create links between view components and the controller actions. Furthermore we used the storyboard to facilitate the navigation of the application. This was done using the navigation controller which is a built in part of the storyboard providing a back button for each screen after the initial screen. Due to the application using auto login we use 2 separate navigation controllers, preventing logged in users accidentally navigating to the login screen. Some navigation is also handled in code when the transition requires more complicated logic.

3.2.2 Controllers

The controllers are created as Swift files in the ViewControllers folder. The controllers implement the UIViewController class which is part of the UIKit package. This gives them the ability to import directly from the views when they are linked in the storyboard. The controllers have the viewDidLoad() method which is called once the view is loaded allowing us to edit and customize the items on the view.

SnapChallenge has 11 views, each with different responsibilities.

As an example of how a view is initialized, the viewDidLoad() method of the main view controller called ViewController is shown below

override func viewDidLoad() {
        super.viewDidLoad()
        data = DataLayer()
        self.navigationItem.hidesBackButton = true
        //deal with notifications here
        locationManager.requestAlwaysAuthorization()
        ChallengesButton.backgroundColor = UIColor.blue
        ChallengesButton.titleLabel?.text = "0"
        let userName = UserDefaults.standard.string(forKey: "userName")!
        data?.getConversationsOfUser(userName: userName, completion: { (conversations)  in
            for id in conversations {
                self.data?.getPostsOfConversation(conversationId: id, completion: {(conversationPosts) in
                    let filtered = conversationPosts.filter({(post) in
                         !post.acceptedBy.contains(userName) && !post.rejectedBy.contains(userName)
                    })
                    self.posts.append(contentsOf: filtered)
                    self.ChallengesButton.titleLabel!.text = self.posts.count.description
                    if(self.posts.count > 0) {
                     self.ChallengesButton.backgroundColor = UIColor.red
                    }
                })
            }
        })
    }

Besides the initialization it is possible to attach actions to the buttons and labels by creating actions that defines the logic of a view component. This can be very useful in cases where data needs to be passed from one controller to the next or something needs to happen on the current view. The challenge() method shown below from the ChallengeViewController is used to send all data needed for a challenge to the ChallengeFriendsTableViewController where the ChallengeFriendsTableViewController uploads it to Firebase based on which friends the user challenges.

func challenge() {
        let vc: ChallengeFriendsTableViewController? = 
                      self.storyboard?.instantiateViewController(withIdentifier: 
                      "ChallengeFriendsTableViewController") as? ChallengeFriendsTableViewController
        if let validVC: ChallengeFriendsTableViewController = vc {
            validVC.post = Post.init(author: UserDefaults.standard.string(forKey: "userName")!, 
                           image: previewImage!.pngData()!, 
                           infoText: descriptionTextField.text, latitude: self.latitude, 
                           longitude: self.longitude)
            self.navigationController?.pushViewController(validVC, animated: true)
        }
    }

This method is called from the sendButtonUp action method which is linked to the button on the ChallengeViewController.

@IBAction func sendButtonUp(_ sender: Any) {
        challenge()
    }

Table views are used widely throughout the application to showcase data in a way that is easy for the user to understand and use. The implementation of table views can be done in multiple ways and each of the table views in the application is created differently. Though this is the case a few things are needed for a table view to function properly.

The first thing a table view needs is a table view cell. A table view cell is created by using a class which extends the UITableViewCell class. The following example showcases the code used for the friends list table view. This is a very simple table view containing two labels in each cell. The first code shows the custom cell class which defines the labels and a method for what the cells contain.

class FriendsListCell: UITableViewCell {
    
    @IBOutlet weak var nameView: UILabel!
    
    @IBOutlet weak var scoreView: UILabel!
    
    func setUser(user: User){
        nameView.text = user.userName
        scoreView.text = "\(user.score)"
    }
}

This is then used in a table view controller which is defined by having the tableView methods which define the number of rows and the contents of each row. The code for these methods is shown below.

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return users.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let user = users[indexPath.row]
        
        let cell = tableView.dequeueReusableCell(withIdentifier: "FriendsListCell") as! FriendsListCell
        cell.setUser(user: user)
        return cell
    }

3.2.3 Model

The model for the application is designed to be used with firebase. This means that the Model folder in the source code contains classes that represent the objects that are to be found in the cloud database. There are three classes that model the objects in Firebase, these are the Conversation, Post and User files. The classes act as templates for which attributes should be stored in Firebase. Below is the Swift file detailing the User class and how the user is stored in firebase for comparison.

class User{
    let userName:String
    var score:Int
    var friends:Array<String>
    var id:String
    
    init(userName:String, score:Int,friends:Array<String>,id:String) {
        self.userName = userName
        self.score = score
        self.friends = friends
        self.id = id
    }
}

The connection to the Firebase database is handled in the Data folder though the use of the DataLayer file. The DataLayer file is implementing the Firebase API to handle updates and creation of new users, posts and conversations. The functions in the DataLayer file work asynchronously with the use of callback methods. These callback methods are used for creating and getting users, adding friends to friends lists, fetching conversations and every other operation that requires the data. An example of a callback method is shown below.

 func logIn(userName:String, password:String,completion: @escaping (_ user:User)->()){
        ref.child("Users").queryOrdered(byChild: "userName")
            .queryEqual(toValue: userName).observe (.value) { (snapshot) in
                snapshot.children.forEach({ (snap) in
                    let convSnap = (snap as! DataSnapshot).value as! [String: AnyObject]
                    //10 ud af 10 sikkerhed
                    let dbPassword:String = convSnap ["password"] as! String
                    let dbScore: Int = convSnap ["score"] as! Int
                    let dbFriends: String = convSnap ["friends"] as! String
                    let dbId: String = (snap as! DataSnapshot).key
                    if password == dbPassword{
                        completion(User(userName: userName, score: dbScore, 
                                   friends: dbFriends.components(separatedBy: ","), id: dbId))
                    } else {
                        completion(User(userName: "failure", score: 0, friends:[],id:"noid"))
                    }
                    return
                })
                completion(User(userName: "failure", score: 0, friends:[],id:"noid"))
        }
    }

4. Discussion

4.1 General discussion

The end result of the development process produced a functional prototype, we believe the application is fun and simple to use. Depending how the users decide to use the application it certainly has the potential to increase the physical activity of the user and connect the user to their peers. The application is by no means a solution to fix obesity or mental health issues in a large regard but it might function as a supplement to, dedicated exercise for physical health, and counseling for mental health issues.

The evaluations we received from the users were positive, in general they liked the concept and gave us good input that we put to use in the development of the application. Especially the design input provided by the potential users were put to use and applied in the application. The feedback that was not implemented in the prototype was mainly due to time restraints and has been added to the future work section.

The application has both pros and cons. The pros of the application is that it has a very low learning curve and can be used by almost anyone. The concept is new and fun for the users while incentivising physical play with the use of sensors.

Some cons of the application is that the layout is inconsistent in the current iteration, the database actions are somewhat unoptimized because they are running asynchronously meaning they are somewhat unpredictable at times.

Compared to our main rival, which would probably be SnapChat, we are still behind them in terms of quality. This is no real surprise seeing how SnapChat is a major company with many talented engineers working full time on the platform, but we believe we captured the essence of what both SnapChat and our application were aiming for. This means that even though we are behind in terms of functionality and design, the prototype was a success.

4.2 Future Work

Mostly due to the time constraints there were features and qualities we envisioned for the application that did not get implemented. These improvements are listed below:

  • Public Challenges.
  • Scoreboards.
  • More ways to issue challenges.
    • Sound based.
    • Guess what to snap based on a caption.
  • Further improving of the UI

If we were to continue the project we would certainly start with these improvements. Furthermore we would do more user testing to get even more feedback on possible improvements to the application.

4.3 Conclusion

We conclude that the project was a success in regard to the description of the portfolio task and what we hoped to develop with this assignment.

5. References

[1] World Health Organization. (2018). Obesity and overweight. [online] Available at: http://www.who.int/news-room/fact-sheets/detail/obesity-and-overweight [Accessed 10 Nov. 2018].

[2] Danskernes sundhed. (2018). Sundhedsstyrelsen. Available at: https://www.sst.dk/da/udgivelser/2018/~/media/73EADC242CDB46BD8ABF9DE895A6132C.ashx [Accessed 10 Nov. 2018]

[3] World Health Organization. (2018). Facts and figures on childhood obesity. [online] Available at: http://www.who.int/end-childhood-obesity/facts/en/ [Accessed 10 Nov. 2018].

[4] Richardson, T., Elliott, P. and Roberts, R. (2017). Relationship between loneliness and mental health in students. Journal of Public Mental Health, 16(2), pp.48-54.

[5] Snapchat.com. (2018). Snapchat – den hurtigste vej til at dele øjeblikket!. [online] Available at: https://www.snapchat.com/l/da-dk/ [Accessed 15 Nov. 2018].

Leave a Reply