Aqua

iOS Programming – Portfolio 2

by Peter Stingel (pesti19)

Overview

  1. Introduction
  2. Methods and Materials
  3. Results
  4. Discussion

Introduction

This is the report that describes the application Aqua. The idea idea of the app is to help easier find places like toilets or tap water. In recent years I was cycling and traveling quite a lot. Each time when I visited a new place and wanted to find toilet I knew only about one place, which is well known to everyone – it’s McDonalds. I searched through AppStore and founds only few app which might help me to find these places, but most of them had terrible design. So, I have decided to create my own App with pleasant UI and UX.

Main goal is to create an app where user will be able easily search and find places with toilets and tap water. Each place is going to be shown on the map and user will able to navigate himself to the place. User will also be able to filter these places, list the places based on the distance from his location, make list of favourite places.

Methods and Materials

Brainstorming

One friend of mine is interested to create a same app for Android . We started with writing down the basic functionality that app should have. After evaluating, whether we are able to implement them. Once we had all this written down, we started to prototype the app look.

First prototype

We created the first prototype using an Adobe application Illustrator. We prototyped Launch and Map Screen all together with the actions you can perform on certain screen.

Evaluation

We showed the first prototype to three potential users and watched them carefully how they interact with the app. After a while we asked them for feedback, what they would liked / din’t like, would like to improve or add to the application.

Second prototype

Based on the feedback we made changed to the application and created an improved version of an application.

Use-Case Diagrams

I created general user case diagram of the basic functionality that app should support.

Implementation

Tools used in the process of creation

  • XCode – An Apple IDE for creating iOS, iPadOS, MacOs, WatchOS apps
  • Swift – programming language that app was written in
  • Frameworks
    • GoogleMapsAPI – Google API that provides all the functionality related to the maps

Results

First prototype

In first prototype we created a design for whole application, based on our personal preferences and what we thought that is missing in apps that are on market now.

Evaluation

Feedback – User no.1

  • try to hide filter menu – it isn’t necessary to see it all the time
  • it would be good to locate place directly on map
  • missing feedback form / help

Feedback – User no.2

  • did you consider creating a floating menu with control functions?
  • there is no option do enter additional details for toilet – price, access to disabled people

Second prototype

Second prototype considers feedback from users and is clearly improved version of the first one.

Use-Case Diagrams

Implementation

User location

//https://developers.google.com/maps/documentation/ios-sdk/current-place-tutorial
extension MapVC: CLLocationManagerDelegate {
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let location: CLLocation = locations.last!
        let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude,
                                              longitude: location.coordinate.longitude,
                                              zoom: zoomLevel)
        
        if mapView.isHidden {
            mapView.isHidden = false
            mapView.camera = camera
        }
        else {
            mapView.animate(to: camera)
            //Stop updating location otherwise it will call the delegate again and again
            self.locationManager.stopUpdatingLocation()
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        switch status {
            case .restricted:
                print("Location access was restricted.")
            case .denied:
                let alert = UIAlertController(title: "Location disabled",
                                              message: "In order to show current location, you need to allow localization in settings",
                                              preferredStyle: UIAlertController.Style.alert)
                alert.addAction(UIAlertAction(title: "OK",
                                              style: UIAlertAction.Style.default,
                                              handler: nil))
                self.present(alert, animated: true, completion: nil)
                mapView.isHidden = false
            case .notDetermined:
                print("Location status not determined.")
            case .authorizedAlways: fallthrough
            case .authorizedWhenInUse:
                print("Location status is OK.")
            @unknown default:
                fatalError()
        }
    }
}

Filtering places

class Parsers {
    static func localCountries() -> [String] {
        if let path = Bundle.main.path(forResource: "countries", ofType: "json") {
            do {
                let jsonData = try Data(contentsOf: URL(fileURLWithPath: path), options: .dataReadingMapped)
                let jsonResult = try JSONSerialization.jsonObject(with: jsonData, options: .allowFragments) as! [String:[String]]
                var cityNames = [String]()
                for country in jsonResult {
                    for city in country.value {
                        let city = "\(city), \(country.key)"
                        cityNames.append(city)
                    }
                }
                return cityNames
            }
            catch {
                print("Error parsing jSON: \(error)")
                return []
            }
        }
        return []
    }
    
    static func getSortedCities() -> Dictionary<Character, [String]> {
        let cities = localCountries()
        var sortedCities: Dictionary<Character, [String]> = Dictionary<Character, [String]>()
        
        if !cities.isEmpty {
            for city in cities {
                let cityLowerCase = city.lowercased()
                let firstChar = cityLowerCase.first!
                if firstChar.isLetter {
                    var unsortedCites = sortedCities[firstChar]
                    if (unsortedCites != nil) {
                        unsortedCites!.append(city)
                        
                        sortedCities.updateValue(unsortedCites!, forKey: firstChar)
                    }
                    else {
                        sortedCities[firstChar] = [city]
                    }
                }
            }
        }
        return sortedCities
    }
}

Adding autocomplete

Setting up autocomplete to search only when at least 3 characters were entered.

 func initSearchField() {
        tfSearch.delegate = self
        tfSearch.minCharactersNumberToStartFiltering = 3
        tfSearch.startVisibleWithoutInteraction = false
        tfSearch.theme.font = UIFont.systemFont(ofSize: 17)
        tfSearch.theme.bgColor = UIColor.white
        tfSearch.theme.borderColor = UIColor.lightGray.withAlphaComponent(0.5)
        tfSearch.theme.separatorColor = UIColor.lightGray.withAlphaComponent(0.5)
        tfSearch.theme.cellHeight = 50
        tfSearch.theme.placeholderColor = UIColor.lightGray
        tfSearch.tableCornerRadius = 18.0
        tfSearch.tableXOffset = -12.0
        tfSearch.tableYOffset = 8.0
        tfSearch.maxNumberOfResults = 3
        tfSearch.itemSelectionHandler = { filteredResults, itemPosition in
            let item = filteredResults[itemPosition]
            self.tfSearch.text = item.title
            self.tfSearch.resignFirstResponder()
        }
    }

Link to BitBucket

link to bitbucket

Video

Discussion

At the beginning of the course I set the goal to create an app which will help users to easier find places with toilets or tap water. This goal was accomplished partially.

In conclusion I have spent more time on graphical part of the app than I expected that I will. However many graphics changes helped the app to look more fresh and modern. For now approximately half of the functionality is working. User can find the places on the map, get their info, list the places from the map in the table view, add new place.

Parts which still need some improvement are sending places to the web server, filtering places, showing favourite places and showing the place based on the search.

Requirements of the course:

  • Multiple Screens / Views [MUST] – ✅
  • A Table View or other structural view [MUST] ✅
  • Buttons, Labels [MUST] ✅
  • Data storage using Core Data [MUST] ✅

Leave a Reply