The Overview

Before tackling this project, I had never touched Xocde, which is an integrated development environment for mac operating systems, and contains software development tools developed by Apple for developing application software for apple devices. After learning how to make mobile web application during a college course, it was only logical for me to take a follow on class that dealt with creating native applications, using Apple’s Xcode application creation software.

For the project I wanted to create a intuitive tipping calculator that was easy to download and use with any confusion. Within this case study I’ve be explaining how from inception, to design, to implementation, and finally to becoming fully functional.

The Context and Challenge

Background

In the fall of 2017, while attending Drexel University, I enrolled in Interactive App Design I, a course that focused on creating a user experience that was optimized for mobile devices. In the course, students learned to build unique web applications that would take advantage of modern mobile capabilities. While discussing possible class projects for me to undertake, it was suggested that due to the frequency in which I dine out, I should create a web application tipping calculator. I thought it was great prospect.

uTip Calculator has been 20 weeks in the making. The few weeks involved developing the app icons, button icons, basic user interfaces and creating responsive functionality that would display, or not display, certain content based on if screen orientation of the mobile device is in landscape or portrait mode. at the end of the ten weeks, I had a fully functioning web application prototype that allowed for me to input a single set of numbers and then use a slider to adjust the tip percentage; combined this gives any user their grand total with tip.

The whole reason, I got into this career field was for the prospect of working with mobile apps. Interactive App Design I allowed me create a web application. It was fun and I learned a lot, but to me, it wasn’t a true application; just a website that you can save to your home screen on you phone. Interactive App Design II, however, built upon the topics covered previously by exploring how to convert web-based applications into cross-platform native applications for mobile devices using Xcode.

The Problem

The genesis of uTip Calculator was born out of my wife and I’s desire to frequently eat out and try new foods. We probably eat out two or three times a week. At the end of every meal I would pull out my iPhone and use the device’s default calculator app, input the bill amount, multiply it by whatever tip percentage I felt was warranted, then calculate that tip amount back into the bill amount to get the total amount owed. A very tedious effort and not very efficient. It never really occurred to me to download a tipping calculator application; for that matter, I didn’t even realize there were tipping calculators. This tipping calculator would seek to solve the issue of inconvenience; because let’s face it, after a good meal, when you are full and sleepy, do you really want to do math?

Goals & Objectives

Working solo, I went into this project with just one simple goal in mind: make a tip calculator that works! Over time that goal expanded outward and milestones along the way were more clearly defined. Functionality was always paramount, with any type of user interface being secondary and only serving to present that functionality in a logical way. When I developed the web app version of the calculator, knew that I wanted to only wanted to have one input field with the tip percentage adjustment functionality being carried over by a slider. I wanted the app to be simple and easy to use. This mindset carried over to the native app. But after doing a bit of research, and looking at other tipping calculator apps, I knew I also wanted to add a split check feature; and this, too, would be executed using a slider. Once I defined and refined the objectives, I set out make those goals accomplishments.

The Process and Insight

I went about creating this application for my own needs. However, I think it’s safe to say that pretty much everyone goes out to eat once in a while. So the target audience for this app, is literally anyone with a smart phone; but more specifically, since I used Xcode, anyone with an iPhone. What follows is the processes I went through to create uTip Calculator …

The App Icon: One first things I did, was to implement the app’s home screen icon into the assets folder in Xcode. I used the same icon that I used for the web version. The color scheme for the app wasn’t going to change even though I had planned on making some significant user interface changes.  Because There are many different screen sizes and resolutions for a the various apple devices, Xcode encourages you upload various sizes on the same icon. In order to efficiently create all the required icon sizes I uploaded my template onto an online resource, makeappicon.com.

The App Wireframes: As you can see that a lot of these initial designs are a little far removed from the finalized design; especially, the area for splitting the check. The first wireframe shows buttons instead of a slider, with an extra button that allows for additional inputing of numbers. I never fully thought through how the app would respond to the “Other” button being clicked; Would it have created a popup with an input field, or just show additional numbers. One thing I was sure on was that not only did I want the user to see the tip amount, but also what the tip percentage was. The idea I had, was to have the the label that says, “Calculated Tip (15%):” to update the default percentage of “15%” every time the user used the slider.


The second iteration of the design, as you can see from the Xcode screenshot below, was a bit more refined. I was hear that the vision of the app started to come together. You’ll notice in how it contrasts with the wireframe above. Firstly, I got ride of the split check buttons and replaced them with a slider. I also switced the placements of the “Total Amount Owed” and “Bill Amount” textfields and input fields. This was not just an aesthetic choice logical one, as it makes the typing easier if the editable areas are on the bottom close to fingers and thumbs. Finally, I placed a bit of style adding more color and adjusting the font sizes based of the hierarchal importance of content. At this point in the process, the only working functionality was the ability to enter numbers into the bill amount input field.


