Skip to content

Commit

Permalink
Merge pull request #22 from Roslund/LocationLogging
Browse files Browse the repository at this point in the history
Location logging
  • Loading branch information
Roslund authored Nov 20, 2019
2 parents 4e04dde + 01fa9c1 commit ad07ab9
Show file tree
Hide file tree
Showing 66 changed files with 10,527 additions and 6 deletions.
2 changes: 2 additions & 0 deletions .jazzy.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
readme: readme.md
github_url: https://github.com/Roslund/sequor
theme: apple

min_acl: internal

Expand Down
22 changes: 21 additions & 1 deletion Sequor.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
objects = {

/* Begin PBXBuildFile section */
AD18F04E2385352300F3D1B8 /* LocationLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD18F04D2385352300F3D1B8 /* LocationLogger.swift */; };
AD18F0502385358300F3D1B8 /* Trip.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD18F04F2385358300F3D1B8 /* Trip.swift */; };
AD1F061A236760CC00F74D9A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD1F0619236760CC00F74D9A /* AppDelegate.swift */; };
AD1F061C236760CC00F74D9A /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD1F061B236760CC00F74D9A /* SceneDelegate.swift */; };
AD1F061E236760CC00F74D9A /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD1F061D236760CC00F74D9A /* HomeView.swift */; };
Expand All @@ -15,6 +17,7 @@
AD1F0626236760CD00F74D9A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AD1F0624236760CD00F74D9A /* LaunchScreen.storyboard */; };
AD1F0631236760CD00F74D9A /* SequorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD1F0630236760CD00F74D9A /* SequorTests.swift */; };
AD1F063C236760CD00F74D9A /* SequorUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD1F063B236760CD00F74D9A /* SequorUITests.swift */; };
ADA166EE238430E700C53998 /* ActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADA166ED238430E700C53998 /* ActivityView.swift */; };
ADBEB00923743CB9001534CD /* DashboardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADBEB00823743CB9001534CD /* DashboardView.swift */; };
ADBEB00D2374423D001534CD /* PurchaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADBEB00C2374423D001534CD /* PurchaseView.swift */; };
ADD8B71D237B0C9F00D8DD55 /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADD8B71C237B0C9F00D8DD55 /* AppState.swift */; };
Expand Down Expand Up @@ -48,6 +51,8 @@
13BD5C0F2375A7CD00B44A26 /* +Double.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "+Double.swift"; sourceTree = "<group>"; };
13BFC8E62368435500BE20D0 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = "<group>"; };
AD114B672378A5E400313515 /* MapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapView.swift; sourceTree = "<group>"; };
AD18F04D2385352300F3D1B8 /* LocationLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationLogger.swift; sourceTree = "<group>"; };
AD18F04F2385358300F3D1B8 /* Trip.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Trip.swift; sourceTree = "<group>"; };
AD1F0616236760CC00F74D9A /* Sequor.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sequor.app; sourceTree = BUILT_PRODUCTS_DIR; };
AD1F0619236760CC00F74D9A /* AppDelegate.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; tabWidth = 2; };
AD1F061B236760CC00F74D9A /* SceneDelegate.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; tabWidth = 2; };
Expand All @@ -63,6 +68,7 @@
AD1F063B236760CD00F74D9A /* SequorUITests.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = SequorUITests.swift; sourceTree = "<group>"; tabWidth = 2; };
AD1F063D236760CD00F74D9A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
AD1F0649236761BD00F74D9A /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
ADA166ED238430E700C53998 /* ActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityView.swift; sourceTree = "<group>"; };
ADA7E08423775FAF0077E225 /* RectangleGraph.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RectangleGraph.swift; sourceTree = "<group>"; };
ADBEB00823743CB9001534CD /* DashboardView.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = DashboardView.swift; sourceTree = "<group>"; tabWidth = 2; };
ADBEB00A23743E12001534CD /* CouponsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CouponsView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -183,6 +189,7 @@
AD1F064A236761C800F74D9A /* Views */ = {
isa = PBXGroup;
children = (
ADA166EC238430D800C53998 /* Components */,
ADDFE16C23748F4B007BD2A8 /* CouponView.swift */,
AD1F061D236760CC00F74D9A /* HomeView.swift */,
ADBEB00823743CB9001534CD /* DashboardView.swift */,
Expand All @@ -192,6 +199,15 @@
path = Views;
sourceTree = "<group>";
};
ADA166EC238430D800C53998 /* Components */ = {
isa = PBXGroup;
children = (
ADD8B722237B4ECF00D8DD55 /* RelativeTime.swift */,
ADA166ED238430E700C53998 /* ActivityView.swift */,
);
path = Components;
sourceTree = "<group>";
};
ADD8B71A237B0BBF00D8DD55 /* Unused */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -219,8 +235,9 @@
ADDFE16923748F24007BD2A8 /* Coupon.swift */,
ADECEB132375AAD70097B726 /* Ticket.swift */,
ADD8B71C237B0C9F00D8DD55 /* AppState.swift */,
ADD8B722237B4ECF00D8DD55 /* RelativeTime.swift */,
ADD8B724237BF99900D8DD55 /* ActivityManager.swift */,
AD18F04D2385352300F3D1B8 /* LocationLogger.swift */,
AD18F04F2385358300F3D1B8 /* Trip.swift */,
);
path = Models;
sourceTree = "<group>";
Expand Down Expand Up @@ -386,8 +403,11 @@
ADDFE16A23748F24007BD2A8 /* Coupon.swift in Sources */,
ADD8B725237BF99900D8DD55 /* ActivityManager.swift in Sources */,
ADD8B71F237B0DDD00D8DD55 /* Profile.swift in Sources */,
ADA166EE238430E700C53998 /* ActivityView.swift in Sources */,
AD1F061C236760CC00F74D9A /* SceneDelegate.swift in Sources */,
AD1F061E236760CC00F74D9A /* HomeView.swift in Sources */,
AD18F0502385358300F3D1B8 /* Trip.swift in Sources */,
AD18F04E2385352300F3D1B8 /* LocationLogger.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
2 changes: 1 addition & 1 deletion Sequor/Models/ActivityManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import CoreMotion

/// Provides the user activity (e.g. Walking, Running, Stationary)
final class ActivityManager: ObservableObject {
let manager = CMMotionActivityManager()
private let manager = CMMotionActivityManager()

/// The activity the user is performing, represented by emoji.
@Published var activityString: String = ""
Expand Down
6 changes: 6 additions & 0 deletions Sequor/Models/AppState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ final class AppState: ObservableObject {
/// Valid coupons the user has erned.
@Published var coupons: [Coupon] = []

@Published var lastTrip: Trip?

var locationLogger: LocationLogger?

init() {
// We probably want to request the state from the backend when we instanciate the object
}
Expand All @@ -27,12 +31,14 @@ final class AppState: ObservableObject {
func activateTicket() {
// Temp for testing. Should make request to server.
activeTicket = Ticket(id: 1, experation: Date(timeInterval: 90*60, since: Date()))
locationLogger = LocationLogger(trip: Trip())
}

/// Sends a request to the server to invalidate the ticket but changing experation date.
func invalidateTicket() {
// Temp for testing. Should make request to server.
activeTicket = nil
lastTrip = locationLogger?.end()
}

}
46 changes: 46 additions & 0 deletions Sequor/Models/LocationLogger.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import CoreLocation

final class LocationLogger: NSObject, ObservableObject, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
var trip: Trip

init(trip: Trip) {
self.trip = trip

super.init()
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()

if CLLocationManager.locationServicesEnabled() {
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.allowsBackgroundLocationUpdates = true
// The minimum distance (measured in meters) a device must
// move horizontally before an update event is generated.
locationManager.distanceFilter = 5.0
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.showsBackgroundLocationIndicator = true
locationManager.requestLocation()
locationManager.startUpdatingLocation()
}
}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
trip.locations += locations.map { location in
Location(timestamp: location.timestamp,
speed: location.speed,
course: location.course,
coordinate: Coordinate(latitude: location.coordinate.latitude,
longitude: location.coordinate.longitude)
)
}
}

func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print(error)
}

func end() -> Trip {
locationManager.stopUpdatingLocation()
return trip
}
}
34 changes: 34 additions & 0 deletions Sequor/Models/Trip.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Foundation

/// Should represent a continuous travel on public transport.
struct Trip: Codable {

/// The date an time the tip started
var startDate: Date = Date()

/// The date an time the tip ended
var endDate: Date?

/// An array of locations captured durring the trip
var locations: [Location] = []
}

/// A GPS location
struct Location: Codable {
/// The timestam the location was recorded
let timestamp: Date
/// Speed at location (m/s)
let speed: Double
/// Course 0-359.9 degrees
let course: Double
/// The poistion
let coordinate: Coordinate
}

/// Position represented by latitude and lognitude
struct Coordinate: Codable {
///The latitude in degrees.
let latitude: Double
///The longitude in degrees.
let longitude: Double
}
27 changes: 27 additions & 0 deletions Sequor/Views/Components/ActivityView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import SwiftUI

/// A swiftUI wrapper around UIActivityViewController.
/// Shows what commonly is refered to as the *ShareSheet*.
/// We can use this to open and save data on device for easy onDevice debugging of tracking.
/// - - -
/// **Usage:**
/// ```swift
/// .sheet(isPresented: $showActivitySheet) {
/// ActivityView(activityItems: [data],
/// applicationActivities: nil)
/// }
/// ```
struct ActivityView: UIViewControllerRepresentable {

let activityItems: [Any]
var applicationActivities: [UIActivity]?

func makeUIViewController(context: UIViewControllerRepresentableContext<ActivityView>) -> UIActivityViewController {
return UIActivityViewController(activityItems: activityItems,
applicationActivities: applicationActivities)
}

func updateUIViewController(_ uiViewController: UIActivityViewController,
context: UIViewControllerRepresentableContext<ActivityView>) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import SwiftUI
/// Provides the relatime time, in minutes, to a given date.
/// And updates it every 30 secounds.
struct RelativeTimeText: View {
@ObservedObject var relativeTime: RelativeTime
@ObservedObject private var relativeTime: RelativeTime
let textAfter: String
let textBefore: String

Expand All @@ -19,7 +19,7 @@ struct RelativeTimeText: View {
}
}

class RelativeTime: ObservableObject {
private class RelativeTime: ObservableObject {
var timer = Timer()
@Published var text: String

Expand Down
20 changes: 18 additions & 2 deletions Sequor/Views/PurchaseView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import SwiftUI
struct PurchaseView: View {
@EnvironmentObject var appState: AppState
@EnvironmentObject var activityManager: ActivityManager
@State private var showActivitySheet = false

var body: some View {
NavigationView {
Expand Down Expand Up @@ -33,7 +34,7 @@ struct PurchaseView: View {
if self.appState.activeTicket == nil {
self.appState.activateTicket()
} else {
self.appState.activeTicket = nil
self.appState.invalidateTicket()
}
}, label: {
HStack {
Expand All @@ -53,7 +54,22 @@ struct PurchaseView: View {
.padding(.horizontal, 20)
.padding(.bottom, 24)

}.navigationBarTitle("Purchase", displayMode: .inline)
}
.navigationBarTitle("Purchase", displayMode: .inline)
.navigationBarItems(trailing:
Button(action: {
self.showActivitySheet = true
},
label: {
Image(systemName: "square.and.arrow.up")
}))
.sheet(isPresented: $showActivitySheet) {
ActivityView(activityItems: [
// swiftlint:disable:next force_try
String(data: try! JSONEncoder().encode(self.appState.locationLogger!.trip), encoding: .utf8)!
], applicationActivities: nil)
}

}
}
}
Expand Down
Loading

0 comments on commit ad07ab9

Please sign in to comment.