Manos Chorianopoulos

new Telematics screens and assets

Showing 31 changed files with 769 additions and 9 deletions
......@@ -14,6 +14,9 @@
1E108A9428A3F9280008B8E7 /* pf_square_sans_pro_extra_black.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 1E108A8F28A3F9280008B8E7 /* pf_square_sans_pro_extra_black.ttf */; };
1E108A9528A3F9280008B8E7 /* pf_square_sans_pro_bold_italic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 1E108A9028A3F9280008B8E7 /* pf_square_sans_pro_bold_italic.ttf */; };
1E108A9628A3F9280008B8E7 /* pf_square_sans_pro_bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 1E108A9128A3F9280008B8E7 /* pf_square_sans_pro_bold.ttf */; };
1E1489752AB48D6400D332BE /* TelematicsMainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E1489742AB48D6400D332BE /* TelematicsMainViewController.swift */; };
1E1489772AB49EA300D332BE /* TelematicsHistoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E1489762AB49EA300D332BE /* TelematicsHistoryViewController.swift */; };
1E1489792AB49EC600D332BE /* TelematicsHistoryAnalysisViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E1489782AB49EC600D332BE /* TelematicsHistoryAnalysisViewController.swift */; };
1E151F1829DAE48500951FA0 /* UnifiedCouponsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E151F1729DAE48500951FA0 /* UnifiedCouponsTableViewCell.swift */; };
1E151F1A29DAE4D500951FA0 /* ActiveCodeTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E151F1929DAE4D500951FA0 /* ActiveCodeTableViewCell.swift */; };
1E15B9A229DDCF02000A408D /* MarketSharingHistoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E15B9A129DDCF02000A408D /* MarketSharingHistoryViewController.swift */; };
......@@ -199,6 +202,9 @@
1E108A9028A3F9280008B8E7 /* pf_square_sans_pro_bold_italic.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = pf_square_sans_pro_bold_italic.ttf; sourceTree = "<group>"; };
1E108A9128A3F9280008B8E7 /* pf_square_sans_pro_bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = pf_square_sans_pro_bold.ttf; sourceTree = "<group>"; };
1E108A9728A3FA9B0008B8E7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
1E1489742AB48D6400D332BE /* TelematicsMainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelematicsMainViewController.swift; sourceTree = "<group>"; };
1E1489762AB49EA300D332BE /* TelematicsHistoryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelematicsHistoryViewController.swift; sourceTree = "<group>"; };
1E1489782AB49EC600D332BE /* TelematicsHistoryAnalysisViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelematicsHistoryAnalysisViewController.swift; sourceTree = "<group>"; };
1E151F1729DAE48500951FA0 /* UnifiedCouponsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnifiedCouponsTableViewCell.swift; sourceTree = "<group>"; };
1E151F1929DAE4D500951FA0 /* ActiveCodeTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveCodeTableViewCell.swift; sourceTree = "<group>"; };
1E15B9A129DDCF02000A408D /* MarketSharingHistoryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketSharingHistoryViewController.swift; sourceTree = "<group>"; };
......@@ -537,6 +543,9 @@
1EB236AE28816CAB0063777A /* NumbersTableViewCell.swift */,
1EB5F4C728536FD60016F36E /* StepsViewController.swift */,
1EF228472AA73E48009DF715 /* TelematicsViewController.swift */,
1E1489742AB48D6400D332BE /* TelematicsMainViewController.swift */,
1E1489762AB49EA300D332BE /* TelematicsHistoryViewController.swift */,
1E1489782AB49EC600D332BE /* TelematicsHistoryAnalysisViewController.swift */,
E6A77860282933E40045BBA8 /* MyApi.h */,
E6A778DC282933E60045BBA8 /* MyApi.m */,
E6A77862282933E50045BBA8 /* MyEmptyClass.swift */,
......@@ -962,6 +971,7 @@
A02F34052882B6E60086465F /* TelcoViewController.swift in Sources */,
E6A77901282933E60045BBA8 /* WLBaseItem.m in Sources */,
1E74838D28378AF40042A589 /* CouponBarcodeViewController.swift in Sources */,
1E1489792AB49EC600D332BE /* TelematicsHistoryAnalysisViewController.swift in Sources */,
1E479FB329DD948B00C38193 /* WalletBadgesTableViewCell.swift in Sources */,
1E151F1829DAE48500951FA0 /* UnifiedCouponsTableViewCell.swift in Sources */,
E6A778F0282933E60045BBA8 /* WLNativeAdsCollectionMode.m in Sources */,
......@@ -1021,6 +1031,7 @@
E6A77A36282BB4CB0045BBA8 /* MakeItAPresentViewController.swift in Sources */,
E6A77947282933E70045BBA8 /* FMDatabaseQueue.m in Sources */,
E6A77922282933E60045BBA8 /* NSData+SSToolkitAdditions.m in Sources */,
1E1489752AB48D6400D332BE /* TelematicsMainViewController.swift in Sources */,
1EA771AC290977CA0030924C /* CopyableLabel.swift in Sources */,
1EB236AB28816B680063777A /* ShareViewController.swift in Sources */,
1EF228482AA73E48009DF715 /* TelematicsViewController.swift in Sources */,
......@@ -1047,6 +1058,7 @@
A04D31DE288FF670000E43B5 /* HistoryViewController.swift in Sources */,
E6A7792A282933E70045BBA8 /* AFNetworkActivityIndicatorManager.m in Sources */,
E6A77914282933E60045BBA8 /* WLUserManager.m in Sources */,
1E1489772AB49EA300D332BE /* TelematicsHistoryViewController.swift in Sources */,
1EB236AF28816CAC0063777A /* NumbersTableViewCell.swift in Sources */,
E6A7794F282933E70045BBA8 /* FMDatabasePool.m in Sources */,
1EB236AD28816C560063777A /* NumberPopupViewController.swift in Sources */,
......
......@@ -300,7 +300,6 @@
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="redeemButtomAction:" destination="CDt-eI-msA" eventType="touchUpInside" id="ZgM-FV-cPH"/>
<action selector="tripButtonTapped:" destination="CkE-e6-QAc" eventType="touchUpInside" id="hmd-Ue-s8Z"/>
</connections>
</button>
......@@ -392,7 +391,52 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="MGA-l3-4Jz" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="138" y="1545"/>
<point key="canvasLocation" x="116" y="2238"/>
</scene>
<!--Telematics Main View Controller-->
<scene sceneID="BFY-HZ-rDp">
<objects>
<viewController storyboardIdentifier="TelematicsMainViewController" id="rLq-1b-nGI" customClass="TelematicsMainViewController" customModule="SwiftWarplyFramework" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="x7s-zd-bAg">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<viewLayoutGuide key="safeArea" id="LMR-ha-1z2"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="aRH-Fl-OPs" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="867" y="2238"/>
</scene>
<!--Telematics History View Controller-->
<scene sceneID="ax9-8b-0Xf">
<objects>
<viewController storyboardIdentifier="TelematicsHistoryViewController" id="niq-m0-9T8" customClass="TelematicsHistoryViewController" customModule="SwiftWarplyFramework" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ijr-jl-PS2">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<viewLayoutGuide key="safeArea" id="4r4-t4-51H"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="fXf-uN-H7T" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1612" y="2238"/>
</scene>
<!--Telematics History Analysis View Controller-->
<scene sceneID="tnC-G4-NTO">
<objects>
<viewController storyboardIdentifier="TelematicsHistoryAnalysisViewController" id="3e7-Qu-SLH" customClass="TelematicsHistoryAnalysisViewController" customModule="SwiftWarplyFramework" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="dBw-ap-NHM">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<viewLayoutGuide key="safeArea" id="xmW-KJ-2ba"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="HvF-nf-rXv" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2341" y="2238"/>
</scene>
<!--Details View Controller-->
<scene sceneID="TPv-Bl-CUP">
......@@ -2532,7 +2576,7 @@
<rect key="frame" x="0.0" y="947.5" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="TeS-tP-Ilh" id="FFV-uA-HHA">
<rect key="frame" x="0.0" y="0.0" width="600" height="44"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="AV7-t1-eK0">
......@@ -2759,7 +2803,7 @@
<rect key="frame" x="0.0" y="991.5" width="414" height="404"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="fgI-zL-RPZ" id="gNB-PU-R1J">
<rect key="frame" x="0.0" y="0.0" width="600" height="404"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="404"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="IZz-Fy-5Iv">
......
{
"images" : [
{
"filename" : "cosmote_insurance_logo.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "cosmote_insurance_logo 1.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "cosmote_insurance_logo 2.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "tel_driving_percentage.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "tel_driving_percentage 1.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "tel_driving_percentage 2.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "tel_driving_rating.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "tel_driving_rating 1.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "tel_driving_rating 2.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "tel_history_bg.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "tel_history_bg 1.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "tel_history_bg 2.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "tel_thumbs_down_gray.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "tel_thumbs_down_gray 1.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "tel_thumbs_down_gray 2.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "tel_thumbs_up_gray.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "tel_thumbs_up_gray 1.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "tel_thumbs_up_gray 2.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
//
// TelematicsHistoryAnalysisViewController.swift
// SwiftWarplyFramework
//
// Created by Manos Chorianopoulos on 15/9/23.
//
import UIKit
@objc public class TelematicsHistoryAnalysisViewController: UIViewController {
public override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
//
// TelematicsHistoryViewController.swift
// SwiftWarplyFramework
//
// Created by Manos Chorianopoulos on 15/9/23.
//
import UIKit
@objc public class TelematicsHistoryViewController: UIViewController {
public override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
//
// TelematicsMainViewController.swift
// SwiftWarplyFramework
//
// Created by Manos Chorianopoulos on 15/9/23.
//
import UIKit
import CoreLocation
import CoreMotion
@objc public class TelematicsMainViewController: UIViewController, CLLocationManagerDelegate, UITextFieldDelegate {
// MARK: Constants and Properties
private var mIsTripStarted = false
private var hasLocationPermissions = false
private var isFirstLoad = true
private var mAccelerationTimestamps = [[String: Any]]()
private var locationManager: CLLocationManager!
private var motionManager: CMMotionManager!
private var lastUpdate: TimeInterval = 0
private var lastX: Double = 0.0
private var lastY: Double = 0.0
private var lastZ: Double = 0.0
private var velocity: Double = 0.0
private var mAcceleration: Double = 0.0
private let ALPHA: Double = 0.8 // Filter factor
private let STOP_THRESHOLD: Double = 8.0 // Stop threshold in m/s²
private let RECORDS_INTERVAL: Int = 5000
private var mLatitude: Double = 0.0
private var mLongitude: Double = 0.0
private var mSpeed: Double = 0.0
private let EARTH_RADIUS: Double = 6371000.0
private let LOCATION_UPDATE_INTERVAL: Double = 1000.0
private var mStartTimestamp: String = ""
private var mStopTimestamp: String = ""
private var orientationCount: Int = 0
private var touchCount: Int = 0
var oldOrientationIsLandscape: Bool = true
private var timerTel: DispatchSourceTimer?
private var recordsSaved: Int = 0
// MARK: Outlets
@IBOutlet private weak var tripButton: UIButton!
// @IBOutlet private weak var sensorDataLabel: UILabel!
// @IBOutlet private weak var velocityLabel: UILabel!
// @IBOutlet private weak var accelerationLabel: UILabel!
// @IBOutlet private weak var avgVelocityLabel: UILabel!
// @IBOutlet private weak var recordsSavedLabel: UILabel!
// @IBOutlet private weak var orientationCountLabel: UILabel!
// @IBOutlet private weak var touchCountLabel: UILabel!
// @IBOutlet private weak var accelerationLimitTextField: UITextField!
// @IBOutlet private weak var sampleTimeTextField: UITextField!
public override func viewDidLoad() {
super.viewDidLoad()
self.hidesBottomBarWhenPushed = true
// self.setupToHideKeyboardOnTapOnView()
setBackButton()
setNavigationTitle("Safe Driving")
locationManager = CLLocationManager()
motionManager = CMMotionManager()
locationManager.delegate = self
// accelerationLimitTextField.delegate = self
// sampleTimeTextField.delegate = self
hasLocationPermissions = authorizationStatusIsGranted(status: CLLocationManager.authorizationStatus())
// orientationCountLabel.text = "0"
// touchCountLabel.text = "0"
// recordsSavedLabel.text = "0"
tripButton.titleLabel?.font = UIFont(name: "PeridotPE-Bold", size: 17)
tripButton.setTitle("Start Trip", for: .normal)
tripButton.setTitleColor(UIColor(red: 0.05, green: 0.65, blue: 0.00, alpha: 1.00), for: .normal)
tripButton.layer.cornerRadius = 15.0
tripButton.frame = CGRect(x: 0.0, y: 0.0, width: tripButton.intrinsicContentSize.width, height: 50)
tripButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 25, bottom: 0, right: 25)
tripButton.backgroundColor = .clear
tripButton.layer.borderWidth = 2
tripButton.layer.borderColor = UIColor(red: 0.05, green: 0.65, blue: 0.00, alpha: 1.00).cgColor
setupOrientationChangeDetection()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.didTapView(sender:)))
// tapGesture.cancelsTouchesInView = false
self.view.addGestureRecognizer(tapGesture)
}
public override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
swiftApi().logTrackersEvent("screen", "TelematicsScreen")
self.navigationController?.hideHairline()
}
public override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if (self.mIsTripStarted == true) {
self.stopTrip()
}
}
deinit {
NotificationCenter.default.removeObserver(self, name: UIDevice.orientationDidChangeNotification, object: nil)
}
// MARK: Actions
@IBAction private func tripButtonTapped(_ sender: UIButton) {
if (mIsTripStarted == true) {
// Stop trip
stopTrip()
} else {
// Start trip
// if let limitText = accelerationLimitTextField.text, limitText.isEmpty {
// // Handle empty limit field
// return
// }
// Disable UI elements
// accelerationLimitTextField.isEnabled = false
// sampleTimeTextField.isEnabled = false
// Start location and sensor updates
requestLocationUpdates()
// registerSensor()
mIsTripStarted = true
// orientationCountLabel.text = "0"
// touchCountLabel.text = "0"
tripButton.setTitle("Stop Trip", for: .normal)
mStartTimestamp = String(Int(Date().timeIntervalSince1970 * 1000)) // time in milliseconds since January 1, 1970
initializeOrientation()
startTimer()
}
}
private func stopTrip() {
mIsTripStarted = false
stopTimer()
unregisterSensor()
stopLocationUpdates()
tripButton.setTitle("Start Trip", for: .normal)
mStopTimestamp = String(Int(Date().timeIntervalSince1970 * 1000)) // time in milliseconds since January 1, 1970
initViews()
// Disable UI elements
// accelerationLimitTextField.isEnabled = true
// sampleTimeTextField.isEnabled = true
saveAccelerationDataToFile()
orientationCount = 0
touchCount = 0
}
private func saveAccelerationDataToFile() {
var jsonArray = [[String: Any]]()
for var jsonObject in mAccelerationTimestamps {
if let parent = jsonObject.keys.first, var jobj = jsonObject[parent] as? [String: Any] {
jobj["stop_time"] = mStopTimestamp
jsonObject[parent] = jobj
}
jsonArray.append(jsonObject)
}
mAccelerationTimestamps = jsonArray
// print("=== mAccelerationTimestamps: ",mAccelerationTimestamps)
sendAccelerationDataToServer(jsonArray)
}
func sendAccelerationDataToServer(_ jsonArray: [[String: Any]]) {
if (mAccelerationTimestamps.isEmpty) {
return
}
swiftApi().sendAccelerationDataAsync(accelerationTimestamps: mAccelerationTimestamps, sendAccelerationDataSuccessCallback, failureCallback: {errorCode in })
}
func sendAccelerationDataSuccessCallback (_ response: swiftApi.GenericResponseModel?) -> Void {
if (response != nil) {
DispatchQueue.main.async {
if (response?.getStatus == 1) {
self.recordsSaved += 1;
// self.recordsSavedLabel.text = String(self.recordsSaved)
} else {
print("=== sendAccelerationDataAsync error ===")
}
}
} else {
print("=== sendAccelerationDataAsync error ===")
}
}
private func initializeOrientation() {
if #available(iOS 13.0, *) {
if let newOrientation = UIApplication.shared.windows.first?.windowScene?.interfaceOrientation {
oldOrientationIsLandscape = newOrientation.isLandscape
}
} else {
let newOrientation = UIDevice.current.orientation
oldOrientationIsLandscape = newOrientation.isLandscape
}
}
// MARK: Sensor and Location Handling
private func registerSensor() {
// Register sensor for accelerometer data
if motionManager.isAccelerometerAvailable {
motionManager.accelerometerUpdateInterval = 0.1
motionManager.startAccelerometerUpdates(to: .main) { (data, error) in
if let accelerationData = data {
self.processAccelerometerData(accelerationData)
}
}
}
}
private func unregisterSensor() {
motionManager.stopAccelerometerUpdates()
}
private func processAccelerometerData(_ accelerationData: CMAccelerometerData) {
// print("=== accelerationData: ",accelerationData)
// sensorDataLabel.text = "\(accelerationData.acceleration.x), \(accelerationData.acceleration.y), \(accelerationData.acceleration.z)"
// timeIntervalSince1970 is the number of seconds since January, 1st, 1970, 12:00 am (mid night)
let currentTime = Date().timeIntervalSince1970
let timeDifference = currentTime - lastUpdate
lastUpdate = currentTime
let time = timeDifference
// Apply low-pass filter
let filteredX = ALPHA * lastX + (1 - ALPHA) * accelerationData.acceleration.x
let filteredY = ALPHA * lastY + (1 - ALPHA) * accelerationData.acceleration.y
let filteredZ = ALPHA * lastZ + (1 - ALPHA) * accelerationData.acceleration.z
// Calculate acceleration in m/s² using filtered values
let accelerationX = (filteredX - lastX) / time
let accelerationY = (filteredY - lastY) / time
let accelerationZ = (filteredZ - lastZ) / time
// Calculate total acceleration
let acceleration = sqrt(pow(accelerationX, 2) + pow(accelerationY, 2) + pow(accelerationZ, 2))
// TODO: CHECK mayby this is correct
// accelerationLabel.text = String(format: "%.1f m/s^2", acceleration)
// print("=== acceleration: ",acceleration)
// If acceleration is below the stop threshold, assume we are in a stop
// if acceleration < STOP_THRESHOLD {
// velocity = 0
// } else {
// Update velocity
velocity = acceleration * time
// }
// print("=== velocity: ",velocity)
// Convert velocity to km/h
mAcceleration = velocity // Convert to km/h
// mAcceleration = velocity * 3.6 // Convert to km/h
// velocityLabel.text = String(format: "%.1f m/s^2", velocity)
// avgVelocityLabel.text = String(format: "%.1f km/h", velocity)
// accelerationLabel.text = String(format: "%.1f m/s^2", velocity)
// Update last values
lastX = filteredX
lastY = filteredY
lastZ = filteredZ
}
private func requestLocationUpdates() {
if CLLocationManager.locationServicesEnabled() {
locationManager.desiredAccuracy = kCLLocationAccuracyBest
// locationManager.requestLocation()
if (!locationServicesIsEnabled()) {
onLocationServicesIsDisabled();
}
else if (authorizationStatusIsDenied(status: CLLocationManager.authorizationStatus())) {
onAuthorizationStatusIsDenied();
}
else if (authorizationStatusNeedRequest(status: CLLocationManager.authorizationStatus())) {
onAuthorizationStatusNeedRequest();
}
else if (authorizationStatusIsGranted(status: CLLocationManager.authorizationStatus())) {
onAuthorizationStatusIsGranted();
}
}
}
private func stopLocationUpdates() {
locationManager.stopUpdatingLocation()
}
// MARK: Helper Methods
private func initViews() {
// velocityLabel.text = "0.0 m/s^2"
// accelerationLabel.text = "0.0 m/s^2"
// avgVelocityLabel.text = "0.0 km/h"
}
private func calculateSpeed(lat1: Double, lon1: Double, lat2: Double, lon2: Double, timeDifferenceInSeconds: Double) -> Double {
let distance = calculateDistance(lat1: lat1, lon1: lon1, lat2: lat2, lon2: lon2)
return (distance / timeDifferenceInSeconds) * 3.6 // Convert to km/h
}
private func calculateDistance(lat1: Double, lon1: Double, lat2: Double, lon2: Double) -> Double {
let x = (lon2 - lon1).toRadians() * cos(((lat1 + lat2) / 2).toRadians())
let y = (lat2 - lat1).toRadians()
return sqrt(x * x + y * y) * EARTH_RADIUS
}
// Orientation Observer
func setupOrientationChangeDetection() {
NotificationCenter.default.addObserver(self, selector: #selector(orientationDidChange), name: UIDevice.orientationDidChangeNotification, object: nil)
}
@objc func orientationDidChange() {
if mIsTripStarted {
if #available(iOS 13.0, *) {
if let newOrientation = UIApplication.shared.windows.first?.windowScene?.interfaceOrientation {
if ((newOrientation.isLandscape || newOrientation.isPortrait) && (newOrientation.isLandscape != oldOrientationIsLandscape)) {
orientationCount += 1
// orientationCountLabel.text = String(orientationCount)
oldOrientationIsLandscape = !oldOrientationIsLandscape
}
}
} else {
let newOrientation = UIDevice.current.orientation
if ((newOrientation.isLandscape || newOrientation.isPortrait) && (newOrientation.isLandscape != oldOrientationIsLandscape)) {
orientationCount += 1
// orientationCountLabel.text = String(orientationCount)
oldOrientationIsLandscape = !oldOrientationIsLandscape
}
}
}
}
// MARK: TapGestureRecognizer callback
@objc func didTapView(sender: UITapGestureRecognizer) {
self.view.endEditing(true);
if (mIsTripStarted == true) {
touchCount += 1;
// touchCountLabel.text = String(touchCount);
}
}
// MARK: Timer
func startTimer() {
// let timeInterval = Int(sampleTimeTextField.text ?? String(RECORDS_INTERVAL)) ?? RECORDS_INTERVAL
let timeInterval = 2000
let queue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".telematics.timer")
timerTel = DispatchSource.makeTimerSource(queue: queue)
timerTel!.schedule(deadline: .now(), repeating: .milliseconds(timeInterval))
timerTel!.setEventHandler { [weak self] in
// do whatever stuff you want on the background queue here here
DispatchQueue.main.async {
// update your model objects and/or UI here
var jsonObject = [String: Any]()
var jsonObjectData = [String: Any]()
let timestamp = String(Int(Date().timeIntervalSince1970 * 1000))
jsonObjectData["acceleration"] = self?.mAcceleration
jsonObjectData["speed"] = self?.mSpeed
jsonObjectData["orientation_count"] = self?.orientationCount
jsonObjectData["touch_count"] = self?.touchCount
jsonObjectData["timestamp"] = timestamp
jsonObjectData["start_time"] = self?.mStartTimestamp
jsonObjectData["stop_time"] = self?.mStopTimestamp
jsonObjectData["latitude"] = self?.mLatitude
jsonObjectData["longitude"] = self?.mLongitude
jsonObjectData["limit"] = self?.getCutOffLimit()
// jsonObjectData["samples"] = Int(self?.sampleTimeTextField.text ?? String(self?.RECORDS_INTERVAL ?? 5000)) ?? self?.RECORDS_INTERVAL ?? 5000
jsonObjectData["samples"] = 2000
jsonObject[timestamp] = jsonObjectData
// let valid = JSONSerialization.isValidJSONObject(jsonObject)
// print("=== valid JSON: ", valid)
self?.mAccelerationTimestamps.append(jsonObject)
// print("=== self?.mAccelerationTimestamps: ", self?.mAccelerationTimestamps)
}
}
timerTel!.resume()
}
func stopTimer() {
timerTel?.cancel()
timerTel = nil
}
func getCutOffLimit() -> String {
// if let limitText = accelerationLimitTextField.text, !limitText.isEmpty, let limitValue = Double(limitText) {
let limitValue = 50.0
if limitValue > mAcceleration {
return "red"
} else {
return "green"
}
// }
//
// return ""
}
// MARK: Location Permissions
func locationServicesIsEnabled() -> Bool {
return (CLLocationManager.locationServicesEnabled()) ? true : false;
}
func authorizationStatusNeedRequest(status: CLAuthorizationStatus) -> Bool {
return (status == .notDetermined) ? true : false;
}
func authorizationStatusIsGranted(status: CLAuthorizationStatus) -> Bool {
return (status == .authorizedAlways || status == .authorizedWhenInUse) ? true : false;
}
func authorizationStatusIsDenied(status: CLAuthorizationStatus) -> Bool {
return (status == .restricted || status == .denied) ? true : false;
}
func onLocationServicesIsDisabled() {
locationManager.requestWhenInUseAuthorization();
}
func onAuthorizationStatusNeedRequest() {
locationManager.requestWhenInUseAuthorization();
}
func onAuthorizationStatusIsGranted() {
// print("=== onAuthorizationStatusIsGranted === ")
locationManager.startUpdatingLocation();
// registerSensor()
if (!isFirstLoad || (isFirstLoad && !hasLocationPermissions)) {
registerSensor()
}
hasLocationPermissions = true
isFirstLoad = false
}
func onAuthorizationStatusIsDenied() {
}
public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
// print("=== locationManager didChangeAuthorization: ",status)
if (authorizationStatusIsDenied(status: status)) {
onAuthorizationStatusIsDenied();
}
else if (authorizationStatusIsGranted(status: status)) {
onAuthorizationStatusIsGranted();
}
}
public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.last {
// print("=== locationManager didUpdateLocations latitude: ",location.coordinate.latitude)
// print("=== locationManager didUpdateLocations longitude: ",location.coordinate.longitude)
if mLatitude != 0 && mLongitude != 0 {
mSpeed = calculateSpeed(lat1: mLatitude, lon1: mLongitude, lat2: location.coordinate.latitude, lon2: location.coordinate.longitude, timeDifferenceInSeconds: LOCATION_UPDATE_INTERVAL / 1000)
// avgVelocityLabel.text = String(format: "%.1f", floor(mSpeed)) + " km/h"
}
mLatitude = location.coordinate.latitude
mLongitude = location.coordinate.longitude
}
}
public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("=== locationManager didFailWithError: ", error)
}
}
extension Double {
func toRadians() -> Double {
return self * .pi / 180.0
}
}
......@@ -498,8 +498,8 @@ import CoreMotion
}
}
extension Double {
func toRadians() -> Double {
return self * .pi / 180.0
}
}
//extension Double {
// func toRadians() -> Double {
// return self * .pi / 180.0
// }
//}
......