– by Camilla Voigt (camkr16) og Jonas Lagoni (jolag16)

Click me to view the video of the application.

1. Introduction

The idea

The idea for this project was to produce an application for roofers in Denmark, to make it possible to calculate and prepare chords and make sure that the employer calculates the salary correctly for the individual roofer.

When a roofer (or a roofer team consisting of 2 persons) has finished a building-project, the roofer has to make a chord accounting for the activities they have done at the roof. An activity could be “Top felt” or “Under felt”. Each activity has serval properties:

Pos number: The unique id for the activity
Type: The name/type of the activity
Quantity: The quantity of the activity
Unit: The unit of the quantity could be m2, lbm, pcs
Price: The price for exactly one quantity
Amount: The price multiplied with the quantity

Problem statement

The challenge for the roofer today is, that they have to use the psysical handbook (made for roofers) to look up each activity for finding the above properties which will constitute the total accounting. The accounting is both time consuming and not an activity that a roofer wants to do because mistakes easily can be made. A mistake could be that the roofer forgets to add an activity to the accounting (and will otherwise not get payed for this activity), the roofer notes a wrong price for the activity or the roofer is adding a wrong activity. Instead of prepare an accounting by them self, they contact their Union 3F which offers to inspect the roof and prepare the accounting for free. The Union is doing the accounting the same way as a roofer do it, but mistakes is avoided.

To reduce time-wasting we made a dictionary which makes it both easy and quickly to look up an activity, add it to a building-project and adjust the amount for the specifik activity. The roofer will then be able to export a final accounting for the building-project and send it to the empolyer. This solution is made both for the roofer and Union and makes it possible to prepare the accounting at the roof and not only when you sit behind the desk again.

A final accounting, made by the Union, looks like this:

2. Methods

Through the project we have used some methods to structure the development of the application.

Brainstorm

To ensure that all requirements in the project-description was met, we made a brainstorm of all the potential ideas that could be made. We also discussed which functionalities and UIkits we wanted to use and deal with. After the brainstorm and considerations about funtionalities, we quickly found out, that it could be fun and interesting to work with a stakeholder which had some real interest in the project and could give us some user-requirements to work with. Based on these considerations and conversations with friends and acquaintances we found out, that there was an actual need in the construction industry which could be interesting to work on with.

Customer meeting

After the brainstorm we contacted a friend (from now on our “costumer”) who had a good and in-depth knowledge with the construction industry. We had a loose dialog about the challenges with the chord accounting and how to remedy the challenges. We started to deduce some user stories from the loose dialog and became aware of, that a meeting with our customer was necessary for a better understanding about the underlying functionalities and which data must be treated and extended for the end-user, and for further use by the employer.

We packed the car and drove towards our customer. Our customer clarified the necessary functionalities to derive the value propotion of the application. Out customer took us through the process of how to record and complete a chord account from start to finish to give us a better understanding of the roofers work flow.

User stories

From the customer meeting we deduced and prioritized the following user stories:

  1.  As a user, I want to be able to add activities to a selected project
  2.  As a user, I want to be able to view previous projects and it’s activities
  3.  As a user, I want to edit og delete activities on a selected project
  4.  As a user, I want to take and add pictures to a selected project.
  5.  As a user, I want to save my projects and activities locally on the phone
  6.  As a user, I want to select between my added projects
  7.  As a user, I want to export my projects as a PDF-file
  8.  As a user, I want to add new projects

It’s important to mention, that not all of the above user stories was implemented as a functionality in the final prototype. This will be elaborated in section 3.X.

Prototyping

From the first and loose dialog with our customer, we made the first edition of our prototype. The prototype is created in draw.io and gave us a good overview of how the application should look like. The first prototype united our ideas and perceptions of how the application should work in practice.

After the actual customer meeting we found our system boundaries and therefore could limit the core functionalities. This leaded to a new and more simple prototype without unnecessary functionalities. The result of the prototypes is shown in section 3.

3. Results

Prototype v.1

First version of the prototype containing functionalities deduced from the first conversation with the customer.

Prototype v.2

Second version of the prototype containing core functionalities deduced from our customer meeting.

Final navigation diagram from the prototype

This navigation diagram is the final version based on the prototypes but altered since we found out that the layout of V.2 was not really that user-friendly, and hard to navigate even for us developing the application. This layout does not include the image browsing and photographing, but since none of the other prototypes included this we decided not to include this in the final navigation diagram.

