sharee.bike-App/TINKLib/ViewModel/Bikes/Bike/BluetoothLock/CloseLockActionViewModel.cs
2023-08-31 12:31:38 +02:00

254 lines
8.6 KiB
C#

using System;
using System.Threading.Tasks;
using Serilog;
using TINK.MultilingualResources;
using TINK.Services.Logging;
using TINK.View;
using static TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command.CloseCommand;
using System.ComponentModel;
namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
{
/// <summary>
/// View model for action close bluetooth lock.
/// </summary>
/// <typeparam name="T"></typeparam>
internal class CloseLockActionViewModel<T> : ICloseCommandListener, INotifyPropertyChanged
{
/// <summary> Notifies view about changes. </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <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; }
/// <summary> Bike close. </summary>
private Model.Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable SelectedBike { get; }
/// <summary>
/// Constructs the object.
/// </summary>
/// <param name="selectedBike">Bike to close.</param>
/// <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>
public CloseLockActionViewModel(
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>
/// Processes the close lock progress.
/// </summary>
/// <param name="step">Current step to process.</param>
public void ReportStep(Step step)
{
switch (step)
{
case Step.StartStopingPolling:
break;
case Step.StartingQueryingLocation:
// 1a.Step: Start query geolocation data.
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationStart;
break;
case Step.ClosingLock:
BikesViewModel.ActionText = AppResources.ActivityTextClosingLock;
break;
case Step.WaitStopPollingQueryLocation:
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocation;
break;
case Step.QueryLocationTerminated:
break;
case Step.UpdateLockingState:
// 1b.Step: Sent info to backend
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdatingLockingState;
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessCloseLockStepUpload;
BikesViewModel.RentalProcess.ImportantStepInfoText = AppResources.MarkingRentalProcessCloseLockCheckLock;
break;
}
}
/// <summary>
/// Processes the close lock state.
/// </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(
AppResources.ErrorCloseLockTitle,
AppResources.ErrorLockOutOfReach,
AppResources.MessageAnswerOk);
break;
case State.CouldntCloseMovingError:
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
BikesViewModel.ActionText = string.Empty;
await ViewService.DisplayAlert(
AppResources.ErrorCloseLockTitle,
AppResources.ErrorLockMoving,
AppResources.MessageAnswerOk);
break;
case State.CouldntCloseBoltBlockedError:
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
BikesViewModel.ActionText = string.Empty;
await ViewService.DisplayAlert(
AppResources.ErrorCloseLockTitle,
AppResources.ErrorCloseLockBoltBlocked,
AppResources.MessageAnswerOk);
break;
case State.GeneralCloseError:
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
BikesViewModel.ActionText = string.Empty;
await ViewService.DisplayAlert(
AppResources.ErrorCloseLockTitle,
details,
AppResources.MessageAnswerOk);
break;
case State.WebConnectFailed:
BikesViewModel.ActionText = AppResources.ActivityTextErrorNoWebUpdateingLockstate;
break;
case State.ResponseIsInvalid:
BikesViewModel.ActionText = AppResources.ActivityTextErrorStatusUpdateingLockstate;
break;
case State.BackendUpdateFailed:
BikesViewModel.ActionText = AppResources.ActivityTextErrorConnectionUpdateingLockstate;
break;
}
}
/// <summary> Close lock in order to pause ride and update COPRI lock state.</summary>
public async Task CloseLockAsync()
{
Log.ForContext<T>().Information("User request to lock bike {bike}.", SelectedBike);
// 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
BikesViewModel.StartRentalProcess(new RentalProcessViewModel(SelectedBike.Id)
{
State = CurrentRentalProcess.CloseLock,
StepIndex = 1,
Result = CurrentStepStatus.None
});
// Close Lock
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessCloseLockStepCloseLock;
BikesViewModel.RentalProcess.ImportantStepInfoText = AppResources.MarkingRentalProcessCloseLockObserve;
try
{
#if USELOCALINSTANCE
var command = new CloseCommand(SelectedBike, GeolocationService, LockService, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager);
await command.Invoke(this);
#else
await SelectedBike.CloseLockAsync(this, stopPollingTask);
#endif
Log.ForContext<T>().Information("User locked {bike} successfully.", SelectedBike);
}
catch (Exception)
{
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
await ViewUpdateManager().StartAsync();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
BikesViewModel.IsIdle = true;
return;
}
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
await ViewUpdateManager().StartAsync();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
// 2. Step
BikesViewModel.RentalProcess.StepIndex = 2;
BikesViewModel.RentalProcess.Result = CurrentStepStatus.None;
BikesViewModel.RentalProcess.ImportantStepInfoText = String.Empty;
// Question if park bike or end rental
IsEndRentalRequested = await ViewService.DisplayAlert(
AppResources.QuestionRentalProcessCloseLockEndOrContinueTitle,
AppResources.QuestionRentalProcessCloseLockEndOrContinueText,
AppResources.QuestionRentalProcessCloseLockEndRentalAnswer,
AppResources.QuestionRentalProcessCloseLockContinueRentalAnswer);
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
// Message for parking bike
if(IsEndRentalRequested == false)
{
await ViewService.DisplayAlert(
AppResources.MessageRentalProcessCloseLockFinishedTitle,
AppResources.MessageRentalProcessCloseLockFinishedText,
AppResources.MessageAnswerOk);
}
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
BikesViewModel.IsIdle = true;
return;
}
/// <summary>
/// Default value of user request to end rental = false.
/// </summary>
private bool isEndRentalRequested = false;
/// <summary>
/// True if user requested End rental.
/// </summary>
public bool IsEndRentalRequested
{
get { return isEndRentalRequested; }
set
{
isEndRentalRequested = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsEndRentalRequested)));
}
}
}
}