Probably the most significant change for the third and final iteration of the wireframes for the calculator’s interface was to remove the white text boxes around all text fields that don’t allow for inputing data. Not only does make it less confusing to the user but it makes the bill amount input field standout, and in a sense directs the user to their first step. At this point, there was still only minimal functionality. But that was about to change.


Code/Dev

One of the first real hard coding I did for the application was create a static output value of $25.00 for the total amount owed and a value of 20% on the tip percentage label. The purpose of this was two-fold: first, outputting these static values helped me gain a better understanding of how coding in Xcode works; second, it also gave me an avenue to explore on how I would code this particular application. You’ll notice in the calculator’s Xcode hosted user interface on the left that there are only symbols in the aforementioned fields; but when this interface is played through the prototype on the right, they are given values.

This is code what I used to output the static data:

uTipCalc.swift

//  uTipCalc.swift
//  uTip Calculator
//
//  Created by Corey Hensley on 3/5/18.
//  Copyright © 2018 Corey Hensley. All rights reserved.
//

import Foundation

class TipCalc {
    var tipAmount: Float = 0
    var enterBillAmount: Float = 0
    var tipPercentage: Float = 0
    var totalAmount: Float = 0
    
    init(totalAmount: Float, tipPercentage: Float){
        self.totalAmount = totalAmount
        self.tipPercentage = tipPercentage
    }
    
    func calculateTip() {
        tipAmount = totalAmount * tipPercentage
        enterBillAmount = tipAmount + totalAmount
    }
}

FirstViewController.swift

//  FirstViewController.swift
//  uTip Calculator
//
//  Created by Corey Hensley on 2/2/18.
//  Copyright © 2018 Corey Hensley. All rights reserved.
//

import UIKit

class FirstViewController: UIViewController {
    // MARK: - IBOutlets
    @IBOutlet weak var billAmountResult: UITextField!
    
    @IBOutlet weak var tipPercentageLabel: UILabel!
    
    @IBOutlet weak var tipPercentageResult: UITextField!
    
    @IBOutlet weak var splitCheckResult: UITextField!
    
    @IBOutlet weak var enterBillAmount: UITextField!
    
    @IBOutlet weak var numberOfPeopleSlider: UISlider!
    
    @IBOutlet weak var tipPercentageSlider: UISlider!
    
    //MARK: - Properties
    var tipCalc = TipCalc(totalAmount: 25.00, tipPercentage: 0.2)
    
    // MARK: - View Controller Lifecycles
    override func viewDidLoad() {
        super.viewDidLoad()
        
        billAmountResult.text = String(format: "%0.2f", arguments: [tipCalc.totalAmount])
        tipPercentageLabel.text = String(format: "Calculated Tip (%d%%):", arguments: [Int(tipCalc.tipPercentage * 100)])
    }
    
    func calcTip() {
        tipCalc.tipPercentage = Float(tipPercentageSlider.value)
    }
}


With some basic code to give me direction, I worked to implement all the pieces I needed: outputting a value from the sliders; calculating the bill amount with a user desired tip percentage, and outputting the total amount and tip amount; and finally dividing the total amount to split the check by whatever the user desires.

The below code reflects the strides I made in making this vision a reality:

uTipCalc.swift

//  uTipCalc.swift
//  uTip Calculator
//
//  Created by Corey Hensley on 3/5/18.
//  Copyright © 2018 Corey Hensley. All rights reserved.
//

import Foundation

class TipCalc {
    var splitCheckAmount: Float = 0
    var tipAmount: Float = 0
    var billAmount: Float = 0//amountBeforeTax
    var splitCheckValue: Float = 0
    var tipPercentage: Float = 0
    var totalAmountOwed: Float = 0
    
    init(splitCheckValue: Float, tipPercentage: Float, billAmount: Float) {
        self.splitCheckValue = splitCheckValue
        self.tipPercentage = tipPercentage
        self.billAmount = billAmount
        
    }
    
    func calculateTip() {
        splitCheckAmount = totalAmountOwed / splitCheckValue
        tipAmount = billAmount * tipPercentage
        totalAmountOwed = tipAmount + billAmount
    }
}

FirstViewController.swift

//  FirstViewController.swift
//  uTip Calculator
//
//  Created by Corey Hensley on 2/2/18.
//  Copyright © 2018 Corey Hensley. All rights reserved.
//

import UIKit