Initial class diagram

Our initial class diagram was somewhat kept towards the end, however we quickly learned that the more special UI elements, such as table and collection view had to have their own class implementations for them to function. Furthermore we quickly realized while introducing these new classes, that some of them depended open being notified when certain changes occurs. This was a perfect example where the observer pattern would come in hand.

 

Final class diagram

For our final class diagram things have changed a bit. As introduced in 3.2.1 the observer pattern introduced the ObserverController along side ObserverProtocol.

The InitialActivitiesJson was changed to associate with the new class InitialActivityJson which is similar to Activity but without the volume. Introducing a superclass BaseActivity to Activity and InitialActivityJson would reduce duplicate code improving the code.

It is also implicit that some of the UI controllers are using the classes Project, Activity and Photos but for the sake of clarity the associations are not shown on the class diagram.

In regards to the MVC pattern our controllers, LocalStorage and ObserverController does not have direct access to the view. In regards to the views they are not in control of directly affecting the models, they are only using the values on the models to display them to the user, and let the controllers know when the user wants to change something. Therefore complies with the MVC pattern. For further development splitting the functionality of LocalStorage and the StorageProtocol would improve the maintainability of the app and would likely be the next step in development.

The Code

Borrowed Code

For the SerachBar implementation we have copied and used the code from raywenderlich.com.

For the UICollectionViewController and UITableViewController we have used copied and used the code from StackOverflow.

Code Library

To see the full implementation, click here.

ObserverController

The application is centered around the ObserverController class and LocalStorage. The ObserverController is handling all possible observers. ObserverController contains a dictionary with all observers where key is an enum of possible observers and value is an array of observers.

class ObserverController{
    enum PossibleObservers{
        case SelectedProject, NewActivity, ActivityAmountChanged, NewProjectAdded
    }
    
    var observers : [PossibleOberservers : [ObserverProtocol]] = [:]
    var selectedProjectId: Int?

 

The function addNewObserver is simply adding a new observer and a listener, to the dictionary of observers. If the new observer does not exist, the new observer is created with a new array of listeners.

    func addNewObserver(observerType: PossibleObservers, listener: ObserverProtocol){
        if observers[observerType] != nil{
            observers[observerType]?.append(listener)
        } else {
            observers[observerType] = [listener]
        }
    }

 

When setSelectedProject is called with a projectId as parameter, it calls the function callListerners which calls the listeners connected with the projectId.

    private func callListeners(forObserverType: PossibleObservers, para: Any){
        if let listeners = observers[forObserverType]{
            for listener in listeners {
                listener.eventHappened(typeOfChange: forObserverType, para: newValue)
            }
        } else {
            print("No listeners for \(forObserverType)")
        }
    }

    func setSelectedProject(newSelectedProjectId: Int){
        selectedProjectId = newSelectedProjectId
        self.callListeners(forObserverType: ObserverController.PossibleOberservers.SelectedProject, newValue: newSelectedProjectId)
    }

4. Discussion

What could be better

Currently the selectedProjectId is located on the ObserverController which might be a bit in violation with the observer pattern since the controller should not contain any other functionality then letting observers know changes has happened. Therefore relocating this variable to maybe a new class might be better in regards to maintainability.

The UI for TabelViews e.g. ActivityTable could be more user-friendly and contain a better overview and a bit more information about each activity. Right now, the information about each activity is unmanageable and it’s not totally clear for the user, what each information cover.

If any errors happens, the user is never alerted and the error is only shown in the log.

Potential rivals

As we know, no other has made a similar application. We actually don’t know how the Union 3F is doing the chord accounts, therefor it could be interesting to contact the Union to know their workflow also in relation to future expansion.

Future expansion and improvements

Do to time constraints we did not implement the functionality of exporting the project, deleting a specific project, activity or photo and viewing a fullscreen version of a photo.

To continue this project we would need to implement the missing functionality and clean up the LocalStorage class so it does not resemble a god class. Further we believe that this app could easily be branched into other areas such as carpentry, masonry and such.

Conclusion

Overall we made an succesfull application for the roofing industry with minimal functionalities. We wanted to develop a complete application with alle the deduced functionalities, but because of lack of time, it wasn’t possible. The application is open for future development in form of more functionalities and expansion to other industries. Furthermore it would be interesting to meet the Union 3F to examine if our application actually could be used by the Union or/and the Roofer and deduce more functionalities that could be useful.

Leave a Reply