BrokenSDU

Christos Anestis Georgiadis – chgeo17

Emil Hannibal Nygaard Frisk – emfri13

https://bitbucket.org/anestis274/brokensdu/src/master/

Introduction

For the purpose of this course, we had to develop an IOS application that meets some specific requirements. Moreover, we had to develop an application that has gamification characteristics and uses some basic IOS application properties. We came up with the idea to develop an application that will not only be fun to use but also useful. After brainstorming was decided to develop an application that would be useful for the SDU but also for the students. Thus, our brainstorming leaded us to the problem of maintaining buildings infrastructures.

This is a very complex task ranging from repeatable day to day activities to larger and sometimes vital damage repairs. It is not a stretch to say that there is a lot more people using a facility, than there are people maintaining it. There is nothing wrong with that, but in the group of people who only use it, there lies valuable knowledge of the buildings condition seen from their perspective. This is especially true for a place like a university, where the people using it comes there every day for years.

Before going too deep in brainstorming of solutions, we researched the domain of maintenance, to find out more of what it encompasses and who is in charge of it at SDU. Technical Service, a division of the Central Administration is in charge of maintenance of the facilities. Their webpage states the following: “Technical Services is responsible for supporting the day-to-day operations at University of Southern Denmark and ensure the best internal and external physical surroundings in close interaction with the faculties and the central administration.” For the repeatable day to day tasks of cleaning, they employ the company ISS. So, the information gathered with the tipping application would be best served by going directly to Technical Service.

But who will be using the application to tip in different maintenance needs? It will be mostly students, and possibly some faculty staff. Both groups have a daily need of the facilities and are probably first to encounter issues. There is however, not many who knows how best to contact Technical Service, if they even know Technical Service are the ones to contact regarding maintenance. So, with a tipping application, we eliminate the need to worry about where to report it too, as that will be handled for you, but is this enough to incentivize students to tip? If for some reason a project room is inoperable, will they report it with the application, or immediately try to find another accommodation to get through the day’s work in? If there really is value in receiving these tips, then some of that value could be re-invested to the tippers, to incentivize the usage of the application to report maintenance issues. You could also look at equipping the ISS staff with an application, that allows them to report issues and/or possibly report the successful fixing of an issue. Our focus though will firstly be on “normal” users, the everyday users of the facility.

But why students should use an application like this if they do not have some benefit? The answer to this problem is that they will collect “CoffeeCoins” in order to get a free cup of coffee. The result of the whole project is that university’s maintenance it will become more efficient and the students more concentrate in the class.

The application that we have developed has the name “BrokenSDU”. The above application constitutes the software that the tipper users will be using. Through this, they will be able to report issues about the area of SDU and earn “CoffeeCoins” to their wallet based on the reports that they make. The main idea of the application includes the participatory reporting of issues like trash, damages, missing inventory, etc. Users will be able to report issues like the above by text and photo and will be rewarded with CoffeeCoins based on the severity of the issue reported. CoffeeCoins can then be spent on free coffee at the cafeterias. This way we hope to make the procedure of the reporting as easy as possible. After the submitting of the report the technical service crew will evaluate the problem and send the CoffeeCoins to the user’s wallet.

 

Methods and materials

Brainstorm

We started the project out with a brainstorm. We sat down together in a room with a blackboard, and turns writing ideas on the board and explaining them to each other. We all had a lot of good suggestions.

Coarse conceptual design

When we had the idea that we were going to go with, we did a quick coarse conceptual design. We sketched out on a high abstraction level, how the application was going to function and what kind of storage we were going to use. We did this so early in the process just to get started on these important design decisions, and so that we could take that with us going into making the prototype.

Prototyping

Then a prototype of the initial conceptual design was created. We created it in the drawing program sketch, it consists of two images outlining a simple user interface with which you can carry out the use cases that we were trying to solve. The minimal viable prototype for the minimal viable product.

Evaluation

We then showed the prototypes to some test users for them to evaluate it and give us feedback. We interviewed the users one by one, while they were using the app. Seeing their reactions, when seeing the different screens for the first time and following the use cases. We did not record or write the specific interview answers down, instead we wrote down the general sense of what they expressed.

Second prototype

Then from the feedback we got from the users, we made some minor changes to the first prototype, and thus we had created a second prototype. We then showed this to some of the previous test users, who were satisfied with the changes.

Fine grained conceptual design

Now with the user feedback integrated into our concept, we started on the fine grained conceptual design.

Use cases

First we worked out the general use cases that our application had to support to solve the problem that we were working on. We thought about the problem that we are are solving from different angles, to figure out how the use cases should look, to support that in the best possible way.

We modeled every use cases with a use case description.

 

