Olafur Oskar Osmarson, Jo-Ari Utsi Sara, L. S.

uluma19, jouts19, luspe19

Introduction

Since the dawn of time, mankind has had an urge to explore the unknown. From the deepest pit of the ocean to a planet millions of miles away, we have always found a way to unfold the mysteries we seek. Before we travel to Mars we have to focus on the mysteries in our own planet. It might not be the deadly environment in Mars we seek, but the more civilized locations that sparks the curiosity. Cities that never sleep, the sparkling ocean, the cold winter exploration in the north, and snorkelling with sharks in tropical lands, gives us more than enough to explore. In 2016 the global economic contribution of tourism was over 7.6 trillion dollars, and if you include accommodation, transportation, entertainment and attractions, then you can add another 2.3 trillion dollars. Today it has never been easier to discover new locations and visit historical sights. More people than ever are travelling to learn about different cultures. One of the issues with this much tourism is that the travel experience can be watered down by only visiting areas where the only population are tourists. The average traveller will not get the true experience of what the location has to offer, thus giving a wrong impression of a culture which can be damaging in the future.

The POIAlert app is essentially an informational travel app. Wherever you go the app will locate the sites that might spark that curiosity we’ve been missing for years. When you open the app, it will display monuments and buildings around your location, while also providing short pieces of information. Should you walk past a famous writer’s house, the app will alert you that you’re in the proximity of a historical building. Applications like Tripadvisor work well for the common tourist, but it has its flaws by only providing the most popular tourist attraction. POIAlert will change that by providing unbiased information about the historical attractions in the area, giving a more non-tourist experience for the traveller.

Methods

Simple Prototyping

Creating a simple prototype at an early stage of our development process has been essential. Thereby, we were able to get a first hands-on and an evaluation (cf. section Evaluations) very quickly.

While creating the prototype we focused on the user interface and establishing basic functionalities instead of technical details

Evaluations

Evaluating the app by us and others has also been a fundamental part of our project work. Evaluation has been integrated into the development process two times. We evaluated the prototype app as well as the final version of the app. The evaluation by others has been conducted orally by advising them to give feedback on the topics usability, functionality and general likability. After that we summarized the different points made distinguished by pros and cons.

Requirements

In order to get an overview about the functionalities we have to implement we created an extended list of requirements. At this, we considered functional as well as non-functional requirements. Functional attributes are describing concrete functions a software must perform whereas non-functional attributes describe quality characteristics as performance. The requirements are displayed in a tabular form.

Use Case Diagrams

For an easy understanding of what the user can do and what the Wikimedia is providing, we created a use case diagram which showcases the different scenarios of the application. A use case diagram simplifies the goal of the application, making the project more understandable and pleasant to work with.

Object Diagrams

To get an overview of how we wanted to structure the code we made an object diagram. Its purpose was to roughly lay out how our controllers and other classes would interact. Making a diagram made the goal more clear than just starting programming with no aim. It also gave us a sense of which variables should be private and which ones should be public when we started coding.

Results

Simple Prototyping

The appearance of the simple prototype can be looked up in the first report. The results of the first evaluation which is based on the first prototype are shown in the following section.

First Evaluation

The following table depicts the key findings of the first evaluation in which we asked other students for feedback after using the prototype app.

ProCon
+ intuitive user Interface
+ clean style
+ interaction with the Map 
– content means a lot of expenditure
– there are alternatives like Tripadvisor which offer similar services

Based on these results we slightly redefined our apps subject. Instead of creating our content by researching locations and places we use the Wikipedia API (cf. section Object diagrams and frameworks) to find places around your current location that have wikipedia entries. Thereby, we achieve a distinction from apps like Tripadvisor in which location are rated and proposed by their popularity. Our app would be an alternative to get an unbiased and neutral insight to places in the area around you.

Requirements

In the following figure the requirements are depicted in a tabular form.

Requirement specification
Functional RequirementsAccess to current GPS location
Generate a list of surrounding locations based on the current GPS location
Show information about locations
Notifications to inform about a location nearby
User Interface containing: 
·      View presenting the different locations
·      A map presenting the different locations
·      A view for basic settings
Non-functional requirementsIntuitive user interface
Conformation to Apple’s user interface guidelines
Asynchronous access of surrounding locations in order to guarantee a satisfying user experience inside the app

Use Case diagram

Object diagram and frameworks

The following figure shows the first draft of our object diagram. It has to be said, that the initial diagram is far from what we ended up with, which was expected.

The following figure depicts the final object diagram.

A bigger version of the figure can be accessed by the following link. https://notendur.hi.is/ooo10/skiptinam/uml.svg

The object diagram shows how the controllers are interconnected. Following the MVC structure in Swift was quite easy, mainly due to how visually based the main programming environment (XCode) is. Having all the views in the storyboard and creating most of them there minimizes the instances of us programatically creating views in the controllers and therefore keeping a good separation between view and controller. In some instances we needed to make views in code and the lines between the controller and view get a little blurred. In the implementation process we tried to keep as much “business logic” as possible, for instance fetching data out of the controllers and rather delegate those responsibilities to dedicated classes (e.g. the Async API Classes). Lastly we must mention that having no database, our model consists entirely of variables that are updated in the controllers.

The three main frameworks we used, excluding UIKit and Foundation, were CoreLocation, MapKit and UserNotifications. With CoreLocation we could get the GPS location of the user using the CLLocationManager by making the controllers that relied on that CLLocationManagerDelegate. The MapKit was essential for manipulating the MapView in our controller for the Map View. Finally UserNotifications we set up in the AppDelegate and made an extension for AppDelegate where it was a UserNotificationsDelegate so that it could schedule and de-schedule notifications coming from the app

