Procházet zdrojové kódy

Added a way to resend unsuccessful rows

Thomas Chef před 3 roky
rodič
revize
1fc65f4c28

+ 0 - 8
JourneyGPSTracker.xcodeproj/project.pbxproj

@@ -7,9 +7,7 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
-		F5A69F9F280C0165001B0EBF /* SendPOSTData.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5A69F9E280C0165001B0EBF /* SendPOSTData.swift */; };
 		F5B11AB7281C40C1008BFBF6 /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = F5B11AB5281C40C1008BFBF6 /* Model.xcdatamodeld */; };
-		F5C6949A281D20F600A01960 /* RepeatingTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5C69499281D20F600A01960 /* RepeatingTimer.swift */; };
 		F5F388C1280B231400087E94 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5F388C0280B231400087E94 /* AppDelegate.swift */; };
 		F5F388C3280B231400087E94 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5F388C2280B231400087E94 /* SceneDelegate.swift */; };
 		F5F388C5280B231400087E94 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5F388C4280B231400087E94 /* ViewController.swift */; };
@@ -19,10 +17,8 @@
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
-		F5A69F9E280C0165001B0EBF /* SendPOSTData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendPOSTData.swift; sourceTree = "<group>"; };
 		F5B11AB3281C4071008BFBF6 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
 		F5B11AB6281C40C1008BFBF6 /* Model.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model.xcdatamodel; sourceTree = "<group>"; };
-		F5C69499281D20F600A01960 /* RepeatingTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepeatingTimer.swift; sourceTree = "<group>"; };
 		F5F388BD280B231400087E94 /* JourneyGPSTracker.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JourneyGPSTracker.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		F5F388C0280B231400087E94 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
 		F5F388C2280B231400087E94 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
@@ -79,9 +75,7 @@
 				F5F388C9280B231500087E94 /* Assets.xcassets */,
 				F5F388CB280B231500087E94 /* LaunchScreen.storyboard */,
 				F5F388CE280B231500087E94 /* Info.plist */,
-				F5A69F9E280C0165001B0EBF /* SendPOSTData.swift */,
 				F5B11AB5281C40C1008BFBF6 /* Model.xcdatamodeld */,
-				F5C69499281D20F600A01960 /* RepeatingTimer.swift */,
 			);
 			path = JourneyGPSTracker;
 			sourceTree = "<group>";
