mirror of
https://dev.azure.com/TeilRad/sharee.bike%20App/_git/Code
synced 2025-06-21 21:46:27 +02:00
Version 3.0.370
This commit is contained in:
parent
f5cf9bb22f
commit
bdb2dec1c1
233 changed files with 10252 additions and 6779 deletions
|
@ -252,18 +252,18 @@ namespace TINK.ViewModel.Account
|
|||
return string.Empty;
|
||||
}
|
||||
|
||||
var bookingStateInfo = string.Format("Aktuell {0} Fahrräder reserviert/ gebucht.", m_iMyBikesCount.Value);
|
||||
var bookingStateInfo = string.Format(AppResources.MarkingAccountReservedBookedBikes, m_iMyBikesCount.Value);
|
||||
|
||||
if (!IsConnected)
|
||||
{
|
||||
// Append offline info
|
||||
return $"{bookingStateInfo} Verbindungsstatus: Offline.";
|
||||
return $"{bookingStateInfo} {AppResources.MarkingAccountConnectionOffline}";
|
||||
}
|
||||
|
||||
if (Exception != null)
|
||||
{
|
||||
// Append offline info
|
||||
return $"{bookingStateInfo} Verbindungstatus: Verbindung unterbrochen. ";
|
||||
return $"{bookingStateInfo} {AppResources.MarkingAccountConnectionInterrupted} ";
|
||||
}
|
||||
|
||||
return bookingStateInfo;
|
||||
|
@ -289,9 +289,9 @@ namespace TINK.ViewModel.Account
|
|||
else
|
||||
{
|
||||
await m_oViewService.DisplayAlert(
|
||||
"Hinweis",
|
||||
"Bitte mit Internet verbinden zum Verwalten der persönlichen Daten.",
|
||||
"OK");
|
||||
AppResources.MessageHintTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -306,10 +306,10 @@ namespace TINK.ViewModel.Account
|
|||
try
|
||||
{
|
||||
// Backup logout message before logout.
|
||||
var l_oMessage = string.Format("Benutzer {0} abgemeldet.", TinkApp.ActiveUser.Mail);
|
||||
var l_oMessage = string.Format(AppResources.MessageLogoutGoodbye, TinkApp.ActiveUser.Mail);
|
||||
|
||||
// Stop polling before requesting bike.
|
||||
await m_oViewUpdateManager.StopUpdatePeridically();
|
||||
await m_oViewUpdateManager.StopAsync();
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -320,12 +320,12 @@ namespace TINK.ViewModel.Account
|
|||
catch (UnsupportedCopriVersionDetectedException)
|
||||
{
|
||||
await m_oViewService.DisplayAlert(
|
||||
AppResources.MessageLogoutErrorTitle,
|
||||
AppResources.ErrorLogoutTitle,
|
||||
string.Format(AppResources.MessageAppVersionIsOutdated, TinkApp.Flavor.GetDisplayName()),
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
// Restart polling again.
|
||||
await m_oViewUpdateManager.StartUpdateAyncPeridically(Polling.ToImmutable());
|
||||
await m_oViewUpdateManager.StartAsync(Polling.ToImmutable());
|
||||
|
||||
IsIdle = true;
|
||||
StatusInfoText = string.Empty;
|
||||
|
@ -337,17 +337,20 @@ namespace TINK.ViewModel.Account
|
|||
if (l_oException is WebConnectFailureException)
|
||||
{
|
||||
await m_oViewService.DisplayAlert(
|
||||
"Verbingungsfehler bei Abmeldung!",
|
||||
string.Format("{0}\r\n{1}", l_oException.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
|
||||
"OK");
|
||||
AppResources.ErrorLogoutTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
await m_oViewService.DisplayAlert("Fehler bei Abmeldung!", l_oException.Message, "OK");
|
||||
await m_oViewService.DisplayAlert(
|
||||
AppResources.ErrorLogoutTitle,
|
||||
l_oException.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
// Restart polling again.
|
||||
await m_oViewUpdateManager.StartUpdateAyncPeridically(Polling.ToImmutable());
|
||||
await m_oViewUpdateManager.StartAsync(Polling.ToImmutable());
|
||||
|
||||
IsIdle = true;
|
||||
StatusInfoText = string.Empty;
|
||||
|
@ -356,8 +359,11 @@ namespace TINK.ViewModel.Account
|
|||
|
||||
TinkApp.ActiveUser.Logout();
|
||||
|
||||
// Display information that log out was perfomrmed.
|
||||
await m_oViewService.DisplayAlert("Auf Wiedersehen!", l_oMessage, "OK");
|
||||
// Display information that log out was performed.
|
||||
await m_oViewService.DisplayAlert(
|
||||
AppResources.MessageLogoutGoodbyeTitle,
|
||||
l_oMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
catch (Exception p_oException)
|
||||
{
|
||||
|
@ -428,7 +434,7 @@ namespace TINK.ViewModel.Account
|
|||
try
|
||||
{
|
||||
// Update bikes at station or my bikes depending on context.
|
||||
await m_oViewUpdateManager.StartUpdateAyncPeridically(Polling.ToImmutable());
|
||||
await m_oViewUpdateManager.StartAsync(Polling.ToImmutable());
|
||||
}
|
||||
catch (Exception l_oExcetion)
|
||||
{
|
||||
|
@ -445,15 +451,15 @@ namespace TINK.ViewModel.Account
|
|||
{
|
||||
Log.ForContext<AccountPageViewModel>().Information($"Entering {nameof(OnDisappearing)}...");
|
||||
|
||||
await m_oViewUpdateManager.StopUpdatePeridically();
|
||||
await m_oViewUpdateManager.StopAsync();
|
||||
|
||||
}
|
||||
catch (Exception l_oException)
|
||||
{
|
||||
await m_oViewService.DisplayAlert(
|
||||
"Fehler",
|
||||
$"Ein unerwarteter Fehler ist aufgetreten. \r\n{l_oException.Message}",
|
||||
"OK");
|
||||
AppResources.ErrorPageNotLoadedTitle,
|
||||
$"{AppResources.ErrorPageNotLoaded}\r\n{l_oException.Message}",
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace TINK.ViewModel.Bikes.Bike.BC.RequestHandler
|
|||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
|
||||
// Stop polling before requesting bike.
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
||||
|
@ -72,8 +72,8 @@ namespace TINK.ViewModel.Bikes.Bike.BC.RequestHandler
|
|||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
string.Format(AppResources.MessageReservationBikeErrorTooManyReservationsRentals, SelectedBike.Id, (exception as BookingDeclinedException).MaxBikesCount),
|
||||
AppResources.MessageHintTitle,
|
||||
string.Format(AppResources.ErrorReservingBikeTooManyReservationsRentals, SelectedBike.Id, (exception as BookingDeclinedException).MaxBikesCount),
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is WebConnectFailureException
|
||||
|
@ -84,8 +84,8 @@ namespace TINK.ViewModel.Bikes.Bike.BC.RequestHandler
|
|||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageReservingBikeErrorConnectionTitle,
|
||||
string.Format("{0}\r\n{1}", exception.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
|
||||
AppResources.ErrorNoConnectionTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
|
@ -93,7 +93,7 @@ namespace TINK.ViewModel.Bikes.Bike.BC.RequestHandler
|
|||
Log.ForContext<Disposable>().Error("User selected centered bike {l_oId} but reserving failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(AppResources.MessageReservingBikeErrorGeneralTitle, exception.Message, AppResources.MessageAnswerOk);
|
||||
await ViewService.DisplayAlert(AppResources.ErrorReservingBikeTitle, exception.Message, AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = string.Empty; // Todo: Remove this statement because in catch block ActionText is already set to empty above.
|
||||
|
@ -104,7 +104,7 @@ namespace TINK.ViewModel.Bikes.Bike.BC.RequestHandler
|
|||
finally
|
||||
{
|
||||
// Restart polling again.
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
|
||||
// Update status text and unlock list of bikes because no more action is pending.
|
||||
BikesViewModel.ActionText = string.Empty; // Todo: Move this statement in front of finally block because in catch block ActionText is already set to empty.
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace TINK.ViewModel.Bikes.Bike.BC.RequestHandler
|
|||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
|
||||
// Stop polling before cancel request.
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -80,7 +80,7 @@ namespace TINK.ViewModel.Bikes.Bike.BC.RequestHandler
|
|||
BikesViewModel.ActionText = String.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
"Verbingungsfehler beim Stornieren der Buchung!",
|
||||
string.Format("{0}\r\n{1}", exception.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
|
||||
AppResources.ErrorNoWeb,
|
||||
"OK");
|
||||
BikesViewModel.IsIdle = true;
|
||||
return this;
|
||||
|
@ -97,7 +97,7 @@ namespace TINK.ViewModel.Bikes.Bike.BC.RequestHandler
|
|||
finally
|
||||
{
|
||||
// Restart polling again.
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
|
||||
// Unlock list of bikes because no more action is pending.
|
||||
BikesViewModel.ActionText = string.Empty; // Todo: Move this statement in front of finally block because in catch block ActionText is already set to empty.
|
||||
|
|
|
@ -202,6 +202,8 @@ namespace TINK.ViewModel.Bikes.Bike
|
|||
|
||||
public string StationId => $"Station {Bike.StationId}";
|
||||
|
||||
public string DisplayName => Bike.GetDisplayName();
|
||||
|
||||
public bool IsBikeWithCopriLock => Bike.LockModel == Model.Bikes.BikeInfoNS.BikeNS.LockModel.Sigo;
|
||||
|
||||
/// Returns if type of bike is a cargo pedelec bike.
|
||||
|
|
|
@ -225,5 +225,6 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
|
|||
}
|
||||
|
||||
public string ErrorText => RequestHandler.ErrorText;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,334 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Serilog;
|
||||
using TINK.Model.Connector;
|
||||
using TINK.Model;
|
||||
using TINK.MultilingualResources;
|
||||
using TINK.Repository.Exception;
|
||||
using TINK.Repository.Request;
|
||||
using TINK.Services.Logging;
|
||||
using TINK.View;
|
||||
using static TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command.CloseCommand;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
|
||||
{
|
||||
/// <summary>
|
||||
/// View model for action close bluetooth lock.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
internal class CloseLockActionViewModel<T> : ICloseCommandListener, INotifyPropertyChanged
|
||||
{
|
||||
/// <summary> Notifies view about changes. </summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
/// <summary>
|
||||
/// View model to be used for progress report and unlocking/ locking view.
|
||||
/// </summary>
|
||||
private IBikesViewModel BikesViewModel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// View service to show modal notifications.
|
||||
/// </summary>
|
||||
private IViewService ViewService { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Service to control locks.
|
||||
/// </summary>
|
||||
private ILocksService LockService { get; }
|
||||
|
||||
/// <summary> Provides a connector object.</summary>
|
||||
protected Func<bool, IConnector> ConnectorFactory { get; }
|
||||
|
||||
/// <summary> Delegate to retrieve connected state. </summary>
|
||||
private Func<bool> IsConnectedDelegate { get; }
|
||||
|
||||
/// <summary>Gets the is connected state. </summary>
|
||||
bool IsConnected;
|
||||
|
||||
/// <summary>Object to start or stop update of view model objects from Copri.</summary>
|
||||
private Func<IPollingUpdateTaskManager> ViewUpdateManager { get; }
|
||||
|
||||
/// <summary> Bike close. </summary>
|
||||
private Model.Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable SelectedBike { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructs the object.
|
||||
/// </summary>
|
||||
/// <param name="selectedBike">Bike to close.</param>
|
||||
/// <param name="viewUpdateManager">Object to start or stop update of view model objects from Copri.</param>
|
||||
/// <param name="viewService">View service to show modal notifications.</param>
|
||||
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
public CloseLockActionViewModel(
|
||||
Model.Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable selectedBike,
|
||||
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||
IViewService viewService,
|
||||
IBikesViewModel bikesViewModel)
|
||||
{
|
||||
SelectedBike = selectedBike;
|
||||
ViewUpdateManager = viewUpdateManager;
|
||||
ViewService = viewService;
|
||||
BikesViewModel = bikesViewModel
|
||||
?? throw new ArgumentException($"Can not construct {GetType().Name}-object. {nameof(bikesViewModel)} must not be null.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes the close lock progress.
|
||||
/// </summary>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(Step step)
|
||||
{
|
||||
switch (step)
|
||||
{
|
||||
case Step.StartStopingPolling:
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
break;
|
||||
|
||||
case Step.StartingQueryingLocation:
|
||||
// 1a.Step: Start query geolocation data.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationStart;
|
||||
break;
|
||||
|
||||
case Step.ClosingLock:
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextClosingLock;
|
||||
break;
|
||||
|
||||
case Step.WaitStopPollingQueryLocation:
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocation;
|
||||
break;
|
||||
|
||||
case Step.QueryLocationTerminated:
|
||||
break;
|
||||
|
||||
case Step.UpdateLockingState:
|
||||
// 1b.Step: Sent info to backend
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdatingLockingState;
|
||||
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessCloseLockStepUpload;
|
||||
BikesViewModel.RentalProcess.ImportantStepInfoText = AppResources.MarkingRentalProcessCloseLockCheckLock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes the close lock state.
|
||||
/// </summary>
|
||||
/// <param name="state">State to process.</param>
|
||||
/// <param name="details">Textual details describing current state.</param>
|
||||
public async Task ReportStateAsync(State state, string details)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case State.OutOfReachError:
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorLockOutOfReach,
|
||||
AppResources.MessageAnswerOk);
|
||||
break;
|
||||
|
||||
case State.CouldntCloseMovingError:
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorLockMoving,
|
||||
AppResources.MessageAnswerOk);
|
||||
break;
|
||||
|
||||
case State.CouldntCloseBoltBlockedError:
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockBoltBlocked,
|
||||
AppResources.MessageAnswerOk);
|
||||
break;
|
||||
|
||||
case State.GeneralCloseError:
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
details,
|
||||
AppResources.MessageAnswerOk);
|
||||
break;
|
||||
|
||||
case State.WebConnectFailed:
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorNoWebUpdateingLockstate;
|
||||
break;
|
||||
|
||||
case State.ResponseIsInvalid:
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorStatusUpdateingLockstate;
|
||||
break;
|
||||
|
||||
case State.BackendUpdateFailed:
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorConnectionUpdateingLockstate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Close lock in order to pause ride and update COPRI lock state.</summary>
|
||||
public async Task CloseLockAsync()
|
||||
{
|
||||
Log.ForContext<T>().Information("User request to lock bike {bike}.", SelectedBike);
|
||||
|
||||
// lock GUI
|
||||
BikesViewModel.IsIdle = false;
|
||||
|
||||
// Stop Updater
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
var stopPollingTask = ViewUpdateManager().StopAsync();
|
||||
|
||||
// Clear logging memory sink to avoid passing log data not related to returning of bike to backend.
|
||||
// Log data is passed to backend when calling CopriCallsHttps.DoReturn().
|
||||
MemoryStackSink.ClearMessages();
|
||||
|
||||
// 1. Step
|
||||
// Parameter for RentalProcess View
|
||||
BikesViewModel.RentalProcess = new RentalProcess(SelectedBike.Id)
|
||||
{
|
||||
State = CurrentRentalProcess.CloseLock,
|
||||
StepIndex = 1,
|
||||
Result = CurrentStepStatus.None
|
||||
};
|
||||
|
||||
// Close Lock
|
||||
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessCloseLockStepCloseLock;
|
||||
BikesViewModel.RentalProcess.ImportantStepInfoText = AppResources.MarkingRentalProcessCloseLockObserve;
|
||||
|
||||
try
|
||||
{
|
||||
#if USELOCALINSTANCE
|
||||
var command = new CloseCommand(SelectedBike, GeolocationService, LockService, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager);
|
||||
await command.Invoke(this);
|
||||
#else
|
||||
await SelectedBike.CloseLockAsync(this, stopPollingTask);
|
||||
#endif
|
||||
Log.ForContext<T>().Information("User locked {bike} successfully.", SelectedBike);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartAsync();
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
|
||||
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
||||
return;
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||||
|
||||
// 2. Step
|
||||
BikesViewModel.RentalProcess.StepIndex = 2;
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.None;
|
||||
BikesViewModel.RentalProcess.ImportantStepInfoText = String.Empty;
|
||||
|
||||
//// Ask if lock is closed
|
||||
//var isLockClosed = await ViewService.DisplayAlert(
|
||||
// AppResources.QuestionRentalProcessCloseLockCheckLockTitle,
|
||||
// AppResources.QuestionRentalProcessCloseLockCheckLockText,
|
||||
// AppResources.QuestionRentalProcessCloseLockCheckLockAnswerYes,
|
||||
// AppResources.QuestionRentalProcessCloseLockCheckLockAnswerNo);
|
||||
|
||||
//// If lock is not closed
|
||||
//if(isLockClosed == false)
|
||||
//{
|
||||
// var retryOrContactresult = await ViewService.DisplayAlert(
|
||||
// AppResources.MessageRentalProcessCloseLockNotClosedTitle,
|
||||
// AppResources.MessageRentalProcessCloseLockNotClosedText,
|
||||
// AppResources.MessageAnswerRetry,
|
||||
// AppResources.MessageAnswerContactSupport);
|
||||
|
||||
// BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
|
||||
// if (retryOrContactresult == true)
|
||||
// {
|
||||
// //restart CloseLock()
|
||||
// }
|
||||
// else if(retryOrContactresult == false)
|
||||
// {
|
||||
// await OpenContactPageAsync();
|
||||
// }
|
||||
//}
|
||||
// If lock is closed
|
||||
//else if(isLockClosed == true)
|
||||
//{
|
||||
IsEndRentalRequested = await ViewService.DisplayAlert(
|
||||
AppResources.QuestionRentalProcessCloseLockEndOrContinueTitle,
|
||||
AppResources.QuestionRentalProcessCloseLockEndOrContinueText,
|
||||
AppResources.QuestionRentalProcessCloseLockEndRentalAnswer,
|
||||
AppResources.QuestionRentalProcessCloseLockContinueRentalAnswer);
|
||||
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||||
|
||||
// Continue with End rental in RequestHandler
|
||||
if (IsEndRentalRequested == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Park bike
|
||||
else if(IsEndRentalRequested == false)
|
||||
{
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageRentalProcessCloseLockFinishedTitle,
|
||||
AppResources.MessageRentalProcessCloseLockFinishedText,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
//}
|
||||
|
||||
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return;
|
||||
}
|
||||
|
||||
/// <summary> Opens support. </summary>
|
||||
//#if USEFLYOUT
|
||||
// public void OpenContactPageAsync()
|
||||
//#else
|
||||
// public async Task OpenContactPageAsync()
|
||||
//#endif
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// // Open Contact Page with Contact information for operator of SelectedBike
|
||||
//#if USEFLYOUT
|
||||
// ViewService.ShowPage(ViewTypes.ContactPage, AppResources.MarkingFeedbackAndContact);
|
||||
//#else
|
||||
// await ViewService.ShowPage("//ContactPage");
|
||||
//#endif
|
||||
// }
|
||||
// catch (Exception p_oException)
|
||||
// {
|
||||
// Log.Error("Ein unerwarteter Fehler ist auf der Seite Kontakt aufgetreten. Kontext: Klick auf Konakt aufnehmen bei Schloss schließen (Schloss nicht zu!). {@Exception}", p_oException);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// True if user requested End rental.
|
||||
/// </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,365 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using TINK.Model.Connector;
|
||||
using TINK.Model;
|
||||
using TINK.MultilingualResources;
|
||||
using TINK.Repository.Exception;
|
||||
using TINK.Repository.Request;
|
||||
using TINK.View;
|
||||
using static TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command.GetLockedLocationCommand;
|
||||
using Serilog;
|
||||
using TINK.Services.BluetoothLock;
|
||||
|
||||
namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
|
||||
{
|
||||
/// <summary>
|
||||
/// Return bike action.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of owner.</typeparam>
|
||||
public class EndRentalActionViewModel<T> : IGetLockedLocationCommandListener
|
||||
{
|
||||
/// <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>
|
||||
/// Service to control locks.
|
||||
/// </summary>
|
||||
private ILocksService LockService { get; }
|
||||
|
||||
/// <summary> Provides a connector object.</summary>
|
||||
protected Func<bool, IConnector> ConnectorFactory { get; }
|
||||
|
||||
/// <summary> Delegate to retrieve connected state. </summary>
|
||||
private Func<bool> IsConnectedDelegate { get; }
|
||||
|
||||
/// <summary>Gets the is connected state. </summary>
|
||||
bool IsConnected;
|
||||
|
||||
/// <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 EndRentalActionViewModel(
|
||||
Model.Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable selectedBike,
|
||||
Func<bool> isConnectedDelegate,
|
||||
Func<bool, IConnector> connectorFactory,
|
||||
ILocksService lockService,
|
||||
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||
IViewService viewService,
|
||||
IBikesViewModel bikesViewModel)
|
||||
{
|
||||
SelectedBike = selectedBike;
|
||||
IsConnectedDelegate = isConnectedDelegate;
|
||||
ConnectorFactory = connectorFactory;
|
||||
LockService = lockService
|
||||
?? throw new ArgumentException($"Can not construct {typeof(EndRentalActionViewModel<T>)}-object. Parameter {nameof(lockService)} must not be null.");
|
||||
ViewUpdateManager = viewUpdateManager;
|
||||
ViewService = viewService;
|
||||
BikesViewModel = bikesViewModel
|
||||
?? throw new ArgumentException($"Can not construct {typeof(EndRentalActionViewModel<T>)}-object. {nameof(bikesViewModel)} must not be null.");
|
||||
|
||||
// Set parameter for RentalProcess View to initial value.
|
||||
BikesViewModel.RentalProcess = new RentalProcess(SelectedBike.Id)
|
||||
{
|
||||
State = CurrentRentalProcess.None,
|
||||
StepIndex = 0,
|
||||
Result = CurrentStepStatus.None
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes the get lock location progress.
|
||||
/// </summary>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(Step step)
|
||||
{
|
||||
switch (step)
|
||||
{
|
||||
case Step.StartingQueryLocation:
|
||||
// 1.Step: Geolocation data
|
||||
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessEndRentalStepGPS;
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocation;
|
||||
break;
|
||||
|
||||
case Step.DisconnectingLockOnDisconnectedNoLocationError:
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextDisconnectingLock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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(State state, string details)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case State.DisconnetedNoLocationError:
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorEndRentalTitle,
|
||||
AppResources.ErrorEndRentalNotAtSuitableStation,
|
||||
AppResources.MessageAnswerOk);
|
||||
break;
|
||||
|
||||
case State.DisconnectError:
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorDisconnect;
|
||||
break;
|
||||
|
||||
case State.QueryLocationSucceeded:
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||||
break;
|
||||
|
||||
case State.QueryLocationFailed:
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorEndRentalTitle,
|
||||
AppResources.ErrorNoLocationPermission,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Return bike. </summary>
|
||||
public async Task EndRentalAsync()
|
||||
{
|
||||
Log.ForContext<T>().Information("User requests to return bike {bike}.", SelectedBike);
|
||||
|
||||
// lock GUI
|
||||
BikesViewModel.IsIdle = false;
|
||||
|
||||
// Stop Updater
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
// 1. Step
|
||||
// Parameter for RentalProcess View
|
||||
BikesViewModel.RentalProcess = new RentalProcess(SelectedBike.Id)
|
||||
{
|
||||
State = CurrentRentalProcess.EndRental,
|
||||
StepIndex = 1,
|
||||
Result = CurrentStepStatus.None
|
||||
};
|
||||
|
||||
// Get Location
|
||||
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessEndRentalStepGPS;
|
||||
BikesViewModel.RentalProcess.ImportantStepInfoText = AppResources.MarkingRentalProcessEndRentalWait;
|
||||
|
||||
LocationDto currentLocationDto = null;
|
||||
try
|
||||
{
|
||||
currentLocationDto = await SelectedBike.GetLockedBikeLocationAsync(this);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartAsync();
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
||||
return;
|
||||
}
|
||||
|
||||
// Send end of rental to backend
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
||||
BookingFinishedModel bookingFinished;
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
try
|
||||
{
|
||||
bookingFinished = await ConnectorFactory(IsConnected).Command.DoReturn(
|
||||
SelectedBike,
|
||||
currentLocationDto);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
if (exception is WebConnectFailureException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<T>().Information("User selected booked bike {bike} but returning failed (Copri server not reachable).", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorEndRentalTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is NotAtStationException notAtStationException)
|
||||
{
|
||||
// COPRI returned an error.
|
||||
Log.ForContext<T>().Information(
|
||||
"User selected booked bike {bike} but returning failed. COPRI returned out of GEO fencing error. Position send to COPRI {@position}.",
|
||||
SelectedBike,
|
||||
currentLocationDto);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorEndRentalTitle,
|
||||
string.Format(AppResources.ErrorEndRentalNotAtStation, notAtStationException.StationNr, notAtStationException.Distance),
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is NoGPSDataException)
|
||||
{
|
||||
// COPRI returned an error.
|
||||
Log.ForContext<T>().Information("User selected booked bike {bike} but returning failed. COPRI returned an no GPS- data error.", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorEndRentalTitle,
|
||||
string.Format(AppResources.ErrorEndRentalUnknownLocation),
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is ResponseException copriException)
|
||||
{
|
||||
// COPRI returned an error.
|
||||
Log.ForContext<T>().Information("User selected booked bike {bike} but returning failed. COPRI returned an error.", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorEndRentalTitle,
|
||||
copriException.Message,
|
||||
copriException.Response,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<T>().Error("User selected booked bike {bike} but returning failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorEndRentalTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
||||
return;
|
||||
}
|
||||
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||||
|
||||
// 2.Step: User feedback on bike condition
|
||||
|
||||
#if !USERFEEDBACKDLG_OFF
|
||||
|
||||
BikesViewModel.RentalProcess.StepIndex = 2;
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.None;
|
||||
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessEndRentalStepFeedback;
|
||||
BikesViewModel.RentalProcess.ImportantStepInfoText = String.Empty;
|
||||
|
||||
var feedBackUri = SelectedBike?.OperatorUri;
|
||||
var feedback = await ViewService.DisplayUserFeedbackPopup(SelectedBike.Drive?.Battery);
|
||||
#endif
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||||
|
||||
// 3.Step
|
||||
|
||||
// Send user feedback to backend
|
||||
BikesViewModel.RentalProcess.StepIndex = 3;
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.None;
|
||||
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessEndRentalStepUpload;
|
||||
BikesViewModel.RentalProcess.ImportantStepInfoText = AppResources.MarkingRentalProcessEndRentalWait;
|
||||
|
||||
IsConnected = IsConnectedDelegate();
|
||||
#if !USERFEEDBACKDLG_OFF
|
||||
try
|
||||
{
|
||||
await ConnectorFactory(IsConnected).Command.DoSubmitFeedback(
|
||||
new UserFeedbackDto
|
||||
{
|
||||
BikeId = SelectedBike.Id,
|
||||
CurrentChargeBars = feedback.CurrentChargeBars,
|
||||
IsBikeBroken = feedback.IsBikeBroken,
|
||||
Message = feedback.Message
|
||||
},
|
||||
feedBackUri);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
if (exception is ResponseException copriException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<T>().Information("Submitting feedback for bike {bike} failed. COPRI returned an error.", SelectedBike);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<T>().Error("Submitting feedback for bike {bike} failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
}
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorSubmitFeedbackTitle,
|
||||
AppResources.ErrorSubmitFeedback,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
#endif
|
||||
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||||
|
||||
// Disconnect lock.
|
||||
try
|
||||
{
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextDisconnectingLock;
|
||||
SelectedBike.LockInfo.State = await LockService.DisconnectAsync(SelectedBike.LockInfo.Id, SelectedBike.LockInfo.Guid);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<T>().Error("Lock can not be disconnected. {Exception}", exception);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorDisconnect;
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
// Confirmation message that rental is ended
|
||||
Log.ForContext<T>().Information("User returned bike {bike} successfully.", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
String.Format(AppResources.MessageRentalProcessEndRentalFinishedTitle, SelectedBike.Id),
|
||||
String.Format(
|
||||
"{0}{1}",
|
||||
!string.IsNullOrWhiteSpace(bookingFinished?.Co2Saving) ?
|
||||
$"{bookingFinished?.Co2Saving}\r\n\r\n"
|
||||
: string.Empty,
|
||||
String.Format(AppResources.MessageRentalProcessEndRentalFinishedText)
|
||||
),
|
||||
AppResources.MessageAnswerOk
|
||||
);
|
||||
|
||||
// Mini survey
|
||||
if (bookingFinished != null && bookingFinished.MiniSurvey.Questions.Count > 0)
|
||||
{
|
||||
await ViewService.PushModalAsync(ViewTypes.MiniSurvey);
|
||||
}
|
||||
|
||||
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
||||
BikesViewModel.IsIdle = true;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,8 +37,14 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
?? 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; }
|
||||
|
|
|
@ -1,24 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Serilog;
|
||||
using TINK.Model;
|
||||
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using TINK.Model.Connector;
|
||||
using TINK.Model.Device;
|
||||
using TINK.Model.User;
|
||||
using TINK.MultilingualResources;
|
||||
using TINK.Repository.Exception;
|
||||
using TINK.Repository.Request;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Services.BluetoothLock.Exception;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.View;
|
||||
using static TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command.GetLockedLocationCommand;
|
||||
using static TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandlerFactory;
|
||||
|
||||
namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
public class BookedClosed : Base, IRequestHandler
|
||||
public class BookedClosed : Base, IRequestHandler, IGetLockedLocationCommandListener
|
||||
{
|
||||
/// <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>
|
||||
|
@ -48,312 +46,54 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
{
|
||||
LockitButtonText = AppResources.ActionOpenAndPause;
|
||||
IsLockitButtonVisible = true; // Show button to enable opening lock in case user took a pause and does not want to return the bike.
|
||||
|
||||
_endRentalActionViewModel = new EndRentalActionViewModel<BookedClosed>(
|
||||
selectedBike,
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the view model for end rental action.
|
||||
/// </summary>
|
||||
private EndRentalActionViewModel<BookedClosed> _endRentalActionViewModel;
|
||||
|
||||
/// <summary> Return bike. </summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption1() => await ReturnBike();
|
||||
public async Task<IRequestHandler> HandleRequestOption1()
|
||||
{
|
||||
await _endRentalActionViewModel.EndRentalAsync();
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
|
||||
/// <summary> Open bike and update COPRI lock state. </summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption2() => await OpenLock();
|
||||
|
||||
/// <summary> Return bike. </summary>
|
||||
public async Task<IRequestHandler> ReturnBike()
|
||||
{
|
||||
BikesViewModel.IsIdle = false;
|
||||
var ctsLocation = new CancellationTokenSource();
|
||||
Task<IGeolocation> currentLocationTask = null;
|
||||
/// <summary>
|
||||
/// Processes the get lock location progress.
|
||||
/// </summary>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(Step step) => _endRentalActionViewModel.ReportStep(step);
|
||||
|
||||
// Try getting geolocation which was requested when closing lock.
|
||||
IGeolocation currentLocation = SelectedBike.LockInfo.Location;
|
||||
var lastConfimredLockStateTimeStamp = SelectedBike.LockInfo.LastLockingStateChange;
|
||||
|
||||
// Check if bike is around.
|
||||
var deviceState = LockService[SelectedBike.LockInfo.Id].GetDeviceState();
|
||||
|
||||
// Check if
|
||||
// - geolocation is already available
|
||||
// - or if bike is in reach so that geolocation makes sense
|
||||
if (currentLocation == null && deviceState != DeviceState.Connected)
|
||||
{
|
||||
// Geolocation information is missing and can not be queried.
|
||||
Log.ForContext<BookedClosed>().Information("User selected booked bike {bike} but returning failed. COPRI returned an error.", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnBikeTitle,
|
||||
AppResources.Error_ReturnBike_Station_Location_Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
// Disconnect lock.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextDisconnectingLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = await LockService.DisconnectAsync(SelectedBike.LockInfo.Id, SelectedBike.LockInfo.Guid);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<BookedClosed>().Error("Lock can not be disconnected. {Exception}", exception);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorDisconnect;
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
// Check if querying geolocation is required.
|
||||
if (currentLocation == null)
|
||||
{
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationStart;
|
||||
|
||||
// Start getting geolocation.
|
||||
try
|
||||
{
|
||||
currentLocationTask = GeolocationService.GetAsync(ctsLocation.Token, DateTime.Now);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedClosed>().Information("Getting geolocation when returning bike {Bike} failed. {Exception}", SelectedBike, ex);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnBikeTitle,
|
||||
AppResources.ErrorReturnBikeLockClosedStartGetGPSExceptionMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
// Ask whether to really return bike?
|
||||
var l_oResult = await ViewService.DisplayAlert(
|
||||
string.Empty,
|
||||
string.Format(AppResources.QuestionReturnBike, SelectedBike.GetFullDisplayName()),
|
||||
AppResources.MessageAnswerYes,
|
||||
AppResources.MessageAnswerNo);
|
||||
|
||||
if (l_oResult == false)
|
||||
{
|
||||
// User aborted returning bike process
|
||||
Log.ForContext<BookedClosed>().Information("User selected booked bike {l_oId} in order to return but action was canceled.", SelectedBike.Id);
|
||||
|
||||
// Cancel getting geolocation.
|
||||
ctsLocation.Cancel();
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedClosed>().Information("Canceling query location failed on abort returning closed bike failed. {Exception}", SelectedBike, ex);
|
||||
}
|
||||
|
||||
BikesViewModel.IsIdle = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
// Lock list to avoid multiple taps while copri action is pending.
|
||||
Log.ForContext<BookedClosed>().Information("Request to return bike {bike} detected.", SelectedBike);
|
||||
|
||||
// Stop polling before returning bike.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
|
||||
// Get geolocation if
|
||||
// - geolocation was not available when closing lock
|
||||
// - bike is around (lock is connected via bluetooth)
|
||||
LocationDto currentLocationDto = null;
|
||||
if (currentLocation == null)
|
||||
{
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocation;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
|
||||
currentLocation = currentLocationTask?.Result ?? null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedClosed>().Information("Returning closed bike {Bike} is not possible. Cancel geolocation query failed. {Exception}", SelectedBike, ex);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorQueryGeolocation,
|
||||
AppResources.ErrorReturnBikeLockClosedGetGPSExceptionMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
lastConfimredLockStateTimeStamp = DateTime.Now;
|
||||
}
|
||||
|
||||
currentLocationDto = currentLocation != null
|
||||
? new LocationDto.Builder
|
||||
{
|
||||
Latitude = currentLocation.Latitude,
|
||||
Longitude = currentLocation.Longitude,
|
||||
Accuracy = currentLocation.Accuracy ?? double.NaN,
|
||||
Age = lastConfimredLockStateTimeStamp is DateTime lastLockState ? lastLockState.Subtract(currentLocation.Timestamp.DateTime) : TimeSpan.MaxValue,
|
||||
}.Build()
|
||||
: null;
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextReturningBike;
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
||||
var feedBackUri = SelectedBike?.OperatorUri;
|
||||
BookingFinishedModel bookingFinished;
|
||||
try
|
||||
{
|
||||
bookingFinished = await ConnectorFactory(IsConnected).Command.DoReturn(
|
||||
SelectedBike,
|
||||
currentLocationDto);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
if (exception is WebConnectFailureException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedClosed>().Information("User selected booked bike {bike} but returning failed (Copri server not reachable).", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorReturnBikeNoWebTitle,
|
||||
string.Format("{0}\r\n{1}", AppResources.ErrorReturnBikeNoWebMessage, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is NotAtStationException notAtStationException)
|
||||
{
|
||||
// COPRI returned an error.
|
||||
Log.ForContext<BookedClosed>().Information(
|
||||
"User selected booked bike {bike} but returning failed. COPRI returned out of GEO fencing error. Position send to COPRI {@position}.",
|
||||
SelectedBike,
|
||||
currentLocationDto);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnBikeTitle,
|
||||
string.Format(AppResources.ErrorReturnBikeNotAtStationMessage, notAtStationException.StationNr, notAtStationException.Distance),
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is NoGPSDataException)
|
||||
{
|
||||
// COPRI returned an error.
|
||||
Log.ForContext<BookedClosed>().Information("User selected booked bike {bike} but returning failed. COPRI returned an no GPS- data error.", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnBikeTitle,
|
||||
string.Format(AppResources.ErrorReturnBikeLockClosedNoGPSMessage),
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is ResponseException copriException)
|
||||
{
|
||||
// COPRI returned an error.
|
||||
Log.ForContext<BookedClosed>().Information("User selected booked bike {bike} but returning failed. COPRI returned an error.", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
"Statusfehler beim Zurückgeben des Rads!",
|
||||
copriException.Message,
|
||||
copriException.Response,
|
||||
"OK");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedClosed>().Error("User selected booked bike {bike} but returning failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnBikeTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
Log.ForContext<BookedClosed>().Information("User returned bike {bike} successfully.", SelectedBike);
|
||||
|
||||
// Disconnect lock.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextDisconnectingLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = await LockService.DisconnectAsync(SelectedBike.LockInfo.Id, SelectedBike.LockInfo.Guid);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<BookedClosed>().Error("Lock can not be disconnected. {Exception}", exception);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorDisconnect;
|
||||
}
|
||||
|
||||
|
||||
#if !USERFEEDBACKDLG_OFF
|
||||
// Do get Feedback
|
||||
var feedback = await ViewService.DisplayUserFeedbackPopup(SelectedBike.Drive?.Battery, bookingFinished?.Co2Saving);
|
||||
IsConnected = IsConnectedDelegate();
|
||||
try
|
||||
{
|
||||
await ConnectorFactory(IsConnected).Command.DoSubmitFeedback(
|
||||
new UserFeedbackDto
|
||||
{
|
||||
BikeId = SelectedBike.Id,
|
||||
CurrentChargeBars = feedback.CurrentChargeBars,
|
||||
IsBikeBroken = feedback.IsBikeBroken,
|
||||
Message = feedback.Message
|
||||
},
|
||||
feedBackUri);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
if (exception is ResponseException copriException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedClosed>().Information("Submitting feedback for bike {bike} failed. COPRI returned an error.", SelectedBike);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedClosed>().Error("Submitting feedback for bike {bike} failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
}
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnSubmitFeedbackTitle,
|
||||
AppResources.ErrorReturnSubmitFeedbackMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
#endif
|
||||
if (bookingFinished != null && bookingFinished.MiniSurvey.Questions.Count > 0)
|
||||
{
|
||||
await ViewService.PushModalAsync(ViewTypes.MiniSurvey);
|
||||
}
|
||||
|
||||
// Restart polling again.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
/// <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(State state, string details) => await _endRentalActionViewModel.ReportStateAsync(state, details);
|
||||
|
||||
/// <summary> Open bike and update COPRI lock state. </summary>
|
||||
public async Task<IRequestHandler> OpenLock()
|
||||
|
@ -364,7 +104,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
// Stop polling before returning bike.
|
||||
BikesViewModel.IsIdle = false;
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOpeningLock;
|
||||
ILockService btLock;
|
||||
|
@ -383,7 +123,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockOutOfReachMessage,
|
||||
AppResources.ErrorLockOutOfReach,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldIsBlockedException)
|
||||
|
@ -392,7 +132,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockBoldIsBlockedMessage,
|
||||
AppResources.ErrorOpenLockBoldBlocked,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldStatusIsUnknownException)
|
||||
|
@ -400,9 +140,9 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<BookedClosed>().Debug("Lock can not be opened. Bold status is unknown. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockStillClosedTitle,
|
||||
AppResources.ErrorOpenLockBoldStatusIsUnknownMessage,
|
||||
"OK");
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockStatusUnknown,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenInconsistentStateExecption inconsistentState
|
||||
&& inconsistentState.State == LockingState.Closed)
|
||||
|
@ -411,17 +151,18 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockStillClosedMessage,
|
||||
"OK");
|
||||
AppResources.ErrorOpenLockStillClosed,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedClosed>().Error("Lock can not be opened. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
exception.Message,
|
||||
"OK");
|
||||
AppResources.ErrorTryAgain,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
// When bold is blocked lock is still closed even if exception occurs.
|
||||
|
@ -431,9 +172,10 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
: LockingState.UnknownDisconnected;
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
|
@ -501,9 +243,10 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
Log.ForContext<BookedClosed>().Information("User paused ride using {bike} successfully.", SelectedBike);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
// Stop polling before getting new auth-values.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQuerryServer;
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
@ -93,8 +93,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<BookedDisconnected>().Information("User selected booked bike {l_oId} to connect to lock. (Copri server not reachable).", SelectedBike.Id);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageConnectLockErrorTitle,
|
||||
$"{AppResources.ErrorConnectLockRentedBikeNoWebMessage}\r\n{exception.Message}\r\n{WebConnectFailureException.GetHintToPossibleExceptionsReasons}",
|
||||
AppResources.ErrorNoConnectionTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
|
@ -102,14 +102,14 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<BookedDisconnected>().Error("User selected booked bike {l_oId} to connect to lock. {@l_oException}", SelectedBike.Id, exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageConnectLockErrorTitle,
|
||||
$"{AppResources.ErrorConnectLockGeneralErrorMessage}\r\n{exception.Message}",
|
||||
AppResources.ErrorConnectLockTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
// Restart polling again.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return this;
|
||||
|
@ -137,8 +137,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
continueConnect = false;
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageConnectLockErrorTitle,
|
||||
AppResources.ErrorFindLockBluetoothNotOn,
|
||||
AppResources.ErrorConnectLockTitle,
|
||||
AppResources.ErrorLockBluetoothNotOn,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is ConnectLocationPermissionMissingException)
|
||||
|
@ -146,8 +146,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
continueConnect = false;
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageConnectLockErrorTitle,
|
||||
AppResources.ErrorFindLockLocationPermissionMissing,
|
||||
AppResources.ErrorConnectLockTitle,
|
||||
AppResources.ErrorNoLocationPermission,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is ConnectLocationOffException)
|
||||
|
@ -155,19 +155,18 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
continueConnect = false;
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageConnectLockErrorTitle,
|
||||
AppResources.ErrorFindLockLocationOff,
|
||||
AppResources.ErrorConnectLockTitle,
|
||||
AppResources.ErrorLockLocationOff,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is OutOfReachException)
|
||||
{
|
||||
Log.ForContext<BookedDisconnected>().Debug("Lock can not be found because out of reach. {Exception}", exception);
|
||||
continueConnect = false;
|
||||
|
||||
continueConnect = await ViewService.DisplayAlert(
|
||||
AppResources.MessageConnectLockErrorTitle,
|
||||
AppResources.ErrorFindLockRentedBikeOutOfReachMessage,
|
||||
AppResources.MessageAnswerRetry,
|
||||
AppResources.MessageAnswerCancel);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorConnectLockTitle,
|
||||
AppResources.ErrorLockOutOfReach,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -176,22 +175,22 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
string message;
|
||||
if (retryCount < 2)
|
||||
{
|
||||
message = AppResources.ErrorBookedSearchMessage;
|
||||
message = AppResources.ErrorConnectLock;
|
||||
}
|
||||
else if (retryCount < 3)
|
||||
{
|
||||
message = AppResources.ErrorBookedSearchMessageEscalationLevel1;
|
||||
message = AppResources.ErrorConnectLockEscalationLevel1;
|
||||
}
|
||||
else
|
||||
{
|
||||
message = AppResources.ErrorBookedSearchMessageEscalationLevel2;
|
||||
message = AppResources.ErrorConnectLockEscalationLevel2;
|
||||
}
|
||||
|
||||
|
||||
continueConnect = await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.MessageConnectLockErrorTitle,
|
||||
AppResources.ErrorConnectLockTitle,
|
||||
message,
|
||||
"", // bool IsReportLevelVerbose ? exception.Message : string.Empty, // or use ActiveUser.DebugLevel.HasFlag(Permissions.ReportLevel) instead?
|
||||
"",
|
||||
AppResources.MessageAnswerRetry,
|
||||
AppResources.MessageAnswerCancel);
|
||||
}
|
||||
|
@ -204,32 +203,32 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
// Quit and restart polling again.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
if (result?.State == null)
|
||||
if (!(result?.State is LockitLockingState lockingState))
|
||||
{
|
||||
Log.ForContext<BookedDisconnected>().Information("Lock for bike {bike} not found.", SelectedBike);
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageConnectLockErrorTitle,
|
||||
$"Schlossstatus des gemieteten Rads konnte nicht ermittelt werden.",
|
||||
AppResources.ErrorConnectLockTitle,
|
||||
AppResources.ErrorLockNoStatus,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
// Restart polling again.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
var state = result.State.Value.GetLockingState();
|
||||
var state = lockingState.GetLockingState();
|
||||
SelectedBike.LockInfo.State = state;
|
||||
SelectedBike.LockInfo.Guid = result?.Guid ?? new Guid();
|
||||
|
||||
|
@ -237,7 +236,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
// Restart polling again.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Serilog;
|
||||
using TINK.Model;
|
||||
|
@ -9,13 +7,11 @@ using TINK.Model.Connector;
|
|||
using TINK.Model.Device;
|
||||
using TINK.Model.User;
|
||||
using TINK.MultilingualResources;
|
||||
using TINK.Repository.Exception;
|
||||
using TINK.Repository.Request;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Services.BluetoothLock.Exception;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Services.Logging;
|
||||
using TINK.View;
|
||||
using static TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command.CloseCommand;
|
||||
using static TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandlerFactory;
|
||||
|
||||
namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
|
@ -34,8 +30,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
IBikesViewModel bikesViewModel,
|
||||
IUser activeUser) : base(
|
||||
selectedBike,
|
||||
AppResources.ActionCloseAndReturn, // Copri button text: "Schloss schließen & Miete beenden"
|
||||
true, // Show button to allow user to return bike.
|
||||
AppResources.ActionClose, // Copri button text: "Close lock"
|
||||
true, // Show button to allow user to close lock.
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
|
@ -46,634 +42,92 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
bikesViewModel,
|
||||
activeUser)
|
||||
{
|
||||
LockitButtonText = AppResources.ActionClose; // BT button text "Schließen".
|
||||
IsLockitButtonVisible = true; // Show button to allow user to lock bike.
|
||||
LockitButtonText = string.Empty;
|
||||
IsLockitButtonVisible = false;
|
||||
|
||||
_closeLockActionViewModel = new CloseLockActionViewModel<BookedOpen>(
|
||||
selectedBike,
|
||||
viewUpdateManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
}
|
||||
|
||||
/// <summary> Close lock and return bike.</summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption1() => await CloseLockAndReturnBike();
|
||||
/// <summary>
|
||||
/// Holds the view model for close action.
|
||||
/// </summary>
|
||||
private CloseLockActionViewModel<BookedOpen> _closeLockActionViewModel;
|
||||
|
||||
/// <summary> Close lock in order to pause ride and update COPRI lock state.</summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption2() => await CloseLock();
|
||||
|
||||
/// <summary> Close lock and return bike.</summary>
|
||||
public async Task<IRequestHandler> CloseLockAndReturnBike()
|
||||
/// <summary> Close lock (and return bike).</summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption1()
|
||||
{
|
||||
// Prevent concurrent interaction
|
||||
BikesViewModel.IsIdle = false;
|
||||
|
||||
// Start getting geolocation.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationStart;
|
||||
var ctsLocation = new CancellationTokenSource();
|
||||
Task<IGeolocation> currentLocationTask = null;
|
||||
var timeStamp = DateTime.Now;
|
||||
try
|
||||
await _closeLockActionViewModel.CloseLockAsync();
|
||||
if(_closeLockActionViewModel.IsEndRentalRequested == false)
|
||||
{
|
||||
currentLocationTask = GeolocationService.GetAsync(ctsLocation.Token, timeStamp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedOpen>().Information("Returning bike {Bike} is not possible. Start query location failed. {Exception}", SelectedBike, ex);
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageErrorQueryLocationStartTitle,
|
||||
$"{AppResources.MessageErrorQueryLocationMessage}\r\n{ex.Message}",
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
// Ask whether to really return bike?
|
||||
var result = await ViewService.DisplayAlert(
|
||||
string.Empty,
|
||||
string.Format(AppResources.QuestionCloseLockAndReturnBike, SelectedBike.GetFullDisplayName()),
|
||||
AppResources.MessageAnswerYes,
|
||||
AppResources.MessageAnswerNo);
|
||||
|
||||
if (result == false)
|
||||
{
|
||||
// User aborted closing and returning bike process
|
||||
Log.ForContext<BookedOpen>().Information("User selected booked bike {l_oId} in order to close and return but action was canceled.", SelectedBike.Id);
|
||||
|
||||
// Cancel getting geolocation.
|
||||
ctsLocation.Cancel();
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedOpen>().Information("Canceling query location failed on abort returning opened bike failed. {Exception}", SelectedBike, ex);
|
||||
}
|
||||
|
||||
BikesViewModel.IsIdle = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
// Start of closing lock and returning bike sequence.
|
||||
Log.ForContext<BookedOpen>().Information("Request to return bike {bike} detected.", SelectedBike);
|
||||
|
||||
// Clear logging memory sink to avoid passing log data not related to returning of bike to back-end.
|
||||
// Log data is passed to back end when calling CopriCallsHttps.DoReturn().
|
||||
MemoryStackSink.ClearMessages();
|
||||
|
||||
// Stop polling before returning bike.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
|
||||
// Notify COPRI about start returning bike sequence: "request=booking_update ... &lock_state=locking ..."
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartReturningBike;
|
||||
IsConnected = IsConnectedDelegate();
|
||||
try
|
||||
{
|
||||
await ConnectorFactory(IsConnected).Command.StartReturningBike(
|
||||
SelectedBike);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
if (exception is WebConnectFailureException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedOpen>().Information("User selected booked bike {bike} but returning failed (Copri server not reachable).", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorReturnBikeNoWebTitle,
|
||||
string.Format("{0}\r\n{1}", AppResources.ErrorReturnBikeNoWebMessage, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Error("User selected booked bike {bike} but returning failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnBikeTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
// Close lock
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextClosingLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())
|
||||
?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
// Signal cts to cancel getting geolocation.
|
||||
ctsLocation.Cancel();
|
||||
Task updateLockingStateTask = Task.CompletedTask;
|
||||
IsConnected = IsConnectedDelegate();
|
||||
try
|
||||
{
|
||||
updateLockingStateTask = ConnectorFactory(IsConnected).Command.UpdateLockingStateAsync(
|
||||
SelectedBike);
|
||||
}
|
||||
catch (Exception innerExceptionStartUpdateLockingState)
|
||||
{
|
||||
// No location information available/ updating state failed.
|
||||
Log.ForContext<BookedOpen>().Information("Start update locking state failed on lock operating error. {Exception}", SelectedBike, innerExceptionStartUpdateLockingState);
|
||||
}
|
||||
|
||||
if (exception is OutOfReachException)
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockOutOfReachMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntCloseMovingException)
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockMovingMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntCloseBoldBlockedException)
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockBoldBlockedMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Error("Lock can not be closed. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
// Wait until cancel getting geolocation has completed.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
try
|
||||
{
|
||||
await Task.WhenAll(new List<Task> { currentLocationTask ?? Task.CompletedTask, updateLockingStateTask });
|
||||
}
|
||||
catch (Exception innerExWhenAll)
|
||||
{
|
||||
// No location information available/ updating state failed.
|
||||
Log.ForContext<BookedOpen>().Information("Canceling query location/ updating lock state failed on closing lock error. {Exception}", SelectedBike, innerExWhenAll);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
// Check locking state.
|
||||
if (SelectedBike.LockInfo.State != LockingState.Closed)
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Error($"Lock can not be closed. Invalid locking state {SelectedBike.LockInfo.State} detected.");
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
|
||||
// Signal cts to cancel getting geolocation.
|
||||
ctsLocation.Cancel();
|
||||
|
||||
// Notify COPRI about closing failure: "request=booking_update ... &lock_state=unlocked ..."
|
||||
Task updateLockingStateTask = Task.CompletedTask;
|
||||
IsConnected = IsConnectedDelegate();
|
||||
try
|
||||
{
|
||||
updateLockingStateTask = ConnectorFactory(IsConnected).Command.UpdateLockingStateAsync(
|
||||
SelectedBike);
|
||||
}
|
||||
catch (Exception innerExceptionStartUpdateLockingState)
|
||||
{
|
||||
// No location information available/ updating state failed.
|
||||
Log.ForContext<BookedOpen>().Information("Start update locking state failed on unexpected state. {Exception}", SelectedBike, innerExceptionStartUpdateLockingState);
|
||||
}
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
SelectedBike.LockInfo.State == LockingState.Open
|
||||
? AppResources.ErrorCloseLockStillOpenMessage
|
||||
: string.Format(AppResources.ErrorCloseLockUnexpectedStateMessage, SelectedBike.LockInfo.State),
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
// Wait until cancel getting geolocation has completed.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
try
|
||||
{
|
||||
await Task.WhenAll(new List<Task> { currentLocationTask ?? Task.CompletedTask, updateLockingStateTask });
|
||||
}
|
||||
catch (Exception innerExWhenAll)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedOpen>().Information("Canceling query location/ updating lock state failed on unexpected lock state failed. {Exception}", SelectedBike, innerExWhenAll);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
// Get geolocation information.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocation;
|
||||
IGeolocation currentLocation = null;
|
||||
try
|
||||
{
|
||||
var task = await Task.WhenAny(new List<Task> { currentLocationTask });
|
||||
currentLocation = currentLocationTask.Result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedOpen>().Information("Returning bike {Bike} is not possible. Query location failed. {Exception}", SelectedBike, ex);
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.MessageErrorQueryLocationTitle,
|
||||
AppResources.MessageErrorQueryLocationMessage,
|
||||
ex.GetErrorMessage(),
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
// Notify COPRI about end of rental: "request=booking_update ... "&state=available" ... &lock_state=locked ..."
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextReturningBike;
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
||||
var feedBackUri = SelectedBike?.OperatorUri;
|
||||
LocationDto currentLocationDto = null;
|
||||
BookingFinishedModel bookingFinished;
|
||||
try
|
||||
{
|
||||
currentLocationDto = currentLocation != null
|
||||
? new LocationDto.Builder
|
||||
{
|
||||
Latitude = currentLocation.Latitude,
|
||||
Longitude = currentLocation.Longitude,
|
||||
Accuracy = currentLocation.Accuracy ?? double.NaN,
|
||||
Age = timeStamp.Subtract(currentLocation.Timestamp.DateTime),
|
||||
}.Build()
|
||||
: null;
|
||||
|
||||
bookingFinished = await ConnectorFactory(IsConnected).Command.DoReturn(
|
||||
return Create(
|
||||
SelectedBike,
|
||||
currentLocationDto,
|
||||
SmartDevice);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
if (exception is WebConnectFailureException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedOpen>().Information(
|
||||
"User selected booked bike {bike} but returning failed (Copri server not reachable).", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorReturnBikeNoWebTitle,
|
||||
string.Format("{0}\r\n{1}", AppResources.ErrorReturnBikeNoWebMessage, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is NotAtStationException notAtStationException)
|
||||
{
|
||||
// COPRI returned an error.
|
||||
Log.ForContext<BookedOpen>().Information(
|
||||
"User selected booked bike {bike} but returning failed. COPRI returned out of GEO fencing error. Position send to COPRI {@position}.",
|
||||
SelectedBike,
|
||||
currentLocationDto);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnBikeTitle,
|
||||
string.Format(AppResources.ErrorReturnBikeNotAtStationMessage, notAtStationException.StationNr, notAtStationException.Distance),
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is NoGPSDataException)
|
||||
{
|
||||
// COPRI returned an error.
|
||||
Log.ForContext<BookedOpen>().Information("User selected booked bike {bike} but returning failed. COPRI returned an no GPS- data error.", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnBikeTitle,
|
||||
string.Format(AppResources.ErrorReturnBikeLockOpenNoGPSMessage),
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is ResponseException copriException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedOpen>().Information("User selected booked bike {bike} but returning failed. COPRI returned an error.", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
"Statusfehler beim Zurückgeben des Rads!",
|
||||
copriException.Message,
|
||||
copriException.Response,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Error("User selected booked bike {bike} but returning failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnBikeTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
|
||||
Log.ForContext<BookedOpen>().Information("User returned bike {bike} successfully.", SelectedBike);
|
||||
var _endRentalActionViewModel = new EndRentalActionViewModel<BookedClosed>(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
ViewService,
|
||||
BikesViewModel);
|
||||
|
||||
// Disconnect lock.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextDisconnectingLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = await LockService.DisconnectAsync(SelectedBike.LockInfo.Id, SelectedBike.LockInfo.Guid);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Error("Lock can not be disconnected. {Exception}", exception);
|
||||
await _endRentalActionViewModel.EndRentalAsync();
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorDisconnect;
|
||||
}
|
||||
|
||||
#if !USERFEEDBACKDLG_OFF
|
||||
// Do get Feedback
|
||||
var feedback = await ViewService.DisplayUserFeedbackPopup(
|
||||
SelectedBike.Drive?.Battery,
|
||||
bookingFinished?.Co2Saving);
|
||||
IsConnected = IsConnectedDelegate();
|
||||
try
|
||||
{
|
||||
await ConnectorFactory(IsConnected).Command.DoSubmitFeedback(
|
||||
new UserFeedbackDto
|
||||
{
|
||||
BikeId = SelectedBike.Id,
|
||||
CurrentChargeBars = feedback.CurrentChargeBars,
|
||||
IsBikeBroken = feedback.IsBikeBroken,
|
||||
Message = feedback.Message
|
||||
},
|
||||
feedBackUri);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
if (exception is ResponseException copriException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedOpen>().Information("Submitting feedback for bike {bike} failed. COPRI returned an error.", SelectedBike);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Error("Submitting feedback for bike {bike} failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
}
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnSubmitFeedbackTitle,
|
||||
AppResources.ErrorReturnSubmitFeedbackMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bookingFinished != null && bookingFinished.MiniSurvey.Questions.Count > 0)
|
||||
{
|
||||
await ViewService.PushModalAsync(ViewTypes.MiniSurvey);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
return Create(
|
||||
SelectedBike,
|
||||
IsConnectedDelegate,
|
||||
ConnectorFactory,
|
||||
GeolocationService,
|
||||
LockService,
|
||||
ViewUpdateManager,
|
||||
SmartDevice,
|
||||
ViewService,
|
||||
BikesViewModel,
|
||||
ActiveUser);
|
||||
}
|
||||
|
||||
/// <summary> Close lock in order to pause ride and update COPRI lock state.</summary>
|
||||
public async Task<IRequestHandler> CloseLock()
|
||||
public Task<IRequestHandler> HandleRequestOption2() => throw new InvalidOperationException();
|
||||
|
||||
/// <summary> Request is not supported, button should be disabled. </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<IRequestHandler> UnsupportedRequest()
|
||||
{
|
||||
// Unlock bike.
|
||||
BikesViewModel.IsIdle = false;
|
||||
Log.ForContext<BookedOpen>().Information("User request to lock bike {bike} in order to pause ride.", SelectedBike);
|
||||
|
||||
// Clear logging memory sink to avoid passing log data not related to returning of bike to back end.
|
||||
// Log data is passed to back end when calling CopriCallsHttps.DoReturn().
|
||||
MemoryStackSink.ClearMessages();
|
||||
|
||||
// Start getting geolocation.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationStart;
|
||||
var ctsLocation = new CancellationTokenSource();
|
||||
Task<IGeolocation> currentLocationTask = null;
|
||||
var timeStamp = DateTime.Now;
|
||||
try
|
||||
{
|
||||
currentLocationTask = GeolocationService.GetAsync(ctsLocation.Token, timeStamp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedOpen>().Information("Closing lock of bike {Bike} is not possible. Starting query location failed. {Exception}", SelectedBike, ex);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorQueryLocationQuery;
|
||||
}
|
||||
|
||||
// Stop polling before returning bike.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
|
||||
// Close lock
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextClosingLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
// Signal cts to cancel getting geolocation.
|
||||
ctsLocation.Cancel();
|
||||
|
||||
if (exception is OutOfReachException)
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. {Exception}", exception);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockOutOfReachMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntCloseMovingException)
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockMovingMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntCloseBoldBlockedException)
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockBoldBlockedMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Error("Lock can not be closed. {Exception}", exception);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
// Update current state from exception
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
// Wait until cancel getting geolocation has completed.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedOpen>().Information("Canceling query location failed on closing lock error. {Exception}", SelectedBike, ex);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
// Get geolocation.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocation;
|
||||
IGeolocation currentLocation = null;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask });
|
||||
currentLocation = currentLocationTask.Result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedOpen>().Information("Getting geolocation when closing lock of bike {Bike} failed. {Exception}", SelectedBike, ex);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorQueryLocationWhenAny;
|
||||
}
|
||||
|
||||
// Keep geolocation where closing action occurred.
|
||||
SelectedBike.LockInfo.Location = currentLocation;
|
||||
|
||||
// Lock list to avoid multiple taps while copri action is pending.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdatingLockingState;
|
||||
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
||||
try
|
||||
{
|
||||
await ConnectorFactory(IsConnected).Command.UpdateLockingStateAsync(
|
||||
SelectedBike,
|
||||
currentLocation != null
|
||||
? new LocationDto.Builder
|
||||
{
|
||||
Latitude = currentLocation.Latitude,
|
||||
Longitude = currentLocation.Longitude,
|
||||
Accuracy = currentLocation.Accuracy ?? double.NaN,
|
||||
Age = timeStamp.Subtract(currentLocation.Timestamp.DateTime),
|
||||
}.Build()
|
||||
: null);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (exception is WebConnectFailureException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedOpen>().Information("User locked bike {bike} in order to pause ride but updating failed (Copri server not reachable).", SelectedBike);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorNoWebUpdateingLockstate;
|
||||
}
|
||||
else if (exception is ResponseException copriException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedOpen>().Information("User locked bike {bike} in order to pause ride but updating failed. Message: {Message} Details: {Details}", SelectedBike, copriException.Message, copriException.Response);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorStatusUpdateingLockstate;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Error("User locked bike {bike} in order to pause ride but updating failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorConnectionUpdateingLockstate;
|
||||
}
|
||||
}
|
||||
|
||||
Log.ForContext<BookedOpen>().Information("User paused ride using {bike} successfully.", SelectedBike);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
Log.ForContext<DisposableDisconnected>().Error("Click of unsupported button click detected.");
|
||||
return await Task.FromResult<IRequestHandler>(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes the close lock progress.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(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(State state, string details) => await _closeLockActionViewModel.ReportStateAsync(state, details);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ using TINK.Services.BluetoothLock;
|
|||
using TINK.Services.BluetoothLock.Exception;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.View;
|
||||
using static TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command.CloseCommand;
|
||||
using static TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandlerFactory;
|
||||
|
||||
namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
|
@ -47,14 +49,28 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
{
|
||||
LockitButtonText = AppResources.ActionClose; // BT button text "Schließen".;
|
||||
IsLockitButtonVisible = true; // Show button to enable opening lock in case user took a pause and does not want to return the bike.
|
||||
|
||||
_closeLockActionViewModel = new CloseLockActionViewModel<BookedOpen>(
|
||||
selectedBike,
|
||||
viewUpdateManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the view model for close action.
|
||||
/// </summary>
|
||||
private CloseLockActionViewModel<BookedOpen> _closeLockActionViewModel;
|
||||
|
||||
/// <summary> Open bike and update COPRI lock state. </summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption1() => await OpenLock();
|
||||
|
||||
/// <summary> Close lock in order to pause ride and update COPRI lock state.</summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption2() => await CloseLock();
|
||||
|
||||
public async Task<IRequestHandler> HandleRequestOption2()
|
||||
{
|
||||
await _closeLockActionViewModel.CloseLockAsync();
|
||||
return Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
/// <summary> Open bike and update COPRI lock state. </summary>
|
||||
public async Task<IRequestHandler> OpenLock()
|
||||
|
@ -65,7 +81,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
// Stop polling before returning bike.
|
||||
BikesViewModel.IsIdle = false;
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOpeningLock;
|
||||
ILockService btLock;
|
||||
|
@ -84,7 +100,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockOutOfReachMessage,
|
||||
AppResources.ErrorLockOutOfReach,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldIsBlockedException)
|
||||
|
@ -93,7 +109,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockBoldIsBlockedMessage,
|
||||
AppResources.ErrorOpenLockBoldBlocked,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldStatusIsUnknownException)
|
||||
|
@ -101,8 +117,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<BookedUnknown>().Debug("Lock can not be opened. Bold status is unknown. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockStillClosedTitle,
|
||||
AppResources.ErrorOpenLockBoldStatusIsUnknownMessage,
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockStatusUnknown,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenInconsistentStateExecption inconsistentState
|
||||
|
@ -112,16 +128,17 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockStillClosedMessage,
|
||||
AppResources.ErrorOpenLockStillClosed,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedUnknown>().Error("Lock can not be opened. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
exception.Message,
|
||||
AppResources.ErrorTryAgain,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
|
@ -132,7 +149,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
: LockingState.UnknownDisconnected;
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -202,178 +219,29 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
Log.ForContext<BookedUnknown>().Information("User paused ride using {bike} successfully.", SelectedBike);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
/// <summary> Close lock in order to pause ride and update COPRI lock state.</summary>
|
||||
public async Task<IRequestHandler> CloseLock()
|
||||
{
|
||||
// Unlock bike.
|
||||
BikesViewModel.IsIdle = false;
|
||||
/// <summary>
|
||||
/// Processes the close lock progress.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(Step step) => _closeLockActionViewModel?.ReportStep(step);
|
||||
|
||||
Log.ForContext<BookedUnknown>().Information("User request to lock bike {bike} in order to pause ride.", SelectedBike);
|
||||
|
||||
// Start getting geolocation.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationStart;
|
||||
var ctsLocation = new CancellationTokenSource();
|
||||
Task<IGeolocation> currentLocationTask = null;
|
||||
var timeStamp = DateTime.Now;
|
||||
try
|
||||
{
|
||||
currentLocationTask = GeolocationService.GetAsync(ctsLocation.Token, timeStamp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedUnknown>().Information("Returning bike {Bike} is not possible. Start query location failed. {Exception}", SelectedBike, ex);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorQueryLocationQuery;
|
||||
}
|
||||
|
||||
// Stop polling before returning bike.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
|
||||
// Close lock
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextClosingLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
// Signal cts to cancel getting geolocation.
|
||||
ctsLocation.Cancel();
|
||||
|
||||
if (exception is OutOfReachException)
|
||||
{
|
||||
Log.ForContext<BookedUnknown>().Debug("Lock can not be closed. {Exception}", exception);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockOutOfReachMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntCloseMovingException)
|
||||
{
|
||||
Log.ForContext<BookedUnknown>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockMovingMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntCloseBoldBlockedException)
|
||||
{
|
||||
Log.ForContext<BookedUnknown>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockBoldBlockedMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedUnknown>().Error("Lock can not be closed. {Exception}", exception);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
// Wait until cancel getting geolocation has completed.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedUnknown>().Information("Canceling query location failed on unexpected lock state failed. {Exception}", SelectedBike, ex);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
// Get geoposition.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocation;
|
||||
IGeolocation currentLocation = null;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
|
||||
currentLocation = currentLocationTask?.Result ?? null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedUnknown>().Information("Get geolocation failed when closing lock of bike {Bike} with unknown state. {Exception}", SelectedBike, ex);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorQueryLocationWhenAny;
|
||||
}
|
||||
|
||||
// Lock list to avoid multiple taps while copri action is pending.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdatingLockingState;
|
||||
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
||||
try
|
||||
{
|
||||
await ConnectorFactory(IsConnected).Command.UpdateLockingStateAsync(
|
||||
SelectedBike,
|
||||
currentLocation != null
|
||||
? new LocationDto.Builder
|
||||
{
|
||||
Latitude = currentLocation.Latitude,
|
||||
Longitude = currentLocation.Longitude,
|
||||
Accuracy = currentLocation.Accuracy ?? double.NaN,
|
||||
Age = timeStamp.Subtract(currentLocation.Timestamp.DateTime),
|
||||
}.Build()
|
||||
: null);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (exception is WebConnectFailureException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedUnknown>().Information("User locked bike {bike} in order to pause ride but updating failed (Copri server not reachable).", SelectedBike);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorNoWebUpdateingLockstate;
|
||||
}
|
||||
else if (exception is ResponseException copriException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedUnknown>().Information("User locked bike {bike} in order to pause ride but updating failed. Message: {Message} Details: {Details}", SelectedBike, copriException.Message, copriException.Response);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorStatusUpdateingLockstate;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedUnknown>().Error("User locked bike {bike} in order to pause ride but updating failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorConnectionUpdateingLockstate;
|
||||
}
|
||||
}
|
||||
|
||||
Log.ForContext<BookedUnknown>().Information("User paused ride using {bike} successfully.", SelectedBike);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
/// <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(State state, string details) => await _closeLockActionViewModel.ReportStateAsync(state, details);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
|
||||
// Stop polling before requesting bike.
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextReservingBike;
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
@ -101,8 +101,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<DisposableDisconnected>().Information("Request declined because maximum count of bikes {l_oException.MaxBikesCount} already requested/ booked.", (exception as BookingDeclinedException).MaxBikesCount);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
string.Format(AppResources.MessageReservationBikeErrorTooManyReservationsRentals, SelectedBike.Id, (exception as BookingDeclinedException).MaxBikesCount),
|
||||
AppResources.MessageHintTitle,
|
||||
string.Format(AppResources.ErrorReservingBikeTooManyReservationsRentals, SelectedBike.Id, (exception as BookingDeclinedException).MaxBikesCount),
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is WebConnectFailureException
|
||||
|
@ -112,23 +112,24 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<DisposableDisconnected>().Information("User selected centered bike {bike} but reserving failed (Copri server not reachable).", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageReservingBikeErrorConnectionTitle,
|
||||
string.Format("{0}\r\n{1}", exception.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
|
||||
AppResources.ErrorNoConnectionTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<DisposableDisconnected>().Error("User selected centered bike {bike} but reserving failed. {@l_oException}", SelectedBike, exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageReservingBikeErrorGeneralTitle,
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorReservingBikeTitle,
|
||||
exception.Message,
|
||||
AppResources.ErrorTryAgain,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
// Restart polling again.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return this;
|
||||
|
@ -160,7 +161,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
// Restart polling again.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -174,7 +175,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
// Restart polling again.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -212,7 +213,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
// Restart polling again.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -236,25 +237,23 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
// Copri server is not reachable.
|
||||
Log.ForContext<DisposableDisconnected>().Information("User selected recently requested bike {l_oId} but booking failed (Copri server not reachable).", SelectedBike.Id);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.MessageRentingBikeErrorConnectionTitle,
|
||||
WebConnectFailureException.GetHintToPossibleExceptionsReasons,
|
||||
l_oException.Message,
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorNoConnectionTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<DisposableDisconnected>().Error("User selected recently requested bike {l_oId} but reserving failed. {@l_oException}", SelectedBike.Id, l_oException);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.MessageRentingBikeErrorGeneralTitle,
|
||||
string.Empty,
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorRentingBikeTitle,
|
||||
l_oException.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -277,7 +276,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockOutOfReachMessage,
|
||||
AppResources.ErrorLockOutOfReach,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldIsBlockedException)
|
||||
|
@ -286,7 +285,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockBoldIsBlockedMessage,
|
||||
AppResources.ErrorOpenLockBoldBlocked,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldStatusIsUnknownException)
|
||||
|
@ -294,8 +293,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<DisposableDisconnected>().Debug("Lock can not be opened. Bold status is unknown. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockStillClosedTitle,
|
||||
AppResources.ErrorOpenLockBoldStatusIsUnknownMessage,
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockStatusUnknown,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenInconsistentStateExecption inconsistentState
|
||||
|
@ -305,7 +304,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockStillClosedMessage,
|
||||
AppResources.ErrorOpenLockStillClosed,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
|
@ -322,7 +321,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
: LockingState.UnknownDisconnected;
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
|
@ -333,7 +332,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
{
|
||||
// Opening lock failed.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
|
@ -404,7 +403,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
Log.ForContext<DisposableDisconnected>().Information("User reserved bike {bike} successfully.", SelectedBike);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
IBikesViewModel bikesViewModel,
|
||||
IUser activeUser) : base(
|
||||
selectedBike,
|
||||
AppResources.ActionBookOrClose,
|
||||
AppResources.ActionCloseOrBook,
|
||||
true, // Show copri button to enable reserving
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
|
@ -76,14 +76,14 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
// Stop polling before requesting bike.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
// Ask whether to really book bike or close lock?
|
||||
var l_oResult = await ViewService.DisplayAlert(
|
||||
string.Empty,
|
||||
$"Fahrrad {SelectedBike.GetFullDisplayName()} mieten oder Schloss schließen?",
|
||||
"Mieten",
|
||||
"Schloss schließen");
|
||||
String.Format(AppResources.QuestionCloseOrBook, SelectedBike.GetFullDisplayName()),
|
||||
AppResources.ActionBook,
|
||||
AppResources.ActionClose);
|
||||
|
||||
if (l_oResult == false)
|
||||
{
|
||||
|
@ -103,7 +103,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockOutOfReachMessage,
|
||||
AppResources.ErrorLockOutOfReach,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntCloseMovingException)
|
||||
|
@ -112,25 +112,26 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockMovingMessage,
|
||||
AppResources.ErrorLockMoving,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntCloseBoldBlockedException)
|
||||
else if (exception is CouldntCloseBoltBlockedException)
|
||||
{
|
||||
Log.ForContext<DisposableOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockBoldBlockedMessage,
|
||||
AppResources.ErrorCloseLockBoltBlocked,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<DisposableOpen>().Error("Lock can not be closed. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
exception.Message,
|
||||
AppResources.ErrorTryAgain,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
|
@ -139,7 +140,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
: LockingState.UnknownDisconnected;
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -159,7 +160,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -206,8 +207,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<DisposableOpen>().Information("User selected requested bike {l_oId} but reserving failed (Copri server not reachable).", SelectedBike.Id);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageRentingBikeErrorConnectionTitle,
|
||||
string.Format(AppResources.MessageErrorLockIsClosedThreeLines, l_oException.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
|
||||
AppResources.ErrorRentingBikeTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
|
@ -215,13 +216,13 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<DisposableOpen>().Error("User selected requested bike {l_oId} but reserving failed. {@l_oException}", SelectedBike.Id, l_oException);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageRentingBikeErrorGeneralTitle,
|
||||
string.Format(AppResources.MessageErrorLockIsClosedTwoLines, l_oException.Message),
|
||||
AppResources.ErrorRentingBikeTitle,
|
||||
string.Format(l_oException.Message, AppResources.ErrorTryAgain),
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
// If booking failed lock bike again because bike is only reserved.
|
||||
BikesViewModel.ActionText = "Verschließe Schloss...";
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextClosingLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
|
@ -250,7 +251,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
// Restart polling again.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
|
||||
// Update status text and unlock list of bikes because no more action is pending.
|
||||
BikesViewModel.ActionText = string.Empty; // Todo: Move this statement in front of finally block because in catch block BikesViewModel.ActionText is already set to empty.
|
||||
|
@ -262,7 +263,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
// Restart polling again.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
|
||||
// Update status text and unlock list of bikes because no more action is pending.
|
||||
BikesViewModel.ActionText = string.Empty; // Todo: Move this statement in front of finally block because in catch block BikesViewModel.ActionText is already set to empty.
|
||||
|
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Threading.Tasks;
|
||||
using Serilog;
|
||||
using TINK.Model.State;
|
||||
using TINK.MultilingualResources;
|
||||
using TINK.View;
|
||||
|
||||
namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
|
||||
|
@ -48,10 +49,10 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
|
|||
// User is not logged in
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
var l_oResult = await ViewService.DisplayAlert(
|
||||
"Hinweis",
|
||||
"Bitte anmelden vor Reservierung eines Fahrrads!\r\nAuf Anmeldeseite wechseln?",
|
||||
"Ja",
|
||||
"Nein");
|
||||
AppResources.QuestionLogInTitle,
|
||||
AppResources.QuestionLogIn,
|
||||
AppResources.MessageAnswerYes,
|
||||
AppResources.MessageAnswerNo);
|
||||
|
||||
if (l_oResult == false)
|
||||
{
|
||||
|
|
|
@ -68,8 +68,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
var l_oResult = await ViewService.DisplayAlert(
|
||||
string.Empty,
|
||||
string.Format(AppResources.QuestionCancelReservation, SelectedBike.GetFullDisplayName()),
|
||||
AppResources.QuestionAnswerYes,
|
||||
AppResources.QuestionAnswerNo);
|
||||
AppResources.MessageAnswerYes,
|
||||
AppResources.MessageAnswerNo);
|
||||
|
||||
if (l_oResult == false)
|
||||
{
|
||||
|
@ -83,7 +83,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
// Stop polling before cancel request.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextCancelingReservation;
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
@ -101,8 +101,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<BikesViewModel>().Error("User selected reserved bike {l_oId} but canceling reservation failed (Invalid auth. response).", SelectedBike.Id);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageCancelReservationBikeErrorGeneralTitle,
|
||||
exception.Message,
|
||||
AppResources.ErrorCancelReservationTitle,
|
||||
AppResources.ErrorAccountInvalidAuthorization,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is WebConnectFailureException
|
||||
|
@ -111,21 +111,22 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
// Copri server is not reachable.
|
||||
Log.ForContext<BikesViewModel>().Information("User selected reserved bike {l_oId} but cancel reservation failed (Copri server not reachable).", SelectedBike.Id);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageCancelReservationBikeErrorConnectionTitle,
|
||||
string.Format("{0}\r\n{1}", exception.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
|
||||
AppResources.ErrorCancelReservationTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BikesViewModel>().Error("User selected reserved bike {l_oId} but cancel reservation failed. {@l_oException}.", SelectedBike.Id, exception);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageCancelReservationBikeErrorGeneralTitle,
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorCancelReservationTitle,
|
||||
exception.Message,
|
||||
AppResources.ErrorTryAgain,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -147,7 +148,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -177,7 +178,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
// Stop polling before cancel request.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
// Book bike prior to opening lock.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextRentingBike;
|
||||
|
@ -195,10 +196,9 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
// Copri server is not reachable.
|
||||
Log.ForContext<ReservedClosed>().Information("User selected requested bike {l_oId} but booking failed (Copri server not reachable).", SelectedBike.Id);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.MessageRentingBikeErrorConnectionTitle,
|
||||
WebConnectFailureException.GetHintToPossibleExceptionsReasons,
|
||||
l_oException.Message,
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorRentingBikeTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
|
@ -206,14 +206,14 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<ReservedClosed>().Error("User selected requested bike {l_oId} but reserving failed. {@l_oException}", SelectedBike.Id, l_oException);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.MessageRentingBikeErrorGeneralTitle,
|
||||
string.Empty,
|
||||
AppResources.ErrorRentingBikeTitle,
|
||||
AppResources.ErrorTryAgain,
|
||||
l_oException.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -234,27 +234,30 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
{
|
||||
Log.ForContext<ReservedClosed>().Debug("Lock can not be opened. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockOutOfReachMessage,
|
||||
AppResources.ErrorLockOutOfReach,
|
||||
AppResources.ErrorOpenLockBikeAlreadyBooked,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldIsBlockedException)
|
||||
{
|
||||
Log.ForContext<ReservedClosed>().Debug("Lock can not be opened. Bold is blocked. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockBoldIsBlockedMessage,
|
||||
AppResources.ErrorOpenLockBoldBlocked,
|
||||
AppResources.ErrorOpenLockBikeAlreadyBooked,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldStatusIsUnknownException)
|
||||
{
|
||||
Log.ForContext<ReservedClosed>().Debug("Lock can not be opened. Bold status is unknown. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockStillClosedTitle,
|
||||
AppResources.ErrorOpenLockBoldStatusIsUnknownMessage,
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockStatusUnknown,
|
||||
AppResources.ErrorOpenLockBikeAlreadyBooked,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenInconsistentStateExecption inconsistentState
|
||||
|
@ -262,16 +265,18 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
{
|
||||
Log.ForContext<ReservedClosed>().Debug("Lock can not be opened. lock reports state closed. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockStillClosedMessage,
|
||||
AppResources.ErrorOpenLockStillClosed,
|
||||
AppResources.ErrorOpenLockBikeAlreadyBooked,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<ReservedClosed>().Error("Lock can not be opened. {Exception}", exception);
|
||||
await ViewService.DisplayAlert(
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorTryAgain,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
@ -281,7 +286,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
: LockingState.UnknownDisconnected;
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
|
@ -292,7 +297,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
{
|
||||
// Opening lock failed.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
|
@ -363,7 +368,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
Log.ForContext<ReservedClosed>().Information("User reserved bike {bike} successfully.", SelectedBike);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
IBikesViewModel bikesViewModel,
|
||||
IUser activeUser) : base(
|
||||
selectedBike,
|
||||
AppResources.ActionCancelRequest, // Copri button text: "Reservierung abbrechen"
|
||||
AppResources.ActionCancelRequest,
|
||||
true, // Show button to enable canceling reservation.
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
|
@ -45,7 +45,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
activeUser)
|
||||
{
|
||||
LockitButtonText = AppResources.ActionSearchLock;
|
||||
IsLockitButtonVisible = true; // Show "Öffnen" button to enable unlocking
|
||||
IsLockitButtonVisible = true; // Show button to search lock.
|
||||
}
|
||||
|
||||
/// <summary> Cancel reservation. </summary>
|
||||
|
@ -63,8 +63,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
var alertResult = await ViewService.DisplayAlert(
|
||||
string.Empty,
|
||||
string.Format(AppResources.QuestionCancelReservation, SelectedBike.GetFullDisplayName()),
|
||||
AppResources.QuestionAnswerYes,
|
||||
AppResources.QuestionAnswerNo);
|
||||
AppResources.MessageAnswerYes,
|
||||
AppResources.MessageAnswerNo);
|
||||
|
||||
if (alertResult == false)
|
||||
{
|
||||
|
@ -78,7 +78,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
// Stop polling before cancel request.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextCancelingReservation;
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
@ -94,8 +94,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
// Copri response is invalid.
|
||||
Log.ForContext<ReservedDisconnected>().Error("User selected reserved bike {l_oId} but canceling reservation failed (Invalid auth. response).", SelectedBike.Id);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageCancelReservationBikeErrorGeneralTitle,
|
||||
exception.Message,
|
||||
AppResources.ErrorCancelReservationTitle,
|
||||
AppResources.ErrorAccountInvalidAuthorization,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is WebConnectFailureException
|
||||
|
@ -104,21 +104,22 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
// Copri server is not reachable.
|
||||
Log.ForContext<ReservedDisconnected>().Information("User selected reserved bike {l_oId} but cancel reservation failed (Copri server not reachable).", SelectedBike.Id);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageCancelReservationBikeErrorConnectionTitle,
|
||||
string.Format("{0}\r\n{1}", exception.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
|
||||
AppResources.ErrorCancelReservationTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<ReservedDisconnected>().Error("User selected reserved bike {l_oId} but cancel reservation failed. {@l_oException}.", SelectedBike.Id, exception);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageCancelReservationBikeErrorGeneralTitle,
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorCancelReservationTitle,
|
||||
exception.Message,
|
||||
"OK");
|
||||
AppResources.ErrorTryAgain,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -127,7 +128,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<ReservedDisconnected>().Information("User canceled reservation of bike {l_oId} successfully.", SelectedBike.Id);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -142,7 +143,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
// Stop polling before getting new auth-values.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQuerryServer;
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
@ -162,23 +163,24 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<ReservedDisconnected>().Information("User selected requested bike {l_oId} to connect to lock. (Copri server not reachable).", SelectedBike.Id);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageErrorConnectTitle,
|
||||
$"{AppResources.ErrorConnectLockReservedBikeNoWebMessage}\r\n{exception.Message}\r\n{WebConnectFailureException.GetHintToPossibleExceptionsReasons}",
|
||||
AppResources.ErrorNoConnectionTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<ReservedDisconnected>().Error("User selected requested bike {l_oId} to scan for lock. {@l_oException}", SelectedBike.Id, exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageErrorConnectTitle,
|
||||
$"{AppResources.ErrorConnectLockGeneralErrorMessage}\r\n{exception.Message}",
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorConnectLockTitle,
|
||||
exception.Message,
|
||||
AppResources.ErrorConnectLock,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
// Restart polling again.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return this;
|
||||
|
@ -212,8 +214,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
continueConnect = false;
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageErrorConnectTitle,
|
||||
AppResources.ErrorFindLockBluetoothNotOn,
|
||||
AppResources.ErrorConnectLockTitle,
|
||||
AppResources.ErrorLockBluetoothNotOn,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is ConnectLocationPermissionMissingException)
|
||||
|
@ -221,8 +223,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
continueConnect = false;
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageConnectLockErrorTitle,
|
||||
AppResources.ErrorFindLockLocationPermissionMissing,
|
||||
AppResources.ErrorConnectLockTitle,
|
||||
AppResources.ErrorNoLocationPermission,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is ConnectLocationOffException)
|
||||
|
@ -230,19 +232,18 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
continueConnect = false;
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageConnectLockErrorTitle,
|
||||
AppResources.ErrorFindLockLocationOff,
|
||||
AppResources.ErrorConnectLockTitle,
|
||||
AppResources.ErrorLockLocationOff,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is OutOfReachException)
|
||||
{
|
||||
Log.ForContext<ReservedDisconnected>().Debug("Lock can not be found because out of reach.. {Exception}", exception);
|
||||
continueConnect = false;
|
||||
|
||||
continueConnect = await ViewService.DisplayAlert(
|
||||
AppResources.MessageErrorConnectTitle,
|
||||
AppResources.ErrorFindLockReservedBikeOutOfReachMessage,
|
||||
AppResources.MessageAnswerRetry,
|
||||
AppResources.MessageAnswerCancel);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorConnectLockTitle,
|
||||
AppResources.ErrorLockOutOfReach,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -251,18 +252,18 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
string message;
|
||||
if (retryCount < 2)
|
||||
{
|
||||
message = AppResources.ErrorReservedSearchMessage;
|
||||
message = AppResources.ErrorConnectLock;
|
||||
}
|
||||
else
|
||||
{
|
||||
message = AppResources.ErrorReservedSearchMessageEscalationLevel1;
|
||||
message = AppResources.ErrorConnectLockEscalationLevel1;
|
||||
}
|
||||
|
||||
Log.ForContext<ReservedDisconnected>().Error("Lock state can not be retrieved. {Exception}", exception);
|
||||
continueConnect = await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.MessageErrorConnectTitle,
|
||||
AppResources.ErrorConnectLockTitle,
|
||||
message,
|
||||
"", // bool IsReportLevelVerbose ? exception.Message : string.Empty, // or use ActiveUser.DebugLevel.HasFlag(Permissions.ReportLevel) instead?
|
||||
"", // Might show detailed info in future versions. Property used earlier: IsReportLevelVerbose. Maybe use ActiveUser.DebugLevel.HasFlag(Permissions.ReportLevel) instead.
|
||||
AppResources.MessageAnswerRetry,
|
||||
AppResources.MessageAnswerCancel);
|
||||
}
|
||||
|
@ -275,32 +276,31 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
// Restart polling again.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
if (result?.State == null)
|
||||
if (!(result?.State is LockitLockingState lockingState))
|
||||
{
|
||||
Log.ForContext<ReservedDisconnected>().Information("Lock for bike {bike} not found.", SelectedBike);
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageErrorConnectTitle,
|
||||
AppResources.ErrorFindLockReservedBikeNoStausMessage,
|
||||
AppResources.ErrorConnectLockTitle,
|
||||
AppResources.ErrorLockNoStatus,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
// Restart polling again.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
var state = result.State.Value.GetLockingState();
|
||||
SelectedBike.LockInfo.State = state;
|
||||
SelectedBike.LockInfo.State = lockingState.GetLockingState();
|
||||
SelectedBike.LockInfo.Guid = result?.Guid ?? new Guid();
|
||||
|
||||
Log.ForContext<ReservedDisconnected>().Information($"State for bike {SelectedBike.Id} updated successfully. Value is {SelectedBike.LockInfo.State}.");
|
||||
|
@ -334,7 +334,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
// Restart polling again.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -358,10 +358,9 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
// Copri server is not reachable.
|
||||
Log.ForContext<ReservedDisconnected>().Information("User selected recently requested bike {l_oId} but booking failed (Copri server not reachable).", SelectedBike.Id);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.MessageRentingBikeErrorConnectionTitle,
|
||||
WebConnectFailureException.GetHintToPossibleExceptionsReasons,
|
||||
l_oException.Message,
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorRentingBikeTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
|
@ -369,14 +368,14 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<ReservedDisconnected>().Error("User selected recently requested bike {l_oId} but reserving failed. {@l_oException}", SelectedBike.Id, l_oException);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.MessageRentingBikeErrorGeneralTitle,
|
||||
string.Empty,
|
||||
AppResources.ErrorRentingBikeTitle,
|
||||
l_oException.Message,
|
||||
AppResources.ErrorTryAgain,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -399,7 +398,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockOutOfReachMessage,
|
||||
AppResources.ErrorLockOutOfReach,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldIsBlockedException)
|
||||
|
@ -408,7 +407,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockBoldIsBlockedMessage,
|
||||
AppResources.ErrorOpenLockBoldBlocked,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldStatusIsUnknownException)
|
||||
|
@ -416,8 +415,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<ReservedDisconnected>().Debug("Lock can not be opened. Bold status is unknown. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockStillClosedTitle,
|
||||
AppResources.ErrorOpenLockBoldStatusIsUnknownMessage,
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockStatusUnknown,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenInconsistentStateExecption inconsistentState
|
||||
|
@ -427,15 +426,16 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockStillClosedMessage,
|
||||
AppResources.ErrorOpenLockStillClosed,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<ReservedDisconnected>().Error("Lock can not be opened. {Exception}", exception);
|
||||
await ViewService.DisplayAlert(
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
exception.Message,
|
||||
AppResources.ErrorTryAgain,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
|
@ -444,7 +444,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
: LockingState.UnknownDisconnected;
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
|
@ -455,7 +455,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
{
|
||||
// Opening lock failed.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
|
@ -528,7 +528,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
// Restart polling again.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
IBikesViewModel bikesViewModel,
|
||||
IUser activeUser) : base(
|
||||
selectedBike,
|
||||
"Rad zurückgeben oder mieten",
|
||||
AppResources.ActionCloseOrBook,
|
||||
true, // Show button to enable canceling reservation.
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
|
@ -67,13 +67,13 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
var l_oResult = await ViewService.DisplayAlert(
|
||||
string.Empty,
|
||||
string.Format("Rad {0} abschließen und zurückgeben oder Rad mieten?", SelectedBike.GetFullDisplayName()),
|
||||
"Zurückgeben",
|
||||
"Mieten");
|
||||
string.Format(AppResources.QuestionCloseOrBook, SelectedBike.GetFullDisplayName()),
|
||||
AppResources.ActionClose,
|
||||
AppResources.ActionBook);
|
||||
|
||||
// Stop polling before cancel request.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
if (l_oResult == false)
|
||||
{
|
||||
|
@ -118,22 +118,23 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<ReservedOpen>().Information("User selected requested bike {l_oId} but booking failed (Copri server not reachable).", SelectedBike.Id);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageRentingBikeErrorConnectionTitle,
|
||||
string.Format(AppResources.MessageErrorLockIsClosedThreeLines, l_oException.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
|
||||
AppResources.ErrorRentingBikeTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<ReservedOpen>().Error("User selected requested bike {l_oId} but reserving failed. {@l_oException}", SelectedBike.Id, l_oException);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageRentingBikeErrorGeneralTitle,
|
||||
string.Format(AppResources.MessageErrorLockIsClosedTwoLines, l_oException.Message),
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorRentingBikeTitle,
|
||||
l_oException.Message,
|
||||
AppResources.ErrorTryAgain,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
// If booking failed lock bike again because bike is only reserved.
|
||||
BikesViewModel.ActionText = "Wiederverschließe Schloss...";
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextClosingLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
|
@ -148,7 +149,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
|
@ -158,7 +159,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<ReservedOpen>().Information("User booked bike {bike} successfully.", SelectedBike);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
|
@ -181,8 +182,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockOutOfReachStateReservedMessage,
|
||||
"OK");
|
||||
AppResources.ErrorLockOutOfReach,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntCloseMovingException)
|
||||
{
|
||||
|
@ -190,17 +191,17 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockMovingMessage,
|
||||
"OK");
|
||||
AppResources.ErrorLockMoving,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntCloseBoldBlockedException)
|
||||
else if (exception is CouldntCloseBoltBlockedException)
|
||||
{
|
||||
Log.ForContext<ReservedOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockBoldBlockedMessage,
|
||||
"OK");
|
||||
AppResources.ErrorCloseLockBoltBlocked,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -208,8 +209,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
string.Format(AppResources.ErrorCloseLockUnkErrorMessage, exception.Message),
|
||||
"OK");
|
||||
string.Format(AppResources.ErrorCloseLock, exception.Message),
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
|
@ -217,7 +218,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
: LockingState.UnknownDisconnected;
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -238,8 +239,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
// Copri response is invalid.
|
||||
Log.ForContext<ReservedOpen>().Error("User selected reserved bike {l_oId} but canceling reservation failed (Invalid auth. response).", SelectedBike.Id);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageCancelReservationBikeErrorGeneralTitle,
|
||||
exception.Message,
|
||||
AppResources.ErrorCancelReservationTitle,
|
||||
AppResources.ErrorAccountInvalidAuthorization,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is WebConnectFailureException
|
||||
|
@ -248,21 +249,22 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
// Copri server is not reachable.
|
||||
Log.ForContext<ReservedOpen>().Information("User selected reserved bike {l_oId} but cancel reservation failed (Copri server not reachable).", SelectedBike.Id);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageCancelReservationBikeErrorConnectionTitle,
|
||||
string.Format("{0}\r\n{1}", exception.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
|
||||
AppResources.ErrorCancelReservationTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<ReservedOpen>().Error("User selected reserved bike {l_oId} but cancel reservation failed. {@l_oException}.", SelectedBike.Id, exception);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageCancelReservationBikeErrorGeneralTitle,
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorCancelReservationTitle,
|
||||
exception.Message,
|
||||
"OK");
|
||||
AppResources.ErrorTryAgain,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -284,7 +286,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -296,7 +298,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
{
|
||||
// Stop polling before requesting bike.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
// Close lock
|
||||
Log.ForContext<ReservedOpen>().Information("User selected disposable bike {bike} in order to manage sound/ alarm settings.", SelectedBike);
|
||||
|
@ -316,7 +318,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
"Fehler beim Abschalten der Sounds!",
|
||||
"Sounds können erst abgeschalten werden, wenn Rad in der Nähe ist.",
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -328,7 +330,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
"Fehler beim Abschalten der Sounds!",
|
||||
exception.Message,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -347,7 +349,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
"Fehler beim Setzen der Alarm-Einstellungen!",
|
||||
"Alarm kann erst eingestellt werden, wenn Rad in der Nähe ist.",
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -359,7 +361,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
"Fehler beim Setzen der Alarms-Einstellungen!",
|
||||
exception.Message,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
@ -378,7 +380,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
"Fehler beim Abschalten des Alarms!",
|
||||
"Alarm kann erst abgeschalten werden, wenn Rad in der Nähe ist.",
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -390,22 +392,22 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
"Fehler beim Abschalten des Alarms!",
|
||||
exception.Message,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
finally
|
||||
{
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
}
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
"Hinweis",
|
||||
AppResources.MessageHintTitle,
|
||||
"Alarm und Sounds erfolgreich abgeschalten.",
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -9,12 +9,13 @@ using TINK.Model.Device;
|
|||
using TINK.Model.User;
|
||||
using TINK.MultilingualResources;
|
||||
using TINK.Repository.Exception;
|
||||
using TINK.Repository.Request;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Services.BluetoothLock.Exception;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.View;
|
||||
using Xamarin.Essentials;
|
||||
using static TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command.CloseCommand;
|
||||
using static TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandlerFactory;
|
||||
|
||||
|
||||
namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
|
@ -48,6 +49,12 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
{
|
||||
LockitButtonText = AppResources.ActionClose; // BT button text "Schließen"
|
||||
IsLockitButtonVisible = true; // Show button to enable opening lock in case user took a pause and does not want to return the bike.
|
||||
|
||||
_closeLockActionViewModel = new CloseLockActionViewModel<BookedOpen>(
|
||||
selectedBike,
|
||||
viewUpdateManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
}
|
||||
|
||||
/// <summary> Open bike and update COPRI lock state. </summary>
|
||||
|
@ -62,7 +69,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
// Stop polling before returning bike.
|
||||
BikesViewModel.IsIdle = false;
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOpeningLock;
|
||||
ILockService btLock;
|
||||
|
@ -79,27 +86,30 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
{
|
||||
Log.ForContext<ReservedUnknown>().Debug("Lock can not be opened. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockOutOfReachMessage,
|
||||
AppResources.ErrorLockOutOfReach,
|
||||
AppResources.ErrorOpenLockBikeAlreadyBooked,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldIsBlockedException)
|
||||
{
|
||||
Log.ForContext<ReservedUnknown>().Debug("Lock can not be opened. bold is blocked. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockBoldIsBlockedMessage,
|
||||
AppResources.ErrorOpenLockBoldBlocked,
|
||||
AppResources.ErrorOpenLockBikeAlreadyBooked,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldStatusIsUnknownException)
|
||||
{
|
||||
Log.ForContext<ReservedUnknown>().Debug("Lock can not be opened. lock reports state unkwnown. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockStillClosedTitle,
|
||||
AppResources.ErrorOpenLockBoldStatusIsUnknownMessage,
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockStatusUnknown,
|
||||
AppResources.ErrorOpenLockBikeAlreadyBooked,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenInconsistentStateExecption inconsistentState
|
||||
|
@ -107,18 +117,20 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
{
|
||||
Log.ForContext<ReservedUnknown>().Debug("Lock can not be opened. lock reports state closed. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockStillClosedMessage,
|
||||
AppResources.ErrorOpenLockStillClosed,
|
||||
AppResources.ErrorOpenLockBikeAlreadyBooked,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<ReservedUnknown>().Error("Lock can not be opened. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
exception.Message,
|
||||
AppResources.ErrorTryAgain,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
|
@ -129,7 +141,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
: LockingState.UnknownDisconnected;
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -199,182 +211,43 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
Log.ForContext<ReservedUnknown>().Information("User paused ride using {bike} successfully.", SelectedBike);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
/// <summary> Close lock in order to pause ride and update COPRI lock state.</summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption2() => await CloseLock();
|
||||
/// <summary>
|
||||
/// Holds the view model for close action.
|
||||
/// </summary>
|
||||
private CloseLockActionViewModel<BookedOpen> _closeLockActionViewModel;
|
||||
|
||||
|
||||
/// <summary> Close lock in order to pause ride and update COPRI lock state.</summary>
|
||||
public async Task<IRequestHandler> CloseLock()
|
||||
/// <summary> Close lock (and return bike).</summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption2()
|
||||
{
|
||||
// Unlock bike.
|
||||
BikesViewModel.IsIdle = false;
|
||||
|
||||
Log.ForContext<ReservedUnknown>().Information("User request to lock bike {bike} in order to pause ride.", SelectedBike);
|
||||
|
||||
// Start getting geolocation.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationStart;
|
||||
var ctsLocation = new CancellationTokenSource();
|
||||
Task<IGeolocation> currentLocationTask = null;
|
||||
var timeStamp = DateTime.Now;
|
||||
try
|
||||
{
|
||||
currentLocationTask = GeolocationService.GetAsync(ctsLocation.Token, timeStamp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<ReservedUnknown>().Information("Returning bike {Bike} is not possible. Start query location failed. {Exception}", SelectedBike, ex);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorQueryLocationQuery;
|
||||
}
|
||||
|
||||
// Stop polling before returning bike.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
|
||||
// Close lock
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextClosingLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
// Signal cts to cancel getting geolocation.
|
||||
ctsLocation.Cancel();
|
||||
|
||||
if (exception is OutOfReachException)
|
||||
{
|
||||
Log.ForContext<ReservedUnknown>().Debug("Lock can not be closed. {Exception}", exception);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockOutOfReachMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntCloseMovingException)
|
||||
{
|
||||
Log.ForContext<ReservedUnknown>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockMovingMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntCloseBoldBlockedException)
|
||||
{
|
||||
Log.ForContext<ReservedUnknown>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockBoldBlockedMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<ReservedUnknown>().Error("Lock can not be closed. {Exception}", exception);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
// Wait until cancel getting geolocation has completed.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<ReservedUnknown>().Information("Canceling query location failed on closing lock error. {Exception}", SelectedBike, ex);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
// Get geolocation.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocation;
|
||||
IGeolocation currentLocation = null;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
|
||||
currentLocation = currentLocationTask?.Result ?? null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<ReservedUnknown>().Information("Returning bike {Bike} is not possible. {Exception}", SelectedBike, ex);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorQueryLocationWhenAny;
|
||||
}
|
||||
|
||||
// Lock list to avoid multiple taps while copri action is pending.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdatingLockingState;
|
||||
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
||||
try
|
||||
{
|
||||
await ConnectorFactory(IsConnected).Command.UpdateLockingStateAsync(
|
||||
SelectedBike,
|
||||
currentLocation != null
|
||||
? new LocationDto.Builder
|
||||
{
|
||||
Latitude = currentLocation.Latitude,
|
||||
Longitude = currentLocation.Longitude,
|
||||
Accuracy = currentLocation.Accuracy ?? double.NaN,
|
||||
Age = timeStamp.Subtract(currentLocation.Timestamp.DateTime),
|
||||
}.Build()
|
||||
: null);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (exception is WebConnectFailureException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<ReservedUnknown>().Information("User locked bike {bike} in order to pause ride but updating failed (Copri server not reachable).", SelectedBike);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorNoWebUpdateingLockstate;
|
||||
}
|
||||
else if (exception is ResponseException copriException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<ReservedUnknown>().Information("User locked bike {bike} in order to pause ride but updating failed. Message: {Message} Details: {Details}", SelectedBike, copriException.Message, copriException.Response);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorStatusUpdateingLockstate;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<ReservedUnknown>().Error("User locked bike {bike} in order to pause ride but updating failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorConnectionUpdateingLockstate;
|
||||
}
|
||||
}
|
||||
|
||||
Log.ForContext<ReservedUnknown>().Information("User paused ride using {bike} successfully.", SelectedBike);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
await _closeLockActionViewModel.CloseLockAsync();
|
||||
return Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Processes the close lock progress.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only used for testing.
|
||||
/// </remarks>
|
||||
/// <param name="step">Current step to process.</param>
|
||||
public void ReportStep(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(State state, string details) => await _closeLockActionViewModel.ReportStateAsync(state, details);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
|
|||
/// <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,
|
||||
|
@ -171,7 +172,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
|
|||
switch (selectedBluetoothLockBike.LockInfo.State)
|
||||
{
|
||||
case LockingState.Closed:
|
||||
// Ride was paused.
|
||||
// User wants to close lock.
|
||||
return new BookedClosed(
|
||||
selectedBluetoothLockBike,
|
||||
isConnectedDelegate,
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
// Stop polling before returning bike.
|
||||
BikesViewModel.IsIdle = false;
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOpeningLock;
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
@ -80,10 +80,9 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedClosed>().Information("User selected bike {id} but opening lock failed (Copri server not reachable).", SelectedBike.Id);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.MessageOpeningLockErrorConnectionTitle,
|
||||
WebConnectFailureException.GetHintToPossibleExceptionsReasons,
|
||||
exception.Message,
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorNoConnectionTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
|
@ -97,7 +96,7 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -105,7 +104,7 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
|
||||
Log.ForContext<BookedClosed>().Information("User paused ride using {bike} successfully.", SelectedBike);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
|
|
@ -64,7 +64,7 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
// Stop polling before returning bike.
|
||||
BikesViewModel.IsIdle = false;
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOpeningLock;
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
@ -81,10 +81,9 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedOpen>().Information("User selected bike {id} but opening lock failed (Copri server not reachable).", SelectedBike.Id);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.MessageOpeningLockErrorConnectionTitle,
|
||||
WebConnectFailureException.GetHintToPossibleExceptionsReasons,
|
||||
exception.Message,
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorNoConnectionTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
|
@ -98,7 +97,7 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -106,7 +105,7 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
|
||||
Log.ForContext<BookedOpen>().Information("User paused ride using {bike} successfully.", SelectedBike);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
|
|
@ -74,7 +74,7 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
|
||||
// Stop polling before returning bike.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
// Book bike prior to opening lock.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextRentingBike;
|
||||
|
@ -92,10 +92,9 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
// Copri server is not reachable.
|
||||
Log.ForContext<DisposableClosed>().Information("User selected bike {id} but booking failed (Copri server not reachable).", SelectedBike.Id);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.MessageRentingBikeErrorConnectionTitle,
|
||||
WebConnectFailureException.GetHintToPossibleExceptionsReasons,
|
||||
exception.Message,
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorNoConnectionTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
|
@ -103,13 +102,13 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
Log.ForContext<DisposableClosed>().Error("User selected bike {id} but booking failed. {@exception}", SelectedBike.Id, exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageRentingBikeErrorGeneralTitle,
|
||||
AppResources.ErrorRentingBikeTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
|
||||
|
@ -118,7 +117,7 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
|
||||
Log.ForContext<DisposableClosed>().Information("User booked and released bike {bike} successfully.", SelectedBike);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -151,7 +150,7 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
|
||||
// Stop polling before requesting bike.
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextReservingBike;
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
@ -170,8 +169,8 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
Log.ForContext<DisposableClosed>().Information("Request declined because maximum count of bikes {l_oException.MaxBikesCount} already requested/ booked.", (exception as BookingDeclinedException).MaxBikesCount);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
string.Format(AppResources.MessageReservationBikeErrorTooManyReservationsRentals, SelectedBike.GetFullDisplayName(), (exception as BookingDeclinedException).MaxBikesCount),
|
||||
AppResources.MessageHintTitle,
|
||||
string.Format(AppResources.ErrorReservingBikeTooManyReservationsRentals, SelectedBike.GetFullDisplayName(), (exception as BookingDeclinedException).MaxBikesCount),
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is WebConnectFailureException
|
||||
|
@ -180,10 +179,9 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
// Copri server is not reachable.
|
||||
Log.ForContext<DisposableClosed>().Information("User selected centered bike {bike} but reserving failed (Copri server not reachable).", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.MessageReservingBikeErrorConnectionTitle,
|
||||
WebConnectFailureException.GetHintToPossibleExceptionsReasons,
|
||||
exception.Message,
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorNoConnectionTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
|
@ -191,14 +189,14 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
Log.ForContext<DisposableClosed>().Error("User selected centered bike {bike} but reserving failed. {@exception}", SelectedBike, exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageReservingBikeErrorGeneralTitle,
|
||||
AppResources.ErrorReservingBikeTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
// Restart polling again.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return this;
|
||||
|
@ -206,7 +204,7 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
|
||||
Log.ForContext<DisposableClosed>().Information("User reserved bike {bike} successfully.", SelectedBike);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
{
|
||||
BikesViewModel.IsIdle = false;
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
// Do get Feedback
|
||||
var feedback = await ViewService.DisplayUserFeedbackPopup(SelectedBike.Drive?.Battery, SelectedBike?.BookingFinishedModel?.Co2Saving);
|
||||
|
@ -93,12 +93,12 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
}
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnSubmitFeedbackTitle,
|
||||
AppResources.ErrorReturnSubmitFeedbackMessage,
|
||||
AppResources.ErrorSubmitFeedbackTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -115,7 +115,7 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
await ViewUpdateManager().StartAsync();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
|
|
@ -62,8 +62,8 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
var result = await ViewService.DisplayAlert(
|
||||
string.Empty,
|
||||
string.Format(AppResources.QuestionCancelReservation, SelectedBike.GetFullDisplayName()),
|
||||
AppResources.QuestionAnswerYes,
|
||||
AppResources.QuestionAnswerNo);
|
||||
AppResources.MessageAnswerYes,
|
||||
AppResources.MessageAnswerNo);
|
||||
|
||||
if (result == false)
|
||||
{
|
||||
|
@ -77,7 +77,7 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
|
||||
// Stop polling before cancel request.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextCancelingReservation;
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
@ -95,7 +95,7 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
Log.ForContext<BikesViewModel>().Error("User selected reserved bike {Id} but canceling reservation failed (Invalid auth. response).", SelectedBike.Id);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageCancelReservationBikeErrorGeneralTitle,
|
||||
AppResources.ErrorCancelReservationTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
@ -104,23 +104,22 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BikesViewModel>().Information("User selected reserved bike {Id} but cancel reservation failed (Copri server not reachable).", SelectedBike.Id);
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.MessageCancelReservationBikeErrorConnectionTitle,
|
||||
WebConnectFailureException.GetHintToPossibleExceptionsReasons,
|
||||
exception.Message,
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCancelReservationTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BikesViewModel>().Error("User selected reserved bike {Id} but cancel reservation failed. {@Exception}.", SelectedBike.Id, exception);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageCancelReservationBikeErrorGeneralTitle,
|
||||
AppResources.ErrorCancelReservationTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -129,7 +128,7 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
Log.ForContext<BikesViewModel>().Information("User canceled reservation of bike {Id} successfully.", SelectedBike.Id);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -159,7 +158,7 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
|
||||
// Stop polling before cancel request.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
await ViewUpdateManager().StopAsync();
|
||||
|
||||
// Book bike prior to opening lock.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextRentingBike;
|
||||
|
@ -177,10 +176,9 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
// Copri server is not reachable.
|
||||
Log.ForContext<ReservedClosed>().Information("User selected requested bike {Id} but booking failed (Copri server not reachable).", SelectedBike.Id);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.MessageRentingBikeErrorConnectionTitle,
|
||||
WebConnectFailureException.GetHintToPossibleExceptionsReasons,
|
||||
exception.Message,
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorNoConnectionTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
|
@ -188,14 +186,14 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
Log.ForContext<ReservedClosed>().Error("User selected requested bike {Id} but reserving failed. {@Exception}", SelectedBike.Id, exception);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.MessageRentingBikeErrorGeneralTitle,
|
||||
AppResources.ErrorRentingBikeTitle,
|
||||
exception.Message,
|
||||
string.Empty,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
@ -203,7 +201,7 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
|||
|
||||
Log.ForContext<ReservedClosed>().Information("User booked and opened bike {bike} successfully.", SelectedBike.Id);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
await ViewUpdateManager().StartAsync(); // Restart polling again.
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Plugin.BLE.Abstractions.Contracts;
|
||||
|
@ -150,7 +151,12 @@ namespace TINK.ViewModel.Bikes
|
|||
|
||||
m_oViewUpdateManager = new IdlePollingUpdateTaskManager();
|
||||
|
||||
BikeCollection = new BikeCollectionMutable();
|
||||
BikeCollection = new BikeCollectionMutable(
|
||||
geolocation,
|
||||
lockService,
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
() => m_oViewUpdateManager);
|
||||
|
||||
BikeCollection.CollectionChanged += OnDecoratedCollectionChanged;
|
||||
|
||||
|
@ -337,6 +343,63 @@ namespace TINK.ViewModel.Bikes
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary> Used to display active rental process.</summary>
|
||||
private IRentalProcess _rentalProcess = new RentalProcess();
|
||||
|
||||
/// <summary> Holds the active rental process.</summary>
|
||||
public IRentalProcess RentalProcess
|
||||
{
|
||||
get => _rentalProcess;
|
||||
set
|
||||
{
|
||||
if (value == _rentalProcess)
|
||||
return;
|
||||
|
||||
_rentalProcess = value;
|
||||
|
||||
BikeInRentalProcess = this.FirstOrDefault(bike => bike.Id == _rentalProcess.BikeId) as Bike.BluetoothLock.BikeViewModel;
|
||||
|
||||
base.OnPropertyChanged(new PropertyChangedEventArgs(nameof(RentalProcess)));
|
||||
base.OnPropertyChanged(new PropertyChangedEventArgs(nameof(BikeInRentalProcess)));
|
||||
}
|
||||
}
|
||||
|
||||
public Bike.BluetoothLock.BikeViewModel BikeInRentalProcess { get; private set; }
|
||||
|
||||
/// <summary> Used to display current step in rental process.</summary>
|
||||
private int? currentStep = null;
|
||||
|
||||
/// <summary> Holds the number of current step in rental process.</summary>
|
||||
public int? CurrentStep
|
||||
{
|
||||
get => currentStep;
|
||||
set
|
||||
{
|
||||
if (value == CurrentStep)
|
||||
return;
|
||||
|
||||
currentStep = value;
|
||||
base.OnPropertyChanged(new PropertyChangedEventArgs(nameof(CurrentStep)));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Used to display status of current step in rental process.</summary>
|
||||
private CurrentStepStatus currentStepStatus = CurrentStepStatus.None;
|
||||
|
||||
/// <summary> Holds the status of current step in rental process.e</summary>
|
||||
public virtual CurrentStepStatus CurrentStepStatus
|
||||
{
|
||||
get => currentStepStatus;
|
||||
set
|
||||
{
|
||||
if (value == CurrentStepStatus)
|
||||
return;
|
||||
|
||||
currentStepStatus = value;
|
||||
base.OnPropertyChanged(new PropertyChangedEventArgs(nameof(CurrentStepStatus)));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsProcessWithRunningProcessView => !isIdle;
|
||||
|
||||
/// <summary> Holds info about current action. </summary>
|
||||
|
@ -389,16 +452,11 @@ namespace TINK.ViewModel.Bikes
|
|||
{
|
||||
get
|
||||
{
|
||||
if (Exception != null)
|
||||
{
|
||||
// An error occurred getting data from copri.
|
||||
return Exception.GetShortErrorInfoText(IsReportLevelVerbose);
|
||||
}
|
||||
|
||||
if (!IsConnected)
|
||||
{
|
||||
return AppResources.ActivityTextConnectionStateOffline;
|
||||
}
|
||||
//if (Exception != null)
|
||||
//{
|
||||
// // An error occurred getting data from copri.
|
||||
// return Exception.GetShortErrorInfoText(IsReportLevelVerbose);
|
||||
//}
|
||||
|
||||
return ActionText ?? string.Empty;
|
||||
}
|
||||
|
@ -471,7 +529,7 @@ namespace TINK.ViewModel.Bikes
|
|||
try
|
||||
{
|
||||
// Update bikes at station or my bikes depending on context.
|
||||
await m_oViewUpdateManager.StartUpdateAyncPeridically(m_oPolling);
|
||||
await m_oViewUpdateManager.StartAsync(m_oPolling);
|
||||
}
|
||||
catch (Exception l_oExcetion)
|
||||
{
|
||||
|
@ -484,7 +542,7 @@ namespace TINK.ViewModel.Bikes
|
|||
/// Currently invoked by code behind, would be nice if called by XAML in future versions.
|
||||
/// </summary>
|
||||
public virtual async Task OnDisappearing()
|
||||
=> await m_oViewUpdateManager.StopUpdatePeridically();
|
||||
=> await m_oViewUpdateManager.StopAsync();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
namespace TINK.ViewModel.Bikes
|
||||
|
||||
namespace TINK.ViewModel.Bikes
|
||||
{
|
||||
public interface IBikesViewModel
|
||||
{
|
||||
/// <summary> Holds info about active rental process. </summary>
|
||||
IRentalProcess RentalProcess { get; set; }
|
||||
|
||||
/// <summary> Holds info about current action. </summary>
|
||||
string ActionText { get; set; }
|
||||
|
||||
|
|
31
TINKLib/ViewModel/Bikes/IRentalProcess.cs
Normal file
31
TINKLib/ViewModel/Bikes/IRentalProcess.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
using TINK.Model;
|
||||
|
||||
namespace TINK.ViewModel.Bikes
|
||||
{
|
||||
public interface IRentalProcess
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the id of the bike which is rental ends.
|
||||
/// </summary>
|
||||
string BikeId { get; }
|
||||
|
||||
CurrentRentalProcess State { get; set; }
|
||||
|
||||
/// <summary> Holds info about current step in rental process. </summary>
|
||||
int? StepIndex { get; set; }
|
||||
|
||||
/// <summary> Holds info about current step of rental process. </summary>
|
||||
string StepInfoText { get; set; }
|
||||
|
||||
/// <summary> Holds important info about current step of rental process. </summary>
|
||||
string ImportantStepInfoText { get; set; }
|
||||
|
||||
/// <summary> Holds info about status of current rental process. </summary>
|
||||
CurrentStepStatus Result { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds the info returned from back end when rent is ended.
|
||||
/// </summary>
|
||||
BookingFinishedModel EndRentalInfo { get; set; }
|
||||
}
|
||||
}
|
133
TINKLib/ViewModel/Bikes/RentalProcess.cs
Normal file
133
TINKLib/ViewModel/Bikes/RentalProcess.cs
Normal file
|
@ -0,0 +1,133 @@
|
|||
|
||||
using System.ComponentModel;
|
||||
using TINK.Model;
|
||||
|
||||
namespace TINK.ViewModel.Bikes
|
||||
{
|
||||
public enum CurrentRentalProcess
|
||||
{
|
||||
None = 0,
|
||||
ReserveBike = 1,
|
||||
StartRental = 2,
|
||||
OpenLock = 3,
|
||||
CloseLock = 4,
|
||||
EndRental = 5,
|
||||
}
|
||||
|
||||
public enum CurrentStepStatus
|
||||
{
|
||||
None = 0,
|
||||
Succeeded = 1,
|
||||
Failed = 2,
|
||||
}
|
||||
|
||||
public class RentalProcess : IRentalProcess, INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public RentalProcess(string bikeId = null) => BikeId = bikeId ?? string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the id of the bike which is rental ends.
|
||||
/// </summary>
|
||||
public string BikeId { get; }
|
||||
|
||||
/// <summary> Holds info about active rental process. </summary>
|
||||
private CurrentRentalProcess _state = CurrentRentalProcess.None;
|
||||
|
||||
/// <summary> Holds info about active rental process. </summary>
|
||||
public CurrentRentalProcess State
|
||||
{
|
||||
get => _state;
|
||||
set
|
||||
{
|
||||
if (_state == value) { return; }
|
||||
|
||||
_state = value;
|
||||
|
||||
if (value == CurrentRentalProcess.None)
|
||||
{
|
||||
StepIndex = null;
|
||||
Result = CurrentStepStatus.None;
|
||||
}
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(State)));
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(StepIndex)));
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Result)));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary> Holds info about current step in rental process. </summary>
|
||||
private int? _stepIndex;
|
||||
|
||||
/// <summary> Holds info about current step in rental process. </summary>
|
||||
public int? StepIndex
|
||||
{
|
||||
get => _stepIndex;
|
||||
set
|
||||
{
|
||||
if (_stepIndex == value) { return; }
|
||||
|
||||
_stepIndex = value;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(StepIndex)));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Holds info about current step. </summary>
|
||||
private string _stepInfoText;
|
||||
|
||||
/// <summary> Holds info about current step. </summary>
|
||||
public string StepInfoText
|
||||
{
|
||||
get => _stepInfoText;
|
||||
set
|
||||
{
|
||||
if (value == _stepInfoText)
|
||||
return;
|
||||
|
||||
_stepInfoText = value;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(StepInfoText)));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Holds important info about current step. </summary>
|
||||
private string _importantStepInfoText;
|
||||
|
||||
/// <summary> Holds important info about current step. </summary>
|
||||
public string ImportantStepInfoText
|
||||
{
|
||||
get => _importantStepInfoText;
|
||||
set
|
||||
{
|
||||
if (value == _importantStepInfoText)
|
||||
return;
|
||||
|
||||
_importantStepInfoText = value;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ImportantStepInfoText)));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Holds info about status of current rental process. </summary>
|
||||
private CurrentStepStatus _result = CurrentStepStatus.None;
|
||||
|
||||
/// <summary> Holds info about status of current rental process. </summary>
|
||||
public CurrentStepStatus Result
|
||||
{
|
||||
get => _result;
|
||||
set
|
||||
{
|
||||
if (_result == value) { return; }
|
||||
|
||||
_result = value;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Result)));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the info returned from back end when rent is ended.
|
||||
/// </summary>
|
||||
public BookingFinishedModel EndRentalInfo { get; set; }
|
||||
|
||||
}
|
||||
}
|
|
@ -253,7 +253,7 @@ namespace TINK.ViewModel.BikesAtStation
|
|||
ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
|
||||
// Stop polling before getting bikes info.
|
||||
await m_oViewUpdateManager.StopUpdatePeridically();
|
||||
await m_oViewUpdateManager.StopAsync();
|
||||
|
||||
ActionText = AppResources.ActivityTextBikesAtStationGetBikes;
|
||||
|
||||
|
@ -284,7 +284,7 @@ namespace TINK.ViewModel.BikesAtStation
|
|||
if (status != Status.Granted)
|
||||
{
|
||||
var dialogResult = await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
AppResources.MessageHintTitle,
|
||||
AppResources.MessageBikesManagementLocationPermissionOpenDialog,
|
||||
AppResources.MessageAnswerYes,
|
||||
AppResources.MessageAnswerNo);
|
||||
|
@ -310,7 +310,7 @@ namespace TINK.ViewModel.BikesAtStation
|
|||
if (GeolocationService.IsGeolcationEnabled == false)
|
||||
{
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
AppResources.MessageHintTitle,
|
||||
AppResources.MessageBikesManagementLocationActivation,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
|
@ -326,7 +326,7 @@ namespace TINK.ViewModel.BikesAtStation
|
|||
if (await BluetoothService.GetBluetoothState() != BluetoothState.On)
|
||||
{
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
AppResources.MessageHintTitle,
|
||||
AppResources.MessageBikesManagementBluetoothActivation,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
|
|
|
@ -165,14 +165,14 @@ namespace TINK.ViewModel.Info
|
|||
{
|
||||
// Ask for permission to append diagnostics.
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.QuestionSupportmailTitle,
|
||||
AppResources.QuestionSupportmailAttachmentTitle,
|
||||
AppResources.QuestionSupportmailAttachment,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
var message = new EmailMessage
|
||||
{
|
||||
To = new List<string> { APPSUPPORTMAILADDRESS },
|
||||
Subject = string.Format(AppResources.SupportmailSubjectAppmail, AppFlavorName)
|
||||
Subject = SelectedStation?.Id != null ? string.Format(AppResources.SupportmailSubjectAppmailWithStation, AppFlavorName, SelectedStation?.Id) : string.Format(AppResources.SupportmailSubjectAppmail, AppFlavorName)
|
||||
};
|
||||
|
||||
// Send with attachment.
|
||||
|
@ -276,7 +276,7 @@ namespace TINK.ViewModel.Info
|
|||
|
||||
/// <summary> Text providing the id of the selected station.</summary>
|
||||
public string SelectedStationId
|
||||
=> SelectedStation?.Id;
|
||||
=> SelectedStation?.Id != null ? SelectedStation?.Id : string.Empty;
|
||||
|
||||
public string SelectedStationName
|
||||
=> SelectedStation?.StationName;
|
||||
|
|
|
@ -292,8 +292,8 @@ namespace TINK.ViewModel.Contact
|
|||
&& status != Status.Granted)
|
||||
{
|
||||
var dialogResult = await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
AppResources.MessageCenterMapLocationPermissionOpenDialog,
|
||||
AppResources.MessageHintTitle,
|
||||
AppResources.ErrorMapCenterNoLocationPermissionOpenDialog,
|
||||
AppResources.MessageAnswerYes,
|
||||
AppResources.MessageAnswerNo);
|
||||
|
||||
|
@ -384,7 +384,7 @@ namespace TINK.ViewModel.Contact
|
|||
// COPRI reports an auth cookie error.
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageWaring,
|
||||
AppResources.MessageMapPageErrorAuthcookieUndefined,
|
||||
AppResources.ErrorMapPageAuthcookieUndefined,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
IsConnected = TinkApp.GetIsConnected();
|
||||
|
@ -419,9 +419,9 @@ namespace TINK.ViewModel.Contact
|
|||
IsProcessWithRunningProcessView = false;
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
"Fehler",
|
||||
$"Beim Anzeigen der Fahrradstandorte- Seite ist ein Fehler aufgetreten.\r\n{l_oException.Message}",
|
||||
"OK");
|
||||
AppResources.ErrorPageNotLoadedTitle,
|
||||
$"{AppResources.ErrorPageNotLoaded}\r\n{l_oException.Message}",
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
IsMapPageEnabled = true;
|
||||
}
|
||||
|
@ -483,10 +483,11 @@ namespace TINK.ViewModel.Contact
|
|||
ActionText = string.Empty;
|
||||
|
||||
Log.ForContext<SelectStationPageViewModel>().Error("Fehler beim Öffnen der Ansicht \"Fahrräder an Station\" aufgetreten. {Exception}", exception);
|
||||
await ViewService.DisplayAlert(
|
||||
"Fehler",
|
||||
$"Fehler beim Öffnen der Ansicht \"Fahrräder an Station\" aufgetreten. {exception.Message}",
|
||||
"OK");
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorPageNotLoadedTitle,
|
||||
$"{AppResources.ErrorPageNotLoaded}\r\n{exception.Message}",
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -636,17 +637,12 @@ namespace TINK.ViewModel.Contact
|
|||
{
|
||||
get
|
||||
{
|
||||
if (Exception != null)
|
||||
{
|
||||
// An error occurred getting data from copri.
|
||||
return Exception.GetShortErrorInfoText(TinkApp.IsReportLevelVerbose);
|
||||
//if (Exception != null)
|
||||
//{
|
||||
// // An error occurred getting data from copri.
|
||||
// return Exception.GetShortErrorInfoText(TinkApp.IsReportLevelVerbose);
|
||||
|
||||
}
|
||||
|
||||
if (!IsConnected)
|
||||
{
|
||||
return AppResources.ActivityTextConnectionStateOffline;
|
||||
}
|
||||
//}
|
||||
|
||||
return ActionText ?? string.Empty;
|
||||
}
|
||||
|
|
|
@ -175,7 +175,7 @@ namespace TINK.ViewModel.FindBike
|
|||
IsConnected = IsConnectedDelegate();
|
||||
|
||||
// Stop polling before getting bikes info.
|
||||
await m_oViewUpdateManager.StopUpdatePeridically();
|
||||
await m_oViewUpdateManager.StopAsync();
|
||||
|
||||
if (string.IsNullOrEmpty(BikeIdUserInput) /* Find bike page flyout was taped */
|
||||
&& BikeCollection.Count > 0 /* Bike was successfully selected */)
|
||||
|
@ -238,10 +238,9 @@ namespace TINK.ViewModel.FindBike
|
|||
// Copri server is not reachable.
|
||||
Log.ForContext<FindBikePageViewModel>().Information("Getting bikes failed (Copri server not reachable).");
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorReturnBikeNoWebTitle,
|
||||
string.Format("{0}\r\n{1}", AppResources.ErrorReturnBikeNoWebMessage, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
|
||||
exception.Message,
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorSelectBikeTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
|
@ -249,7 +248,7 @@ namespace TINK.ViewModel.FindBike
|
|||
Log.ForContext<FindBikePageViewModel>().Error("Getting bikes failed. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
AppResources.ErrorSelectBikeTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
@ -271,8 +270,8 @@ namespace TINK.ViewModel.FindBike
|
|||
if (selectedBike == null)
|
||||
{
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
string.Format(AppResources.MessageErrorSelectBikeNoBikeFound, BikeIdUserInput),
|
||||
AppResources.MessageHintTitle,
|
||||
string.Format(AppResources.ErrorSelectBikeNoBikeFound, BikeIdUserInput),
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
ActionText = string.Empty;
|
||||
|
@ -311,7 +310,7 @@ namespace TINK.ViewModel.FindBike
|
|||
if (permissionResult != Status.Granted)
|
||||
{
|
||||
var dialogResult = await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
AppResources.MessageHintTitle,
|
||||
AppResources.MessageBikesManagementLocationPermissionOpenDialog,
|
||||
AppResources.MessageAnswerYes,
|
||||
AppResources.MessageAnswerNo);
|
||||
|
@ -335,7 +334,7 @@ namespace TINK.ViewModel.FindBike
|
|||
else
|
||||
{
|
||||
var dialogResult = await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
AppResources.MessageHintTitle,
|
||||
AppResources.MessageBikesManagementLocationPermissionOpenDialog,
|
||||
AppResources.MessageAnswerYes,
|
||||
AppResources.MessageAnswerNo);
|
||||
|
@ -361,7 +360,7 @@ namespace TINK.ViewModel.FindBike
|
|||
if (GeolocationService.IsGeolcationEnabled == false)
|
||||
{
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
AppResources.MessageHintTitle,
|
||||
AppResources.MessageBikesManagementLocationActivation,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
|
@ -378,7 +377,7 @@ namespace TINK.ViewModel.FindBike
|
|||
if (await BluetoothService.GetBluetoothState() != BluetoothState.On)
|
||||
{
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
AppResources.MessageHintTitle,
|
||||
AppResources.MessageBikesManagementBluetoothActivation,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
|
@ -419,7 +418,7 @@ namespace TINK.ViewModel.FindBike
|
|||
catch (Exception exception)
|
||||
{
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageErrorSelectBikeTitle,
|
||||
AppResources.ErrorSelectBikeTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
|
@ -506,6 +505,5 @@ namespace TINK.ViewModel.FindBike
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Threading.Tasks;
|
||||
using System.Threading.Tasks;
|
||||
using TINK.Settings;
|
||||
|
||||
namespace TINK.ViewModel
|
||||
|
@ -7,14 +7,14 @@ namespace TINK.ViewModel
|
|||
{
|
||||
/// <summary>
|
||||
/// Invoked when page is shown.
|
||||
/// Actuates and awaits the first update process and starts a task wich actuate the subseqent update tasks.
|
||||
/// Actuates and awaits the first update process and starts a task which actuate the subsequent update tasks.
|
||||
/// </summary>
|
||||
Task StartUpdateAyncPeridically(PollingParameters p_oPolling = null);
|
||||
Task StartAsync(PollingParameters p_oPolling = null);
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when pages is closed/ hidden.
|
||||
/// Stops update process.
|
||||
/// </summary>
|
||||
Task StopUpdatePeridically();
|
||||
Task StopAsync();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,12 +7,12 @@ namespace TINK.ViewModel
|
|||
/// <remarks> Object MapPage calls OnDisappearing for some reasons after first start after installation before OnAppearing. This requires a IdlePollingUpdateManager to exist.</remarks>
|
||||
public class IdlePollingUpdateTaskManager : IPollingUpdateTaskManager
|
||||
{
|
||||
public async Task StartUpdateAyncPeridically(PollingParameters p_oPeriode)
|
||||
public async Task StartAsync(PollingParameters p_oPeriode)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task StopUpdatePeridically()
|
||||
public async Task StopAsync()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
|
|
@ -223,8 +223,8 @@ namespace TINK.ViewModel
|
|||
else
|
||||
{
|
||||
await m_oViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
AppResources.MessageLoginRegisterNoNet,
|
||||
AppResources.MessageHintTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
});
|
||||
|
@ -239,8 +239,8 @@ namespace TINK.ViewModel
|
|||
else
|
||||
{
|
||||
await m_oViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
AppResources.MessageLoginRecoverPassword,
|
||||
AppResources.MessageHintTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
});
|
||||
|
@ -290,7 +290,7 @@ namespace TINK.ViewModel
|
|||
Log.ForContext<LoginPageViewModel>().Error("Login failed (invalid. auth. response). {@l_oException}.", l_oException);
|
||||
|
||||
await m_oViewService.DisplayAlert(
|
||||
AppResources.MessageLoginErrorTitle,
|
||||
AppResources.ErrorLoginTitle,
|
||||
l_oException.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
|
@ -301,7 +301,7 @@ namespace TINK.ViewModel
|
|||
catch (UnsupportedCopriVersionDetectedException)
|
||||
{
|
||||
await m_oViewService.DisplayAlert(
|
||||
AppResources.MessageLoginErrorTitle,
|
||||
AppResources.ErrorLoginTitle,
|
||||
string.Format(
|
||||
AppResources.MessageAppVersionIsOutdated,
|
||||
TinkApp.Flavor.GetDisplayName()),
|
||||
|
@ -319,8 +319,8 @@ namespace TINK.ViewModel
|
|||
Log.ForContext<LoginPageViewModel>().Information("Login failed (web communication exception). {@l_oException}.", l_oException);
|
||||
|
||||
await m_oViewService.DisplayAlert(
|
||||
AppResources.MessageLoginConnectionErrorTitle,
|
||||
string.Format("{0}\r\n{1}", l_oException.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
|
||||
AppResources.ErrorNoConnectionTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (l_oException is UsernamePasswordInvalidException)
|
||||
|
@ -328,15 +328,15 @@ namespace TINK.ViewModel
|
|||
// Cookie is empty.
|
||||
Log.ForContext<LoginPageViewModel>().Error("Login failed (empty cookie). {@l_oException}.", l_oException);
|
||||
await m_oViewService.DisplayAlert(
|
||||
AppResources.MessageLoginErrorTitle,
|
||||
string.Format(AppResources.MessageLoginConnectionErrorMessage, l_oException.Message),
|
||||
AppResources.ErrorLoginTitle,
|
||||
string.Format(AppResources.ErrorLoginNoCookie, l_oException.Message),
|
||||
"OK");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<LoginPageViewModel>().Error("Login failed. {@l_oException}.", l_oException);
|
||||
await m_oViewService.DisplayAlert(
|
||||
AppResources.MessageLoginErrorTitle,
|
||||
AppResources.ErrorLoginTitle,
|
||||
l_oException.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
|
|
@ -377,7 +377,7 @@ namespace TINK.ViewModel.Map
|
|||
{
|
||||
// Show COPRI message once.
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleInformation,
|
||||
AppResources.MessageInformationTitle,
|
||||
resultStationsAndBikes.GeneralData.MerchantMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}, null);
|
||||
|
@ -442,7 +442,7 @@ namespace TINK.ViewModel.Map
|
|||
try
|
||||
{
|
||||
// Update bikes at station or my bikes depending on context.
|
||||
await m_oViewUpdateManager.StartUpdateAyncPeridically(Polling);
|
||||
await m_oViewUpdateManager.StartAsync(Polling);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
@ -463,9 +463,9 @@ namespace TINK.ViewModel.Map
|
|||
IsNavBarVisible = true;
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
"Fehler",
|
||||
$"Beim Anzeigen der Fahrradstandorte- Seite ist ein Fehler aufgetreten.\r\n{l_oException.Message}",
|
||||
"OK");
|
||||
AppResources.ErrorPageNotLoadedTitle,
|
||||
$"{AppResources.ErrorPageNotLoaded}\r\n{l_oException.Message}",
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
IsMapPageEnabled = true;
|
||||
}
|
||||
|
@ -512,7 +512,7 @@ namespace TINK.ViewModel.Map
|
|||
// COPRI reports an auth cookie error.
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageWaring,
|
||||
AppResources.MessageMapPageErrorAuthcookieUndefined,
|
||||
AppResources.ErrorMapPageAuthcookieUndefined,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
IsConnected = TinkApp.GetIsConnected();
|
||||
|
@ -607,8 +607,8 @@ namespace TINK.ViewModel.Map
|
|||
&& status != Status.Granted)
|
||||
{
|
||||
var dialogResult = await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
AppResources.MessageCenterMapLocationPermissionOpenDialog,
|
||||
AppResources.MessageHintTitle,
|
||||
AppResources.ErrorMapCenterNoLocationPermissionOpenDialog,
|
||||
AppResources.MessageAnswerYes,
|
||||
AppResources.MessageAnswerNo);
|
||||
|
||||
|
@ -727,7 +727,7 @@ namespace TINK.ViewModel.Map
|
|||
{
|
||||
Log.Information("Map page is disappearing...");
|
||||
|
||||
await m_oViewUpdateManager.StopUpdatePeridically();
|
||||
await m_oViewUpdateManager.StopAsync();
|
||||
}
|
||||
|
||||
/// <summary> User clicked on a bike. </summary>
|
||||
|
@ -764,9 +764,9 @@ namespace TINK.ViewModel.Map
|
|||
|
||||
Log.ForContext<MapPageViewModel>().Error("Fehler beim Öffnen der Ansicht \"Fahrräder an Station\" aufgetreten. {Exception}", exception);
|
||||
await ViewService.DisplayAlert(
|
||||
"Fehler",
|
||||
$"Fehler beim Öffnen der Ansicht \"Fahrräder an Station\" aufgetreten. {exception.Message}",
|
||||
"OK");
|
||||
AppResources.ErrorPageNotLoadedTitle,
|
||||
$"{AppResources.ErrorPageNotLoaded}\r\n {exception.Message}",
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -931,15 +931,11 @@ namespace TINK.ViewModel.Map
|
|||
{
|
||||
get
|
||||
{
|
||||
if (Exception != null)
|
||||
{
|
||||
// An error occurred getting data from copri.
|
||||
return Exception.GetShortErrorInfoText(TinkApp.IsReportLevelVerbose);
|
||||
}
|
||||
if (!IsConnected)
|
||||
{
|
||||
return AppResources.ActivityTextConnectionStateOffline;
|
||||
}
|
||||
//if (Exception != null)
|
||||
//{
|
||||
// // An error occurred getting data from copri.
|
||||
// return Exception.GetShortErrorInfoText(TinkApp.IsReportLevelVerbose);
|
||||
//}
|
||||
|
||||
return ActionText ?? string.Empty;
|
||||
}
|
||||
|
@ -968,9 +964,9 @@ namespace TINK.ViewModel.Map
|
|||
|
||||
Log.ForContext<MapPageViewModel>().Error("Fehler beim Öffnen der Ansicht \"Meine Räder\" aufgetreten. {Exception}", exception);
|
||||
await ViewService.DisplayAlert(
|
||||
"Fehler",
|
||||
$"Fehler beim Öffnen der Ansicht \"Meine Räder\" aufgetreten. {exception.Message}",
|
||||
"OK");
|
||||
AppResources.ErrorPageNotLoadedTitle,
|
||||
$"{AppResources.ErrorPageNotLoaded}\r\n{exception.Message}",
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1023,7 +1019,7 @@ namespace TINK.ViewModel.Map
|
|||
|
||||
// Stop polling.
|
||||
ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await m_oViewUpdateManager.StopUpdatePeridically();
|
||||
await m_oViewUpdateManager.StopAsync();
|
||||
|
||||
// Clear error info.
|
||||
Exception = null;
|
||||
|
@ -1063,7 +1059,7 @@ namespace TINK.ViewModel.Map
|
|||
try
|
||||
{
|
||||
// Update bikes at station or my bikes depending on context.
|
||||
await m_oViewUpdateManager.StartUpdateAyncPeridically(Polling);
|
||||
await m_oViewUpdateManager.StartAsync(Polling);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
@ -1084,9 +1080,9 @@ namespace TINK.ViewModel.Map
|
|||
IsNavBarVisible = true;
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
"Fehler",
|
||||
AppResources.MessageMapPageErrorSwitch,
|
||||
String.Format(AppResources.MessageMapPageErrorSwitch, l_oException.Message),
|
||||
AppResources.ErrorPageNotLoadedTitle,
|
||||
AppResources.ErrorMapPageSwitchBikeType,
|
||||
String.Format(AppResources.ErrorMapPageSwitchBikeType, l_oException.Message),
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
IsMapPageEnabled = true;
|
||||
|
|
|
@ -142,8 +142,8 @@ namespace TINK.ViewModel.MiniSurvey
|
|||
}
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnSubmitFeedbackTitle,
|
||||
AppResources.ErrorReturnSubmitFeedbackMessage,
|
||||
AppResources.ErrorSubmitFeedbackTitle,
|
||||
AppResources.ErrorNoWeb,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ namespace TINK.ViewModel.MyBikes
|
|||
ActionText = AppResources.ActivityTextMyBikesLoadingBikes;
|
||||
|
||||
// Stop polling before getting bikes info.
|
||||
await m_oViewUpdateManager.StopUpdatePeridically();
|
||||
await m_oViewUpdateManager.StopAsync();
|
||||
|
||||
var bikesOccupied = await ConnectorFactory(IsConnected).Query.GetBikesOccupiedAsync();
|
||||
|
||||
|
@ -171,7 +171,7 @@ namespace TINK.ViewModel.MyBikes
|
|||
if (permissionResult != Status.Granted)
|
||||
{
|
||||
var dialogResult = await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
AppResources.MessageHintTitle,
|
||||
AppResources.MessageBikesManagementLocationPermissionOpenDialog,
|
||||
AppResources.MessageAnswerYes,
|
||||
AppResources.MessageAnswerNo);
|
||||
|
@ -197,7 +197,7 @@ namespace TINK.ViewModel.MyBikes
|
|||
if (GeolocationService.IsGeolcationEnabled == false)
|
||||
{
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
AppResources.MessageHintTitle,
|
||||
AppResources.MessageBikesManagementLocationActivation,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
|
@ -214,7 +214,7 @@ namespace TINK.ViewModel.MyBikes
|
|||
if (await BluetoothService.GetBluetoothState() != BluetoothState.On)
|
||||
{
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
AppResources.MessageHintTitle,
|
||||
AppResources.MessageBikesManagementBluetoothActivation,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace TINK.ViewModel
|
|||
/// Actuates and awaits the first update process and starts a task wich actuate the subseqent update tasks.
|
||||
/// </summary>
|
||||
/// <param name="pollingParameters">Parametes holding polling period, if null last parameters are used if available.</param>
|
||||
public async Task StartUpdateAyncPeridically(PollingParameters pollingParameters = null)
|
||||
public async Task StartAsync(PollingParameters pollingParameters = null)
|
||||
{
|
||||
if (UpdateTask != null)
|
||||
{
|
||||
|
@ -81,7 +81,7 @@ namespace TINK.ViewModel
|
|||
/// Invoked when pages is closed/ hidden.
|
||||
/// Stops update process.
|
||||
/// </summary>
|
||||
public async Task StopUpdatePeridically()
|
||||
public async Task StopAsync()
|
||||
{
|
||||
if (UpdateTask == null)
|
||||
{
|
||||
|
|
|
@ -319,16 +319,16 @@ namespace TINK.ViewModel
|
|||
|
||||
TinkApp.UpdateConnector();
|
||||
|
||||
await m_oViewUpdateManager.StopUpdatePeridically();
|
||||
await m_oViewUpdateManager.StopAsync();
|
||||
|
||||
Log.ForContext<SettingsPageViewModel>().Information($"{nameof(OnDisappearing)} done.");
|
||||
}
|
||||
catch (Exception l_oException)
|
||||
{
|
||||
await m_oViewService.DisplayAlert(
|
||||
"Fehler",
|
||||
$"Ein unerwarteter Fehler ist aufgetreten. \r\n{l_oException.Message}",
|
||||
"OK");
|
||||
AppResources.ErrorPageNotLoadedTitle,
|
||||
$"{AppResources.ErrorPageNotLoaded}\r\n{l_oException.Message}",
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -204,7 +204,7 @@ namespace TINK.ViewModel
|
|||
|
||||
l_oError = new FormattedString();
|
||||
l_oError.Spans.Add(new Span { Text = "Information!\r\n", FontAttributes = FontAttributes.Bold });
|
||||
l_oError.Spans.Add(new Span { Text = $"{exception.Message}\r\n{WebConnectFailureException.GetHintToPossibleExceptionsReasons}" });
|
||||
l_oError.Spans.Add(new Span { Text = $"{exception.Message}\r\n{AppResources.ErrorNoWeb}" });
|
||||
return l_oError;
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue