mirror of
https://dev.azure.com/TeilRad/sharee.bike%20App/_git/Code
synced 2024-11-06 02:56:32 +01:00
616 lines
20 KiB
C#
616 lines
20 KiB
C#
|
using System;
|
||
|
using System.Threading.Tasks;
|
||
|
using ShareeBike.Model.Connector;
|
||
|
using ShareeBike.MultilingualResources;
|
||
|
using ShareeBike.View;
|
||
|
using Serilog;
|
||
|
using StartReservationCommand = ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.StartReservationCommand;
|
||
|
using AuthCommand = ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.AuthCommand;
|
||
|
using StartRentalCommand = ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.StartRentalCommand;
|
||
|
using ConnectAndGetStateCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.ConnectAndGetStateCommand;
|
||
|
using DisconnectCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.DisconnectCommand;
|
||
|
using System.ComponentModel;
|
||
|
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||
|
|
||
|
namespace ShareeBike.ViewModel.Bikes.Bike
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Return bike action.
|
||
|
/// </summary>
|
||
|
/// <typeparam name="T">Type of owner.</typeparam>
|
||
|
public class StartReservationOrRentalActionViewModel<T> :
|
||
|
StartReservationCommand.IStartReservationCommandListener,
|
||
|
AuthCommand.IAuthCommandListener, StartRentalCommand.IStartRentalCommandListener,
|
||
|
ConnectAndGetStateCommand.IConnectAndGetStateCommandListener,
|
||
|
DisconnectCommand.IDisconnectCommandListener,
|
||
|
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 </summary>
|
||
|
private IBikeInfoMutable SelectedBike { get; set; }
|
||
|
|
||
|
/// <summary> Provides a connector object.</summary>
|
||
|
protected Func<bool, IConnector> ConnectorFactory { 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 StartReservationOrRentalActionViewModel(
|
||
|
IBikeInfoMutable selectedBike,
|
||
|
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||
|
IViewService viewService,
|
||
|
IBikesViewModel bikesViewModel)
|
||
|
{
|
||
|
SelectedBike = selectedBike;
|
||
|
ViewUpdateManager = viewUpdateManager;
|
||
|
ViewService = viewService;
|
||
|
BikesViewModel = bikesViewModel
|
||
|
?? throw new ArgumentException($"Can not construct {typeof(EndRentalActionViewModel<T>)}-object. {nameof(bikesViewModel)} must not be null.");
|
||
|
|
||
|
// Set parameter for RentalProcess View to initial value.
|
||
|
BikesViewModel.StartRentalProcess(new RentalProcessViewModel(SelectedBike.Id)
|
||
|
{
|
||
|
State = CurrentRentalProcess.None,
|
||
|
StepIndex = 0,
|
||
|
Result = CurrentStepStatus.None
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Processes the start reservation progress.
|
||
|
/// </summary>
|
||
|
/// <param name="step">Current step to process.</param>
|
||
|
public void ReportStep(StartReservationCommand.Step step)
|
||
|
{
|
||
|
switch (step)
|
||
|
{
|
||
|
case StartReservationCommand.Step.ReserveBike:
|
||
|
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessRequestBikeFirstStepRequest;
|
||
|
BikesViewModel.ActionText = AppResources.ActivityTextReservingBike;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Processes the start reservation state.
|
||
|
/// </summary>
|
||
|
/// <param name="state">State to process.</param>
|
||
|
/// <param name="details">Textual details describing current state.</param>
|
||
|
public async Task ReportStateAsync(StartReservationCommand.State state, string details)
|
||
|
{
|
||
|
switch (state)
|
||
|
{
|
||
|
case StartReservationCommand.State.TooManyBikesError:
|
||
|
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||
|
BikesViewModel.ActionText = string.Empty;
|
||
|
await ViewService.DisplayAlert(
|
||
|
AppResources.MessageHintTitle,
|
||
|
string.Format(AppResources.ErrorReservingBikeTooManyReservationsRentals, SelectedBike.Id, details),
|
||
|
AppResources.MessageAnswerOk);
|
||
|
break;
|
||
|
|
||
|
case StartReservationCommand.State.WebConnectFailed:
|
||
|
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||
|
BikesViewModel.ActionText = string.Empty;
|
||
|
await ViewService.DisplayAlert(
|
||
|
AppResources.ErrorNoConnectionTitle,
|
||
|
AppResources.ErrorNoWeb,
|
||
|
AppResources.MessageAnswerOk);
|
||
|
break;
|
||
|
|
||
|
case StartReservationCommand.State.GeneralStartReservationError:
|
||
|
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||
|
BikesViewModel.ActionText = string.Empty;
|
||
|
await ViewService.DisplayAdvancedAlert(
|
||
|
AppResources.ErrorReservingBikeTitle,
|
||
|
details,
|
||
|
AppResources.ErrorTryAgain,
|
||
|
AppResources.MessageAnswerOk);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Processes the start reservation progress.
|
||
|
/// </summary>
|
||
|
/// <param name="step">Current step to process.</param>
|
||
|
public void ReportStep(AuthCommand.Step step)
|
||
|
{
|
||
|
switch (step)
|
||
|
{
|
||
|
case AuthCommand.Step.Authenticate:
|
||
|
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessRequestBikeFirstStepAuthenticateInfo;
|
||
|
BikesViewModel.ActionText = AppResources.ActivityTextAuthenticate;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Processes the authentication state.
|
||
|
/// </summary>
|
||
|
/// <param name="state">State to process.</param>
|
||
|
/// <param name="details">Textual details describing current state.</param>
|
||
|
public async Task ReportStateAsync(AuthCommand.State state, string details)
|
||
|
{
|
||
|
switch (state)
|
||
|
{
|
||
|
|
||
|
case AuthCommand.State.WebConnectFailed:
|
||
|
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||
|
BikesViewModel.ActionText = string.Empty;
|
||
|
await ViewService.DisplayAlert(
|
||
|
AppResources.ErrorNoConnectionTitle,
|
||
|
AppResources.ErrorNoWeb,
|
||
|
AppResources.MessageAnswerOk);
|
||
|
break;
|
||
|
|
||
|
case AuthCommand.State.GeneralAuthError:
|
||
|
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||
|
BikesViewModel.ActionText = string.Empty;
|
||
|
await ViewService.DisplayAdvancedAlert(
|
||
|
AppResources.ErrorAccountInvalidAuthorization,
|
||
|
details,
|
||
|
AppResources.ErrorTryAgain,
|
||
|
AppResources.MessageAnswerOk);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Processes the authentication progress.
|
||
|
/// </summary>
|
||
|
/// <param name="step">Current step to process.</param>
|
||
|
public void ReportStep(StartRentalCommand.Step step)
|
||
|
{
|
||
|
switch (step)
|
||
|
{
|
||
|
case StartRentalCommand.Step.RentBike:
|
||
|
BikesViewModel.ActionText = AppResources.ActivityTextRentingBike;
|
||
|
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessRequestBikeSecondStepStartRental;
|
||
|
BikesViewModel.RentalProcess.ImportantStepInfoText =
|
||
|
SelectedBike.LockInfo.State != LockingState.Open
|
||
|
? AppResources.MarkingRentalProcessRequestBikeSecondStepStartRentalWait
|
||
|
: string.Empty;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Processes the start rental state.
|
||
|
/// </summary>
|
||
|
/// <param name="state">State to process.</param>
|
||
|
/// <param name="details">Textual details describing current state.</param>
|
||
|
public async Task ReportStateAsync(StartRentalCommand.State state, string details)
|
||
|
{
|
||
|
switch (state)
|
||
|
{
|
||
|
case StartRentalCommand.State.WebConnectFailed:
|
||
|
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||
|
BikesViewModel.ActionText = string.Empty;
|
||
|
await ViewService.DisplayAlert(
|
||
|
AppResources.ErrorNoConnectionTitle,
|
||
|
AppResources.ErrorNoWeb,
|
||
|
AppResources.MessageAnswerOk);
|
||
|
break;
|
||
|
|
||
|
case StartRentalCommand.State.GeneralStartRentalError:
|
||
|
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||
|
BikesViewModel.ActionText = string.Empty;
|
||
|
await ViewService.DisplayAlert(
|
||
|
AppResources.ErrorRentingBikeTitle,
|
||
|
details,
|
||
|
AppResources.ErrorTryAgain,
|
||
|
AppResources.MessageAnswerOk);
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Processes the connect to lock progress.
|
||
|
/// </summary>
|
||
|
/// <param name="step">Current step to process.</param>
|
||
|
public void ReportStep(ConnectAndGetStateCommand.Step step)
|
||
|
{
|
||
|
switch (step)
|
||
|
{
|
||
|
case ConnectAndGetStateCommand.Step.ConnectLock:
|
||
|
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessRequestBikeFirstStepConnect;
|
||
|
BikesViewModel.ActionText = AppResources.ActivityTextSearchingLock;
|
||
|
break;
|
||
|
|
||
|
case ConnectAndGetStateCommand.Step.GetLockingState:
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Processes the connect to lock state.
|
||
|
/// </summary>
|
||
|
/// <param name="state">State to process.</param>
|
||
|
/// <param name="details">Textual details describing current state.</param>
|
||
|
public async Task ReportStateAsync(ConnectAndGetStateCommand.State state, string details)
|
||
|
{
|
||
|
if (StartedWithReservation == true)
|
||
|
{
|
||
|
switch (state)
|
||
|
{
|
||
|
case ConnectAndGetStateCommand.State.OutOfReachError:
|
||
|
BikesViewModel.ActionText = string.Empty;
|
||
|
await ViewService.DisplayAlert(
|
||
|
AppResources.ErrorConnectLockTitle,
|
||
|
AppResources.ErrorLockOutOfReach,
|
||
|
AppResources.MessageAnswerOk);
|
||
|
break;
|
||
|
|
||
|
case ConnectAndGetStateCommand.State.BluetoothOff:
|
||
|
BikesViewModel.ActionText = string.Empty;
|
||
|
await ViewService.DisplayAlert(
|
||
|
AppResources.ErrorConnectLockTitle,
|
||
|
AppResources.ErrorLockBluetoothNotOn,
|
||
|
AppResources.MessageAnswerOk);
|
||
|
break;
|
||
|
|
||
|
case ConnectAndGetStateCommand.State.NoLocationPermission:
|
||
|
BikesViewModel.ActionText = string.Empty;
|
||
|
await ViewService.DisplayAlert(
|
||
|
AppResources.ErrorConnectLockTitle,
|
||
|
AppResources.ErrorNoLocationPermission,
|
||
|
AppResources.MessageAnswerOk);
|
||
|
break;
|
||
|
|
||
|
case ConnectAndGetStateCommand.State.LocationServicesOff:
|
||
|
BikesViewModel.ActionText = string.Empty;
|
||
|
await ViewService.DisplayAlert(
|
||
|
AppResources.ErrorConnectLockTitle,
|
||
|
AppResources.ErrorLockLocationOff,
|
||
|
AppResources.MessageAnswerOk);
|
||
|
break;
|
||
|
|
||
|
case ConnectAndGetStateCommand.State.GeneralConnectLockError:
|
||
|
BikesViewModel.ActionText = string.Empty;
|
||
|
await ViewService.DisplayAdvancedAlert(
|
||
|
AppResources.ErrorConnectLockTitle,
|
||
|
details,
|
||
|
AppResources.ErrorTryAgain,
|
||
|
AppResources.MessageAnswerOk);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
switch (state)
|
||
|
{
|
||
|
case ConnectAndGetStateCommand.State.OutOfReachError:
|
||
|
BikesViewModel.ActionText = AppResources.ActivityTextLockIsOutOfReach;
|
||
|
break;
|
||
|
|
||
|
case ConnectAndGetStateCommand.State.BluetoothOff:
|
||
|
BikesViewModel.ActionText = string.Empty;
|
||
|
await ViewService.DisplayAlert(
|
||
|
AppResources.ErrorConnectLockTitle,
|
||
|
AppResources.ErrorLockBluetoothNotOn,
|
||
|
AppResources.MessageAnswerOk);
|
||
|
break;
|
||
|
|
||
|
case ConnectAndGetStateCommand.State.NoLocationPermission:
|
||
|
BikesViewModel.ActionText = AppResources.ActivityTextErrorQueryLocationQuery;
|
||
|
break;
|
||
|
|
||
|
case ConnectAndGetStateCommand.State.LocationServicesOff:
|
||
|
BikesViewModel.ActionText = AppResources.ActivityTextErrorQueryLocationQuery;
|
||
|
break;
|
||
|
|
||
|
case ConnectAndGetStateCommand.State.GeneralConnectLockError:
|
||
|
BikesViewModel.ActionText = AppResources.ErrorConnectLockTitle;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Processes the disconnect lock progress.
|
||
|
/// </summary>
|
||
|
/// <param name="step">Current step to process.</param>
|
||
|
public void ReportStep(DisconnectCommand.Step step)
|
||
|
{
|
||
|
switch (step)
|
||
|
{
|
||
|
case DisconnectCommand.Step.DisconnectLock:
|
||
|
BikesViewModel.ActionText = AppResources.ActivityTextDisconnectingLock;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Processes the disconnect lock state.
|
||
|
/// </summary>
|
||
|
/// <param name="state">State to process.</param>
|
||
|
/// <param name="details">Textual details describing current state.</param>
|
||
|
public Task ReportStateAsync(DisconnectCommand.State state, string details)
|
||
|
{
|
||
|
switch (state)
|
||
|
{
|
||
|
case DisconnectCommand.State.GeneralDisconnectError:
|
||
|
BikesViewModel.ActionText = AppResources.ActivityTextErrorDisconnect;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return Task.CompletedTask;
|
||
|
}
|
||
|
|
||
|
/// <summary> Request bike. </summary>
|
||
|
public async Task StartReservationOrRentalAsync()
|
||
|
{
|
||
|
Log.ForContext<T>().Information("User request to end rental of bike {bikeId}.", SelectedBike.Id);
|
||
|
|
||
|
// lock GUI
|
||
|
BikesViewModel.IsIdle = false;
|
||
|
|
||
|
// Stop Updater
|
||
|
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||
|
await ViewUpdateManager().StopAsync();
|
||
|
|
||
|
// 1. Step
|
||
|
// Parameter for RentalProcess View
|
||
|
BikesViewModel.StartRentalProcess(new RentalProcessViewModel(SelectedBike.Id)
|
||
|
{
|
||
|
State = CurrentRentalProcess.StartReservationOrRental,
|
||
|
StepIndex = 1,
|
||
|
Result = CurrentStepStatus.None
|
||
|
});
|
||
|
|
||
|
// 1a.Step: Reserve bike or authenticate, if already reserved
|
||
|
if(SelectedBike.State.Value != Model.State.InUseStateEnum.Reserved)
|
||
|
{
|
||
|
startedWithReservation = false;
|
||
|
try
|
||
|
{
|
||
|
#if USELOCALINSTANCE
|
||
|
var command = new StartReservationCommand(SelectedBike, ConnectorFactory, ViewUpdateManager);
|
||
|
await command.Invoke(this);
|
||
|
#else
|
||
|
await SelectedBike.ReserveBikeAsync(this);
|
||
|
#endif
|
||
|
}
|
||
|
catch (Exception exception)
|
||
|
{
|
||
|
Log.ForContext<T>().Information("Reservation of bike {bikeId} failed. {@exception}", SelectedBike.Id, exception);
|
||
|
|
||
|
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||
|
await ViewUpdateManager().StartAsync();
|
||
|
|
||
|
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
||
|
BikesViewModel.ActionText = string.Empty;
|
||
|
BikesViewModel.IsIdle = true;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
startedWithReservation = true;
|
||
|
try
|
||
|
{
|
||
|
#if USELOCALINSTANCE
|
||
|
var command = new AuthCommand(SelectedBike, ConnectorFactory, ViewUpdateManager);
|
||
|
await command.Invoke(this);
|
||
|
#else
|
||
|
await SelectedBike.AuthAsync(this);
|
||
|
#endif
|
||
|
}
|
||
|
catch (Exception exception)
|
||
|
{
|
||
|
Log.ForContext<T>().Information("User could not be authenticated for bike {bikeId}. {@exception}", SelectedBike.Id, exception);
|
||
|
|
||
|
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||
|
await ViewUpdateManager().StartAsync();
|
||
|
|
||
|
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
||
|
BikesViewModel.ActionText = string.Empty;
|
||
|
BikesViewModel.IsIdle = true;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||
|
|
||
|
// 2. Step
|
||
|
BikesViewModel.RentalProcess.StepIndex = 2;
|
||
|
BikesViewModel.RentalProcess.Result = CurrentStepStatus.None;
|
||
|
BikesViewModel.RentalProcess.ImportantStepInfoText = string.Empty;
|
||
|
|
||
|
// 2a.Step: Get locking state
|
||
|
try
|
||
|
{
|
||
|
#if USELOCALINSTANCE
|
||
|
var command = new ConnectLockAndGetLockingStateCommand(SelectedBike, LockService, ConnectorFactory, ViewUpdateManager);
|
||
|
await command.Invoke(this);
|
||
|
#else
|
||
|
await SelectedBike.ConnectAsync(this);
|
||
|
#endif
|
||
|
}
|
||
|
catch (Exception exception)
|
||
|
{
|
||
|
Log.ForContext<T>().Information("Lock of bike {bikeId} could not be connected. {@exception}", SelectedBike.Id, exception);
|
||
|
}
|
||
|
|
||
|
var isStartRentalRequested = false;
|
||
|
switch(SelectedBike.LockInfo.State)
|
||
|
{
|
||
|
|
||
|
case LockingState.UnknownDisconnected:
|
||
|
// Lock is not connected: Bike is reserved confirmation
|
||
|
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessRequestBikeSecondStepReserve;
|
||
|
isStartRentalRequested = false;
|
||
|
break;
|
||
|
|
||
|
case LockingState.Closed:
|
||
|
case LockingState.UnknownFromHardwareError:
|
||
|
|
||
|
if (startedWithReservation == false)
|
||
|
{
|
||
|
// Lock is connected: Ask whether to start rental & open lock
|
||
|
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessRequestBikeSecondStepRent;
|
||
|
|
||
|
isStartRentalRequested = await ViewService.DisplayAlert(
|
||
|
AppResources.QuestionRentalProcessRentBikeTitle,
|
||
|
(SelectedBike.AaRideType == Model.Bikes.BikeInfoNS.BikeNS.AaRideType.AaRide
|
||
|
? AppResources.QuestionRentalProcessRentAndOpenAaBikeText
|
||
|
: AppResources.QuestionRentalProcessRentAndOpenBikeText),
|
||
|
AppResources.QuestionRentalProcessRentBikeRentAndOpenAnswer,
|
||
|
AppResources.ActionCancel);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
isStartRentalRequested = true;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case LockingState.Open:
|
||
|
isStartRentalRequested = true;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// User does not want to start rental -> only reserve
|
||
|
if (isStartRentalRequested == false)
|
||
|
{
|
||
|
// Bikes is reserved confirmation
|
||
|
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessRequestBikeSecondStepReserve;
|
||
|
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||
|
|
||
|
await ViewService.DisplayAlert(
|
||
|
AppResources.MessageRentalProcessReserveBikeFinishedTitle,
|
||
|
String.Format(AppResources.MessageRentalProcessReserveBikeFinishedText),
|
||
|
AppResources.MessageAnswerOk);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// 2a.Step: Rent bike
|
||
|
try
|
||
|
{
|
||
|
#if USELOCALINSTANCE
|
||
|
var command = new StartRentalCommand(SelectedBike, LockService, ConnectorFactory, ViewUpdateManager);
|
||
|
await command.Invoke(this);
|
||
|
#else
|
||
|
await SelectedBike.RentBikeAsync(this);
|
||
|
#endif
|
||
|
continueWithOpenLock = true;
|
||
|
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||
|
}
|
||
|
catch (Exception exception)
|
||
|
{
|
||
|
Log.ForContext<T>().Information("Rental of bike {bikeId} could not be started. {@exception}", SelectedBike.Id, exception);
|
||
|
|
||
|
switch (SelectedBike.LockInfo.State)
|
||
|
{
|
||
|
case LockingState.Closed:
|
||
|
|
||
|
// Disconnect lock.
|
||
|
try
|
||
|
{
|
||
|
BikesViewModel.ActionText = AppResources.ActivityTextDisconnectingLock;
|
||
|
#if USELOCALINSTANCE
|
||
|
var command = new DisconnectCommand(SelectedBike, LockService);
|
||
|
await command.Invoke(this);
|
||
|
#else
|
||
|
await SelectedBike.DisconnectAsync(this);
|
||
|
Log.ForContext<T>().Information("Lock of bike {bikeId} was disconnected successfully.", SelectedBike.Id);
|
||
|
#endif
|
||
|
}
|
||
|
catch (Exception disconnectException)
|
||
|
{
|
||
|
Log.ForContext<T>().Information("Lock of bike {bikeId} can not be disconnected. {@exception}", SelectedBike.Id, disconnectException);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case LockingState.Open:
|
||
|
|
||
|
await ViewService.DisplayAlert(
|
||
|
AppResources.ErrorRentingBikeTitle,
|
||
|
String.Format(AppResources.ErrorRentingBikeQuestionIfCloseLock, SelectedBike.Id),
|
||
|
AppResources.MessageAnswerOk);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||
|
await ViewUpdateManager().StartAsync();
|
||
|
|
||
|
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
||
|
BikesViewModel.ActionText = string.Empty;
|
||
|
BikesViewModel.IsIdle = true;
|
||
|
|
||
|
continueWithOpenLock = false;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||
|
await ViewUpdateManager().StartAsync();
|
||
|
|
||
|
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
||
|
BikesViewModel.ActionText = string.Empty;
|
||
|
BikesViewModel.IsIdle = true;
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Default value of user request to open lock = false.
|
||
|
/// </summary>
|
||
|
private bool continueWithOpenLock = false;
|
||
|
|
||
|
/// <summary>
|
||
|
/// True if to continue with open lock.
|
||
|
/// </summary>
|
||
|
public bool ContinueWithOpenLock
|
||
|
{
|
||
|
get { return continueWithOpenLock; }
|
||
|
set
|
||
|
{
|
||
|
continueWithOpenLock = value;
|
||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ContinueWithOpenLock)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Default value of user started request with reservation = false.
|
||
|
/// </summary>
|
||
|
private bool startedWithReservation = false;
|
||
|
|
||
|
/// <summary>
|
||
|
/// True if user started request with reservation.
|
||
|
/// </summary>
|
||
|
public bool StartedWithReservation
|
||
|
{
|
||
|
get { return startedWithReservation; }
|
||
|
set
|
||
|
{
|
||
|
startedWithReservation = value;
|
||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(StartedWithReservation)));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|