Skip to content

Commit

Permalink
updated the Demo App to semi sensibly use the new recorder/segment/pr…
Browse files Browse the repository at this point in the history
…ocessor architecture #11
  • Loading branch information
sobri909 committed May 2, 2018
1 parent 2237993 commit eb3389c
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 104 deletions.
32 changes: 7 additions & 25 deletions LocoKit Demo App/MapView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,8 @@ import MapKit

class MapView: MKMapView {

let timeline: TimelineManager

init(timeline: TimelineManager) {
self.timeline = timeline

init() {
super.init(frame: CGRect.zero)

self.delegate = self
self.isRotateEnabled = false
self.isPitchEnabled = false
Expand Down Expand Up @@ -162,7 +157,7 @@ class MapView: MKMapView {

var coords = path.samples.compactMap { $0.location?.coordinate }
let line = PathPolyline(coordinates: &coords, count: coords.count)
line.color = timeline.activeItems.contains(path) ? .brown : .darkGray
line.color = .brown

add(line)
}
Expand All @@ -173,7 +168,7 @@ class MapView: MKMapView {
addAnnotation(VisitAnnotation(coordinate: center.coordinate, visit: visit))

let circle = VisitCircle(center: center.coordinate, radius: visit.radius2sd)
circle.color = timeline.activeItems.contains(visit) ? .orange : .darkGray
circle.color = .orange
add(circle, level: .aboveLabels)
}

Expand All @@ -199,26 +194,13 @@ class MapView: MKMapView {
extension MapView: MKMapViewDelegate {

func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if let path = overlay as? PathPolyline {
return path.renderer

} else if let circle = overlay as? VisitCircle {
return circle.renderer

} else {
fatalError("you wot?")
}
if let path = overlay as? PathPolyline { return path.renderer }
if let circle = overlay as? VisitCircle { return circle.renderer }
fatalError("you wot?")
}

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if let annotation = annotation as? VisitAnnotation {
let view = annotation.view
if !timeline.activeItems.contains(annotation.visit) {
view.image = UIImage(named: "inactiveDot")
}
return view
}
return nil
return (annotation as? VisitAnnotation)?.view
}

}
28 changes: 10 additions & 18 deletions LocoKit Demo App/TimelineView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,13 @@ import Anchorage

class TimelineView: UIScrollView {

let timeline: TimelineManager

lazy var rows: UIStackView = {
let box = UIStackView()
box.axis = .vertical
return box
}()

init(timeline: TimelineManager) {
self.timeline = timeline
init() {
super.init(frame: CGRect.zero)
backgroundColor = .white
alwaysBounceVertical = true
Expand Down Expand Up @@ -54,11 +51,12 @@ class TimelineView: UIScrollView {
return
}

var nextItem: TimelineItem?
for timelineItem in items {
if let next = nextItem, next.previousItem != timelineItem || timelineItem.nextItem != next { addDataGap() }
nextItem = timelineItem
add(timelineItem)
if timelineItem.isDataGap {
addDataGap(timelineItem)
} else {
add(timelineItem)
}
}
}

Expand All @@ -70,10 +68,6 @@ class TimelineView: UIScrollView {
}
if timelineItem.isCurrentItem {
title += "Current "
} else if timeline.activeItems.contains(timelineItem) {
title += "Active "
} else {
title += "Finalised "
}
title += timelineItem.isNolo ? "Nolo" : timelineItem is Visit ? "Visit" : "Path"
if let path = timelineItem as? Path, let activityType = path.movingActivityType {
Expand Down Expand Up @@ -130,16 +124,14 @@ class TimelineView: UIScrollView {
rows.addRow(leftText: "ItemId", rightText: timelineItem.itemId.uuidString, background: debugColor)
}

func addDataGap(duration: TimeInterval? = nil) {
func addDataGap(_ timelineItem: TimelineItem) {
guard timelineItem.isDataGap else { return }

rows.addGap(height: 14)
rows.addUnderline()
rows.addGap(height: 14)

if let duration = duration {
rows.addSubheading(title: "Timeline Gap (\(String(duration: duration)))", color: .red)
} else {
rows.addSubheading(title: "Timeline Gap", color: .red)
}
rows.addSubheading(title: "Timeline Gap (\(String(duration: timelineItem.duration)))", color: .red)

rows.addGap(height: 14)
rows.addUnderline()
Expand Down
102 changes: 41 additions & 61 deletions LocoKit Demo App/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,57 +13,58 @@ import CoreLocation

class ViewController: UIViewController {

/**
The recording manager for Timeline Items (Visits and Paths)
// using an Activity Types Classifier requires an API key (see below)
let useActivityTypesClassifier = false

- Note: Use a plain TimelineManager() instead if you don't require persistent SQL storage
**/
let timeline: TimelineManager = PersistentTimelineManager()
// use a plain TimelineStore instead of PersistentTimelineStore if you don't require persistent SQL storage
let store: TimelineStore = PersistentTimelineStore()

lazy var mapView = { return MapView(timeline: self.timeline) }()
lazy var timelineView = { return TimelineView(timeline: self.timeline) }()
var recorder: TimelineRecorder

var dataSet: TimelineSegment?

lazy var mapView = { return MapView() }()
lazy var timelineView = { return TimelineView() }()
let classifierView = ClassifierView()
let settingsView = SettingsView()
let locoView = LocoView()
let logView = LogView()

// MARK: controller lifecycle

override func viewDidLoad() {
super.viewDidLoad()

// the CoreLocation / CoreMotion recording singleton
let loco = LocomotionManager.highlander

/** EXAMPLE SETTINGS **/
init() {
if useActivityTypesClassifier {

// enable this if you have an API key and want to determine activity types
timeline.activityTypeClassifySamples = false

if timeline.activityTypeClassifySamples {
// using an Activity Types Classifier requires an API key
// API keys can be created at: https://www.bigpaua.com/arckit/account
LocoKitService.apiKey = "<insert your API key here>"

recorder = TimelineRecorder(store: store, classifier: TimelineClassifier.highlander)

} else {
recorder = TimelineRecorder(store: store)
}

// this accuracy level is excessive, and is for demo purposes only.
// the default value (30 metres) best balances accuracy with energy use.
loco.maximumDesiredLocationAccuracy = kCLLocationAccuracyNearestTenMeters
super.init(nibName: nil, bundle: nil)
}

// this is independent of the user's setting, and will show a blue bar if user has denied "always"
loco.locationManager.allowsBackgroundLocationUpdates = true
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

/** TIMELINE STARTUP **/
override func viewDidLoad() {
super.viewDidLoad()

// restore the active timeline items from local db
if let timeline = timeline as? PersistentTimelineManager {
timeline.bootstrapActiveItems()
if let store = store as? PersistentTimelineStore {
let query = "deleted = 0 AND endDate > datetime('now','-24 hours') AND startDate < datetime('now') ORDER BY startDate DESC"
dataSet = TimelineSegment(for: query, in: store) {
onMain { self.update() }
}
}

/** EXAMPLE OBSERVERS **/

// observe new timeline items
when(timeline, does: .newTimelineItem) { _ in
if let currentItem = self.timeline.currentItem {
when(.newTimelineItem) { _ in
if let currentItem = self.recorder.currentItem {
log(".newTimelineItem (\(String(describing: type(of: currentItem))))")
}
onMain {
Expand All @@ -74,29 +75,23 @@ class ViewController: UIViewController {
}

// observe timeline item updates
when(timeline, does: .updatedTimelineItem) { _ in
when(.updatedTimelineItem) { _ in
onMain {
let items = self.itemsToShow
self.mapView.update(with: items)
self.timelineView.update(with: items)
}
}

// observe timeline items finalised after post processing
when(timeline, does: .finalisedTimelineItem) { note in
if let item = note.userInfo?["timelineItem"] as? TimelineItem {
log(".finalisedTimelineItem (\(String(describing: type(of: item))))")
}
onMain { self.timelineView.update(with: self.itemsToShow) }
}

when(timeline, does: .mergedTimelineItems) { note in
when(.mergedTimelineItems) { note in
if let description = note.userInfo?["merge"] as? String {
log(".mergedItems (\(description))")
}
onMain { self.timelineView.update(with: self.itemsToShow) }
}

let loco = LocomotionManager.highlander

// observe incoming location / locomotion updates
when(loco, does: .locomotionSampleUpdated) { _ in
self.locomotionSampleUpdated()
Expand Down Expand Up @@ -125,14 +120,6 @@ class ViewController: UIViewController {
log(".stoppedSleepMode")
}

when(.debugInfo) { note in
if let info = note.userInfo?["info"] as? String {
log(".debug (\(info))")
} else {
log(".debug (nil)")
}
}

when(settingsView, does: .settingsChanged) { _ in
self.mapView.update(with: self.itemsToShow)
self.setNeedsStatusBarAppearanceUpdate()
Expand Down Expand Up @@ -175,7 +162,7 @@ class ViewController: UIViewController {
@objc func tappedStart() {
log("tappedStart()")

timeline.startRecording()
recorder.startRecording()

startButton.isHidden = true
stopButton.isHidden = false
Expand All @@ -184,7 +171,7 @@ class ViewController: UIViewController {
@objc func tappedStop() {
log("tappedStop()")

timeline.stopRecording()
recorder.stopRecording()

stopButton.isHidden = true
startButton.isHidden = false
Expand Down Expand Up @@ -287,9 +274,9 @@ class ViewController: UIViewController {
}

var itemsToShow: [TimelineItem] {
if timeline is PersistentTimelineManager { return persistentItemsToShow }
if store is PersistentTimelineStore { return persistentItemsToShow }

guard let currentItem = timeline.currentItem else { return [] }
guard let currentItem = recorder.currentItem else { return [] }

// collect the linked list of timeline items
var items: [TimelineItem] = [currentItem]
Expand All @@ -303,14 +290,7 @@ class ViewController: UIViewController {
}

var persistentItemsToShow: [TimelineItem] {
guard let timeline = timeline as? PersistentTimelineManager else { return [] }

// make sure the db is fresh
timeline.store.save()

// feth all items in the past 24 hours
let boundary = Date(timeIntervalSinceNow: -60 * 60 * 24)
return timeline.store.items(where: "deleted = 0 AND endDate > ? ORDER BY endDate DESC", arguments: [boundary])
return dataSet?.timelineItems ?? []
}

// MARK: view property getters
Expand Down

0 comments on commit eb3389c

Please sign in to comment.