For brevity we will cover what we consider to be the main properties and methods of the app. For our notifications the vital property is the constant notificationCenter (type UNUserNotificationCenter). Through this constant we scheduled and de-scheduled all of our notifications. The most prominent notification methods were:

// Schedules a notification with a location trigger

func scheduleLocationNotification(withTitle title: String, withBody body: String, withLat lat: Double, withLon lon: Double) {
        let content = UNMutableNotificationContent()
        let categoryIdentifier = "Delete Notification Type"
        
        content.title = title
        content.body = body
        content.sound = UNNotificationSound.default
        content.badge = 1
        content.categoryIdentifier = categoryIdentifier
        
        let center = CLLocationCoordinate2D(latitude: lat, longitude: lon)
        let region = CLCircularRegion(center: center, radius: RADIUS, identifier: title)
        region.notifyOnEntry = true
        region.notifyOnExit = false
        let trigger = UNLocationNotificationTrigger(region: region, repeats: false)
        
        let request = UNNotificationRequest(identifier: title, content: content, trigger: trigger)
        
        notificationCenter.add(request) { (error) in
            if let error = error {
                print("Error \(error.localizedDescription)")
            }
        }
        
        let snoozeAction = UNNotificationAction(identifier: "Snooze", title: "Snooze", options: [])
        let deleteAction = UNNotificationAction(identifier: "DeleteAction", title: "Delete", options: [.destructive])
        let category = UNNotificationCategory(identifier: categoryIdentifier, actions: [snoozeAction, deleteAction], intentIdentifiers: [], options: [])
        
        notificationCenter.setNotificationCategories([category])
    }
    
    /**
     Unused but something we would have used to deschedule notifications of pois that are no longer in your vicinity
     */
    func descheduleAllNotifications() {
        notificationCenter.removeAllPendingNotificationRequests()
    }

These two functions handled the scheduling and descheduling of notifications respectively. For the location of the user the most important property was the locationManager constant. With that constant we requested access to the user’s locations and received the user’s location after being granted that request. The most notable methods throughout the app are setPlaces() in ViewController and setInfo()/setInfo(title: String) in ListOfPOIsViewController /MapOfPOIsViewController.

// Set the info of the selected cell to be passed to the next view 
func setInfo() {
        
        let operation = AsyncExtractAPICallOperation()
        operation.id = "\(places[selectedCellIndex]["pageid"] as! Int)"
        
        operation.completionBlock = {
            DispatchQueue.main.async {
                switch operation.results {
                case let .success(data):
                    print(data!)
                    self.info = data!
                case let .failure(error):
                    print(error)
                case .none:
                    break
                }
            }
        }
        
        let operationQueue = OperationQueue()
        operationQueue.addOperation(operation)
    }

In both methods we make sure that we have the location of the user with a guard statement. We then define an AsyncOperation object into which we pass the needed parameters. We then define a closure that we want executed last after all information is in the object by defining a closure and passing it to the completionBlock attribute of the operation. We then define an OperationQueue object and add our operation to it and it will run in the correct order, assuring us that the relevant information will be in the object before the API is called. The reason for doing it like this (asynchronously) is so that we don’t need to freeze the app between views. This ensures that the user will be able to interact with the app even though the information has not yet arrived to the next view. Then as soon as the information arrives the view will update. It should be noted that all our asynchronous code is from a mix of tutorials off the internet. Therefore there is really not one single reference for it.

Our original intention was to make the content for the app ourselves, but we concluded that it would amount to tedious work. Therefore we decided to make use of the MediaWiki API to get information from Wikipedia based on coordinates as well as page id’s and more. This way the app should theoretically work everywhere in the world and not just Odense where we would’ve created our material. Calling the API in itself is not complicated (tutorial on API calls in Swift that we relied on: https://medium.com/better-programming/basic-api-request-with-swift-4-d8bf829524) (MediaWiki Geosearch API: https://www.mediawiki.org/wiki/API:Geosearch). However the challenge was not making the application wait while getting the response which we talked about earlier.

Second evaluation

In the following table the comments and findings on the final version of the app is summarized.

ProCon
+ intuitive user Interface
+clean style
+ interaction with the Map
+ Using wikipedia API is great 
– History function would be great
– no categorization of results

Discussion

Within the class “iOS Programming” we were able to create an app which allows you to find interesting places around your current location based on the Wikipedia API (cf. section Object diagrams and frameworks). Further information about locations can be accessed either by scrolling through a list or interacting with a map. Using asynchronous data requests guarantees a fluent user experience. The orientation at Apple’s user interface guidelines provided an intuitive user interface. This has been proven by the user feedback during our app evaluations.

In general integrating the user, his experience and opinion has been essential for the development process. Due to the results of our first evaluation we were able to redirect our project. Using the Wikipedia API to find locations is unbiased, neutral, different and new way to discover a new or also known environment. In this manner we differ from other more touristy apps as Tripadvisor and offer a unique way of exploring.

Overall we were able to fulfill our defined requirements. Moreover, our second evaluation yielded excellent feedback from the user concerning user experience and the idea in general. Nevertheless, there is always space for improvements. The evaluation also showed that a history function and categorizable results would be great.

Outlook

Looking on, we would have liked to implement the settings view and controller so the user would be able to decide the maximum amount of results as well as the radius in which he wants to be notified of places. Originally we wanted to be able to categorize the points of interest displayed to the user. However, by using information from Wikipedia, it would be quite the challenge to categorize the places found, as well as the large amount of categories would make it too challenging, so we decided to forego that feature.

As well as implementing the settings we would have wanted to use the Core Data framework to implement some sort of history of places you have already been notified of or have already visited. This is probably not as much a challenge as categorizing. The best way would probably be to keep a local database with core data of the page ids that have already been notified.

Youtube Video

Leave a Reply