diff --git a/ios/Flutter/.last_build_id b/ios/Flutter/.last_build_id index 9694297e..3aa2cd1e 100644 --- a/ios/Flutter/.last_build_id +++ b/ios/Flutter/.last_build_id @@ -1 +1 @@ -067d482a9455eae7d109c3ac5a36de46 \ No newline at end of file +3f3d14a0ae775b56806906c2cb14a1f0 \ No newline at end of file diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 793c05d7..e686619c 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -17,9 +17,8 @@ import GoogleMaps HMGPlatformBridge.initialize(flutterViewController: mainViewController) } - HMG_Geofence.initGeofencing() if let _ = launchOptions?[.location] { - + HMG_Geofence.initGeofencing() } return super.application(application, didFinishLaunchingWithOptions: launchOptions) diff --git a/ios/Runner/Helper/Extensions.swift b/ios/Runner/Helper/Extensions.swift index f65b2fa3..a8793617 100644 --- a/ios/Runner/Helper/Extensions.swift +++ b/ios/Runner/Helper/Extensions.swift @@ -120,3 +120,13 @@ extension UIView{ } +extension UIViewController{ + func showAlert(withTitle: String, message: String){ + let alert = UIAlertController(title: withTitle, message: message, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "OK", style: .destructive, handler: nil)) + present(alert, animated: true) { + + } + } +} + diff --git a/ios/Runner/Helper/GeoZoneModel.swift b/ios/Runner/Helper/GeoZoneModel.swift index d4c6c9e3..a6e10a45 100644 --- a/ios/Runner/Helper/GeoZoneModel.swift +++ b/ios/Runner/Helper/GeoZoneModel.swift @@ -6,6 +6,7 @@ // import UIKit +import CoreLocation class GeoZoneModel{ var geofenceId:Int = -1 @@ -20,7 +21,26 @@ class GeoZoneModel{ var isCity:String? func identifier() -> String{ - return "\(geofenceId)_\(description)" + return "\(geofenceId)_hmg_geozone" + } + + func message() -> String{ + return description + } + + func toRegion(locationManager:CLLocationManager) -> CLCircularRegion?{ + if let rad = radius, let lat = latitude?.removeSpace(), let long = longitude?.removeSpace(), + let radius_d = Double("\(rad)"), let lat_d = Double(lat), let long_d = Double(long){ + + let coordinate = CLLocationCoordinate2D(latitude: lat_d, longitude: long_d) + let validatedRadius = min(radius_d, locationManager.maximumRegionMonitoringDistance) + + let region = CLCircularRegion(center: coordinate, radius: validatedRadius, identifier: identifier()) + region.notifyOnExit = true + region.notifyOnEntry = true + return region + } + return nil } class func from(json:[String:Any]) -> GeoZoneModel{ diff --git a/ios/Runner/Helper/GlobalHelper.swift b/ios/Runner/Helper/GlobalHelper.swift index 0e767a96..925b89eb 100644 --- a/ios/Runner/Helper/GlobalHelper.swift +++ b/ios/Runner/Helper/GlobalHelper.swift @@ -19,11 +19,29 @@ func dictionaryArray(from:String) -> [[String:Any]]{ } +func showNotification(identifier:String? = nil, title:String?, subtitle:String?, message:String?, sound:UNNotificationSound = UNNotificationSound.default){ + let notificationContent = UNMutableNotificationContent() + + if identifier != nil { notificationContent.categoryIdentifier = identifier! } + if title != nil { notificationContent.title = title! } + if subtitle != nil { notificationContent.body = message! } + if message != nil { notificationContent.subtitle = subtitle! } + + notificationContent.sound = UNNotificationSound.default + let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false) + let request = UNNotificationRequest(identifier: "\(Date().timeIntervalSinceNow)", content: notificationContent, trigger: trigger) + UNUserNotificationCenter.current().add(request) { error in + if let error = error { + print("Error: \(error)") + } + } +} + func httpPostRequest(urlString:String, jsonBody:[String:Any], completion:((Bool,[String:Any]?)->Void)?){ let json: [String: Any] = jsonBody let jsonData = try? JSONSerialization.data(withJSONObject: json) - + // create post request let url = URL(string: urlString)! var request = URLRequest(url: url) @@ -31,7 +49,7 @@ func httpPostRequest(urlString:String, jsonBody:[String:Any], completion:((Bool, request.addValue("*/*", forHTTPHeaderField: "Accept") request.httpMethod = "POST" request.httpBody = jsonData - + let task = URLSession.shared.dataTask(with: request) { data, response, error in guard let data = data, error == nil else { print(error?.localizedDescription ?? "No data") @@ -49,7 +67,7 @@ func httpPostRequest(urlString:String, jsonBody:[String:Any], completion:((Bool, } } - + task.resume() } diff --git a/ios/Runner/Helper/HMG_Geofence.swift b/ios/Runner/Helper/HMG_Geofence.swift index 7f20d489..2836cf11 100644 --- a/ios/Runner/Helper/HMG_Geofence.swift +++ b/ios/Runner/Helper/HMG_Geofence.swift @@ -38,7 +38,9 @@ class HMG_Geofence:NSObject{ private static var shared_:HMG_Geofence? class func shared() -> HMG_Geofence{ - assert(shared_ != nil, "HMG_Geofence is not initialized, call initGeofencing() function first.") + if HMG_Geofence.shared_ == nil{ + HMG_Geofence.initGeofencing() + } return shared_! } @@ -48,28 +50,33 @@ class HMG_Geofence:NSObject{ } func register(geoZones:[GeoZoneModel]){ - self.geoZones = geoZones - - // self.geoZones?.forEach({ (zone) in - // startMonitoring(zone: zone) - // }) - let z = geoZones[14] - if monitoredRegions().filter { $0.identifier == z.identifier()}.isEmpty{ - startMonitoring(zone: z) - } + self.geoZones = geoZones + let monitoredRegions_ = monitoredRegions() + self.geoZones?.forEach({ (zone) in + if let region = zone.toRegion(locationManager: locationManager){ + if let already = monitoredRegions_.first(where: {$0.identifier == zone.identifier()}){ + debugPrint("Already monitering region: \(already)") + }else{ + startMonitoring(region: region) + } + }else{ + debugPrint("Invalid region: \(zone.latitude ?? "invalid_latitude"),\(zone.longitude ?? "invalid_longitude"),r\(zone.radius ?? 0) | \(zone.identifier())") + } + }) } func monitoredRegions() -> Set{ return locationManager.monitoredRegions } + } // CLLocationManager Delegates extension HMG_Geofence : CLLocationManagerDelegate{ - func startMonitoring(zone: GeoZoneModel) { + func startMonitoring(region: CLCircularRegion) { if !CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self) { return } @@ -82,13 +89,9 @@ extension HMG_Geofence : CLLocationManagerDelegate{ debugPrint(message) } - if let fenceRegion = region(with: zone){ - locationManager.startMonitoring(for: fenceRegion) - locationManager.requestState(for: fenceRegion) - debugPrint("Monitering region: \(fenceRegion.center) | \(fenceRegion.identifier)") - }else{ - debugPrint("Invalid region: \(zone.latitude ?? ""),\(zone.longitude ?? ""),r\(zone.radius ?? 0) | \(zone.identifier())") - } + locationManager.startMonitoring(for: region) + locationManager.requestState(for: region) + debugPrint("Starts monitering region: \(region)") } func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) { @@ -120,70 +123,58 @@ extension HMG_Geofence : CLLocationManagerDelegate{ extension HMG_Geofence{ func handleEvent(for region: CLRegion!, transition:Transition, location:CLLocation?) { - if let zone = geoZone(by: region.identifier){ - notifyUser(forZone: zone, transition: transition, location: locationManager.location) - notifyServer(forZone: zone, transition: transition, location: locationManager.location) - } - } - - func region(with geoZone: GeoZoneModel) -> CLCircularRegion? { - - if !geoZone.identifier().isEmpty, - let radius = geoZone.radius, let lat = geoZone.latitude?.removeSpace(), let long = geoZone.longitude?.removeSpace(), - let radius_d = Double("\(radius)"), let lat_d = Double(lat), let long_d = Double(long){ - - let coordinate = CLLocationCoordinate2D(latitude: lat_d, longitude: long_d) - let region = CLCircularRegion(center: coordinate, radius: radius_d, identifier: geoZone.identifier()) - - region.notifyOnEntry = true - region.notifyOnExit = true - return region - - } - - return nil + notifyUser(forRegion: region, transition: transition, location: locationManager.location) + notifyServer(forRegion: region, transition: transition, location: locationManager.location) } func geoZone(by id: String) -> GeoZoneModel? { - return geoZones?.first(where: { $0.identifier() == id}) + var zone:GeoZoneModel? = nil + if let zones_ = geoZones{ + zone = zones_.first(where: { $0.identifier() == id}) + }else{ + // let jsonArray = UserDefaults.standard.string(forKey: "hmg-geo-fences") + } + return zone } - func notifyUser(forZone:GeoZoneModel, transition:Transition, location:CLLocation?){ - if UIApplication.shared.applicationState == .active { - mainViewController.showAlert(withTitle: transition.name(), message: forZone.identifier()) - } else { - let notificationContent = UNMutableNotificationContent() - notificationContent.title = transition.name() - notificationContent.body = forZone.identifier() - notificationContent.sound = UNNotificationSound.default - let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false) - let request = UNNotificationRequest(identifier: "\(Date().timeIntervalSinceNow)", - content: notificationContent, - trigger: trigger) - UNUserNotificationCenter.current().add(request) { error in - if let error = error { - print("Error: \(error)") - } + func notifyUser(forRegion:CLRegion, transition:Transition, location:CLLocation?){ + if let zone = geoZone(by: forRegion.identifier){ + if UIApplication.shared.applicationState == .active { + mainViewController.showAlert(withTitle: transition.name(), message: zone.message()) + }else{ + } } } - func notifyServer(forZone:GeoZoneModel, transition:Transition, location:CLLocation?){ - flutterMethodChannel?.invokeMethod("getLogGeofenceFullUrl", arguments: nil){ fullUrlString in - if let url = fullUrlString as? String{ - flutterMethodChannel?.invokeMethod("getDefaultHttpParameters", arguments: nil){ params in - if let body = params as? [String : Any]{ - httpPostRequest(urlString: url, jsonBody: body){ (status,json) in - if let json_ = json , status{ - }else{ - } - } - } - } + func notifyServer(forRegion:CLRegion, transition:Transition, location:CLLocation?){ + showNotification(title: "Notifying server..." , subtitle: forRegion.identifier, message: "") + + if let idString = forRegion.identifier.split(separator: "_").first, let idInt = Int(idString){ + let body:[String:Any] = ["PointsID":idInt,"GeoType":transition.rawValue,"PatientID":"1231755"] + let url = "https://hmgwebservices.com/Services/Patients.svc/REST/GeoF_InsertPatientFileInfo" + httpPostRequest(urlString: url, jsonBody: body){ (status,json) in + showNotification(title: transition.name(), subtitle: forRegion.identifier, message: status ? "Success: notified to server ✔️" : "Failed to notified server ✖️") } } } + // func notifyServer(forRegion:GeoZoneModel, transition:Transition, location:CLLocation?){ + // flutterMethodChannel?.invokeMethod("getLogGeofenceFullUrl", arguments: nil){ fullUrlString in + // if let url = fullUrlString as? String{ + // flutterMethodChannel?.invokeMethod("getDefaultHttpParameters", arguments: nil){ params in + // if var body = params as? [String : Any]{ + // body.updateValue(forZone.geofenceId, forKey: "PointsID") + // body.updateValue(transition.rawValue, forKey: "GeoType") + // httpPostRequest(urlString: url, jsonBody: body){ (status,json) in + // showNotification(title: transition.name(), subtitle: forZone.identifier(), message: status ? "Success: sent to server ✔️" : "Failed: sent to server ✖️") + // } + // } + // } + // } + // } + // } + } diff --git a/ios/gpx.gpx b/ios/gpx.gpx new file mode 100644 index 00000000..addbfa24 --- /dev/null +++ b/ios/gpx.gpx @@ -0,0 +1 @@ + Sverrir Sigmundarson Office Office Panorama Mall Panorama Mall Saudi Architects Crossing Saudi Architects Crossing Office Office \ No newline at end of file diff --git a/lib/config/config.dart b/lib/config/config.dart index c82c8593..4a420ec8 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -12,10 +12,10 @@ const EXA_CART_API_BASE_URL = 'https://mdlaboratories.com/exacartapi'; const PACKAGES_CATEGORIES = '/api/categories'; const PACKAGES_PRODUCTS = '/api/products'; -const BASE_URL = 'https://uat.hmgwebservices.com/'; +// const BASE_URL = 'https://uat.hmgwebservices.com/'; const PING_SERVICE = 'Services/Weather.svc/REST/CheckConnectivity'; -// const BASE_URL = 'https://hmgwebservices.com/'; +const BASE_URL = 'https://hmgwebservices.com/'; const GET_PROJECT = 'Services/Lists.svc/REST/GetProject'; ///Geofencing diff --git a/lib/core/service/geofencing/GeofencingServices.dart b/lib/core/service/geofencing/GeofencingServices.dart index f3c2081f..a186b4c4 100644 --- a/lib/core/service/geofencing/GeofencingServices.dart +++ b/lib/core/service/geofencing/GeofencingServices.dart @@ -20,6 +20,8 @@ class GeofencingServices extends BaseService { Future> getAllGeoZones(GeoZonesRequestModel request) async { hasError = false; + + var _zonesJsonString; await baseAppClient.post(GET_GEO_ZONES, onSuccess: (dynamic response, int statusCode) { var zones = response['GeoF_PointsList']; zones.forEach((json) { @@ -28,13 +30,16 @@ class GeofencingServices extends BaseService { if (kDebugMode || testZones) addTestingGeoZones(zones); - var zonesJsonString = json.encode(zones); - AppSharedPreferences().setString(HMG_GEOFENCES, zonesJsonString); - debugPrint("GEO ZONES saved to AppPreferences with key '$HMG_GEOFENCES'"); + _zonesJsonString = json.encode(zones); }, onFailure: (String error, int statusCode) { hasError = true; return Future.error(error); }, body: request.toFlatMap()); + + AppSharedPreferences pref = AppSharedPreferences(); + await pref.setString(HMG_GEOFENCES, _zonesJsonString); + debugPrint("GEO ZONES saved to AppPreferences with key '$HMG_GEOFENCES'"); + return geoZones; } @@ -51,8 +56,10 @@ class GeofencingServices extends BaseService { } addTestingGeoZones(List zones) { - zones.add({"GEOF_ID": 100, "zkH": "", "Latitude": "24.691136", "Longitude": "46.650116", "Radius": 100, "Type": 1}); - zones.add({"GEOF_ID": 101, "csO": "", "Latitude": "24.7087913", "Longitude": "46.6656461", "Radius": 100, "Type": 1}); - zones.add({"GEOF_ID": 102, "msH": "", "Latitude": "24.777577", "Longitude": "46.652675", "Radius": 100, "Type": 1}); + zones.add({"GEOF_ID": -1, "Description": "ZiK Home", "Latitude": "24.691136", "Longitude": "46.650116", "Radius": 100, "Type": 1}); + zones.add({"GEOF_ID": -2, "Description": "CS Office", "Latitude": "24.7087913", "Longitude": "46.6656461", "Radius": 100, "Type": 1}); + zones.add({"GEOF_ID": -3, "Description": "Mahmoud Shrouf Home", "Latitude": "24.777577", "Longitude": "46.652675", "Radius": 100, "Type": 1}); + zones.add({"GEOF_ID": -4, "Description": "Panorama Mall", "Latitude": "24.692453", "Longitude": "46.669168", "Radius": 450, "Type": 1}); + zones.add({"GEOF_ID": -5, "Description": "Saudi Architects Crossing", "Latitude": "24.698375", "Longitude": "46.668567", "Radius": 140, "Type": 1}); } }