Use case <identification of the use case>
Summary <brief description of the use case>
Actor <name of actor activating the use case>
Precondition <prior condition that must be met for the use case to be executed>
Description Basic path

<use case> INITIATES WHEN <actor> <activity>

  1. [<predcondition>] <actor> | <entity> <activity> [<restriction>]
  2. [<predcondition>] <actor> | <entity> <activity> [<restriction>]

      n) [<predcondition>] <actor> | <entity> <activity> [<restriction>]

Alternative path

<Event>

  1. <actor> | <entity> <activity> [<restriction>]
  2. <actor> | <entity> <activity> [<restriction>]

Post condition <condition that must be met when the execution of the use case culminates>

 

And a standard use case diagram.

We did this for the completeness and to ease the implementation phase, but most of all we did it for the way it helps you weed out possible errors with your concept, and make it the design a little (or a lot) better.

Object diagram

The natural next step was to create an object diagram, to show how the functionality of the use cases structurally were to be divided over classes (the types of which are model, view or controller). We modeled this using a UML class diagram.

 

 

Implementation

Then we implemented the application. The implementation was done using Xcode, in the Swift programming language, using no third party libraries and git with github for collaboration.

Results

Brainstorm

  • Drawing of what we did

Coarse conceptual design

You can see the artifacts of our coarse conceptual design here, it’s manifested as a couple of collages.

This first collage, is trying to visualize the general perspective from user’s point of view. The report data is going to be stored in the cloud using firebase, and when you’ve earned enough points, you can use the application to redeem a free coffee in the canteen.

The second collage, is trying to visualize a more general view of the whole project. As you can notice part of the system is also the the crew because is responsible for the evaluation of the reports and and fixing the problems.

 

Prototyping

The prototype we created is two screens, one with the login form and another screen showing the users points, a button for redeeming coffee with the points, and the form for reporting issues. The minimal design for doing the task.

Evaluation

Interviewee 1

  • Immediate reaction was positive
  • Giving coffee for the reports is great incentive
  • Might be a good idea to have the points and redeem button on a separate screen

Interviewee 2

  • Coffee good idea
  • Simple user interface
  • Points and redeem by itself

Interviewee 3

  • Annoying that you have to log in
  • Besides user interface easy to use
  • Coffee is good incentive

What we took away from this is that coffee is a great incentive, and that we had to put the points and the redeem button on a screen by itself.

Second prototype

The updated prototype, has an extra screen with the points and the redeem button by itself.

 

When interviewee 1 and 2 were showed this, they expressed that they thought it to be satisfactory.

Fine grained conceptual design

Use case specifications

 

Use case Log in
Summary The user logs in to the app
Actor User
Precondition <empty>
Description Basic path

Log in initiates when user opens the application

  1. If user has login credentials, user inputs them into the text fields. Else, go to alternate path.
  2. User clicks the log in button.
  3. System verifies the credentials and logs the user in

Alternate path

If user does not have login credentials

  1. The user clicks the register button.
  2. The user inputs an email address and a password into the designated text fields.
  3. The user clicks register.
  4. The system saves the credentials and logs the user in
Post condition The user is logged in (and has registered)

 

Use case Report an issue
Summary The user reports an issue
Actor User
Precondition The user must be logged in
Description Basic path

Report an issue initiates when, the user is logged in and clicks the report button

  1. The user inputs the title and description of the issue
  2. The user click the take picture button
  3. The user takes picture
  4. The user submits issue
  5. The system saves the submission and awards the user points
Post condition An issue is submitted by the user

 

Use case Redeem
Summary The user uses points to redeem coffee
Actor User
Precondition The user must be logged in
Description Basic path

Redeem initiates when the user clicks the “use” button

  1. The system shows popup with confirmation that one coffee has been paid for
  2. The user shows the confirmation popup to the canteen employee
  3. The canteen employee verifies the purchase
  4. The user clicks the “ok” button on the popup
Post condition The user has redeemed a coffee

 

 

Use case diagram

 

The use case diagrams displays the actors that interact with the different usecases. For our application there is 3 actors; user, canteen employee and the system itself.

 

Object Diagram

 

 

Implementation

In the pictures below are represented the login, register page and part of the authentication code. The authentication of the system is provided using Firebase.

import UIKit
import FirebaseAuth

class LogInViewController: UIViewController {

    @IBOutlet weak var emailTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!
    