@@ -158,11 +152,9 @@
 			buildActionMask = 2147483647;
 			files = (
 				F5F388C5280B231400087E94 /* ViewController.swift in Sources */,
-				F5C6949A281D20F600A01960 /* RepeatingTimer.swift in Sources */,
 				F5F388C1280B231400087E94 /* AppDelegate.swift in Sources */,
 				F5B11AB7281C40C1008BFBF6 /* Model.xcdatamodeld in Sources */,
 				F5F388C3280B231400087E94 /* SceneDelegate.swift in Sources */,
-				F5A69F9F280C0165001B0EBF /* SendPOSTData.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 15 - 0
JourneyGPSTracker/Base.lproj/Main.storyboard

@@ -70,11 +70,26 @@
                                 <nil key="textColor"/>
                                 <nil key="highlightedColor"/>
                             </label>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Latest TS sent:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="y63-gU-mRJ">
+                                <rect key="frame" x="34" y="354" width="115" height="21"/>
+                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                <nil key="textColor"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="-" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="EhI-Pa-ZNA" userLabel="LatestTSSent">
+                                <rect key="frame" x="166" y="354" width="186" height="21"/>
+                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                <nil key="textColor"/>
+                                <nil key="highlightedColor"/>
+                            </label>
                         </subviews>
                         <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
                         <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                     </view>
                     <connections>
+                        <outlet property="latestTSSent" destination="EhI-Pa-ZNA" id="aGH-ln-pi5"/>
                         <outlet property="noOfRxGPSPos" destination="gjP-2D-NvA" id="7hy-Mg-Vvj"/>
                         <outlet property="noOfSentGPSToServer" destination="yVZ-Xq-Fgc" id="LkD-uQ-QI7"/>
                         <outlet property="pauseSwitch" destination="1zW-3R-nTk" id="z9y-HB-zSj"/>

+ 0 - 45
JourneyGPSTracker/RepeatingTimer.swift

@@ -1,45 +0,0 @@
-//
-//  RepeatingTimer.swift
-//  JourneyGPSTracker
-//
-//  Created by Thomas Chef on 2022-04-30.
-//  Copyright © 2022 Thomas Chef. All rights reserved.
-//
-
-import Foundation
-
-class RepeatingTimer {
-    let timeInterval: TimeInterval
-    init(timeInterval: TimeInterval) {
-        self.timeInterval = timeInterval
-    }
-    private lazy var timer: DispatchSourceTimer = {
-        let t = DispatchSource.makeTimerSource()
-        t.schedule(deadline: .now() + self.timeInterval, repeating:                             self.timeInterval)
-        t.setEventHandler(handler: { [weak self] in
-            self?.eventHandler?()
-        })
-        return t
-    }()
-    var eventHandler: (() -> Void)?
-    private enum State {
-        case suspended
-        case resumed
-    }
-    private var state: State = .suspended
-    func resume() {
-        if state == .resumed {
-            return
-        }
-        state = .resumed
-        timer.resume()
-    }
-    
-    func suspend() {
-        if state == .suspended {
-            return
-        }
-        state = .suspended
-        timer.suspend()
-    }
-}

+ 0 - 65
JourneyGPSTracker/SendPOSTData.swift

@@ -1,65 +0,0 @@
-//
-//  SendPOSTData.swift
-//  JourneyGPSTracker
-//
-//  Created by Thomas Chef on 2022-04-17.
-//  Copyright © 2022 Thomas Chef. All rights reserved.
-//
-
-import Foundation
-import CoreLocation
-import UIKit
-import CoreData
-
-struct GPS_POS_LOG: Codable {
-    var latitude: Double
-    var longitude: Double
-    var ts: String
-}
-
-func sendToHttpServer(gpsPosLog: [GPS_POS_LOG]) {
-
-    print("sendToHttpServer()")
-        
-    let jsonEncoder = JSONEncoder()
-    jsonEncoder.outputFormatting = .prettyPrinted
-  
-    var uploadData:Data?
-    do {
-        uploadData = try jsonEncoder.encode(gpsPosLog)
-    } catch {
-        print(error.localizedDescription)
-        return
-    }
-    //print( gpsPosLog )
-    
-    let url = URL(string: "http://chef.maya.se/gpsapi/registerGPSlocation.php")!
-    var request = URLRequest(url: url)
-    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
-    request.httpMethod = "POST"
-    
-    let task = URLSession.shared.uploadTask(with: request, from: uploadData) { data, response, error in
-        if let error = error {
-            print ("error: \(error)")
-            return
-        }
-        guard let response = response as? HTTPURLResponse,
-            (200...299).contains(response.statusCode) else {
-            print ("200-299 server error")
-            return
-        }
-        if let mimeType = response.mimeType,
-            mimeType == "text/html",
-            let data = data,
-            let dataString = String(data: data, encoding: .utf8) {
-            print ("got data: \(dataString)")
-        }
-        else {
-            print("KALLE:" + String(response.mimeType!))
-        }
-    }
-    task.resume()
-
-}
-
-//}

+ 122 - 52
JourneyGPSTracker/ViewController.swift

@@ -12,7 +12,14 @@ import CoreData
 
 class ViewController: UIViewController {
     
+    struct GPS_POS_LOG: Codable {
+        var latitude: Double
+        var longitude: Double
+        var ts: String
+    }
+   
     
+    @IBOutlet weak var latestTSSent: UILabel!
     @IBOutlet weak var noOfRxGPSPos: UILabel!
     @IBOutlet weak var noOfSentGPSToServer: UILabel!
     @IBOutlet weak var pauseSwitch: UISwitch!
@@ -28,8 +35,8 @@ class ViewController: UIViewController {
     
     let appDelegate = UIApplication.shared.delegate as! AppDelegate
     
+    var latestDateSuccSent: Date = Date(timeIntervalSinceReferenceDate: -123456789.0)
     
-
     override func viewDidLoad() {
         super.viewDidLoad()
         locationManager = CLLocationManager()
@@ -44,57 +51,105 @@ class ViewController: UIViewController {
         
     }
     
-    func convertStartDate(StartDate: Date) -> String {
-
-        let dateFormatter = DateFormatter()
-        dateFormatter.timeZone = TimeZone.current
-        dateFormatter.dateFormat = "yyy-MM-dd' 'HH:mm:ss"
-        let dateString = dateFormatter.string(from: StartDate)
-        //dateFormatter.dateFormat = "yyy-MM-dd HH:mm:ss +0000"
-        //let date = dateFormatter.date(from: dateString)
-        return dateString
-    }
+   
     
+    // This timer is used to send data to the back-end server every 60 seconds
+    // Data source is the core data DB
     func setupTimer() {
         
         _ = Timer.scheduledTimer(withTimeInterval: 60.0, repeats: true) { [self] timer in
             
-            print("New Timer fired!")
+            var latestDate: Date = Date(timeIntervalSinceReferenceDate: -123456789.0)
             
             let cnxt = self.appDelegate.persistentContainer.viewContext
             let request: NSFetchRequest<GPS> = GPS.fetchRequest()
+            let myPredicate = NSPredicate(format: "ts > %@", latestDateSuccSent as CVarArg)
+            
+            request.predicate = myPredicate
             
             do {
                 let fd = try cnxt.fetch(request)
-                print( "Cnt:" + String(fd.count) )
+                print( "Timer: DB Request returned:" + String(fd.count) )
                 
-                var positions: [GPS_POS_LOG] = []
-                
-                fd.forEach { row in
-                    let ts = self.convertStartDate(StartDate: row.ts!)
-                    let gpsPosLog = GPS_POS_LOG(latitude:row.latitude,longitude: row.longitud,ts: ts)
-                    positions.append(gpsPosLog)
-                    cnxt.delete(row)
-                    self.noOfSentToServer += 1
+                if( fd.count > 0 ) {
+                    var positions: [GPS_POS_LOG] = []
+                    
+                    fd.forEach { row in
+                        let ts = convertStartDate(StartDate: row.ts!)
+                        let gpsPosLog = GPS_POS_LOG(latitude:row.latitude,longitude: row.longitud,ts: ts)
+                        positions.append(gpsPosLog)
+                        //cnxt.delete(row)          // This row deletes the row in the DB
+                        self.noOfSentToServer += 1
+                        
+                        if( row.ts! > latestDate ) {
+                            latestDate = row.ts!;       // Save the latest date
+                        }
+                    }
+                    sendToHttpServer(gpsPosLog: positions, latestDate: latestDate)
+                    noOfSentGPSToServer.text = String(noOfSentToServer) // Update GUI
+                }
+                else {
+                    print("Timer: No data to send to back-end");
                 }
-                sendToHttpServer(gpsPosLog: positions)
-                noOfSentGPSToServer.text = String(noOfSentToServer)
                 
             } catch let error as NSError {
-                print("Could not fetch. \(error), \(error.userInfo)")
+                print("Timer: Could not fetch. \(error), \(error.userInfo)")
             }
             if( self.trackingActivateSwitch.isOn == false ) {
                 timer.invalidate()
-                print("Stopping Timer")
+                print("Timer: Stopping Timer")
             }
+            
+            latestTSSent.text = convertStartDate(StartDate: latestDate)
         }
     }
     
+    func sendToHttpServer(gpsPosLog: [GPS_POS_LOG], latestDate: Date) {
+
+        let jsonEncoder = JSONEncoder()
+        jsonEncoder.outputFormatting = .prettyPrinted
+      
+        var uploadData:Data?
+        do {
+            uploadData = try jsonEncoder.encode(gpsPosLog)
+        } catch {
+            print(error.localizedDescription)
+            return
+        }
+        //print( gpsPosLog )
+        
+        let url = URL(string: "http://chef.maya.se/gpsapi/registerGPSlocation.php")!
+        var request = URLRequest(url: url)
+        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
+        request.httpMethod = "POST"
+        
+        let task = URLSession.shared.uploadTask(with: request, from: uploadData) { data, response, error in
+            if let error = error {
+                print ("HTTP: error: \(error)")
+                return
+            }
+            guard let response = response as? HTTPURLResponse,
+                (200...299).contains(response.statusCode) else {
+                print ("HTTP: 200-299 server error")
+                return
+            }
+            if let mimeType = response.mimeType,
+                mimeType == "text/html",
+                let data = data,
+                let dataString = String(data: data, encoding: .utf8) {
+                print ("HTTP: got data: \(dataString)")
+                print ("HTTP: Latest date sent: " + self.convertStartDate(StartDate: latestDate))
+                //self.latestTSSent.text = self.convertStartDate(StartDate: latestDate)
+                self.latestDateSuccSent = latestDate
+            }
+            else {
+                print("HTTP: KALLE:" + String(response.mimeType!))
+            }
+        }
+        task.resume()
 
-    
-    @objc func fireTimer() {
     }
-    
+   
     @IBAction func tackingPauseChanged(_ sender: UISwitch) {
         print("Pause-Switch Changed !")
         switch sender.isOn {
@@ -119,6 +174,7 @@ class ViewController: UIViewController {
             } catch {
                 // Error Handling
             }
+            latestDateSuccSent = Date(timeIntervalSinceReferenceDate: -123456789.0)
             print("ON")
             locationManager?.startUpdatingLocation()
             pauseSwitch.isEnabled = true
@@ -126,6 +182,7 @@ class ViewController: UIViewController {
             noOfSentToServer = 0
             noOfRxGPSPos.text = String(noOfSentPos)
             noOfSentGPSToServer.text = String(noOfSentToServer)
+            latestTSSent.text = "-"
             setupTimer()
         default:
             print("OFF")
@@ -139,44 +196,28 @@ class ViewController: UIViewController {
 }
 
 extension ViewController: CLLocationManagerDelegate {
-  // handle delegate methods of location manager here
-    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
-        print("location manager authorization status changed")
-        
-        switch status {
-        case .authorizedAlways:
-            print("user allow app to get location data when app is active or in background")
-        case .authorizedWhenInUse:
-            print("user allow app to get location data only when app is active")
-        case .denied:
-            print("user tap 'disallow' on the permission dialog, cant get location data")
-        case .restricted:
-            print("parental control setting disallow location data")
-        case .notDetermined:
-            print("the location permission dialog haven't shown before, user haven't tap allow/disallow")
-        }
-    }
+
     
     // Step 7: Handle the location information
+    // This function is called when there is a new location available
+    // The data is put into the core data DB
     func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
         
-        print("LocationManager didUpdateLocations: numberOfLocation: \(locations.count)")
+        print("Got a new position: numberOfLocations received: \(locations.count)")
         let dateFormatter = DateFormatter()
         dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
         
+        
+        
         noOfSentPos += 1
         noOfRxGPSPos.text = String(noOfSentPos)
         
-        //placeOrder(didUpdateLocations: locations)
-        
         let managedContext = appDelegate.persistentContainer.viewContext
         let entity = NSEntityDescription.entity(forEntityName: "GPS", in: managedContext)!
 
         // Loop through all GPS Positions and send them to the Database
         locations.forEach { (location) in
-            //print("LocationManager didUpdateLocations: \(dateFormatter.string(from: location.timestamp)); \(location.coordinate.latitude), \(location.coordinate.longitude)")
-            print("LocationManager horizontalAccuracy: \(location.horizontalAccuracy)")
-            //print("LocationManager verticalAccuracy: \(location.verticalAccuracy)")
+            //print("LocationManager horizontalAccuracy: \(location.horizontalAccuracy)")
             
             let pos = NSManagedObject(entity: entity,insertInto: managedContext)
             pos.setValue(location.coordinate.longitude, forKey: "longitud")
@@ -184,7 +225,6 @@ extension ViewController: CLLocationManagerDelegate {
             pos.setValue(location.timestamp, forKey: "ts")
             do {
                 try managedContext.save()
-                //people.append(person)
             } catch let error as NSError {
                 print("Could not save. \(error), \(error.userInfo)")
             }
@@ -200,5 +240,35 @@ extension ViewController: CLLocationManagerDelegate {
          return
       }
     }
+    
+    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
+        print("location manager authorization status changed")
+        
+        switch status {
+        case .authorizedAlways:
+            print("user allow app to get location data when app is active or in background")
+        case .authorizedWhenInUse:
+            print("user allow app to get location data only when app is active")
+        case .denied:
+            print("user tap 'disallow' on the permission dialog, cant get location data")
+        case .restricted:
+            print("parental control setting disallow location data")
+        case .notDetermined:
+            print("the location permission dialog haven't shown before, user haven't tap allow/disallow")
+        }
+    }
+    
+    func convertStartDate(StartDate: Date) -> String {
+
+        let dateFormatter = DateFormatter()
+        dateFormatter.timeZone = TimeZone.current
+        dateFormatter.dateFormat = "yyy-MM-dd' 'HH:mm:ss"
+        let dateString = dateFormatter.string(from: StartDate)
+        //dateFormatter.dateFormat = "yyy-MM-dd HH:mm:ss +0000"
+        //let date = dateFormatter.date(from: dateString)
+        return dateString
+    }
+
+
 }