using GMCabsDriverAssistant.Models; using GMCabsDriverAssistant.Services; using GMCabsDriverAssistant.Utils; using GMCabsDriverAssistant.ViewModels; using GMCabsDriverAssistantSolution.Views; //using Plugin.BluetoothLE; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Text; using System.Threading; //using Xamarin.CommunityToolkit.Extensions; using Microsoft.Maui; using Microsoft.Maui.Controls; using GMCabsDriverAssistantSolution.ViewModels; namespace GMCabsDriverAssistant.UserControl.ViewModels { public delegate void BluetoothStatusChanged(); class TripInformationViewModel : BaseViewModel { [Browsable(true)] [Category("Action")] [Description("Invoked when user clicks button")] public event BluetoothStatusChanged BluetoothStatusChanged; #region Fields private bool hasUnreadNotifications; public int seconds = 0; public string timerSeconds = "00:00:00"; public string pickUpAddress = ""; public string dropUpAddress = ""; private bool isBookingAvailable; private string startTripButtonText; private bool visibleTrip; private string startSuburb; private bool isStartTripButtonVisible; private string pickUpDateTimeOrEndSuburb; //private List Characteristics; private bool foundDevice = false; //private IAdapter adapter; public bool MeterTripStarted; private int lastMeterTripStatus = -1; private string startTimeOrEndLocation; private bool isOkButtonVisible = false; public int autocloseOkSecond = 30; Page _page; private int mainStackLayoutMargin; private int indicatorMargin; private int logoMargin; private bool isDummyButtonsVisible; private int controlsMargin; private int dummyButtonLayoutMargin; private bool duressReleased; private int duressSeconds; private string duressButtonText; private string bluetoothConnectionStatusText; private string imageIcon; private int topLayoutMargin; private int rightLayoutMargin; private bool isPlotButtonVisible; #endregion #region Properties public Command OnStartEndTripClick { get; } MeterTrip meterTrip = new MeterTrip(); public ObservableCollection Bookings { get; } public Command BookingTapped { get; } public double CurrentLat { get; set; } public double CurrentLng { get; set; } public Location CurrentLocation { get; set; } public Command onStartTripClick { get; } public Command OnOkButtonClick { get; } public string StartTripButtonText { get => startTripButtonText; set => SetProperty(ref startTripButtonText, value); } public bool HasUnreadNotifications { get => hasUnreadNotifications; set => SetProperty(ref hasUnreadNotifications, value); } public string TimerSeconds { get => timerSeconds; set => SetProperty(ref timerSeconds, value); } public string PickUpAddress { get => pickUpAddress; set { SetProperty(ref pickUpAddress, value); } } public string DropUpAddress { get => dropUpAddress; set { SetProperty(ref dropUpAddress, value); } } public bool IsBookingAvailable { get => isBookingAvailable; set => SetProperty(ref isBookingAvailable, value); } public bool VisibleTrip { get => visibleTrip; set => SetProperty(ref visibleTrip, value); } public string StartSuburb { get => startSuburb; set { SetProperty(ref startSuburb, value); } } public bool IsStartTripButtonVisible { get => isStartTripButtonVisible; set => SetProperty(ref isStartTripButtonVisible, value); } public string PickUpDateTimeOrEndSuburb { get => pickUpDateTimeOrEndSuburb; set => SetProperty(ref pickUpDateTimeOrEndSuburb, value); } public Thickness MainStackLayoutMargin { get { return new Thickness(mainStackLayoutMargin, 0, mainStackLayoutMargin, 20); } } public Thickness IndicatorMargin { get { return new Thickness(0, indicatorMargin, 0, 0); } } public Thickness LogoMargin { #if DEBUG get { return new Thickness(0, logoMargin, 0, 0); } #else get { return new Thickness(logoMargin, 0 , 0, 0); } #endif } public Thickness ImageLayoutMargin { #if DEBUG get { return new Thickness(0, topLayoutMargin, rightLayoutMargin, 0); } #else get { return new Thickness(0, topLayoutMargin, rightLayoutMargin, 0); } #endif } public Thickness ControlsMargin { get { return new Thickness(0, controlsMargin, 0, 0); } } public Thickness DummyButtonLayoutMargin { get { return new Thickness(0, dummyButtonLayoutMargin, 0, 0); } } public bool IsDummyButtonsVisible { get => isDummyButtonsVisible; set { SetProperty(ref isDummyButtonsVisible, value); } } public Command onCancelTripClick { get; } public Command OnMeterStartTripClick { get; } public Command OnMeterEndTripClick { get; } public string StartTimeOrEndLocation { get => startTimeOrEndLocation; set => SetProperty(ref startTimeOrEndLocation, value); } public bool IsOkButtonVisible { get => isOkButtonVisible; set => SetProperty(ref isOkButtonVisible, value); } public string BluetoothConnectionStatusText { get => bluetoothConnectionStatusText; set { SetProperty(ref bluetoothConnectionStatusText, value); BluetoothStatusChanged?.Invoke(); } } public string DuressButtonText { get => duressButtonText; set { SetProperty(ref duressButtonText, value); } } public string ImageIcon { get => imageIcon; set { SetProperty(ref imageIcon, value); } } public bool IsPlotButtonVisible { get => isPlotButtonVisible; set => SetProperty(ref isPlotButtonVisible, value); } #endregion #region Constructor public TripInformationViewModel() { ContinuouslyShowAllPropertiesStatus(); ShowStartTimerDuration(DispatchAppComponentService.isTripStarted); CountEndTripDuration(DispatchAppComponentService.isTripEndeded); lastMeterTripStatus = Preferences.Get("MeterTripStatus", 0); OnOkButtonClick = new Command(OnOkClick); OnStartEndTripClick = new Command(OnStartEndTripButtonClick); OnMeterStartTripClick = new Command(CallMeterStartTrip); OnMeterEndTripClick = new Command(MeterEndTrip); DuressButtonText = "!"; CheckForConnectedMeter(); #if DEBUG mainStackLayoutMargin = 30; indicatorMargin = 5; logoMargin = 20; IsDummyButtonsVisible = true; controlsMargin = 20; dummyButtonLayoutMargin = 10; topLayoutMargin = -5; rightLayoutMargin = -15; #else mainStackLayoutMargin = 30; indicatorMargin = 5; logoMargin = 20; IsDummyButtonsVisible = true; controlsMargin = 20; dummyButtonLayoutMargin = 10; topLayoutMargin = -5; rightLayoutMargin = -15; #endif } #endregion #region Methods private void OnStartEndTripButtonClick(object obj) { ManageDriverTrip(false); } private void OnOkClick() { DispatchAppComponentService.OnOkClick(); DispatchAppComponentService.isPlotButtonVisible = true; ShowAllPropertiesStatus(); } private void MeterStartTrip() { // setting MeterTripStarted only here to ensure a manual trip does not get mistaken for a meter trip if (!MeterTripStarted) { StartTripButtonText = DispatchAppComponentService.MeterStartTrip(); ManageDriverTrip(true); } } private void MeterEndTrip() { if (MeterTripStarted) { StartTripButtonText = DispatchAppComponentService.MeterEndTrip(); ManageDriverTrip(true); } } public void StartDriverDuress() { duressReleased = false; duressSeconds = 0; bool hasVibrated = false; Device.StartTimer(TimeSpan.FromSeconds(1), () => { duressSeconds++; if (duressSeconds > 2) { if (!hasVibrated) { hasVibrated = true; Vibration.Vibrate(TimeSpan.FromSeconds(1)); } } if (duressReleased) { return false; } else { return true; } }); } public async void EndDriverDuress() { duressReleased = true; Vibration.Cancel(); if (duressSeconds > 2) { var token = Preferences.Get(SecureStorageData.Token,""); GMCabsDriverService gmCabsDriverService = new GMCabsDriverService(); var currentLocation = Geolocation.GetLastKnownLocationAsync(); double currentLat = 0; double currentLng = 0; if (currentLocation != null && currentLocation.Result != null) { currentLat = currentLocation.Result.Latitude; currentLng = currentLocation.Result.Longitude; } await gmCabsDriverService.DriverDistress(token, currentLat, currentLng); DuressButtonText = "..."; await System.Threading.Tasks.Task.Delay(2000); DuressButtonText = "!"; } } private void ShowStartTimerDuration(bool isTripStarted) { seconds = DispatchAppComponentService.seconds; if (isTripStarted) { Device.StartTimer(TimeSpan.FromSeconds(1), () => { var meterRunningStatus = Preferences.Get("MeterRunningStatus", ""); if (meterRunningStatus == "Running") { Device.BeginInvokeOnMainThread(() => { ++seconds; DispatchAppComponentService.StartTrip(seconds); TimerSeconds = DispatchAppComponentService.timerSeconds; DispatchAppComponentService.seconds = seconds; }); } if (meterRunningStatus == "Running") return true; else return false; }); } } private void CountEndTripDuration(bool isTripEnded) { autocloseOkSecond = DispatchAppComponentService.autocloseOkSecond; if (isTripEnded) { Device.StartTimer(TimeSpan.FromSeconds(1), () => { var meterRunningStatus = Preferences.Get("MeterRunningStatus", ""); if (meterRunningStatus == "Stopped") { if (autocloseOkSecond == 0) { Device.BeginInvokeOnMainThread(() => { OnOkClick(); }); } else { --autocloseOkSecond; DispatchAppComponentService.autocloseOkSecond = autocloseOkSecond; } } if (meterRunningStatus == "Stopped") return true; else return false; }); } } private void ShowAllPropertiesStatus() { ImageIcon = DispatchAppComponentService.imageIcon; IsStartTripButtonVisible = DispatchAppComponentService.isStartTripButtonVisible; IsPlotButtonVisible = DispatchAppComponentService.isPlotButtonVisible; StartTripButtonText = DispatchAppComponentService.startTripButtonText; MeterTripStarted = DispatchAppComponentService.meterTripStarted; VisibleTrip = DispatchAppComponentService.visibleTrip; StartSuburb = DispatchAppComponentService.startSuburb; PickUpDateTimeOrEndSuburb = DispatchAppComponentService.pickUpDateTimeOrEndSuburb; StartTimeOrEndLocation = DispatchAppComponentService.startTimeOrEndLocation; IsOkButtonVisible = DispatchAppComponentService.isOkButtonVisible; TimerSeconds = DispatchAppComponentService.timerSeconds; } private void ContinuouslyShowAllPropertiesStatus() { Device.StartTimer(TimeSpan.FromSeconds(1), () => { Device.BeginInvokeOnMainThread(() => { ShowAllPropertiesStatus(); }); return true; }); } public void SetTripStartEndButtonPosition() { DispatchAppComponentService.isPlotButtonVisible= false; ShowAllPropertiesStatus(); } #endregion #region Trip Handling private void ManageDriverTrip(bool fromMeter) { if (StartTripButtonText.Equals("START TRIP")) { DispatchAppComponentService.isTripStarted = true; DispatchAppComponentService.isTripEndeded = false; DispatchAppComponentService.ManageDriverTrip(fromMeter); StartTimeOrEndLocation = DispatchAppComponentService.startTimeOrEndLocation; StartTrip(fromMeter); TimerSeconds = DispatchAppComponentService.timerSeconds; DispatchAppComponentService.seconds = seconds = 0; ShowStartTimerDuration(DispatchAppComponentService.isTripStarted); DispatchAppComponentService.isPlotButtonVisible = false; } else if (StartTripButtonText.Equals("DROP OFF")) { DispatchAppComponentService.isTripStarted = false; DispatchAppComponentService.isTripEndeded = true; DispatchAppComponentService.ManageDriverTrip(fromMeter); StartTimeOrEndLocation = DispatchAppComponentService.startTimeOrEndLocation; EndTrip(fromMeter); IsOkButtonVisible = DispatchAppComponentService.isOkButtonVisible; DispatchAppComponentService.autocloseOkSecond = autocloseOkSecond = 30; CountEndTripDuration(DispatchAppComponentService.isTripEndeded); } } private async void StartTrip(bool fromMeter) { DispatchAppComponentService.startSuburb = await DispatchAppComponentService.GetSuburbName(fromMeter, true); MeterTripStarted = DispatchAppComponentService.meterTripStarted; ImageIcon = DispatchAppComponentService.imageIcon; VisibleTrip = DispatchAppComponentService.visibleTrip; StartSuburb = DispatchAppComponentService.startSuburb; PickUpDateTimeOrEndSuburb = DispatchAppComponentService.pickUpDateTimeOrEndSuburb; StartTripButtonText = DispatchAppComponentService.startTripButtonText; } private async void EndTrip(bool fromMeter) { DispatchAppComponentService.pickUpDateTimeOrEndSuburb = await DispatchAppComponentService.GetSuburbName(fromMeter, false); MeterTripStarted = DispatchAppComponentService.meterTripStarted; PickUpDateTimeOrEndSuburb = DispatchAppComponentService.pickUpDateTimeOrEndSuburb; ImageIcon = DispatchAppComponentService.imageIcon; IsStartTripButtonVisible = DispatchAppComponentService.isStartTripButtonVisible; } private void CallMeterStartTrip() { DispatchAppComponentService.startTripButtonText = "START TRIP"; DispatchAppComponentService.meterTripStarted = false; DispatchAppComponentService.isTripStarted = true; DispatchAppComponentService.isTripEndeded = false; DispatchAppComponentService.isOkButtonVisible = false; DispatchAppComponentService.isStartTripButtonVisible = true; DispatchAppComponentService.ManageDriverTrip(false); StartTimeOrEndLocation = DispatchAppComponentService.startTimeOrEndLocation; StartTrip(false); TimerSeconds = DispatchAppComponentService.timerSeconds; DispatchAppComponentService.seconds = seconds = 0; ShowStartTimerDuration(DispatchAppComponentService.isTripStarted); } #endregion Trip Handling #region Meter Handling private void CheckForConnectedMeter() { // ConnectToMeter(); } //private void ConnectToMeter() //{ // adapter = CrossBleAdapter.Current; // var status = adapter.Status.ToString(); // if (status.Contains("Off")) // { // bluetoothConnectionStatusText = "Bluetooth connection off..."; // } // else // { // BluetoothConnectionStatusText = "Checking meter connection..."; // BluetoothConnectionStatusText = $"Adapter status {CrossBleAdapter.Current.Status.ToString()}"; // IDevice bondedDevice = null; // CrossBleAdapter.Current.GetConnectedDevices().Subscribe(deviceResult => // { // bondedDevice = deviceResult.GetEnumerator().Current; // }); // if (bondedDevice != null && bondedDevice.Status == ConnectionStatus.Connected) // { // ListenForCharacteristic(bondedDevice); // } // else // { // CrossBleAdapter.Current.GetPairedDevices().Subscribe(devices => // { // if (devices != null) // { // ConnectionConfig conConfig = new ConnectionConfig(); // conConfig.AutoConnect = true; // BluetoothConnectionStatusText = $"Listening for paired device"; // foreach (var pairedDevice in devices) // { // pairedDevice.ConnectWait(conConfig).Subscribe(device => // { // Xamarin.Forms.Device.BeginInvokeOnMainThread(() => { BluetoothConnectionStatusText = $"{device.Status}"; }); // ListenForCharacteristic(pairedDevice); // }); // } // } // }); // if (CrossBleAdapter.Current.IsScanning) // { // BluetoothConnectionStatusText = $"resuming scan"; // } // else // { // BluetoothConnectionStatusText = $"Adapter status {CrossBleAdapter.Current.Status.ToString()} - Scanning"; // Characteristics = new List(); // var scanResult = CrossBleAdapter.Current.Scan().Subscribe(scResult => { CheckDevice(scResult); }, exception => // { // Xamarin.Forms.Device.BeginInvokeOnMainThread(() => { BluetoothConnectionStatusText = $"Error: {exception.Message}"; }); // }); // } // } // } //} //private void CheckDevice(IScanResult scanResult) //{ // if (scanResult.Device.Name != null && scanResult.Device.Name.StartsWith("MTI_") && !foundDevice) // { // BluetoothConnectionStatusText = $"Meter found - {scanResult.Device.Name}"; // foundDevice = true; // CrossBleAdapter.Current.StopScan(); // ConnectToDevice(scanResult.Device); // } //} //private void ConnectToDevice(IDevice discoveredDevice) //{ // ConnectionConfig conConfig = new ConnectionConfig(); // conConfig.AutoConnect = true; // Xamarin.Forms.Device.BeginInvokeOnMainThread(() => { BluetoothConnectionStatusText = $"Device Details - P:{discoveredDevice.PairingStatus.ToString()} - C:{discoveredDevice.IsConnected()}"; }); // if (discoveredDevice.IsConnected()) // { // Xamarin.Forms.Device.BeginInvokeOnMainThread(() => { BluetoothConnectionStatusText = $"Searching for GUIDs"; }); // ListenForCharacteristic(discoveredDevice); // } // else // { // if (discoveredDevice.PairingStatus == PairingStatus.NotPaired) // { // Xamarin.Forms.Device.BeginInvokeOnMainThread(() => { BluetoothConnectionStatusText = $"Pairing"; }); // discoveredDevice.PairingRequest("191135"); // } // Xamarin.Forms.Device.BeginInvokeOnMainThread(() => { BluetoothConnectionStatusText = $"Connecting"; }); // discoveredDevice.ConnectWait(conConfig).Subscribe(device => // { // Xamarin.Forms.Device.BeginInvokeOnMainThread(() => { BluetoothConnectionStatusText = $"{device.Status}"; }); // ListenForCharacteristic(device); // }); // } //} //private void ListenForCharacteristic(IDevice device) //{ // bool subscribed = false; // try // { // device.GetKnownCharacteristics(Guid.Parse("de201840-063f-11e5-be3e-0002a5d5c51b"), new Guid[] { Guid.Parse("de000180-063f-11e5-9e69-0002a5d5c503") }).Subscribe(characteristics => // { // Xamarin.Forms.Device.BeginInvokeOnMainThread(() => { BluetoothConnectionStatusText = $"Service Detected"; }); // if (characteristics != null) // { // characteristics.RegisterAndNotify().Subscribe(registerResult => // { // // RegisterAndNotify seems to keep firing each time, there must be a better way // // to do this only once, currently just setting a local flag. // if (!subscribed) // { // Xamarin.Forms.Device.BeginInvokeOnMainThread(() => // { // BluetoothConnectionStatusText = "Ready"; // }); // subscribed = true; // characteristics.WhenNotificationReceived().Subscribe(notification => { CheckNotification(notification); }); // } // }); // } // }); // } // catch(Exception ex) // { // } //} //private void CheckNotification(CharacteristicGattResult notification) //{ // if (notification != null && notification.Data != null && notification.Characteristic != null && notification.Characteristic.Uuid.ToString() == "de000180-063f-11e5-9e69-0002a5d5c503") // { // string data = $"Date:{DateTime.Now.ToString("HH:mm:ss")}, Description:{notification.Characteristic.Uuid},Data:{BitConverter.ToString(notification.Data)}\n"; // Xamarin.Forms.Device.BeginInvokeOnMainThread(() => // { // int tripStatus = 0; // if (notification.Data[0] != 0) { tripStatus = 1; } // if (lastMeterTripStatus != tripStatus) // { // lastMeterTripStatus = tripStatus; // Preferences.Set("MeterTripStatus", tripStatus); // if (tripStatus == 0) // { // MeterEndTrip(); // } // else if (tripStatus == 1) // { // //MeterStartTrip(); // CallMeterStartTrip(); // } // } // }); // } //} #endregion Meter Handling } }