    @IBAction func logInButton(_ sender: Any) {
        let userEmail = emailTextField.text;
        let userPassword = passwordTextField.text;
        if(userEmail != "" && userPassword != ""){
            Auth.auth().signIn(withEmail: userEmail!, password: userPassword!) { (user, error) in
                if (user != nil){
                    self.presentMainFrameScreen();
                }else{
                    var alert = UIAlertController(title:"Alert",message: "Something went wrong!", preferredStyle:UIAlertController.Style.alert);
                    let okAction = UIAlertAction (title:"Ok", style: UIAlertAction.Style.default, handler:nil);
                    alert.addAction(okAction)
                    self.present(alert, animated:true, completion:nil);                }
            }
        }
    }
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    override func viewDidAppear(_ animated: Bool) {
        if Auth.auth().currentUser != nil {
            self.presentMainFrameScreen();
        }
    }
    
    func presentMainFrameScreen(){
        let st:UIStoryboard = UIStoryboard(name: "Main", bundle: nil);
        let mainUI:MainFrameViewController = st.instantiateViewController(withIdentifier: "MainFrameViewController") as! MainFrameViewController
        self.present(mainUI, animated:  true, completion: nil);
    }
}

 

Below is presented part of the code for the user’s registration.

import UIKit
import FirebaseAuth

class RegisterPageViewController: UIViewController {

    @IBOutlet weak var userEmailTextField: UITextField!
    @IBOutlet weak var userPasswordTextField: UITextField!
    @IBOutlet weak var userRepeatPasswordTextField: UITextField!
    
    @IBAction func registerButton(_ sender: Any) {
        
        var userEmail = userEmailTextField.text;
        var userPassword = userPasswordTextField.text;
        var userRepeatPassword = userRepeatPasswordTextField.text;
        
        //Check for empty fields
        if(userEmail!.isEmpty || userPassword!.isEmpty || userRepeatPassword!.isEmpty){
            displayAlert(ms:"All fields are required.")
            return;
        }
        
        //If password match
        if(userPassword != userRepeatPassword){
            displayAlert(ms:"Passwords do not match!")
            return;
        }
        
        //Store data
        Auth.auth().createUser(withEmail: userEmail!, password: userPassword!) { (user, error) in
            if(user != nil){
                //Display alert message
                var alert = UIAlertController(title:"Alert",message:"Registration is completed!", preferredStyle:UIAlertController.Style.alert);
                let okAction = UIAlertAction (title:"Ok", style: UIAlertAction.Style.default){
                    action in
                    self.dismiss(animated: true, completion: nil);
                }
                alert.addAction(okAction);
                self.present(alert, animated:true, completion:nil);
            }else{
                self.displayAlert(ms:"Something went wrong!");
            }
        }
    }
    @IBAction func cancelButton(_ sender: Any) {
        self.dismiss(animated: true, completion: nil);
        
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    func displayAlert(ms:String){
        
        var alert = UIAlertController(title:"Alert",message:ms, preferredStyle:UIAlertController.Style.alert);
        let okAction = UIAlertAction (title:"Ok", style: UIAlertAction.Style.default, handler:nil);
        
        alert.addAction(okAction);
        self.present(alert, animated:true, completion:nil);
    }
}

 

 

The firebase class that we have developed is presented below. This class implements all the important functionality for the connection and communication with the FireBase database.

//
//  fireBase.swift
//  BrokenSDU
//
//  Created by Aa on 27/11/2018.
//  Copyright © 2018 SDU. All rights reserved.
//

import Foundation
import Firebase
import FirebaseDatabase

class FireBase {
    
    static var refReports: DatabaseReference!
    
    static func createReport(description: String,
                             
                             room: String,
                             timestamp: Date,
                             title: String,
                             userId: String) -> Bool {
        var flag = false
        let db = Firestore.firestore()
        var ref: DocumentReference? = nil
        ref = db.collection("reports").addDocument(data: [
            "title":title, "description":description, "room":room,"date":timestamp, "userId":userId])
        { err in
            if let err = err {
                print("Error adding document: \(err)")
                flag = false
            } else {
                print("Document added with ID: \(ref!.documentID)")
                flag = true
            }
        }
        return flag;
    }
    
    static func getUserID() -> String{
        return Auth.auth().currentUser!.uid.description
    }
    
}

 

Below is presented a snapshot of the report view and some part of the code. When users submit their report, the application confirm also with a sound.

import UIKit
import Firebase
import AVFoundation

class ReportViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    var dataController: DataControllerProtocol!
    var view_: ReportView?
    var userId = Auth.auth().currentUser!.uid
    
    override func viewDidLoad() {
        view_ = self.view as? ReportView
        dataController = FirebaseDataController.instance
    }
    
