2022-10-26 20:53:18 +02:00
using System ;
2022-04-25 22:15:15 +02:00
using System.Threading.Tasks ;
2022-08-30 15:42:25 +02:00
using Serilog ;
2024-04-09 12:53:23 +02:00
using ShareeBike.Model.Bikes.BikeInfoNS.CopriLock ;
using ShareeBike.Model.Connector ;
using ShareeBike.Model.Device ;
using ShareeBike.Model.State ;
using ShareeBike.Model.User ;
using ShareeBike.MultilingualResources ;
using ShareeBike.Repository.Exception ;
using ShareeBike.Services.CopriApi.Exception ;
using ShareeBike.View ;
2022-04-25 22:15:15 +02:00
2024-04-09 12:53:23 +02:00
namespace ShareeBike.ViewModel.Bikes.Bike.CopriLock.RequestHandler
2022-04-25 22:15:15 +02:00
{
2022-09-06 16:08:19 +02:00
using IRequestHandler = BluetoothLock . IRequestHandler ;
public class DisposableClosed : Base , IRequestHandler
{
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...).</param>
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
public DisposableClosed (
IBikeInfoMutable selectedBike ,
Func < bool > isConnectedDelegate ,
Func < bool , IConnector > connectorFactory ,
Func < IPollingUpdateTaskManager > viewUpdateManager ,
ISmartDevice smartDevice ,
IViewService viewService ,
IBikesViewModel bikesViewModel ,
IUser activeUser ) : base (
selectedBike ,
2023-11-06 12:23:09 +01:00
AppResources . ActionOpenLockAndRentBike , // Button text: "Schloss öffnen & Rad mieten"
2022-09-06 16:08:19 +02:00
true , // Show copri button to enable booking and opening
isConnectedDelegate ,
connectorFactory ,
viewUpdateManager ,
smartDevice ,
viewService ,
bikesViewModel ,
activeUser )
{
2023-11-06 12:23:09 +01:00
LockitButtonText = AppResources . ActionReserveBike ; // Copri text: "Rad reservieren"
2022-09-06 16:08:19 +02:00
IsLockitButtonVisible = true ;
}
/// <summary>Reserve bike and connect to lock.</summary>
public async Task < IRequestHandler > HandleRequestOption1 ( ) = > await BookAndRelease ( ) ;
public async Task < IRequestHandler > HandleRequestOption2 ( ) = > await Reserve ( ) ;
/// <summary>Book bike and open lock.</summary>
public async Task < IRequestHandler > BookAndRelease ( )
{
BikesViewModel . IsIdle = false ;
// Ask whether to really book bike?
var alertResult = await ViewService . DisplayAlert (
string . Empty ,
string . Format ( AppResources . QuestionOpenLockAndBookBike , SelectedBike . GetFullDisplayName ( ) ) ,
AppResources . MessageAnswerYes ,
AppResources . MessageAnswerNo ) ;
if ( alertResult = = false )
{
// User aborted booking process
2023-04-19 12:14:14 +02:00
Log . ForContext < DisposableClosed > ( ) . Information ( "User selected bike {bike} in order to book and release bike from station but action was canceled." , SelectedBike ) ;
2022-09-06 16:08:19 +02:00
BikesViewModel . IsIdle = true ;
return this ;
}
// Book and release bike from station.
Log . ForContext < DisposableClosed > ( ) . Information ( "User selected bike {bike} in order to book and release bike from station." , SelectedBike ) ;
// Stop polling before returning bike.
BikesViewModel . ActionText = AppResources . ActivityTextOneMomentPlease ;
2023-08-31 12:20:06 +02:00
await ViewUpdateManager ( ) . StopAsync ( ) ;
2022-09-06 16:08:19 +02:00
// Book bike prior to opening lock.
BikesViewModel . ActionText = AppResources . ActivityTextRentingBike ;
IsConnected = IsConnectedDelegate ( ) ;
try
{
await ConnectorFactory ( IsConnected ) . Command . BookAndOpenAync ( SelectedBike ) ;
}
catch ( Exception exception )
{
BikesViewModel . ActionText = string . Empty ;
if ( exception is WebConnectFailureException )
{
// Copri server is not reachable.
Log . ForContext < DisposableClosed > ( ) . Information ( "User selected bike {id} but booking failed (Copri server not reachable)." , SelectedBike . Id ) ;
2023-08-31 12:20:06 +02:00
await ViewService . DisplayAlert (
AppResources . ErrorNoConnectionTitle ,
AppResources . ErrorNoWeb ,
2022-09-06 16:08:19 +02:00
AppResources . MessageAnswerOk ) ;
}
else
{
Log . ForContext < DisposableClosed > ( ) . Error ( "User selected bike {id} but booking failed. {@exception}" , SelectedBike . Id , exception ) ;
await ViewService . DisplayAlert (
2023-08-31 12:20:06 +02:00
AppResources . ErrorRentingBikeTitle ,
2022-09-06 16:08:19 +02:00
exception . Message ,
AppResources . MessageAnswerOk ) ;
}
BikesViewModel . ActionText = AppResources . ActivityTextStartingUpdater ;
2023-08-31 12:20:06 +02:00
await ViewUpdateManager ( ) . StartAsync ( ) ; // Restart polling again.
2022-09-06 16:08:19 +02:00
BikesViewModel . ActionText = string . Empty ;
BikesViewModel . IsIdle = true ; // Unlock GUI
return RequestHandlerFactory . Create ( SelectedBike , IsConnectedDelegate , ConnectorFactory , ViewUpdateManager , SmartDevice , ViewService , BikesViewModel , ActiveUser ) ;
}
Log . ForContext < DisposableClosed > ( ) . Information ( "User booked and released bike {bike} successfully." , SelectedBike ) ;
BikesViewModel . ActionText = AppResources . ActivityTextStartingUpdater ;
2023-08-31 12:20:06 +02:00
await ViewUpdateManager ( ) . StartAsync ( ) ; // Restart polling again.
2022-09-06 16:08:19 +02:00
BikesViewModel . ActionText = string . Empty ;
BikesViewModel . IsIdle = true ; // Unlock GUI
return RequestHandlerFactory . Create ( SelectedBike , IsConnectedDelegate , ConnectorFactory , ViewUpdateManager , SmartDevice , ViewService , BikesViewModel , ActiveUser ) ;
}
/// <summary>Reserve bike.</summary>
public async Task < IRequestHandler > Reserve ( )
{
BikesViewModel . IsIdle = false ;
// Ask whether to really reserve bike?
var alertResult = await ViewService . DisplayAlert (
string . Empty ,
2023-06-06 12:00:24 +02:00
string . Format (
AppResources . QuestionReserveBike ,
SelectedBike . GetFullDisplayName ( ) ,
SelectedBike . TariffDescription ? . MaxReservationTimeSpan . TotalMinutes ? ? 0 ) ,
2022-09-06 16:08:19 +02:00
AppResources . MessageAnswerYes ,
AppResources . MessageAnswerNo ) ;
if ( alertResult = = false )
{
// User aborted booking process
2023-04-19 12:14:14 +02:00
Log . ForContext < DisposableClosed > ( ) . Information ( "User selected centered bike {bike} in order to reserve but action was canceled." , SelectedBike ) ;
2022-09-06 16:08:19 +02:00
BikesViewModel . IsIdle = true ;
return this ;
}
Log . ForContext < DisposableClosed > ( ) . Information ( "Request to reserve for bike {bike} detected." , SelectedBike ) ;
BikesViewModel . ActionText = AppResources . ActivityTextOneMomentPlease ;
// Stop polling before requesting bike.
2023-08-31 12:20:06 +02:00
await ViewUpdateManager ( ) . StopAsync ( ) ;
2022-09-06 16:08:19 +02:00
BikesViewModel . ActionText = AppResources . ActivityTextReservingBike ;
IsConnected = IsConnectedDelegate ( ) ;
try
{
await ConnectorFactory ( IsConnected ) . Command . DoReserve ( SelectedBike ) ;
}
catch ( Exception exception )
{
BikesViewModel . ActionText = string . Empty ;
if ( exception is BookingDeclinedException )
{
// Too many bikes booked.
Log . ForContext < DisposableClosed > ( ) . Information ( "Request declined because maximum count of bikes {l_oException.MaxBikesCount} already requested/ booked." , ( exception as BookingDeclinedException ) . MaxBikesCount ) ;
await ViewService . DisplayAlert (
2023-08-31 12:20:06 +02:00
AppResources . MessageHintTitle ,
string . Format ( AppResources . ErrorReservingBikeTooManyReservationsRentals , SelectedBike . GetFullDisplayName ( ) , ( exception as BookingDeclinedException ) . MaxBikesCount ) ,
2022-09-06 16:08:19 +02:00
AppResources . MessageAnswerOk ) ;
}
2022-10-26 20:53:18 +02:00
else if ( exception is WebConnectFailureException
| | exception is RequestNotCachableException )
2022-09-06 16:08:19 +02:00
{
// Copri server is not reachable.
2023-04-19 12:14:14 +02:00
Log . ForContext < DisposableClosed > ( ) . Information ( "User selected centered bike {bike} but reserving failed (Copri server not reachable)." , SelectedBike ) ;
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
await ViewService . DisplayAlert (
AppResources . ErrorNoConnectionTitle ,
AppResources . ErrorNoWeb ,
2022-09-06 16:08:19 +02:00
AppResources . MessageAnswerOk ) ;
}
else
{
2023-04-19 12:14:14 +02:00
Log . ForContext < DisposableClosed > ( ) . Error ( "User selected centered bike {bike} but reserving failed. {@exception}" , SelectedBike , exception ) ;
2022-09-06 16:08:19 +02:00
await ViewService . DisplayAlert (
2023-08-31 12:20:06 +02:00
AppResources . ErrorReservingBikeTitle ,
2022-09-06 16:08:19 +02:00
exception . Message ,
AppResources . MessageAnswerOk ) ;
}
// Restart polling again.
BikesViewModel . ActionText = AppResources . ActivityTextStartingUpdater ;
2023-08-31 12:20:06 +02:00
await ViewUpdateManager ( ) . StartAsync ( ) ;
2022-09-06 16:08:19 +02:00
BikesViewModel . ActionText = string . Empty ;
BikesViewModel . IsIdle = true ;
return this ;
}
Log . ForContext < DisposableClosed > ( ) . Information ( "User reserved bike {bike} successfully." , SelectedBike ) ;
BikesViewModel . ActionText = AppResources . ActivityTextStartingUpdater ;
2023-08-31 12:20:06 +02:00
await ViewUpdateManager ( ) . StartAsync ( ) ; // Restart polling again.
2022-09-06 16:08:19 +02:00
BikesViewModel . ActionText = string . Empty ;
BikesViewModel . IsIdle = true ; // Unlock GUI
return RequestHandlerFactory . Create ( SelectedBike , IsConnectedDelegate , ConnectorFactory , ViewUpdateManager , SmartDevice , ViewService , BikesViewModel , ActiveUser ) ;
}
}
2022-04-25 22:15:15 +02:00
}