diff --git a/TINKLib/ViewModel/FindBike/FindBikePageViewModel.cs b/TINKLib/ViewModel/FindBike/FindBikePageViewModel.cs index 908c372..b7f11e6 100644 --- a/TINKLib/ViewModel/FindBike/FindBikePageViewModel.cs +++ b/TINKLib/ViewModel/FindBike/FindBikePageViewModel.cs @@ -29,6 +29,13 @@ namespace TINK.ViewModel.FindBike { public class FindBikePageViewModel : BikesViewModel, INotifyCollectionChanged, INotifyPropertyChanged { + + /// Text entered by user to specify a bike. + public string BikeIdUserInput { get; set; } + + /// Holds all bikes available. + public BikeCollection Bikes { get; set; } + /// /// Constructs bike collection view model in case information about occupied bikes is available. /// @@ -66,23 +73,174 @@ namespace TINK.ViewModel.FindBike /// public async Task OnAppearing() { - // Get my bikes from COPRI - Log.ForContext().Information("User request to show page MyBikes/ page re-appearing"); + Log.ForContext().Information("User request to show page FindBike- page re-appearing"); ActionText = AppResources.ActivityTextMyBikesLoadingBikes; var bikes = await ConnectorFactory(IsConnected).Query.GetBikesAsync(); Exception = bikes.Exception; // Update communication error from query for bikes occupied. - - BikeIds = bikes.Response.Select(x => x.Id); + Bikes = bikes.Response; ActionText = ""; IsIdle = true; } + /// Command object to bind select bike button to view model. + public System.Windows.Input.ICommand OnSelectBikeRequest => new Xamarin.Forms.Command(async () => await SelectBike()); - public IEnumerable BikeIds { get; set; } + /// Select a bike by ID + public async Task SelectBike() + { + var selectedBike = Bikes.FirstOrDefault(x => x.Id == BikeIdUserInput); + if (selectedBike == null) + { + await ViewService.DisplayAlert("Fehler bei Radauswahl!", $"Kein Rad mit Id {BikeIdUserInput} gefunden.", "OK"); + return; + } + + var bikeCollection = new BikeCollection(new Dictionary { { selectedBike.Id, selectedBike } }); + + var lockIdList = bikeCollection + .GetLockIt() + .Cast() + .Select(x => x.LockInfo) + .ToList(); + + if (LockService is ILocksServiceFake serviceFake) + { + serviceFake.UpdateSimulation(bikeCollection); + } + + // Check bluetooth and location permission and states + ActionText = AppResources.ActivityTextCheckBluetoothState; + + if (bikeCollection.FirstOrDefault(x => x is BikeInfo btBike) != null + && RuntimePlatform == Device.Android) + { + // Check location permission + var status = await PermissionsService.CheckPermissionStatusAsync(); + if (status != PermissionStatus.Granted) + { + var permissionResult = await PermissionsService.RequestPermissionAsync(); + + if (permissionResult != PermissionStatus.Granted) + { + var dialogResult = await ViewService.DisplayAlert( + AppResources.MessageTitleHint, + AppResources.MessageBikesManagementLocationPermissionOpenDialog, + AppResources.MessageAnswerYes, + AppResources.MessageAnswerNo); + + if (!dialogResult) + { + // User decided not to give access to locations permissions. + BikeCollection.Update(bikeCollection); + + //await OnAppearing(() => UpdateTask()); + + ActionText = ""; + IsIdle = true; + return; + } + + // Open permissions dialog. + PermissionsService.OpenAppSettings(); + } + } + + // Location state + if (Geolocation.IsGeolcationEnabled == false) + { + await ViewService.DisplayAlert( + AppResources.MessageTitleHint, + AppResources.MessageBikesManagementLocationActivation, + AppResources.MessageAnswerOk); + + BikeCollection.Update(bikeCollection); + + await OnAppearing(() => UpdateTask()); + + ActionText = ""; + IsIdle = true; + return; + } + + // Bluetooth state + if (await BluetoothService.GetBluetoothState() != BluetoothState.On) + { + await ViewService.DisplayAlert( + AppResources.MessageTitleHint, + AppResources.MessageBikesManagementBluetoothActivation, + AppResources.MessageAnswerOk); + + BikeCollection.Update(bikeCollection); + + await OnAppearing(() => UpdateTask()); + + ActionText = ""; + IsIdle = true; + return; + } + } + + // Connect to bluetooth devices. + ActionText = AppResources.ActivityTextSearchBikes; + IEnumerable locksInfoTdo; + try + { + locksInfoTdo = await LockService.GetLocksStateAsync( + lockIdList.Select(x => x.ToLockInfoTdo()).ToList(), + LockService.TimeOut.MultiConnect); + } + catch (Exception exception) + { + Log.ForContext().Error("Getting bluetooth state failed. {Exception}", exception); + locksInfoTdo = new List(); + } + + var locksInfo = lockIdList.UpdateById(locksInfoTdo); + + BikeCollection.Update(bikeCollection.UpdateLockInfo(locksInfo)); + + await OnAppearing(() => UpdateTask()); + + ActionText = ""; + IsIdle = true; + + } + + /// Create task which updates my bike view model. + private void UpdateTask() + { + // Start task which periodically updates pins. + PostAction( + unused => + { + ActionText = AppResources.ActivityTextUpdating; + IsConnected = IsConnectedDelegate(); + }, + null); + + var result = ConnectorFactory(IsConnected).Query.GetBikesOccupiedAsync().Result; + + var bikes = result.Response; + + var exception = result.Exception; + if (exception != null) + { + Log.ForContext().Error("Getting bikes occupied in polling context failed with exception {Exception}.", exception); + } + + PostAction( + unused => + { + BikeCollection.Update(bikes); // Updating collection leads to update of GUI. + Exception = result.Exception; + ActionText = string.Empty; + }, + null); + } } }