mirror of
https://dev.azure.com/TeilRad/sharee.bike%20App/_git/Code
synced 2025-06-22 05:47:28 +02:00
Version 3.0.381
This commit is contained in:
parent
f963c0a219
commit
3a363acf3a
1525 changed files with 60589 additions and 125098 deletions
|
@ -0,0 +1,280 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.MultilingualResources;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using BikeInfoMutable = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.BikeInfoMutable;
|
||||
using DisconnectCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.DisconnectCommand;
|
||||
|
||||
namespace ShareeBike.ViewModel.Bikes.Bike.BluetoothLock
|
||||
{
|
||||
/// <summary>
|
||||
/// View model for a ILockIt bike.
|
||||
/// Provides functionality for views
|
||||
/// - MyBikes
|
||||
/// - BikesAtStation
|
||||
/// </summary>
|
||||
public class BikeViewModel : BikeViewModelBase, INotifyPropertyChanged, DisconnectCommand.IDisconnectCommandListener
|
||||
{
|
||||
public Xamarin.Forms.Command ShowTrackingInfoCommand { get; private set; }
|
||||
public Xamarin.Forms.Command ShowRideTypeInfoCommand { get; private set; }
|
||||
public Xamarin.Forms.Command ShowBikeIsBoundToCityInfoCommand { get; private set; }
|
||||
|
||||
/// <summary> Notifies GUI about changes. </summary>
|
||||
public override event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private IGeolocationService GeolocationService { get; }
|
||||
|
||||
private ILocksService LockService { get; }
|
||||
|
||||
/// <summary> Holds object which manages requests. </summary>
|
||||
private IRequestHandler RequestHandler { get; set; }
|
||||
|
||||
/// <summary> Raises events in order to update GUI.</summary>
|
||||
public override void RaisePropertyChanged(object sender, PropertyChangedEventArgs eventArgs) => PropertyChanged?.Invoke(sender, eventArgs);
|
||||
|
||||
/// <summary> Raises events if property values changed in order to update GUI.</summary>
|
||||
private void RaisePropertyChangedEvent(
|
||||
IRequestHandler lastHandler,
|
||||
string lastStateText = null,
|
||||
Xamarin.Forms.Color? lastStateColor = null)
|
||||
{
|
||||
if (lastHandler.ButtonText != ButtonText)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonText)));
|
||||
}
|
||||
|
||||
if (lastHandler.IsButtonVisible != IsButtonVisible)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsButtonVisible)));
|
||||
}
|
||||
|
||||
if (lastHandler.LockitButtonText != LockitButtonText)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(LockitButtonText)));
|
||||
}
|
||||
|
||||
if (lastHandler.IsLockitButtonVisible != IsLockitButtonVisible)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsLockitButtonVisible)));
|
||||
}
|
||||
|
||||
if (RequestHandler.ErrorText != lastHandler.ErrorText)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ErrorText)));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(lastStateText) && lastStateText != StateText)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(StateText)));
|
||||
}
|
||||
|
||||
if (lastStateColor != null && lastStateColor != StateColor)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(StateColor)));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the view model for requesting a bike action.
|
||||
/// </summary>
|
||||
private readonly DisconnectLockActionViewModel<BikeViewModel> _disconnectLockActionViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// Processes the renting a bike progress.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(DisconnectCommand.Step step) => _disconnectLockActionViewModel?.ReportStep(step);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the renting a bike state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="state">State to process.</param>
|
||||
/// <param name="details">Textual details describing current state.</param>
|
||||
public async Task ReportStateAsync(DisconnectCommand.State state, string details) => await _disconnectLockActionViewModel.ReportStateAsync(state, details);
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a bike view model object.
|
||||
/// </summary>
|
||||
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...)</param>
|
||||
/// <param name="selectedBike">Bike to be displayed.</param>
|
||||
/// <param name="user">Object holding logged in user or an empty user object.</param>
|
||||
/// <param name="viewContext"> Holds the view context in which bike view model is used.</param>
|
||||
/// <param name="stateInfoProvider">Provides in use state information.</param>
|
||||
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||
/// <param name="openUrlInBrowser">Delegate to open browser.</param>
|
||||
public BikeViewModel(
|
||||
Func<bool> isConnectedDelegate,
|
||||
Func<bool, IConnector> connectorFactory,
|
||||
IGeolocationService geolocationService,
|
||||
ILocksService lockService,
|
||||
Action<string> bikeRemoveDelegate,
|
||||
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||
ISmartDevice smartDevice,
|
||||
IViewService viewService,
|
||||
BikeInfoMutable selectedBike,
|
||||
IUser user,
|
||||
ViewContext viewContext,
|
||||
IInUseStateInfoProvider stateInfoProvider,
|
||||
IBikesViewModel bikesViewModel,
|
||||
Action<string> openUrlInBrowser) : base(isConnectedDelegate, connectorFactory, bikeRemoveDelegate, viewUpdateManager, smartDevice, viewService, selectedBike, user, viewContext, stateInfoProvider, bikesViewModel, openUrlInBrowser)
|
||||
{
|
||||
ShowTrackingInfoCommand = new Xamarin.Forms.Command(async () => {
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
"Tracking",
|
||||
TariffDescription.TrackingInfoText,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
});
|
||||
|
||||
ShowRideTypeInfoCommand = new Xamarin.Forms.Command(async () => {
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageAaRideTypeInfoTitle,
|
||||
TariffDescription.RideTypeText,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
});
|
||||
|
||||
ShowBikeIsBoundToCityInfoCommand = new Xamarin.Forms.Command(async () => {
|
||||
|
||||
// later, if value comes from backend: message = TariffDescription.CityAreaType
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageBikeIsBoundToCityInfoTitle,
|
||||
String.Format(AppResources.MessageBikeIsBoundToCityInfoText,selectedBike.TypeOfBike),
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
});
|
||||
|
||||
_disconnectLockActionViewModel = new DisconnectLockActionViewModel<BikeViewModel>(
|
||||
selectedBike,
|
||||
viewUpdateManager,
|
||||
bikesViewModel);
|
||||
|
||||
RequestHandler = user.IsLoggedIn
|
||||
? RequestHandlerFactory.Create(
|
||||
selectedBike,
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocationService,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
user)
|
||||
: new NotLoggedIn(
|
||||
selectedBike.State.Value,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
GeolocationService = geolocationService
|
||||
?? throw new ArgumentException($"Can not instantiate {this.GetType().Name}-object. Parameter {nameof(geolocationService)} can not be null.");
|
||||
|
||||
LockService = lockService
|
||||
?? throw new ArgumentException($"Can not instantiate {this.GetType().Name}-object. Parameter {nameof(lockService)} can not be null.");
|
||||
|
||||
selectedBike.PropertyChanged += (sender, ev) =>
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsButtonVisible)));
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsLockitButtonVisible)));
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(OnButtonClicked)));
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(OnLockitButtonClicked)));
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles BikeInfoMutable events.
|
||||
/// Helper member to raise events. Maps model event change notification to view model events.
|
||||
/// Todo: Check which events are received here and filter, to avoid event storm.
|
||||
/// </summary>
|
||||
public override async void OnSelectedBikeStateChanged()
|
||||
{
|
||||
if (Bike.State.Value == Model.State.InUseStateEnum.Disposable)
|
||||
{
|
||||
await _disconnectLockActionViewModel.DisconnectLockAsync();
|
||||
}
|
||||
|
||||
var lastHandler = RequestHandler;
|
||||
RequestHandler = RequestHandlerFactory.Create(
|
||||
Bike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
|
||||
RaisePropertyChangedEvent(lastHandler);
|
||||
}
|
||||
|
||||
public bool IsBikeBoundToCity
|
||||
=> Bike.AaRideType == ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.AaRideType.NoAaRide ? true : false;
|
||||
|
||||
/// <summary> Gets visibility of the copri command button. </summary>
|
||||
public bool IsButtonVisible
|
||||
=> RequestHandler.IsButtonVisible;
|
||||
|
||||
/// <summary> Gets the text of the copri command button. </summary>
|
||||
public string ButtonText => RequestHandler.ButtonText;
|
||||
|
||||
/// <summary> Gets visibility of the ILockIt command button. </summary>
|
||||
public bool IsLockitButtonVisible
|
||||
=> RequestHandler.IsLockitButtonVisible;
|
||||
|
||||
/// <summary> Gets the text of the ILockIt command button. </summary>
|
||||
public string LockitButtonText => RequestHandler.LockitButtonText;
|
||||
|
||||
/// <summary> Processes request to perform a copri action (reserve bike and cancel reservation).
|
||||
/// Button only enabled if data is up to date = not from cache. </summary>
|
||||
public System.Windows.Input.ICommand OnButtonClicked => new Xamarin.Forms.Command(async () => await ClickButton(RequestHandler.HandleRequestOption1()));
|
||||
|
||||
/// <summary> Processes request to perform a ILockIt action (unlock bike and lock bike).
|
||||
/// Button only enabled if data is up to date = not from cache. </summary>
|
||||
public System.Windows.Input.ICommand OnLockitButtonClicked => new Xamarin.Forms.Command(async () => await ClickButton(RequestHandler.HandleRequestOption2()));
|
||||
|
||||
/// <summary> Processes request to perform a copri action (reserve bike and cancel reservation). </summary>
|
||||
private async Task ClickButton(Task<IRequestHandler> handleRequest)
|
||||
{
|
||||
var lastHandler = RequestHandler;
|
||||
var lastState = Bike.State.Value;
|
||||
var lastStateText = StateText;
|
||||
var lastStateColor = StateColor;
|
||||
|
||||
RequestHandler = await handleRequest;
|
||||
|
||||
CheckRemoveBike(Id, lastState);
|
||||
|
||||
if (RuntimeHelpers.Equals(lastHandler, RequestHandler))
|
||||
{
|
||||
// No state change occurred (same instance is returned).
|
||||
return;
|
||||
}
|
||||
|
||||
RaisePropertyChangedEvent(
|
||||
lastHandler,
|
||||
lastStateText,
|
||||
lastStateColor);
|
||||
}
|
||||
|
||||
public string ErrorText => RequestHandler.ErrorText;
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,414 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Serilog;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command;
|
||||
using ShareeBike.MultilingualResources;
|
||||
using ShareeBike.Services.Logging;
|
||||
using ShareeBike.View;
|
||||
using CloseCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.CloseCommand;
|
||||
using CancelReservationCommand = ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.CancelReservationCommand;
|
||||
using DisconnectCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.DisconnectCommand;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace ShareeBike.ViewModel.Bikes.Bike.BluetoothLock
|
||||
{
|
||||
/// <summary>
|
||||
/// View model for action close bluetooth lock.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
internal class CloseLockActionViewModel<T> : CloseCommand.ICloseCommandListener, CancelReservationCommand.ICancelReservationCommandListener, 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 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(CloseCommand.Step step)
|
||||
{
|
||||
switch (step)
|
||||
{
|
||||
case CloseCommand.Step.StartStopingPolling:
|
||||
break;
|
||||
|
||||
case CloseCommand.Step.StartingQueryingLocation:
|
||||
// 1a.Step: Start query geolocation data.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationStart;
|
||||
break;
|
||||
|
||||
case CloseCommand.Step.ClosingLock:
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextClosingLock;
|
||||
break;
|
||||
|
||||
case CloseCommand.Step.WaitStopPollingQueryLocation:
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocation;
|
||||
break;
|
||||
|
||||
case CloseCommand.Step.QueryLocationTerminated:
|
||||
break;
|
||||
|
||||
case CloseCommand.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(CloseCommand.State state, string details)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case CloseCommand.State.OutOfReachError:
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorLockOutOfReach,
|
||||
AppResources.MessageAnswerOk);
|
||||
break;
|
||||
|
||||
case CloseCommand.State.CouldntCloseMovingError:
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorLockMoving,
|
||||
AppResources.MessageAnswerOk);
|
||||
break;
|
||||
|
||||
case CloseCommand.State.CouldntCloseBoltBlockedError:
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockBoltBlocked,
|
||||
AppResources.MessageAnswerOk);
|
||||
break;
|
||||
|
||||
case CloseCommand.State.GeneralCloseError:
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
details,
|
||||
AppResources.MessageAnswerOk);
|
||||
break;
|
||||
|
||||
case CloseCommand.State.WebConnectFailed:
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorNoWebUpdateingLockstate;
|
||||
break;
|
||||
|
||||
case CloseCommand.State.ResponseIsInvalid:
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorStatusUpdateingLockstate;
|
||||
break;
|
||||
|
||||
case CloseCommand.State.BackendUpdateFailed:
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorConnectionUpdateingLockstate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes the start reservation progress.
|
||||
/// </summary>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(CancelReservationCommand.Step step)
|
||||
{
|
||||
switch (step)
|
||||
{
|
||||
case CancelReservationCommand.Step.CancelReservation:
|
||||
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessCancelReservation;
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextCancelingReservation;
|
||||
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(CancelReservationCommand.State state, string details)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case CancelReservationCommand.State.InvalidResponse:
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCancelReservationTitle,
|
||||
AppResources.ErrorAccountInvalidAuthorization,
|
||||
AppResources.MessageAnswerOk);
|
||||
break;
|
||||
|
||||
case CancelReservationCommand.State.WebConnectFailed:
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorNoConnectionTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
break;
|
||||
|
||||
case CancelReservationCommand.State.GeneralCancelReservationError:
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorCancelReservationTitle,
|
||||
details,
|
||||
AppResources.ErrorTryAgain,
|
||||
AppResources.MessageAnswerOk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes the disconnect from lock progress.
|
||||
/// </summary>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(DisconnectCommand.Step step)
|
||||
{
|
||||
switch (step)
|
||||
{
|
||||
case DisconnectCommand.Step.DisconnectLock:
|
||||
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessCloseLockStepUpload;
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextDisconnectingLock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes the disconnect from lock state.
|
||||
/// </summary>
|
||||
/// <param name="state">State to process.</param>
|
||||
/// <param name="details">Textual details describing current state.</param>
|
||||
public async Task ReportStateAsync(DisconnectCommand.State state, string details)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
|
||||
case DisconnectCommand.State.GeneralDisconnectError:
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorAccountInvalidAuthorization,
|
||||
details,
|
||||
AppResources.ErrorTryAgain,
|
||||
AppResources.MessageAnswerOk);
|
||||
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 close lock of bike {bikeId}.", SelectedBike.Id);
|
||||
|
||||
// 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
|
||||
switch(SelectedBike.State.Value)
|
||||
{
|
||||
case Model.State.InUseStateEnum.Reserved:
|
||||
BikesViewModel.StartRentalProcess(new RentalProcessViewModel(SelectedBike.Id)
|
||||
{
|
||||
State = CurrentRentalProcess.CloseLockAndCancelReservation,
|
||||
StepIndex = 1,
|
||||
Result = CurrentStepStatus.None
|
||||
});
|
||||
break;
|
||||
|
||||
case Model.State.InUseStateEnum.Disposable:
|
||||
BikesViewModel.StartRentalProcess(new RentalProcessViewModel(SelectedBike.Id)
|
||||
{
|
||||
State = CurrentRentalProcess.CloseDisposableLock,
|
||||
StepIndex = 1,
|
||||
Result = CurrentStepStatus.None
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
BikesViewModel.StartRentalProcess(new RentalProcessViewModel(SelectedBike.Id)
|
||||
{
|
||||
State = CurrentRentalProcess.CloseLock,
|
||||
StepIndex = 1,
|
||||
Result = CurrentStepStatus.None
|
||||
});
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// 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("Lock of bike {bikeId} closed successfully.", SelectedBike.Id);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<T>().Information("Lock of bike {bikeId} can not be closed. {@exception}", SelectedBike.Id, exception);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StartAsync();
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
||||
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;
|
||||
|
||||
|
||||
if (SelectedBike.State.Value == Model.State.InUseStateEnum.Reserved)
|
||||
{
|
||||
// Cancel reservation
|
||||
try
|
||||
{
|
||||
#if USELOCALINSTANCE
|
||||
var command = new CancelReservationCommand(SelectedBike, ConnectorFactory, ViewUpdateManager);
|
||||
await command.Invoke(this);
|
||||
#else
|
||||
await SelectedBike.CancelReservationAsync(this);
|
||||
#endif
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<T>().Information("Reservation of bike {bikeId} could not be canceled. {@exception}", SelectedBike.Id, exception);
|
||||
}
|
||||
}
|
||||
|
||||
// If bike is not reserved/booked, disconnect lock
|
||||
if (SelectedBike.State.Value == Model.State.InUseStateEnum.Disposable)
|
||||
{
|
||||
try
|
||||
{
|
||||
#if USELOCALINSTANCE
|
||||
var command = new DisconnectCommand(SelectedBike, ConnectorFactory, ViewUpdateManager);
|
||||
await command.Invoke(this);
|
||||
#else
|
||||
await SelectedBike.DisconnectAsync(this);
|
||||
#endif
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<T>().Information("Lock of bike {bikeId} could not be disconnected. {@exception}", SelectedBike.Id, exception);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Question if park bike or end rental
|
||||
IsEndRentalRequested = await ViewService.DisplayAlert(
|
||||
AppResources.QuestionRentalProcessCloseLockEndOrContinueTitle,
|
||||
AppResources.QuestionRentalProcessCloseLockEndOrContinueText,
|
||||
AppResources.ActionEndRental,
|
||||
AppResources.QuestionRentalProcessCloseLockContinueRentalAnswer);
|
||||
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||||
|
||||
// Message for parking bike
|
||||
if (IsEndRentalRequested == false)
|
||||
{
|
||||
Log.ForContext<T>().Information("User request to park bike {bikeId}.", SelectedBike.Id);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageRentalProcessCloseLockFinishedTitle,
|
||||
AppResources.MessageRentalProcessCloseLockFinishedText,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.MultilingualResources;
|
||||
using ShareeBike.View;
|
||||
using Serilog;
|
||||
using ConnectAndGetStateCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.ConnectAndGetStateCommand;
|
||||
using AuthCommand = ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.AuthCommand;
|
||||
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 ConnectLockActionViewModel<T> :
|
||||
AuthCommand.IAuthCommandListener,
|
||||
ConnectAndGetStateCommand.IConnectAndGetStateCommandListener
|
||||
{
|
||||
/// <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 ConnectLockActionViewModel(
|
||||
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.");
|
||||
}
|
||||
|
||||
/// <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 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Search and connect to lock. </summary>
|
||||
public async Task ConnectLockAsync()
|
||||
{
|
||||
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();
|
||||
|
||||
// 1a.Step: Authenticate
|
||||
try
|
||||
{
|
||||
#if USELOCALINSTANCE
|
||||
var command = new AuthCommand(SelectedBike, ConnectorFactory, ViewUpdateManager);
|
||||
await command.Invoke(this);
|
||||
#else
|
||||
await SelectedBike.AuthAsync(this);
|
||||
#endif
|
||||
Log.ForContext<T>().Information("User authenticated for bike {bikeId} successfully.", SelectedBike.Id);
|
||||
}
|
||||
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.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
}
|
||||
|
||||
// 1b.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
|
||||
Log.ForContext<T>().Information("Lock of {bikeId} connected successfully.", SelectedBike.Id);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<T>().Information("Lock of bike {bikeId} could not be connected. {@exception}", SelectedBike.Id, exception);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using ShareeBike.MultilingualResources;
|
||||
using Serilog;
|
||||
using DisconnectCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.DisconnectCommand;
|
||||
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 DisconnectLockActionViewModel<T> :
|
||||
DisconnectCommand.IDisconnectCommandListener
|
||||
{
|
||||
/// <summary>
|
||||
/// View model to be used for progress report and unlocking/ locking view.
|
||||
/// </summary>
|
||||
private IBikesViewModel BikesViewModel { get; set; }
|
||||
|
||||
/// <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>
|
||||
/// 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="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
public DisconnectLockActionViewModel(
|
||||
IBikeInfoMutable selectedBike,
|
||||
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||
IBikesViewModel bikesViewModel)
|
||||
{
|
||||
SelectedBike = selectedBike;
|
||||
ViewUpdateManager = viewUpdateManager;
|
||||
BikesViewModel = bikesViewModel
|
||||
?? throw new ArgumentException($"Can not construct {GetType().Name}-object. {nameof(bikesViewModel)} must not be null.");
|
||||
}
|
||||
|
||||
/// <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> Disconnect lock. </summary>
|
||||
public async Task DisconnectLockAsync()
|
||||
{
|
||||
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();
|
||||
|
||||
try
|
||||
{
|
||||
#if USELOCALINSTANCE
|
||||
var command = new DisonnectCommand(SelectedBike, LockService);
|
||||
await command.Invoke(this);
|
||||
#else
|
||||
await SelectedBike.DisconnectAsync(this);
|
||||
#endif
|
||||
Log.ForContext<T>().Information("Lock of {bikeId} disconnected successfully.", SelectedBike.Id);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<T>().Information("Lock of bike {bikeId} could not be disconnected. {@exception}", SelectedBike.Id, exception);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,224 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Serilog;
|
||||
using ShareeBike.MultilingualResources;
|
||||
using ShareeBike.Services.Logging;
|
||||
using ShareeBike.View;
|
||||
using static ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.OpenCommand;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace ShareeBike.ViewModel.Bikes.Bike.BluetoothLock
|
||||
{
|
||||
/// <summary>
|
||||
/// View model for action open bluetooth lock.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
internal class OpenLockActionViewModel<T> : IOpenCommandListener
|
||||
{
|
||||
/// <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 open. </summary>
|
||||
private Model.Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable SelectedBike { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructs the object.
|
||||
/// </summary>
|
||||
/// <param name="selectedBike">Bike to open.</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 OpenLockActionViewModel(
|
||||
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 open lock progress.
|
||||
/// </summary>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(Step step)
|
||||
{
|
||||
switch (step)
|
||||
{
|
||||
case Step.OpeningLock:
|
||||
// 1a.Step: Open lock
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOpeningLock;
|
||||
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessOpenLockStepOpenLock;
|
||||
BikesViewModel.RentalProcess.ImportantStepInfoText = AppResources.MarkingRentalProcessOpenLockObserve;
|
||||
break;
|
||||
|
||||
case Step.GetLockInfos:
|
||||
// 1b.Step: Get lock infos
|
||||
BikesViewModel.RentalProcess.ImportantStepInfoText = AppResources.MarkingRentalProcessOpenLockWait;
|
||||
break;
|
||||
|
||||
case Step.WaitStopPolling:
|
||||
// 1c.Step: Wait for polling to be stopped
|
||||
break;
|
||||
|
||||
case Step.UpdateLockingState:
|
||||
// 1c.Step: Sent info to backend
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdatingLockingState;
|
||||
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessOpenLockStepUpload;
|
||||
BikesViewModel.RentalProcess.ImportantStepInfoText = AppResources.MarkingRentalProcessOpenLockWait;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes the open 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.ErrorOpenLockTitle,
|
||||
AppResources.ErrorLockOutOfReach,
|
||||
AppResources.MessageAnswerOk);
|
||||
break;
|
||||
|
||||
case State.CouldntOpenBoldStatusIsUnknownError:
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockStatusUnknown,
|
||||
AppResources.MessageAnswerOk);
|
||||
break;
|
||||
|
||||
case State.CouldntOpenBoldIsBlockedError:
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockBoldBlocked,
|
||||
AppResources.MessageAnswerOk);
|
||||
break;
|
||||
|
||||
case State.CouldntOpenInconsistentStateError:
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockStillClosed,
|
||||
AppResources.MessageAnswerOk);
|
||||
break;
|
||||
|
||||
case State.GeneralOpenError:
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
details,
|
||||
AppResources.MessageAnswerOk);
|
||||
break;
|
||||
|
||||
case State.StopPollingFailed:
|
||||
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> Open lock in order to pause ride and update COPRI lock state.</summary>
|
||||
public async Task OpenLockAsync()
|
||||
{
|
||||
Log.ForContext<T>().Information("User request to open lock of bike {bikeId}.", SelectedBike.Id);
|
||||
|
||||
// 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.OpenLock,
|
||||
StepIndex = 1,
|
||||
Result = CurrentStepStatus.None
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
#if USELOCALINSTANCE
|
||||
var command = new OpenCommand(SelectedBike, GeolocationService, LockService, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager);
|
||||
await command.Invoke(this);
|
||||
#else
|
||||
await SelectedBike.OpenLockAsync(this, stopPollingTask);
|
||||
#endif
|
||||
Log.ForContext<T>().Information("Lock of bike {bikeId} opened successfully.", SelectedBike.Id);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<T>().Information("Lock of bike {bikeId} can not be opened. {@exception}", SelectedBike.Id, exception);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StartAsync();
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return;
|
||||
}
|
||||
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
//Confirmation message
|
||||
Log.ForContext<T>().Information("User request to park bike {bikeId}.", SelectedBike.Id);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageRentalProcessOpenLockFinishedTitle,
|
||||
AppResources.MessageRentalProcessOpenLockFinishedText,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
using System;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
|
||||
namespace ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
public abstract class Base : BC.RequestHandler.Base<Model.Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs the request handler base.
|
||||
/// </summary>
|
||||
/// <param name="selectedBike">Bike which is reserved or for which reservation is canceled.</param>
|
||||
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...)</param>
|
||||
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||
public Base(
|
||||
Model.Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable selectedBike,
|
||||
string buttonText,
|
||||
bool isCopriButtonVisible,
|
||||
Func<bool> isConnectedDelegate,
|
||||
Func<bool, IConnector> connectorFactory,
|
||||
IGeolocationService geolocation,
|
||||
ILocksService lockService,
|
||||
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||
ISmartDevice smartDevice,
|
||||
IViewService viewService,
|
||||
IBikesViewModel bikesViewModel,
|
||||
IUser activeUser) : base(selectedBike, buttonText, isCopriButtonVisible, isConnectedDelegate, connectorFactory, viewUpdateManager, smartDevice, viewService, bikesViewModel, activeUser)
|
||||
{
|
||||
GeolocationService = geolocation
|
||||
?? throw new ArgumentException($"Can not construct {GetType().Name}-object. Parameter {nameof(geolocation)} must not be null.");
|
||||
|
||||
LockService = lockService
|
||||
?? throw new ArgumentException($"Can not construct {GetType().Name}-object. Parameter {nameof(lockService)} must not be null.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Service to query geolocation information.
|
||||
/// </summary>
|
||||
protected IGeolocationService GeolocationService { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Service to control locks.
|
||||
/// </summary>
|
||||
protected ILocksService LockService { get; }
|
||||
|
||||
public string LockitButtonText { get; protected set; }
|
||||
|
||||
public bool IsLockitButtonVisible { get; protected set; }
|
||||
|
||||
public string ErrorText => string.Empty;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.MultilingualResources;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using EndRentalCommand = ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.EndRentalCommand;
|
||||
using OpenCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.OpenCommand;
|
||||
using static ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandlerFactory;
|
||||
|
||||
namespace ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
public class BookedClosed : Base, IRequestHandler, EndRentalCommand.IEndRentalCommandListener, OpenCommand.IOpenCommandListener
|
||||
{
|
||||
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...)</param>
|
||||
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||
public BookedClosed(
|
||||
IBikeInfoMutable selectedBike,
|
||||
Func<bool> isConnectedDelegate,
|
||||
Func<bool, IConnector> connectorFactory,
|
||||
IGeolocationService geolocation,
|
||||
ILocksService lockService,
|
||||
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||
ISmartDevice smartDevice,
|
||||
IViewService viewService,
|
||||
IBikesViewModel bikesViewModel,
|
||||
IUser activeUser) : base(
|
||||
selectedBike,
|
||||
AppResources.ActionEndRental, // End Rental
|
||||
true, // Show button
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser)
|
||||
{
|
||||
LockitButtonText = AppResources.ActionOpenLock; // Open Lock
|
||||
IsLockitButtonVisible = true; // Show button
|
||||
|
||||
_openLockActionViewModel = new OpenLockActionViewModel<BookedClosed>(
|
||||
selectedBike,
|
||||
viewUpdateManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
_endRentalActionViewModel = new EndRentalActionViewModel<BookedClosed>(
|
||||
selectedBike,
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
viewUpdateManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the view model for end rental action.
|
||||
/// </summary>
|
||||
private readonly EndRentalActionViewModel<BookedClosed> _endRentalActionViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// Processes the get lock location progress.
|
||||
/// </summary>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(EndRentalCommand.Step step) => _endRentalActionViewModel.ReportStep(step);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the get lock location state.
|
||||
/// </summary>
|
||||
/// <param name="state">State to process.</param>
|
||||
/// <param name="details">Textual details describing current state.</param>
|
||||
public async Task ReportStateAsync(EndRentalCommand.State state, string details) => await _endRentalActionViewModel.ReportStateAsync(state, details);
|
||||
|
||||
/// <summary> End Rental. </summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption1()
|
||||
{
|
||||
await _endRentalActionViewModel.EndRentalAsync();
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the view model for close action.
|
||||
/// </summary>
|
||||
private readonly OpenLockActionViewModel<BookedClosed> _openLockActionViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// Processes the open lock progress.
|
||||
/// </summary>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(OpenCommand.Step step) => _openLockActionViewModel.ReportStep(step);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the open lock state.
|
||||
/// </summary>
|
||||
/// <param name="state">State to process.</param>
|
||||
/// <param name="details">Textual details describing current state.</param>
|
||||
public async Task ReportStateAsync(OpenCommand.State state, string details) => await _openLockActionViewModel.ReportStateAsync(state, details);
|
||||
|
||||
|
||||
/// <summary> Open lock. </summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption2()
|
||||
{
|
||||
await _openLockActionViewModel.OpenLockAsync();
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Serilog;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.MultilingualResources;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using ConnectCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.ConnectAndGetStateCommand;
|
||||
using static ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandlerFactory;
|
||||
|
||||
namespace ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
public class BookedDisconnected : Base, IRequestHandler, ConnectCommand.IConnectAndGetStateCommandListener
|
||||
{
|
||||
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...)</param>
|
||||
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||
public BookedDisconnected(
|
||||
IBikeInfoMutable selectedBike,
|
||||
Func<bool> isConnectedDelegate,
|
||||
Func<bool, IConnector> connectorFactory,
|
||||
IGeolocationService geolocation,
|
||||
ILocksService lockService,
|
||||
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||
ISmartDevice smartDevice,
|
||||
IViewService viewService,
|
||||
IBikesViewModel bikesViewModel,
|
||||
IUser activeUser) :
|
||||
base(
|
||||
selectedBike,
|
||||
AppResources.ActionSearchLock, // Connect Lock
|
||||
true, // Show button
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser)
|
||||
{
|
||||
LockitButtonText = GetType().Name;
|
||||
IsLockitButtonVisible = false;
|
||||
|
||||
_connectLockActionViewModel = new ConnectLockActionViewModel<BookedDisconnected>(
|
||||
selectedBike,
|
||||
viewUpdateManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the view model for connecting to lock action.
|
||||
/// </summary>
|
||||
private readonly ConnectLockActionViewModel<BookedDisconnected> _connectLockActionViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// Processes the connect to lock progress.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(ConnectCommand.Step step) => _connectLockActionViewModel?.ReportStep(step);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the connect to lock state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="state">State to process.</param>
|
||||
/// <param name="details">Textual details describing current state.</param>
|
||||
public async Task ReportStateAsync(ConnectCommand.State state, string details) => await _connectLockActionViewModel.ReportStateAsync(state, details);
|
||||
|
||||
|
||||
public async Task<IRequestHandler> HandleRequestOption2() => await UnsupportedRequest();
|
||||
|
||||
/// <summary> Scan for lock.</summary>
|
||||
/// <returns></returns>
|
||||
public async Task<IRequestHandler> HandleRequestOption1()
|
||||
{
|
||||
await _connectLockActionViewModel.ConnectLockAsync();
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
|
||||
/// <summary> Request is not supported, button should be disabled. </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<IRequestHandler> UnsupportedRequest()
|
||||
{
|
||||
Log.ForContext<BookedDisconnected>().Error("Click of unsupported button click detected.");
|
||||
return await Task.FromResult<IRequestHandler>(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,264 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Serilog;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.MultilingualResources;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using CloseCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.CloseCommand;
|
||||
using static ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandlerFactory;
|
||||
using ShareeBike.Services.BluetoothLock.Exception;
|
||||
|
||||
namespace ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
public class BookedOpen : Base, IRequestHandler, CloseCommand.ICloseCommandListener
|
||||
{
|
||||
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||
public BookedOpen(
|
||||
IBikeInfoMutable selectedBike,
|
||||
Func<bool> isConnectedDelegate,
|
||||
Func<bool, IConnector> connectorFactory,
|
||||
IGeolocationService geolocation,
|
||||
ILocksService lockService,
|
||||
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||
ISmartDevice smartDevice,
|
||||
IViewService viewService,
|
||||
IBikesViewModel bikesViewModel,
|
||||
IUser activeUser) : base(
|
||||
selectedBike,
|
||||
AppResources.ActionCloseLock, // Close Lock
|
||||
true, // Show button
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser)
|
||||
{
|
||||
LockitButtonText = activeUser.DebugLevel.HasFlag(Model.User.Account.Permissions.ManageAlarmAndSounds) ? AppResources.ActionLockSettings : GetType().Name;
|
||||
IsLockitButtonVisible = activeUser.DebugLevel.HasFlag(Model.User.Account.Permissions.ManageAlarmAndSounds);
|
||||
|
||||
_closeLockActionViewModel = new CloseLockActionViewModel<BookedOpen>(
|
||||
selectedBike,
|
||||
viewUpdateManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the view model for close action.
|
||||
/// </summary>
|
||||
private readonly CloseLockActionViewModel<BookedOpen> _closeLockActionViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// Processes the close lock progress.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(CloseCommand.Step step) => _closeLockActionViewModel?.ReportStep(step);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the close lock state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="state">State to process.</param>
|
||||
/// <param name="details">Textual details describing current state.</param>
|
||||
public async Task ReportStateAsync(CloseCommand.State state, string details) => await _closeLockActionViewModel.ReportStateAsync(state, details);
|
||||
|
||||
|
||||
/// <summary> Close lock (and return bike).</summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption1()
|
||||
{
|
||||
await _closeLockActionViewModel.CloseLockAsync();
|
||||
if(_closeLockActionViewModel.IsEndRentalRequested == false)
|
||||
{
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
|
||||
var _endRentalActionViewModel = new EndRentalActionViewModel<BookedClosed>(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
ViewUpdateManager,
|
||||
ViewService,
|
||||
BikesViewModel);
|
||||
|
||||
await _endRentalActionViewModel.EndRentalAsync();
|
||||
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
|
||||
public async Task<IRequestHandler> HandleRequestOption2()
|
||||
{
|
||||
if (ActiveUser.DebugLevel.HasFlag(Model.User.Account.Permissions.ManageAlarmAndSounds))
|
||||
{
|
||||
await ManageLockSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
|
||||
/// <summary> Manage sound/ alarm settings. </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<IRequestHandler> ManageLockSettings()
|
||||
{
|
||||
// Stop polling before requesting bike.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
// Go to lock settings
|
||||
Log.ForContext<ReservedOpen>().Information("User selected bike {bikeId} in order to manage sound/ alarm settings.", SelectedBike.Id);
|
||||
|
||||
// Alarm settings
|
||||
var resultAlarm = await ViewService.DisplayAlert(
|
||||
"Alarm einstellen",
|
||||
"Alarm auf Einstellung 'niedrige Sensitivität' setzen oder Alarm ausschalten?",
|
||||
"Auf niedrige Sensitivität",
|
||||
"Alarm aus");
|
||||
|
||||
try
|
||||
{
|
||||
if (resultAlarm == true)
|
||||
{
|
||||
// Lower alarm sensitivity.
|
||||
BikesViewModel.ActionText = "Setzen Alarm-Einstellungen...";
|
||||
await LockService[SelectedBike.LockInfo.Id].SetAlarmSettingsAsync(AlarmSettings.SmallSensivitySilent);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Switch off alarm.
|
||||
BikesViewModel.ActionText = "Alarm ausschalten...";
|
||||
await LockService[SelectedBike.LockInfo.Id].SetIsAlarmOffAsync(true);
|
||||
}
|
||||
}
|
||||
catch (OutOfReachException exception)
|
||||
{
|
||||
Log.ForContext<ReservedOpen>().Debug("Can not set alarm settings. {Exception}", exception);
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
"Fehler beim Setzen der Alarm-Einstellungen!",
|
||||
"Alarm kann erst eingestellt werden, wenn Rad in der Nähe ist.",
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
return this;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<ReservedOpen>().Error("Can not set alarm settings. {Exception}", exception);
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
"Fehler beim Setzen der Alarms-Einstellungen!",
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// Sound settings
|
||||
var resultSound = await ViewService.DisplayAlert(
|
||||
"Sounds einstellen",
|
||||
"Sounds auf Einstellung 'Warnung' setzen oder alle Sounds ausschalten?",
|
||||
"Auf Warnung",
|
||||
"Alles aus");
|
||||
|
||||
try
|
||||
{
|
||||
if (resultSound == true)
|
||||
{
|
||||
BikesViewModel.ActionText = "Sounds einstellen auf 'Warnung'...";
|
||||
await LockService[SelectedBike.LockInfo.Id].SetSoundAsync(SoundSettings.Warn);
|
||||
}
|
||||
else
|
||||
{
|
||||
BikesViewModel.ActionText = "Alle Sounds ausschalten...";
|
||||
await LockService[SelectedBike.LockInfo.Id].SetSoundAsync(SoundSettings.AllOff);
|
||||
}
|
||||
}
|
||||
catch (OutOfReachException exception)
|
||||
{
|
||||
Log.ForContext<ReservedOpen>().Debug("Can not set sounds. {Exception}", exception);
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
"Fehler beim Einstellen der Sounds!",
|
||||
"Sounds können erst eingestellt werden, wenn Rad in der Nähe ist.",
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
return this;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<ReservedOpen>().Error("Can not set sounds. {Exception}", exception);
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
"Fehler beim Einstellen der Sounds!",
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
return Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary> Request is not supported, button should be disabled. </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<IRequestHandler> UnsupportedRequest()
|
||||
{
|
||||
Log.ForContext<DisposableDisconnected>().Error("Click of unsupported button click detected.");
|
||||
return await Task.FromResult<IRequestHandler>(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.MultilingualResources;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using CloseCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.CloseCommand;
|
||||
using OpenCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.OpenCommand;
|
||||
using static ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandlerFactory;
|
||||
|
||||
namespace ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
public class BookedUnknown : Base, IRequestHandler, CloseCommand.ICloseCommandListener, OpenCommand.IOpenCommandListener
|
||||
{
|
||||
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...).</param>
|
||||
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||
public BookedUnknown(
|
||||
IBikeInfoMutable selectedBike,
|
||||
Func<bool> isConnectedDelegate,
|
||||
Func<bool, IConnector> connectorFactory,
|
||||
IGeolocationService geolocation,
|
||||
ILocksService lockService,
|
||||
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||
ISmartDevice smartDevice,
|
||||
IViewService viewService,
|
||||
IBikesViewModel bikesViewModel,
|
||||
IUser activeUser) : base(
|
||||
selectedBike,
|
||||
AppResources.ActionOpenLock, // Open Lock
|
||||
true, // Show button
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser)
|
||||
{
|
||||
LockitButtonText = AppResources.ActionCloseLock; // Close Lock
|
||||
IsLockitButtonVisible = true; // Show button
|
||||
|
||||
_openLockActionViewModel = new OpenLockActionViewModel<BookedUnknown>(
|
||||
selectedBike,
|
||||
viewUpdateManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
_closeLockActionViewModel = new CloseLockActionViewModel<BookedUnknown>(
|
||||
selectedBike,
|
||||
viewUpdateManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the view model for close action.
|
||||
/// </summary>
|
||||
private readonly OpenLockActionViewModel<BookedUnknown> _openLockActionViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// Processes the open lock progress.
|
||||
/// </summary>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(OpenCommand.Step step) => _openLockActionViewModel.ReportStep(step);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the open lock state.
|
||||
/// </summary>
|
||||
/// <param name="state">State to process.</param>
|
||||
/// <param name="details">Textual details describing current state.</param>
|
||||
public async Task ReportStateAsync(OpenCommand.State state, string details) => await _openLockActionViewModel.ReportStateAsync(state, details);
|
||||
|
||||
/// <summary> Open bike and update COPRI lock state. </summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption1()
|
||||
{
|
||||
await _openLockActionViewModel.OpenLockAsync();
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the view model for close action.
|
||||
/// </summary>
|
||||
private readonly CloseLockActionViewModel<BookedUnknown> _closeLockActionViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// Processes the close lock progress.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(CloseCommand.Step step) => _closeLockActionViewModel?.ReportStep(step);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the close lock state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="state">State to process.</param>
|
||||
/// <param name="details">Textual details describing current state.</param>
|
||||
public async Task ReportStateAsync(CloseCommand.State state, string details) => await _closeLockActionViewModel.ReportStateAsync(state, details);
|
||||
|
||||
|
||||
/// <summary> Close lock in order to pause ride and update COPRI lock state.</summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption2()
|
||||
{
|
||||
await _closeLockActionViewModel.CloseLockAsync();
|
||||
if (_closeLockActionViewModel.IsEndRentalRequested == false)
|
||||
{
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
|
||||
var _endRentalActionViewModel = new EndRentalActionViewModel<BookedClosed>(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
ViewUpdateManager,
|
||||
ViewService,
|
||||
BikesViewModel);
|
||||
|
||||
await _endRentalActionViewModel.EndRentalAsync();
|
||||
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Serilog;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.MultilingualResources;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using StartReservationCommand = ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.StartReservationCommand;
|
||||
using static ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandlerFactory;
|
||||
|
||||
namespace ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
public class DisposableDisconnected : Base, IRequestHandler, StartReservationCommand.IStartReservationCommandListener
|
||||
{
|
||||
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...).</param>
|
||||
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||
public DisposableDisconnected(
|
||||
IBikeInfoMutable selectedBike,
|
||||
Func<bool> isConnectedDelegate,
|
||||
Func<bool, IConnector> connectorFactory,
|
||||
IGeolocationService geolocation,
|
||||
ILocksService lockService,
|
||||
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||
ISmartDevice smartDevice,
|
||||
IViewService viewService,
|
||||
IBikesViewModel bikesViewModel,
|
||||
IUser activeUser) : base(
|
||||
selectedBike,
|
||||
AppResources.ActionRequestBike, // Reserve / Rent Bike
|
||||
true, // Show button
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser)
|
||||
{
|
||||
LockitButtonText = GetType().Name;
|
||||
IsLockitButtonVisible = false;
|
||||
|
||||
_startReservationOrRentalActionViewModel = new StartReservationOrRentalActionViewModel<DisposableDisconnected>(
|
||||
selectedBike,
|
||||
viewUpdateManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the view model for requesting a bike action.
|
||||
/// </summary>
|
||||
private readonly StartReservationOrRentalActionViewModel<DisposableDisconnected> _startReservationOrRentalActionViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// Processes the reserving a bike progress.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(StartReservationCommand.Step step) => _startReservationOrRentalActionViewModel?.ReportStep(step);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the reserving a bike state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <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) => await _startReservationOrRentalActionViewModel.ReportStateAsync(state, details);
|
||||
|
||||
|
||||
/// <summary>Reserve bike, connect to lock, open lock and rent bike.</summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption1()
|
||||
{
|
||||
await _startReservationOrRentalActionViewModel.StartReservationOrRentalAsync();
|
||||
if (_startReservationOrRentalActionViewModel.ContinueWithOpenLock == false)
|
||||
{
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
|
||||
var _openLockActionViewModel = new OpenLockActionViewModel<BookedClosed>(
|
||||
SelectedBike,
|
||||
ViewUpdateManager,
|
||||
ViewService,
|
||||
BikesViewModel);
|
||||
|
||||
await _openLockActionViewModel.OpenLockAsync();
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
|
||||
public async Task<IRequestHandler> HandleRequestOption2() => await UnsupportedRequest();
|
||||
|
||||
/// <summary> Request is not supported, button should be disabled. </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<IRequestHandler> UnsupportedRequest()
|
||||
{
|
||||
Log.ForContext<DisposableDisconnected>().Error("Click of unsupported button click detected.");
|
||||
return await Task.FromResult<IRequestHandler>(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.MultilingualResources;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using StartReservationCommand = ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.StartReservationCommand;
|
||||
using CloseCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.CloseCommand;
|
||||
using static ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandlerFactory;
|
||||
|
||||
namespace ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
/// <summary> Bike is disposable, lock is open and connected to app. </summary>
|
||||
/// <remarks>
|
||||
/// This state can not be occur because
|
||||
/// - app does not allow to return bike/ cancel reservation when lock is not closed
|
||||
/// - as long as app is connected to lock
|
||||
/// - lock can not be opened manually
|
||||
/// - no other device can access lock
|
||||
/// </remarks>
|
||||
public class DisposableOpen : Base, IRequestHandler, StartReservationCommand.IStartReservationCommandListener, CloseCommand.ICloseCommandListener
|
||||
{
|
||||
/// <summary> Bike is disposable, lock is open and can be reached via bluetooth. </summary>
|
||||
/// <remarks>
|
||||
/// This state should never occur because as long as a ILOCKIT is connected it
|
||||
/// - cannot be closed manually
|
||||
/// - no other device can access lock
|
||||
/// - app itself should never event attempt to open a lock which is not rented.
|
||||
/// </remarks>
|
||||
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...)</param>
|
||||
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||
public DisposableOpen(
|
||||
IBikeInfoMutable selectedBike,
|
||||
Func<bool> isConnectedDelegate,
|
||||
Func<bool, IConnector> connectorFactory,
|
||||
IGeolocationService geolocation,
|
||||
ILocksService lockService,
|
||||
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||
ISmartDevice smartDevice,
|
||||
IViewService viewService,
|
||||
IBikesViewModel bikesViewModel,
|
||||
IUser activeUser) : base(
|
||||
selectedBike,
|
||||
AppResources.ActionRequestBike, // Reserve / Rent Bike
|
||||
true, // Show button
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser)
|
||||
{
|
||||
LockitButtonText = AppResources.ActionCloseLock; // Close Lock
|
||||
IsLockitButtonVisible = true; // Show button
|
||||
|
||||
_startReservationOrRentalActionViewModel = new StartReservationOrRentalActionViewModel<DisposableOpen>(
|
||||
selectedBike,
|
||||
viewUpdateManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
_closeLockActionViewModel = new CloseLockActionViewModel<DisposableOpen>(
|
||||
selectedBike,
|
||||
viewUpdateManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the view model for requesting a bike action.
|
||||
/// </summary>
|
||||
private readonly StartReservationOrRentalActionViewModel<DisposableOpen> _startReservationOrRentalActionViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// Processes the reserving a bike progress.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(StartReservationCommand.Step step) => _startReservationOrRentalActionViewModel?.ReportStep(step);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the reserving a bike state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <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) => await _startReservationOrRentalActionViewModel.ReportStateAsync(state, details);
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Holds the view model for close action.
|
||||
/// </summary>
|
||||
private readonly CloseLockActionViewModel<DisposableOpen> _closeLockActionViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// Processes the close lock progress.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(CloseCommand.Step step) => _closeLockActionViewModel?.ReportStep(step);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the close lock state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="state">State to process.</param>
|
||||
/// <param name="details">Textual details describing current state.</param>
|
||||
public async Task ReportStateAsync(CloseCommand.State state, string details) => await _closeLockActionViewModel.ReportStateAsync(state, details);
|
||||
|
||||
|
||||
/// <summary>Rents bike by reserving bike and renting bike.</summary>
|
||||
/// <returns>Next request handler.</returns>
|
||||
public async Task<IRequestHandler> HandleRequestOption1()
|
||||
{
|
||||
await _startReservationOrRentalActionViewModel.StartReservationOrRentalAsync();
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
|
||||
/// <summary>Closes Lock.</summary>
|
||||
/// <returns>Next request handler.</returns>
|
||||
public async Task<IRequestHandler> HandleRequestOption2()
|
||||
{
|
||||
await _closeLockActionViewModel.CloseLockAsync();
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System.Threading.Tasks;
|
||||
|
||||
namespace ShareeBike.ViewModel.Bikes.Bike.BluetoothLock
|
||||
{
|
||||
public interface IRequestHandler : IRequestHandlerBase
|
||||
{
|
||||
/// <summary> Gets a value indicating whether the ILockIt button which is managed by request handler is visible or not. </summary>
|
||||
bool IsLockitButtonVisible { get; }
|
||||
|
||||
/// <summary> Gets the text of the ILockIt button which is managed by request handler. </summary>
|
||||
string LockitButtonText { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Performs the copri action to be executed when user presses the copri button managed by request handler.
|
||||
/// </summary>
|
||||
/// <returns>New handler object if action succeeded, same handler otherwise.</returns>
|
||||
Task<IRequestHandler> HandleRequestOption1();
|
||||
|
||||
Task<IRequestHandler> HandleRequestOption2();
|
||||
|
||||
/// <summary>
|
||||
/// Holds error description (invalid state).
|
||||
/// </summary>
|
||||
string ErrorText { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Serilog;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.State;
|
||||
|
||||
namespace ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
public class InvalidState : IRequestHandler
|
||||
{
|
||||
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||
public InvalidState(
|
||||
IBikesViewModel bikesViewModel,
|
||||
InUseStateEnum copriState,
|
||||
LockingState lockingState,
|
||||
string errorText)
|
||||
{
|
||||
BikesViewModel = bikesViewModel
|
||||
?? throw new ArgumentException($"Can not construct {GetType().Name}-object. {nameof(bikesViewModel)} must not be null.");
|
||||
|
||||
ErrorText = errorText;
|
||||
|
||||
Log.Error($"{errorText}. Copri state is {copriState} and lock state is {lockingState}.");
|
||||
}
|
||||
|
||||
/// <summary>View model to be used for progress report and unlocking/ locking view.</summary>
|
||||
public IBikesViewModel BikesViewModel { get; }
|
||||
|
||||
public bool IsLockitButtonVisible => false;
|
||||
|
||||
public string LockitButtonText => GetType().Name;
|
||||
|
||||
public bool IsConnected => false;
|
||||
|
||||
public bool IsButtonVisible => false;
|
||||
|
||||
public string ButtonText => GetType().Name;
|
||||
|
||||
/// <summary> Gets if the bike has to be removed after action has been completed. </summary>
|
||||
public bool IsRemoveBikeRequired => false;
|
||||
|
||||
public string ErrorText { get; }
|
||||
|
||||
public async Task<IRequestHandler> HandleRequestOption2()
|
||||
{
|
||||
Log.ForContext<InvalidState>().Error($"Click of unsupported button {nameof(HandleRequestOption2)} detected.");
|
||||
return await Task.FromResult<IRequestHandler>(this);
|
||||
}
|
||||
|
||||
public async Task<IRequestHandler> HandleRequestOption1()
|
||||
{
|
||||
Log.ForContext<InvalidState>().Error($"Click of unsupported button {nameof(HandleRequestOption1)} detected.");
|
||||
return await Task.FromResult<IRequestHandler>(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Serilog;
|
||||
using ShareeBike.Model.State;
|
||||
using ShareeBike.MultilingualResources;
|
||||
using ShareeBike.View;
|
||||
|
||||
namespace ShareeBike.ViewModel.Bikes.Bike.BluetoothLock
|
||||
{
|
||||
public class NotLoggedIn : IRequestHandler
|
||||
{
|
||||
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||
public NotLoggedIn(
|
||||
InUseStateEnum state,
|
||||
IViewService viewService,
|
||||
IBikesViewModel bikesViewModel)
|
||||
{
|
||||
ButtonText = BC.StateToText.GetActionText(state);
|
||||
ViewService = viewService;
|
||||
BikesViewModel = bikesViewModel
|
||||
?? throw new ArgumentException($"Can not construct {GetType().Name}-object. {nameof(bikesViewModel)} must not be null.");
|
||||
}
|
||||
|
||||
/// <summary>View model to be used for progress report and unlocking/ locking view.</summary>
|
||||
public IBikesViewModel BikesViewModel { get; }
|
||||
|
||||
public bool IsButtonVisible => true;
|
||||
|
||||
public bool IsLockitButtonVisible => false;
|
||||
|
||||
public string ButtonText { get; private set; }
|
||||
|
||||
public string LockitButtonText => GetType().Name;
|
||||
|
||||
/// <summary>
|
||||
/// Reference on view service to show modal notifications and to perform navigation.
|
||||
/// </summary>
|
||||
private IViewService ViewService { get; }
|
||||
|
||||
public bool IsConnected => throw new NotImplementedException();
|
||||
|
||||
/// <summary> Gets if the bike has to be removed after action has been completed. </summary>
|
||||
public bool IsRemoveBikeRequired => false;
|
||||
|
||||
public async Task<IRequestHandler> HandleRequestOption1()
|
||||
{
|
||||
Log.ForContext<BikesViewModel>().Information("User selected bike but is not logged in.");
|
||||
|
||||
// User is not logged in
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
var l_oResult = await ViewService.DisplayAlert(
|
||||
AppResources.QuestionLogInTitle,
|
||||
AppResources.QuestionLogIn,
|
||||
AppResources.MessageAnswerYes,
|
||||
AppResources.MessageAnswerNo);
|
||||
|
||||
if (l_oResult == false)
|
||||
{
|
||||
// User aborted booking process
|
||||
BikesViewModel.IsIdle = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Switch to map page
|
||||
await ViewService.ShowPage("//LoginPage");
|
||||
}
|
||||
catch (Exception p_oException)
|
||||
{
|
||||
Log.ForContext<BikesViewModel>().Error("Ein unerwarteter Fehler ist in der Klasse NotLoggedIn aufgetreten. Kontext: Aufruf nach Reservierungsversuch ohne Anmeldung. {@Exception}", p_oException);
|
||||
BikesViewModel.IsIdle = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
BikesViewModel.IsIdle = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public async Task<IRequestHandler> HandleRequestOption2()
|
||||
{
|
||||
Log.ForContext<NotLoggedIn>().Error("Click of unsupported button detected.");
|
||||
return await Task.FromResult(this);
|
||||
}
|
||||
|
||||
public string ErrorText => string.Empty;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.MultilingualResources;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using IBikeInfoMutable = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable;
|
||||
using CancelReservationCommand = ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.CancelReservationCommand;
|
||||
using StartRentalCommand = ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.StartRentalCommand;
|
||||
using static ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandlerFactory;
|
||||
|
||||
namespace ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
/// <summary> Bike is reserved, lock is closed and connected to app. </summary>
|
||||
/// <remarks>
|
||||
/// Occurs when
|
||||
/// - bike was reserved out of reach and is in reach now
|
||||
/// - bike is reserved while in reach
|
||||
/// </remarks>
|
||||
public class ReservedClosed : Base, IRequestHandler, CancelReservationCommand.ICancelReservationCommandListener, StartRentalCommand.IStartRentalCommandListener
|
||||
{
|
||||
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...)</param>
|
||||
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||
public ReservedClosed(
|
||||
IBikeInfoMutable selectedBike,
|
||||
Func<bool> isConnectedDelegate,
|
||||
Func<bool, IConnector> connectorFactory,
|
||||
IGeolocationService geolocation,
|
||||
ILocksService lockService,
|
||||
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||
ISmartDevice smartDevice,
|
||||
IViewService viewService,
|
||||
IBikesViewModel bikesViewModel,
|
||||
IUser activeUser) : base(
|
||||
selectedBike,
|
||||
AppResources.ActionCancelReservation, // Cancel Reservation
|
||||
true, // Show button
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser)
|
||||
{
|
||||
LockitButtonText = AppResources.ActionOpenLockAndRentBike; // Rent Bike
|
||||
IsLockitButtonVisible = true; // Show button
|
||||
|
||||
_cancelReservationActionViewModel = new CancelReservationActionViewModel<ReservedClosed>(
|
||||
selectedBike,
|
||||
viewUpdateManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
_startRentalActionViewModel = new StartReservationOrRentalActionViewModel<ReservedClosed>(
|
||||
selectedBike,
|
||||
viewUpdateManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the view model for requesting a bike action.
|
||||
/// </summary>
|
||||
private readonly CancelReservationActionViewModel<ReservedClosed> _cancelReservationActionViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// Processes the canceling of reservation progress.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(CancelReservationCommand.Step step) => _cancelReservationActionViewModel?.ReportStep(step);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the canceling of reservation state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="state">State to process.</param>
|
||||
/// <param name="details">Textual details describing current state.</param>
|
||||
public async Task ReportStateAsync(CancelReservationCommand.State state, string details) => await _cancelReservationActionViewModel.ReportStateAsync(state, details);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Holds the view model for requesting a bike action.
|
||||
/// </summary>
|
||||
private readonly StartReservationOrRentalActionViewModel<ReservedClosed> _startRentalActionViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// Processes the renting a bike progress.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(StartRentalCommand.Step step) => _startRentalActionViewModel?.ReportStep(step);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the renting a bike state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <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) => await _startRentalActionViewModel.ReportStateAsync(state, details);
|
||||
|
||||
|
||||
/// <summary> Cancel reservation. </summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption1()
|
||||
{
|
||||
await _cancelReservationActionViewModel.CancelReservationAsync();
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
|
||||
/// <summary> Open lock and rent bike. </summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption2()
|
||||
{
|
||||
await _startRentalActionViewModel.StartReservationOrRentalAsync();
|
||||
if (_startRentalActionViewModel.ContinueWithOpenLock == false)
|
||||
{
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
|
||||
var _openLockActionViewModel = new OpenLockActionViewModel<BookedClosed>(
|
||||
SelectedBike,
|
||||
ViewUpdateManager,
|
||||
ViewService,
|
||||
BikesViewModel);
|
||||
|
||||
await _openLockActionViewModel.OpenLockAsync();
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.MultilingualResources;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using CancelReservationCommand = ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.CancelReservationCommand;
|
||||
using StartRentalCommand = ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.StartRentalCommand;
|
||||
using static ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandlerFactory;
|
||||
|
||||
namespace ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
public class ReservedDisconnected : Base, IRequestHandler, CancelReservationCommand.ICancelReservationCommandListener, StartRentalCommand.IStartRentalCommandListener
|
||||
{
|
||||
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...)</param>
|
||||
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||
public ReservedDisconnected(
|
||||
IBikeInfoMutable selectedBike,
|
||||
Func<bool> isConnectedDelegate,
|
||||
Func<bool, IConnector> connectorFactory,
|
||||
IGeolocationService geolocation,
|
||||
ILocksService lockService,
|
||||
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||
ISmartDevice smartDevice,
|
||||
IViewService viewService,
|
||||
IBikesViewModel bikesViewModel,
|
||||
IUser activeUser) : base(
|
||||
selectedBike,
|
||||
AppResources.ActionCancelReservation, // Cancel Reservation
|
||||
true, // Show button
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser)
|
||||
{
|
||||
LockitButtonText = AppResources.ActionRentBike; // Rent bike
|
||||
IsLockitButtonVisible = true; // Show button
|
||||
|
||||
_cancelReservationlActionViewModel = new CancelReservationActionViewModel<ReservedDisconnected>(
|
||||
selectedBike,
|
||||
viewUpdateManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
_startRentalActionViewModel = new StartReservationOrRentalActionViewModel<ReservedDisconnected>(
|
||||
selectedBike,
|
||||
viewUpdateManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the view model for requesting a bike action.
|
||||
/// </summary>
|
||||
private readonly CancelReservationActionViewModel<ReservedDisconnected> _cancelReservationlActionViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// Processes the canceling of reservation progress.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(CancelReservationCommand.Step step) => _cancelReservationlActionViewModel?.ReportStep(step);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the canceling of reservation state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="state">State to process.</param>
|
||||
/// <param name="details">Textual details describing current state.</param>
|
||||
public async Task ReportStateAsync(CancelReservationCommand.State state, string details) => await _cancelReservationlActionViewModel.ReportStateAsync(state, details);
|
||||
|
||||
/// <summary> Cancel reservation. </summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption1()
|
||||
{
|
||||
await _cancelReservationlActionViewModel.CancelReservationAsync();
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the view model for requesting a bike action.
|
||||
/// </summary>
|
||||
private readonly StartReservationOrRentalActionViewModel<ReservedDisconnected> _startRentalActionViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// Processes the renting a bike progress.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(StartRentalCommand.Step step) => _startRentalActionViewModel?.ReportStep(step);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the renting a bike state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <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) => await _startRentalActionViewModel.ReportStateAsync(state, details);
|
||||
|
||||
|
||||
/// <summary> Connect to reserved bike ask whether to rent bike or not and if yes open lock. </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<IRequestHandler> HandleRequestOption2()
|
||||
{
|
||||
await _startRentalActionViewModel.StartReservationOrRentalAsync();
|
||||
if (_startRentalActionViewModel.ContinueWithOpenLock == false)
|
||||
{
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
|
||||
var _openLockActionViewModel = new OpenLockActionViewModel<BookedClosed>(
|
||||
SelectedBike,
|
||||
ViewUpdateManager,
|
||||
ViewService,
|
||||
BikesViewModel);
|
||||
|
||||
await _openLockActionViewModel.OpenLockAsync();
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.MultilingualResources;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using IBikeInfoMutable = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable;
|
||||
using CloseCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.CloseCommand;
|
||||
using StartRentalCommand = ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.StartRentalCommand;
|
||||
using static ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandlerFactory;
|
||||
|
||||
namespace ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
/// <summary> Bike is reserved, lock is open and connected to app. </summary>
|
||||
/// <remarks>
|
||||
/// This state might occur when a ILOCKIT was manually opened (color code) and app connects afterwards.
|
||||
/// This should never during ILOCKIT is connected to app because
|
||||
/// - manually opening lock is not possible when lock is connected
|
||||
/// - two devices can not simultaneously connect to same lock.
|
||||
public class ReservedOpen : Base, IRequestHandler, CloseCommand.ICloseCommandListener, StartRentalCommand.IStartRentalCommandListener
|
||||
{
|
||||
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...)</param>
|
||||
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||
public ReservedOpen(
|
||||
IBikeInfoMutable selectedBike,
|
||||
Func<bool> isConnectedDelegate,
|
||||
Func<bool, IConnector> connectorFactory,
|
||||
IGeolocationService geolocation,
|
||||
ILocksService lockService,
|
||||
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||
ISmartDevice smartDevice,
|
||||
IViewService viewService,
|
||||
IBikesViewModel bikesViewModel,
|
||||
IUser activeUser) : base(
|
||||
selectedBike,
|
||||
AppResources.ActionCloseLock, // Close Lock
|
||||
true, // Show button
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser)
|
||||
{
|
||||
LockitButtonText = AppResources.ActionRentBike; // Rent bike
|
||||
IsLockitButtonVisible = true; // Show button
|
||||
|
||||
_closeLockActionViewModel = new CloseLockActionViewModel<ReservedOpen>(
|
||||
selectedBike,
|
||||
viewUpdateManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
_startRentalActionViewModel = new StartReservationOrRentalActionViewModel<ReservedOpen>(
|
||||
selectedBike,
|
||||
viewUpdateManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the view model for close action.
|
||||
/// </summary>
|
||||
private readonly CloseLockActionViewModel<ReservedOpen> _closeLockActionViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// Processes the close lock progress.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(CloseCommand.Step step) => _closeLockActionViewModel?.ReportStep(step);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the close lock state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="state">State to process.</param>
|
||||
/// <param name="details">Textual details describing current state.</param>
|
||||
public async Task ReportStateAsync(CloseCommand.State state, string details) => await _closeLockActionViewModel.ReportStateAsync(state, details);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Holds the view model for requesting a bike action.
|
||||
/// </summary>
|
||||
private readonly StartReservationOrRentalActionViewModel<ReservedOpen> _startRentalActionViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// Processes the renting a bike progress.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(StartRentalCommand.Step step) => _startRentalActionViewModel?.ReportStep(step);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the renting a bike state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <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) => await _startRentalActionViewModel.ReportStateAsync(state, details);
|
||||
|
||||
|
||||
/// <summary> Close lock. </summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption1()
|
||||
{
|
||||
await _closeLockActionViewModel.CloseLockAsync();
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
|
||||
/// <summary> Start Rental. </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<IRequestHandler> HandleRequestOption2()
|
||||
{
|
||||
await _startRentalActionViewModel.StartReservationOrRentalAsync();
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.MultilingualResources;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using CloseCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.CloseCommand;
|
||||
using StartRentalCommand = ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.StartRentalCommand;
|
||||
using static ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandlerFactory;
|
||||
|
||||
namespace ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
public class ReservedUnknown : Base, IRequestHandler, CloseCommand.ICloseCommandListener, StartRentalCommand.IStartRentalCommandListener
|
||||
{
|
||||
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...)</param>
|
||||
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||
public ReservedUnknown(
|
||||
IBikeInfoMutable selectedBike,
|
||||
Func<bool> isConnectedDelegate,
|
||||
Func<bool, IConnector> connectorFactory,
|
||||
IGeolocationService geolocation,
|
||||
ILocksService lockService,
|
||||
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||
ISmartDevice smartDevice,
|
||||
IViewService viewService,
|
||||
IBikesViewModel bikesViewModel,
|
||||
IUser activeUser) : base(
|
||||
selectedBike,
|
||||
AppResources.ActionCloseLock, // Close Lock
|
||||
true, // Show button
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser)
|
||||
{
|
||||
LockitButtonText = AppResources.ActionRentBike; // Rent Bike
|
||||
IsLockitButtonVisible = true; // Show button
|
||||
|
||||
_closeLockActionViewModel = new CloseLockActionViewModel<ReservedUnknown>(
|
||||
selectedBike,
|
||||
viewUpdateManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
_startRentalActionViewModel = new StartReservationOrRentalActionViewModel<ReservedUnknown>(
|
||||
selectedBike,
|
||||
viewUpdateManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the view model for close action.
|
||||
/// </summary>
|
||||
private readonly CloseLockActionViewModel<ReservedUnknown> _closeLockActionViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// Processes the close lock progress.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(CloseCommand.Step step) => _closeLockActionViewModel?.ReportStep(step);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the close lock state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="state">State to process.</param>
|
||||
/// <param name="details">Textual details describing current state.</param>
|
||||
public async Task ReportStateAsync(CloseCommand.State state, string details) => await _closeLockActionViewModel.ReportStateAsync(state, details);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Holds the view model for requesting a bike action.
|
||||
/// </summary>
|
||||
private readonly StartReservationOrRentalActionViewModel<ReservedUnknown> _startRentalActionViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// Processes the renting a bike progress.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(StartRentalCommand.Step step) => _startRentalActionViewModel?.ReportStep(step);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the renting a bike state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <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) => await _startRentalActionViewModel.ReportStateAsync(state, details);
|
||||
|
||||
/// <summary> Open bike and update COPRI lock state. </summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption2()
|
||||
{
|
||||
await _startRentalActionViewModel.StartReservationOrRentalAsync();
|
||||
if (_startRentalActionViewModel.ContinueWithOpenLock == false)
|
||||
{
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
|
||||
var _openLockActionViewModel = new OpenLockActionViewModel<BookedClosed>(
|
||||
SelectedBike,
|
||||
ViewUpdateManager,
|
||||
ViewService,
|
||||
BikesViewModel);
|
||||
|
||||
await _openLockActionViewModel.OpenLockAsync();
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
/// <summary> Close lock (and return bike).</summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption1()
|
||||
{
|
||||
await _closeLockActionViewModel.CloseLockAsync();
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
using System;
|
||||
using Serilog;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.MultilingualResources;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
|
||||
|
||||
namespace ShareeBike.ViewModel.Bikes.Bike.BluetoothLock
|
||||
{
|
||||
public static class RequestHandlerFactory
|
||||
{
|
||||
/// <summary> Creates a request handler.</summary>
|
||||
/// <param name="selectedBike"></param>
|
||||
/// <param name="isConnectedDelegate"></param>
|
||||
/// <param name="connectorFactory"></param>
|
||||
/// <param name="geolocation"></param>
|
||||
/// <param name="viewUpdateManager"></param>
|
||||
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...)</param>
|
||||
/// <param name="viewService"></param>
|
||||
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||
/// <param name="context">Specifies the context (last action performed).</param>
|
||||
/// <returns>Request handler.</returns>
|
||||
public static IRequestHandler Create(
|
||||
Model.Bikes.BikeInfoNS.BC.IBikeInfoMutable selectedBike,
|
||||
Func<bool> isConnectedDelegate,
|
||||
Func<bool, IConnector> connectorFactory,
|
||||
IGeolocationService geolocation,
|
||||
ILocksService lockService,
|
||||
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||
ISmartDevice smartDevice,
|
||||
IViewService viewService,
|
||||
IBikesViewModel bikesViewModel,
|
||||
IUser activeUser)
|
||||
{
|
||||
if (!(selectedBike is IBikeInfoMutable selectedBluetoothLockBike))
|
||||
return null;
|
||||
|
||||
switch (selectedBluetoothLockBike.State.Value)
|
||||
{
|
||||
case Model.State.InUseStateEnum.Disposable:
|
||||
|
||||
// Bike is reserved, select action depending on lock state.
|
||||
switch (selectedBluetoothLockBike.LockInfo.State)
|
||||
{
|
||||
case LockingState.Open:
|
||||
case LockingState.UnknownFromHardwareError:
|
||||
// Unexpected state detected.
|
||||
/// This state is unexpected because
|
||||
/// - app does not allow to return bike/ cancel reservation when lock is closed
|
||||
/// - as long as app is connected to lock
|
||||
/// - lock can not be opened manually
|
||||
/// - no other device can access lock
|
||||
/// Nevertheless this state is not expected let user either
|
||||
/// - close lock or
|
||||
/// - rent bike
|
||||
/// </remarks>
|
||||
Log.Error("Unexpected state {BookingState}/ {LockingState} detected.", selectedBluetoothLockBike.State.Value, selectedBluetoothLockBike.LockInfo.State);
|
||||
return new DisposableOpen(
|
||||
selectedBluetoothLockBike,
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
case LockingState.Closed:
|
||||
case LockingState.UnknownDisconnected:
|
||||
// Do not allow interaction with lock before reserving bike.
|
||||
return new DisposableDisconnected(
|
||||
selectedBluetoothLockBike,
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
default:
|
||||
// Invalid state detected. Lock must never be open if bike is reserved.
|
||||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
case Model.State.InUseStateEnum.Reserved:
|
||||
|
||||
// Bike is reserved, select action depending on lock state.
|
||||
switch (selectedBluetoothLockBike.LockInfo.State)
|
||||
{
|
||||
case LockingState.Closed:
|
||||
// Lock could not be opened after reserving bike.
|
||||
return new ReservedClosed(
|
||||
selectedBluetoothLockBike,
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
case LockingState.UnknownDisconnected:
|
||||
return new ReservedDisconnected(
|
||||
selectedBluetoothLockBike,
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
case LockingState.Open:
|
||||
// Unwanted state detected.
|
||||
/// This state might occur when a ILOCKIT was manually opened (color code) and app connects afterwards.
|
||||
Log.Error("Unwanted state {BookingState}/ {LockingState} detected.", selectedBluetoothLockBike.State.Value, selectedBluetoothLockBike.LockInfo.State);
|
||||
return new ReservedOpen(
|
||||
selectedBluetoothLockBike,
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
case LockingState.UnknownFromHardwareError:
|
||||
// User wants to return bike/ pause ride.
|
||||
return new ReservedUnknown(
|
||||
selectedBluetoothLockBike,
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
default:
|
||||
// Invalid state detected. Lock must never be open if bike is reserved.
|
||||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
case Model.State.InUseStateEnum.Booked:
|
||||
|
||||
// Bike is booked, select action depending on lock state.
|
||||
switch (selectedBluetoothLockBike.LockInfo.State)
|
||||
{
|
||||
case LockingState.Closed:
|
||||
// User wants to close lock.
|
||||
return new BookedClosed(
|
||||
selectedBluetoothLockBike,
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
case LockingState.Open:
|
||||
// User wants to return bike/ pause ride.
|
||||
return new BookedOpen(
|
||||
selectedBluetoothLockBike,
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
case LockingState.UnknownFromHardwareError:
|
||||
// User wants to return bike/ pause ride.
|
||||
return new BookedUnknown(
|
||||
selectedBluetoothLockBike,
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
case LockingState.UnknownDisconnected:
|
||||
// Invalid state detected.
|
||||
// If bike is booked lock state must be queried before creating view model.
|
||||
return new BookedDisconnected(
|
||||
selectedBluetoothLockBike,
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
default:
|
||||
// Invalid state detected. Lock must never be open if bike is reserved.
|
||||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
default:
|
||||
// Unexpected copri state detected.
|
||||
Log.Error("Unexpected locking {BookingState}/ {LockingState} detected.", selectedBluetoothLockBike.State.Value, selectedBluetoothLockBike.LockInfo.State);
|
||||
return new InvalidState(
|
||||
bikesViewModel,
|
||||
selectedBluetoothLockBike.State.Value,
|
||||
selectedBluetoothLockBike.LockInfo.State,
|
||||
string.Format(AppResources.MarkingBikeInfoErrorStateUnknownDetected, selectedBluetoothLockBike.Description));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue