2023-08-31 12:20:06 +02:00
|
|
|
using System;
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
using Serilog;
|
2024-04-09 12:53:23 +02:00
|
|
|
using ShareeBike.MultilingualResources;
|
|
|
|
using ShareeBike.Services.Logging;
|
|
|
|
using ShareeBike.View;
|
|
|
|
using static ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.OpenCommand;
|
2023-08-31 12:20:06 +02:00
|
|
|
using System.ComponentModel;
|
|
|
|
|
2024-04-09 12:53:23 +02:00
|
|
|
namespace ShareeBike.ViewModel.Bikes.Bike.BluetoothLock
|
2023-08-31 12:20:06 +02:00
|
|
|
{
|
|
|
|
/// <summary>
|
2024-04-09 12:53:23 +02:00
|
|
|
/// View model for action open bluetooth lock.
|
2023-08-31 12:20:06 +02:00
|
|
|
/// </summary>
|
|
|
|
/// <typeparam name="T"></typeparam>
|
2024-04-09 12:53:23 +02:00
|
|
|
internal class OpenLockActionViewModel<T> : IOpenCommandListener
|
2023-08-31 12:20:06 +02:00
|
|
|
{
|
|
|
|
/// <summary>
|
|
|
|
/// View model to be used for progress report and unlocking/ locking view.
|
|
|
|
/// </summary>
|
|
|
|
private IBikesViewModel BikesViewModel { get; set; }
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// View service to show modal notifications.
|
|
|
|
/// </summary>
|
|
|
|
private IViewService ViewService { get; }
|
|
|
|
|
|
|
|
/// <summary>Object to start or stop update of view model objects from Copri.</summary>
|
|
|
|
private Func<IPollingUpdateTaskManager> ViewUpdateManager { get; }
|
|
|
|
|
2024-04-09 12:53:23 +02:00
|
|
|
/// <summary> Bike open. </summary>
|
2023-08-31 12:20:06 +02:00
|
|
|
private Model.Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable SelectedBike { get; }
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Constructs the object.
|
|
|
|
/// </summary>
|
2024-04-09 12:53:23 +02:00
|
|
|
/// <param name="selectedBike">Bike to open.</param>
|
2023-08-31 12:20:06 +02:00
|
|
|
/// <param name="viewUpdateManager">Object to start or stop update of view model objects from Copri.</param>
|
|
|
|
/// <param name="viewService">View service to show modal notifications.</param>
|
|
|
|
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
|
|
|
/// <exception cref="ArgumentException"></exception>
|
2024-04-09 12:53:23 +02:00
|
|
|
public OpenLockActionViewModel(
|
2023-08-31 12:20:06 +02:00
|
|
|
Model.Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable selectedBike,
|
|
|
|
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
|
|
|
IViewService viewService,
|
|
|
|
IBikesViewModel bikesViewModel)
|
|
|
|
{
|
|
|
|
SelectedBike = selectedBike;
|
|
|
|
ViewUpdateManager = viewUpdateManager;
|
|
|
|
ViewService = viewService;
|
|
|
|
BikesViewModel = bikesViewModel
|
|
|
|
?? throw new ArgumentException($"Can not construct {GetType().Name}-object. {nameof(bikesViewModel)} must not be null.");
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
2024-04-09 12:53:23 +02:00
|
|
|
/// Processes the open lock progress.
|
2023-08-31 12:20:06 +02:00
|
|
|
/// </summary>
|
|
|
|
/// <param name="step">Current step to process.</param>
|
|
|
|
public void ReportStep(Step step)
|
|
|
|
{
|
|
|
|
switch (step)
|
|
|
|
{
|
2024-04-09 12:53:23 +02:00
|
|
|
case Step.OpeningLock:
|
|
|
|
// 1a.Step: Open lock
|
|
|
|
BikesViewModel.ActionText = AppResources.ActivityTextOpeningLock;
|
|
|
|
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessOpenLockStepOpenLock;
|
|
|
|
BikesViewModel.RentalProcess.ImportantStepInfoText = AppResources.MarkingRentalProcessOpenLockObserve;
|
2023-08-31 12:20:06 +02:00
|
|
|
break;
|
|
|
|
|
2024-04-09 12:53:23 +02:00
|
|
|
case Step.GetLockInfos:
|
|
|
|
// 1b.Step: Get lock infos
|
|
|
|
BikesViewModel.RentalProcess.ImportantStepInfoText = AppResources.MarkingRentalProcessOpenLockWait;
|
2023-08-31 12:20:06 +02:00
|
|
|
break;
|
|
|
|
|
2024-04-09 12:53:23 +02:00
|
|
|
case Step.WaitStopPolling:
|
|
|
|
// 1c.Step: Wait for polling to be stopped
|
2023-08-31 12:20:06 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Step.UpdateLockingState:
|
2024-04-09 12:53:23 +02:00
|
|
|
// 1c.Step: Sent info to backend
|
2023-08-31 12:20:06 +02:00
|
|
|
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdatingLockingState;
|
2024-04-09 12:53:23 +02:00
|
|
|
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessOpenLockStepUpload;
|
|
|
|
BikesViewModel.RentalProcess.ImportantStepInfoText = AppResources.MarkingRentalProcessOpenLockWait;
|
2023-08-31 12:20:06 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
2024-04-09 12:53:23 +02:00
|
|
|
/// Processes the open lock state.
|
2023-08-31 12:20:06 +02:00
|
|
|
/// </summary>
|
|
|
|
/// <param name="state">State to process.</param>
|
|
|
|
/// <param name="details">Textual details describing current state.</param>
|
|
|
|
public async Task ReportStateAsync(State state, string details)
|
|
|
|
{
|
|
|
|
switch (state)
|
|
|
|
{
|
|
|
|
case State.OutOfReachError:
|
|
|
|
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
|
|
|
BikesViewModel.ActionText = string.Empty;
|
|
|
|
await ViewService.DisplayAlert(
|
2024-04-09 12:53:23 +02:00
|
|
|
AppResources.ErrorOpenLockTitle,
|
2023-08-31 12:20:06 +02:00
|
|
|
AppResources.ErrorLockOutOfReach,
|
|
|
|
AppResources.MessageAnswerOk);
|
|
|
|
break;
|
|
|
|
|
2024-04-09 12:53:23 +02:00
|
|
|
case State.CouldntOpenBoldStatusIsUnknownError:
|
2023-08-31 12:20:06 +02:00
|
|
|
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
|
|
|
BikesViewModel.ActionText = string.Empty;
|
|
|
|
await ViewService.DisplayAlert(
|
2024-04-09 12:53:23 +02:00
|
|
|
AppResources.ErrorOpenLockTitle,
|
|
|
|
AppResources.ErrorOpenLockStatusUnknown,
|
2023-08-31 12:20:06 +02:00
|
|
|
AppResources.MessageAnswerOk);
|
|
|
|
break;
|
|
|
|
|
2024-04-09 12:53:23 +02:00
|
|
|
case State.CouldntOpenBoldIsBlockedError:
|
2023-08-31 12:20:06 +02:00
|
|
|
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
|
|
|
BikesViewModel.ActionText = string.Empty;
|
|
|
|
await ViewService.DisplayAlert(
|
2024-04-09 12:53:23 +02:00
|
|
|
AppResources.ErrorOpenLockTitle,
|
|
|
|
AppResources.ErrorOpenLockBoldBlocked,
|
2023-08-31 12:20:06 +02:00
|
|
|
AppResources.MessageAnswerOk);
|
|
|
|
break;
|
|
|
|
|
2024-04-09 12:53:23 +02:00
|
|
|
case State.CouldntOpenInconsistentStateError:
|
2023-08-31 12:20:06 +02:00
|
|
|
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
|
|
|
BikesViewModel.ActionText = string.Empty;
|
|
|
|
await ViewService.DisplayAlert(
|
2024-04-09 12:53:23 +02:00
|
|
|
AppResources.ErrorOpenLockTitle,
|
|
|
|
AppResources.ErrorOpenLockStillClosed,
|
|
|
|
AppResources.MessageAnswerOk);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case State.GeneralOpenError:
|
|
|
|
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
|
|
|
BikesViewModel.ActionText = string.Empty;
|
|
|
|
await ViewService.DisplayAlert(
|
|
|
|
AppResources.ErrorOpenLockTitle,
|
2023-08-31 12:20:06 +02:00
|
|
|
details,
|
|
|
|
AppResources.MessageAnswerOk);
|
|
|
|
break;
|
|
|
|
|
2024-04-09 12:53:23 +02:00
|
|
|
case State.StopPollingFailed:
|
|
|
|
break;
|
|
|
|
|
2023-08-31 12:20:06 +02:00
|
|
|
case State.WebConnectFailed:
|
|
|
|
BikesViewModel.ActionText = AppResources.ActivityTextErrorNoWebUpdateingLockstate;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case State.ResponseIsInvalid:
|
|
|
|
BikesViewModel.ActionText = AppResources.ActivityTextErrorStatusUpdateingLockstate;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case State.BackendUpdateFailed:
|
|
|
|
BikesViewModel.ActionText = AppResources.ActivityTextErrorConnectionUpdateingLockstate;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-09 12:53:23 +02:00
|
|
|
/// <summary> Open lock in order to pause ride and update COPRI lock state.</summary>
|
|
|
|
public async Task OpenLockAsync()
|
2023-08-31 12:20:06 +02:00
|
|
|
{
|
2024-04-09 12:53:23 +02:00
|
|
|
Log.ForContext<T>().Information("User request to open lock of bike {bikeId}.", SelectedBike.Id);
|
2023-08-31 12:20:06 +02:00
|
|
|
|
|
|
|
// lock GUI
|
|
|
|
BikesViewModel.IsIdle = false;
|
|
|
|
|
|
|
|
// Stop Updater
|
|
|
|
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
|
|
|
var stopPollingTask = ViewUpdateManager().StopAsync();
|
|
|
|
|
|
|
|
// Clear logging memory sink to avoid passing log data not related to returning of bike to backend.
|
|
|
|
// Log data is passed to backend when calling CopriCallsHttps.DoReturn().
|
|
|
|
MemoryStackSink.ClearMessages();
|
|
|
|
|
|
|
|
// 1. Step
|
|
|
|
// Parameter for RentalProcess View
|
2023-08-31 12:31:38 +02:00
|
|
|
BikesViewModel.StartRentalProcess(new RentalProcessViewModel(SelectedBike.Id)
|
2023-08-31 12:20:06 +02:00
|
|
|
{
|
2024-04-09 12:53:23 +02:00
|
|
|
State = CurrentRentalProcess.OpenLock,
|
2023-08-31 12:20:06 +02:00
|
|
|
StepIndex = 1,
|
|
|
|
Result = CurrentStepStatus.None
|
2023-08-31 12:31:38 +02:00
|
|
|
});
|
2023-08-31 12:20:06 +02:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
#if USELOCALINSTANCE
|
2024-04-09 12:53:23 +02:00
|
|
|
var command = new OpenCommand(SelectedBike, GeolocationService, LockService, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager);
|
2023-08-31 12:20:06 +02:00
|
|
|
await command.Invoke(this);
|
|
|
|
#else
|
2024-04-09 12:53:23 +02:00
|
|
|
await SelectedBike.OpenLockAsync(this, stopPollingTask);
|
2023-08-31 12:20:06 +02:00
|
|
|
#endif
|
2024-04-09 12:53:23 +02:00
|
|
|
Log.ForContext<T>().Information("Lock of bike {bikeId} opened successfully.", SelectedBike.Id);
|
2023-08-31 12:20:06 +02:00
|
|
|
}
|
2023-11-06 12:23:09 +01:00
|
|
|
catch (Exception exception)
|
2023-08-31 12:20:06 +02:00
|
|
|
{
|
2024-04-09 12:53:23 +02:00
|
|
|
Log.ForContext<T>().Information("Lock of bike {bikeId} can not be opened. {@exception}", SelectedBike.Id, exception);
|
|
|
|
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
2023-08-31 12:20:06 +02:00
|
|
|
await ViewUpdateManager().StartAsync();
|
|
|
|
|
|
|
|
BikesViewModel.ActionText = string.Empty;
|
|
|
|
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
2023-08-31 12:31:38 +02:00
|
|
|
BikesViewModel.IsIdle = true;
|
2023-08-31 12:20:06 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-04-09 12:53:23 +02:00
|
|
|
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
|
|
|
|
2023-08-31 12:20:06 +02:00
|
|
|
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
|
|
|
await ViewUpdateManager().StartAsync();
|
|
|
|
BikesViewModel.ActionText = string.Empty;
|
|
|
|
|
2024-04-09 12:53:23 +02:00
|
|
|
//Confirmation message
|
|
|
|
Log.ForContext<T>().Information("User request to park bike {bikeId}.", SelectedBike.Id);
|
|
|
|
await ViewService.DisplayAlert(
|
|
|
|
AppResources.MessageRentalProcessOpenLockFinishedTitle,
|
|
|
|
AppResources.MessageRentalProcessOpenLockFinishedText,
|
|
|
|
AppResources.MessageAnswerOk);
|
2023-08-31 12:20:06 +02:00
|
|
|
|
|
|
|
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
|
|
|
BikesViewModel.IsIdle = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|