class FirstViewController: UIViewController, UITextFieldDelegate {
    // MARK: - IBOutlets
    @IBOutlet weak var totalAmountOwedResult: UITextField!
    @IBOutlet weak var tipPercentageLabel: UILabel!
    @IBOutlet weak var splitCheckLabel: UILabel!
    @IBOutlet weak var tipPercentageResult: UITextField!
    @IBOutlet weak var splitCheckResult: UITextField!
    @IBOutlet weak var billAmountEntered: UITextField!
    
    @IBOutlet weak var splitCheckSlider: UISlider!
    @IBOutlet weak var tipPercentageSlider: UISlider!
    
    //MARK: - Properties
    var tipCalc = TipCalc(splitCheckValue: 20.00, tipPercentage: 0.15, billAmount: 25.00)
    
    // MARK: - View Controller Lifecycles
    override func viewDidLoad() {
        super.viewDidLoad()
        
        splitCheckLabel.text = String(format: "Individual Total for 1:", arguments:
            [Int(tipCalc.splitCheckAmount)])
        tipPercentageLabel.text = String(format: "Calculated Tip (%d%%):", arguments:
            [Int(tipCalc.tipPercentage * 100)])
        totalAmountOwedResult.text = String(format: "%0.02f", arguments:
            [Int(tipCalc.billAmount + tipCalc.tipAmount)])
    }
    
    func calcTip() {
        tipCalc.splitCheckValue = Float(splitCheckSlider.value)
        tipCalc.tipPercentage = Float(tipPercentageSlider.value / 100)
        tipCalc.billAmount = (billAmountEntered.text! as NSString).floatValue
        tipCalc.calculateTip()
        updateUI()
    }
    
    func updateUI() {
        splitCheckResult.text = String(format: "$%0.02f", arguments:
            [tipCalc.splitCheckAmount])
        tipPercentageResult.text = String(format: "$%0.02f", arguments:
            [tipCalc.tipAmount])
        totalAmountOwedResult.text = String(format: "$%0.02f", arguments:
            [tipCalc.billAmount + tipCalc.tipAmount])
    }

    // MARK: UIControl Events
    
    @IBAction func billAmountEnteredChanged(_ sender: AnyObject) {
        calcTip()
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        if textField == billAmountEntered {
            textField.resignFirstResponder()
            calcTip()
        }
        return true
    }
    
    @IBAction func splitCheckSliderValueChanged(_ sender: AnyObject) {
        splitCheckLabel.text! = String(format: "Individual Total for %1d%:", arguments:
            [Int(splitCheckSlider.value)])
        calcTip()
    }
    
    @IBAction func splitCheckSliderSnaps(_ sender: UISlider) {
        splitCheckSlider.value = roundf(splitCheckSlider.value)
    }
    
    @IBAction func tipPercentageSliderValueChanged(_ sender: AnyObject) {
        tipPercentageLabel.text! = String(format: "Calculated Tip (%1d%%):", arguments:
        [Int(tipPercentageSlider.value)])
        calcTip()
    }
    
    @IBAction func tipPercentageSliderSnaps(_ sender: UISlider) {
        tipPercentageSlider.value = roundf(tipPercentageSlider.value)
    }
    
    
    // MARK: Pushing Content Up w/ Active Keyboard
    
    func textFieldDidBeginEditing(_ textField: UITextField) {
        movTextField(textField: textField, moveDistance: -250, up: true)
    }
    
    func textFieldDidEndEditing(_ textField: UITextField) {
        movTextField(textField: textField, moveDistance: -250, up: false)
    }
    func textFieldShouldClear(_ textField: UITextField) ->Bool {
        textField.resignFirstResponder()
        return true
    }
    
    func movTextField(textField: UITextField, moveDistance: Int, up: Bool) {
        let moveDuration = 0.3
        let movement: CGFloat = CGFloat(up ? moveDistance : -moveDistance)
        
        UIView.beginAnimations("animateTextField", context: nil)
        UIView.setAnimationBeginsFromCurrentState(true)
        UIView.setAnimationDuration(moveDuration)
        self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
        UIView.commitAnimations()
    }
    
}

Solution and Results

As you can see from the video below the app works! It was quite a process to get to this point. I would that probably the most taxing challenge I faced was getting the sliders to snap to designated whole values. At first I didn’t even contemplate that the sliders not snapping to values would be an issue, as they still worked at outputting a value. The problem was, I wasn’t getting precise tip percentages, nor was I getting precise split check numbers. The solution here was rethinking certain aspects of the code, going back to basics rethinking my approach to the code. Some key feature include: the keyboard pushing the content up so the user can see what they are typing into the input field; Both the tip percentage and split check labels, update with a value based off slider position.

On a whole I find the app a success. Given more time, I would like further develop the interface and refine the user experience. Perhaps in future updates I can create a rating system for the places, I’ve used my app in. This was a great experience, and got me excited to do more with mobile apps in the future.