    @IBAction func takePicture() {
        if UIImagePickerController.isSourceTypeAvailable(.camera) {
            let imagePicker = UIImagePickerController()
            imagePicker.delegate = self
            imagePicker.sourceType = .camera
            self.present(imagePicker, animated: true, completion: nil)
        }
    }
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
            view_?.imageView.image = image
        }
        picker.dismiss(animated: true, completion: nil)
    }
    
    func playSound() {
        do {
            if let fileURL = Bundle.main.path(forResource: "sound.mp3", ofType: nil) {
                let audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: fileURL))
                audioPlayer.play()
            } else {
                print("No file with specified name exists")
            }
        } catch let error {
            print("Can't play the audio file failed with an error \(error.localizedDescription)")
        }
    }
    
    @IBAction func submitReport() {
        let report = dataController.createReport(description: (view_?.descriptionTextField.text)!, image: (view_?.imageView.image?.jpegData(compressionQuality: 0.1))!, room: (view_?.roomTextField.text)!, timestamp: Date(), title: (view_?.titleTextField.text)!, userId: userId)
        dataController.saveReport(report: report)
        playSound()
        self.dismiss(animated: true, completion: nil)
    }
}

 

 

Below is presented the code for the implementation of the HistoryTable. As you can notice tableview is used.

//
//  HistoryViewControllerTableViewController.swift
//  BrokenSDU
//
//  Created by Emil Frisk on 23/11/2018.
//  Copyright © 2018 SDU. All rights reserved.
//

import UIKit
import Firebase

class HistoryTableViewController: UITableViewController {
    var dataController: DataControllerProtocol?
    var reports: [Report] = []
    var userId = Auth.auth().currentUser!.uid

    override func viewDidLoad() {
        super.viewDidLoad()
        dataController = FirebaseDataController.instance
        dataController?.loadReports(userId: userId) { report in
            self.reports.append(report)
            DispatchQueue.main.async {
                self.tableView.reloadData()
            }
        }
        
        
        // Uncomment the following line to preserve selection between presentations
        // self.clearsSelectionOnViewWillAppear = false

        // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
        // self.navigationItem.rightBarButtonItem = self.editButtonItem
    }

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return reports.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let report = reports[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: "reportCell", for: indexPath) as! ReportCell
        cell.titleLabel.text = report.title
        cell.descriptionLabel.text = report.description_
        if let imageData = report.image {
            cell.imageView_.image = UIImage(data: imageData)
        }
        cell.roomLabel.text = report.room
        
        return cell
    }
    
    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 70
    }

    /*
    // Override to support conditional editing of the table view.
    override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        // Return false if you do not want the specified item to be editable.
        return true
    }
    */

    /*
    // Override to support editing the table view.
    override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == .delete {
            // Delete the row from the data source
            tableView.deleteRows(at: [indexPath], with: .fade)
        } else if editingStyle == .insert {
            // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
        }    
    }
    */

    /*
    // Override to support rearranging the table view.
    override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {

    }
    */

    /*
    // Override to support conditional rearranging of the table view.
    override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
        // Return false if you do not want the item to be re-orderable.
        return true
    }
    */

    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destination.
        // Pass the selected object to the new view controller.
    }
    */

}

 

A short video is presented below.

 

Discussion

The requirements for this project was to create an IOS application that has gamification characteristics and uses at least one sensor, audio, tableView, labels, buttons, CoreData and have multiple screens, etc. After of our brainstorming we have full fill all the requirements creating the “BrokenSDU”. The “BrokenSDU” is an application that could have great potential  and be very useful for the technical staff at SDU or other organizations that wishe to utilize the system. The current practice of issue reporting to the technical staff can be confusing and difficult. Having a reporting application ready at hand and rewards the users with coins towards free coffee, will help both the technical staff find the issues and the students and lecturers who use the rooms and equipment each and every day.

It was really important to design an application that will be efficient to use, so we got many times feedback from users in order to be sure for it. In the current implementation the part that missing is when users want to use their points. We could not implement this part yet because it is necessary to create a communication channel between the application, the SDU and the caffeteries.

Really interesting is that there is not any other application that could do this kind of task for the SDU. So, the next step could be to come in contact with the technical support of the SDU and cooperate in order to develop a complete and useful system for the SDU but for the students also. If something like that happened then we could implement new functionalities for the application like location detection using a combination of wifi and BLE depending on the building. Moreover, it could be more efficient if users authentication was through SDU’s authentication system and through Firebase.

To sum up, this project could evolve into something really useful for the students and also helpful for the staff of the university. When the application is completed, it will only take minutes to detect a problem and some hours for the problem to be fixed. This will make the facilities of the university a really better place with less problems.

 

 

Evaluation

If there had been more time for the project, we could have recorded and transcribed the interview. This would have made the analysis of the feedback more transparent, instead of it happening in the moment. Also if the group of interviewees had been bigger or there would have been different interviewers, this would almost be obligatory. To ease the analysis, you could also standardize the questions.

 

Leave a Reply