2022-10-17 18:45:38 +02:00
|
|
|
using System;
|
2021-05-13 20:03:07 +02:00
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
using System.ComponentModel;
|
2023-08-31 12:20:06 +02:00
|
|
|
using System.Linq;
|
2021-05-13 20:03:07 +02:00
|
|
|
using System.Threading;
|
|
|
|
using System.Threading.Tasks;
|
2022-08-30 15:42:25 +02:00
|
|
|
using Plugin.BLE.Abstractions.Contracts;
|
|
|
|
using Serilog;
|
|
|
|
using TINK.Model.Bikes;
|
2021-05-13 20:03:07 +02:00
|
|
|
using TINK.Model.Connector;
|
2022-08-30 15:42:25 +02:00
|
|
|
using TINK.Model.Device;
|
|
|
|
using TINK.Model.User;
|
2021-05-13 20:03:07 +02:00
|
|
|
using TINK.Services.BluetoothLock;
|
2022-04-10 17:38:34 +02:00
|
|
|
using TINK.Services.Geolocation;
|
2022-08-30 15:42:25 +02:00
|
|
|
using TINK.Services.Permissions;
|
2021-05-13 20:03:07 +02:00
|
|
|
using TINK.View;
|
|
|
|
using TINK.ViewModel.Bikes.Bike;
|
|
|
|
|
|
|
|
namespace TINK.ViewModel.Bikes
|
|
|
|
{
|
2022-09-06 16:08:19 +02:00
|
|
|
public abstract class BikesViewModel : ObservableCollection<BikeViewModelBase>, IBikesViewModel
|
|
|
|
{
|
|
|
|
/// <summary> Provides info about the smart device (phone, tablet, ...).</summary>
|
|
|
|
protected ISmartDevice SmartDevice;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Reference on view service to show modal notifications and to perform navigation.
|
|
|
|
/// </summary>
|
|
|
|
protected IViewService ViewService { get; }
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Holds the exception which occurred getting bikes occupied information.
|
|
|
|
/// </summary>
|
|
|
|
private Exception m_oException;
|
|
|
|
|
|
|
|
/// <summary> Provides a connector object.</summary>
|
|
|
|
protected Func<bool, IConnector> ConnectorFactory { get; }
|
|
|
|
|
2023-04-05 15:02:10 +02:00
|
|
|
protected IGeolocationService GeolocationService { get; }
|
2022-09-06 16:08:19 +02:00
|
|
|
|
|
|
|
/// <summary> Provides a connector object.</summary>
|
|
|
|
protected ILocksService LockService { get; }
|
|
|
|
|
|
|
|
/// <summary> Delegate to retrieve connected state. </summary>
|
|
|
|
protected Func<bool> IsConnectedDelegate { get; }
|
|
|
|
|
2023-04-19 12:14:14 +02:00
|
|
|
/// <summary>Holds whether to poll or not and the period length is polling is on.</summary>
|
2022-09-06 16:08:19 +02:00
|
|
|
private TINK.Settings.PollingParameters m_oPolling;
|
|
|
|
|
|
|
|
/// <summary> Object to manage update of view model objects from Copri.</summary>
|
|
|
|
protected IPollingUpdateTaskManager m_oViewUpdateManager;
|
|
|
|
|
|
|
|
/// <summary> Action to post to GUI thread.</summary>
|
|
|
|
public Action<SendOrPostCallback, object> PostAction { get; }
|
|
|
|
|
|
|
|
/// <summary> Delegate to open browser. </summary>
|
|
|
|
private Action<string> OpenUrlInBrowser { get; }
|
|
|
|
|
|
|
|
/// <summary>Enables derived class to fire property changed event. </summary>
|
|
|
|
/// <param name="p_oEventArgs"></param>
|
|
|
|
protected override void OnPropertyChanged(PropertyChangedEventArgs p_oEventArgs) => base.OnPropertyChanged(p_oEventArgs);
|
|
|
|
|
|
|
|
/// <summary>
|
2023-04-19 12:14:14 +02:00
|
|
|
/// Handles events from bike view model which require GUI updates.
|
2022-09-06 16:08:19 +02:00
|
|
|
/// </summary>
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
/// <param name="e"></param>
|
|
|
|
private void OnBikeRequestHandlerPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
|
|
{
|
|
|
|
OnPropertyChanged(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Instantiates a new item.
|
|
|
|
/// </summary>
|
|
|
|
Func<IInUseStateInfoProvider> m_oItemFactory;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Constructs bike collection view model.
|
|
|
|
/// </summary>
|
|
|
|
/// </param>
|
2023-07-04 11:06:38 +02:00
|
|
|
/// <param name="user">Mail address of active user.</param>
|
|
|
|
/// <param name="viewContext"> Holds the view context in which bikes view model is used.</param>
|
2022-09-06 16:08:19 +02:00
|
|
|
/// <param name="isReportLevelVerbose">True if report level is verbose, false if not.</param>
|
2023-04-19 12:14:14 +02:00
|
|
|
/// <param name="permissions">Holds object to query location permissions.</param>
|
2022-09-06 16:08:19 +02:00
|
|
|
/// <param name="bluetoothLE">Holds object to query bluetooth state.</param>
|
|
|
|
/// <param name="runtimPlatform">Specifies on which platform code is run.</param>
|
|
|
|
/// <param name="isConnectedDelegate">Returns if mobile is connected to web or not.</param>
|
|
|
|
/// <param name="connectorFactory">Connects system to copri for purposes of requesting a bike/ cancel request.</param>
|
|
|
|
/// <param name="lockService">Service to control lock retrieve info.</param>
|
2023-04-19 12:14:14 +02:00
|
|
|
/// <param name="p_oPolling"> Holds whether to poll or not and the period length is polling is on. </param>
|
2022-09-06 16:08:19 +02:00
|
|
|
/// <param name="postAction">Executes actions on GUI thread.</param>
|
|
|
|
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...)</param>
|
2023-04-19 12:14:14 +02:00
|
|
|
/// <param name="viewService">Interface to actuate methods on GUI.</param>
|
2022-09-06 16:08:19 +02:00
|
|
|
/// <param name="openUrlInBrowser">Delegate to open browser.</param>
|
|
|
|
public BikesViewModel(
|
|
|
|
User user,
|
2023-07-04 11:06:38 +02:00
|
|
|
ViewContext viewContext,
|
2022-09-06 16:08:19 +02:00
|
|
|
ILocationPermission permissions,
|
|
|
|
IBluetoothLE bluetoothLE,
|
|
|
|
string runtimPlatform,
|
|
|
|
Func<bool> isConnectedDelegate,
|
|
|
|
Func<bool, IConnector> connectorFactory,
|
2023-04-05 15:02:10 +02:00
|
|
|
IGeolocationService geolocation,
|
2022-09-06 16:08:19 +02:00
|
|
|
ILocksService lockService,
|
|
|
|
TINK.Settings.PollingParameters polling,
|
|
|
|
Action<SendOrPostCallback, object> postAction,
|
|
|
|
ISmartDevice smartDevice,
|
|
|
|
IViewService viewService,
|
|
|
|
Action<string> openUrlInBrowser,
|
|
|
|
Func<IInUseStateInfoProvider> itemFactory)
|
|
|
|
{
|
|
|
|
User = user
|
|
|
|
?? throw new ArgumentException("Can not instantiate bikes page view model- object. No user available.");
|
|
|
|
|
|
|
|
RuntimePlatform = runtimPlatform
|
|
|
|
?? throw new ArgumentException("Can not instantiate bikes page view model- object. No runtime platform information available.");
|
|
|
|
|
|
|
|
PermissionsService = permissions
|
|
|
|
?? throw new ArgumentException("Can not instantiate bikes page view model- object. No permissions available.");
|
|
|
|
|
|
|
|
BluetoothService = bluetoothLE
|
|
|
|
?? throw new ArgumentException("Can not instantiate bikes page view model- object. No bluetooth available.");
|
|
|
|
|
|
|
|
ConnectorFactory = connectorFactory
|
|
|
|
?? throw new ArgumentException("Can not instantiate bikes page view model- object. No connector available.");
|
|
|
|
|
2023-04-05 15:02:10 +02:00
|
|
|
GeolocationService = geolocation
|
2022-09-06 16:08:19 +02:00
|
|
|
?? throw new ArgumentException("Can not instantiate bikes page view model- object. No geolocation object available.");
|
|
|
|
|
|
|
|
LockService = lockService
|
|
|
|
?? throw new ArgumentException("Can not instantiate bikes page view model- object. No lock service object available.");
|
|
|
|
|
|
|
|
IsConnectedDelegate = isConnectedDelegate
|
|
|
|
?? throw new ArgumentException("Can not instantiate bikes page view model- object. No is connected delegate available.");
|
|
|
|
|
|
|
|
m_oItemFactory = itemFactory
|
|
|
|
?? throw new ArgumentException("Can not instantiate bikes page view model- object. No factory member available.");
|
|
|
|
|
|
|
|
PostAction = postAction
|
|
|
|
?? throw new ArgumentException("Can not instantiate bikes page view model- object. No post action available.");
|
|
|
|
|
|
|
|
SmartDevice = smartDevice
|
|
|
|
?? throw new ArgumentException("Can not instantiate bikes page view model- object. No smart device object available.");
|
|
|
|
|
|
|
|
ViewService = viewService
|
|
|
|
?? throw new ArgumentException("Can not instantiate bikes page view model- object. No view available.");
|
|
|
|
|
2023-07-04 11:06:38 +02:00
|
|
|
ViewContext = viewContext;
|
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
m_oViewUpdateManager = new IdlePollingUpdateTaskManager();
|
|
|
|
|
2023-08-31 12:20:06 +02:00
|
|
|
BikeCollection = new BikeCollectionMutable(
|
|
|
|
geolocation,
|
|
|
|
lockService,
|
|
|
|
isConnectedDelegate,
|
|
|
|
connectorFactory,
|
|
|
|
() => m_oViewUpdateManager);
|
2022-09-06 16:08:19 +02:00
|
|
|
|
|
|
|
BikeCollection.CollectionChanged += OnDecoratedCollectionChanged;
|
|
|
|
|
|
|
|
m_oPolling = polling;
|
|
|
|
|
|
|
|
OpenUrlInBrowser = openUrlInBrowser;
|
|
|
|
|
|
|
|
CollectionChanged += (sender, eventargs) =>
|
|
|
|
{
|
2023-04-19 12:14:14 +02:00
|
|
|
// Notify about bikes occurring/ vanishing from list.
|
2022-09-06 16:08:19 +02:00
|
|
|
OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsBikesListVisible)));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Is invoked if decorated bike collection changes.
|
|
|
|
/// Collection of view model objects has to be synced.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="p_oSender">Sender of the event.</param>
|
|
|
|
/// <param name="p_oEventArgs">Event arguments.</param>
|
|
|
|
private void OnDecoratedCollectionChanged(object p_oSender, System.Collections.Specialized.NotifyCollectionChangedEventArgs p_oEventArgs)
|
|
|
|
{
|
|
|
|
switch (p_oEventArgs.Action)
|
|
|
|
{
|
|
|
|
case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
|
|
|
|
|
2023-04-19 12:14:14 +02:00
|
|
|
// New bike available (new arrived at station or bike was booked on a different device)
|
2022-09-06 16:08:19 +02:00
|
|
|
foreach (var bike in BikeCollection)
|
|
|
|
{
|
|
|
|
if (Contains(bike.Id))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
var bikeViewModel = BikeViewModelFactory.Create(
|
|
|
|
IsConnectedDelegate,
|
|
|
|
ConnectorFactory,
|
2023-04-05 15:02:10 +02:00
|
|
|
GeolocationService,
|
2022-09-06 16:08:19 +02:00
|
|
|
LockService,
|
|
|
|
(id) => Remove(id),
|
|
|
|
() => m_oViewUpdateManager,
|
|
|
|
SmartDevice,
|
|
|
|
ViewService,
|
|
|
|
bike,
|
|
|
|
User,
|
2023-07-04 11:06:38 +02:00
|
|
|
ViewContext,
|
2022-09-06 16:08:19 +02:00
|
|
|
m_oItemFactory(),
|
|
|
|
this,
|
|
|
|
OpenUrlInBrowser);
|
|
|
|
|
|
|
|
bikeViewModel.PropertyChanged += OnBikeRequestHandlerPropertyChanged;
|
|
|
|
|
|
|
|
Add(bikeViewModel);
|
|
|
|
}
|
2021-05-13 20:03:07 +02:00
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
break;
|
2021-05-13 20:03:07 +02:00
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
|
2021-05-13 20:03:07 +02:00
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
// Bike was removed (either a different user requested/ booked a bike or request expired or bike was returned.)
|
|
|
|
foreach (BikeViewModelBase l_oBike in Items)
|
|
|
|
{
|
|
|
|
if (!BikeCollection.ContainsKey(l_oBike.Id))
|
|
|
|
{
|
|
|
|
l_oBike.PropertyChanged -= OnBikeRequestHandlerPropertyChanged;
|
2021-05-13 20:03:07 +02:00
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
Remove(l_oBike);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2021-05-13 20:03:07 +02:00
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
break;
|
2022-10-17 18:45:38 +02:00
|
|
|
|
|
|
|
case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
|
|
|
|
// Empty collection.
|
|
|
|
// Occurs in context of find bike page when searching for second, third, ... bike (reopen of page via flyout).
|
|
|
|
ClearItems();
|
|
|
|
break;
|
2022-09-06 16:08:19 +02:00
|
|
|
}
|
|
|
|
}
|
2021-05-13 20:03:07 +02:00
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
/// <summary> All bikes to be displayed. </summary>
|
|
|
|
protected BikeCollectionMutable BikeCollection { get; private set; }
|
2021-05-13 20:03:07 +02:00
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
protected User User { get; private set; }
|
2021-05-13 20:03:07 +02:00
|
|
|
|
2023-07-04 11:06:38 +02:00
|
|
|
/// <summary> Holds the view context in which bikes view model is used.</summary>
|
|
|
|
private ViewContext ViewContext { get; }
|
|
|
|
|
2021-06-26 20:57:55 +02:00
|
|
|
#if USCSHARP9
|
|
|
|
public bool IsReportLevelVerbose { get; init; }
|
|
|
|
#else
|
2022-09-06 16:08:19 +02:00
|
|
|
public bool IsReportLevelVerbose { get; set; }
|
2021-06-26 20:57:55 +02:00
|
|
|
#endif
|
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
/// <summary> Specified whether code is run under iOS or Android.</summary>
|
|
|
|
protected string RuntimePlatform { get; private set; }
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Service to manage permissions (location) of the app.
|
|
|
|
/// </summary>
|
|
|
|
protected ILocationPermission PermissionsService { get; private set; }
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Service to manage bluetooth stack.
|
|
|
|
/// </summary>
|
|
|
|
protected IBluetoothLE BluetoothService { get; private set; }
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// User which is logged in.
|
|
|
|
/// </summary>
|
|
|
|
public User ActiveUser
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return User;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Exception which occurred getting bike information.
|
|
|
|
/// </summary>
|
|
|
|
protected Exception Exception
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return m_oException;
|
|
|
|
}
|
|
|
|
|
|
|
|
set
|
|
|
|
{
|
|
|
|
var l_oException = m_oException;
|
|
|
|
var statusInfoText = StatusInfoText;
|
|
|
|
m_oException = value;
|
|
|
|
if ((m_oException != null && l_oException == null)
|
|
|
|
|| (m_oException == null && l_oException != null))
|
|
|
|
{
|
|
|
|
// Because an error occurred non error related info must be hidden.
|
|
|
|
OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsIdle)));
|
|
|
|
OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsBikesListVisible)));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (statusInfoText != StatusInfoText)
|
|
|
|
{
|
|
|
|
OnPropertyChanged(new PropertyChangedEventArgs(nameof(StatusInfoText)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Bike selected in list of bikes, null if no bike is selected.
|
|
|
|
/// Binds to GUI.
|
|
|
|
/// </summary>
|
|
|
|
public BikeViewModelBase SelectedBike { get; set; }
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// True if bikes list has to be displayed.
|
|
|
|
/// </summary>
|
|
|
|
public bool IsBikesListVisible
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
// If an exception occurred there is no information about occupied bikes available.
|
|
|
|
return Count > 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary> Used to block more than on copri requests at a given time.</summary>
|
|
|
|
private bool isIdle = false;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// True if any action can be performed (request and cancel request)
|
|
|
|
/// </summary>
|
|
|
|
public virtual bool IsIdle
|
|
|
|
{
|
|
|
|
get => isIdle;
|
|
|
|
set
|
|
|
|
{
|
|
|
|
if (value == isIdle)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Log.ForContext<BikesViewModel>().Debug($"Switch value of {nameof(IsIdle)} to {value}.");
|
|
|
|
isIdle = value;
|
|
|
|
base.OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsIdle)));
|
2023-01-18 14:22:51 +01:00
|
|
|
base.OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsProcessWithRunningProcessView)));
|
2022-09-06 16:08:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-31 12:20:06 +02:00
|
|
|
/// <summary> Used to display active rental process.</summary>
|
2023-08-31 12:31:38 +02:00
|
|
|
private IRentalProcessViewModel _rentalProcess = new RentalProcessViewModel();
|
2023-08-31 12:20:06 +02:00
|
|
|
|
|
|
|
/// <summary> Holds the active rental process.</summary>
|
2023-08-31 12:31:38 +02:00
|
|
|
public IRentalProcessViewModel RentalProcess => _rentalProcess;
|
2023-08-31 12:20:06 +02:00
|
|
|
|
2023-08-31 12:31:38 +02:00
|
|
|
/// <summary>
|
|
|
|
/// Starts the rental process.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="processViewModel">Rental process values to start with.</param>
|
|
|
|
public void StartRentalProcess(IRentalProcessViewModel processViewModel)
|
|
|
|
{
|
|
|
|
if (processViewModel == _rentalProcess)
|
|
|
|
return;
|
2023-08-31 12:20:06 +02:00
|
|
|
|
2023-08-31 12:31:38 +02:00
|
|
|
_rentalProcess.LoadFrom(processViewModel);
|
|
|
|
BikeInRentalProcess = this.FirstOrDefault(bike => bike.Id == _rentalProcess.BikeId) as Bike.BluetoothLock.BikeViewModel;
|
2023-08-31 12:20:06 +02:00
|
|
|
|
2023-08-31 12:31:38 +02:00
|
|
|
base.OnPropertyChanged(new PropertyChangedEventArgs(nameof(RentalProcess)));
|
|
|
|
base.OnPropertyChanged(new PropertyChangedEventArgs(nameof(BikeInRentalProcess)));
|
2023-08-31 12:20:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-18 14:22:51 +01:00
|
|
|
public bool IsProcessWithRunningProcessView => !isIdle;
|
2022-09-06 16:08:19 +02:00
|
|
|
|
|
|
|
/// <summary> Holds info about current action. </summary>
|
|
|
|
private string actionText;
|
|
|
|
|
|
|
|
/// <summary> Holds info about current action. </summary>
|
|
|
|
public string ActionText
|
|
|
|
{
|
|
|
|
get => actionText;
|
|
|
|
set
|
|
|
|
{
|
|
|
|
var statusInfoText = StatusInfoText;
|
|
|
|
actionText = value;
|
|
|
|
|
|
|
|
if (statusInfoText == StatusInfoText)
|
|
|
|
{
|
|
|
|
// Nothing to do because value did not change.
|
|
|
|
Log.ForContext<BikesViewModel>().Debug($"Property {nameof(ActionText)} set to value \"{actionText}\" but {nameof(StatusInfoText)} did not change.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Log.ForContext<BikesViewModel>().Debug($"Property {nameof(ActionText)} set to value \"{actionText}\" .");
|
|
|
|
OnPropertyChanged(new PropertyChangedEventArgs(nameof(StatusInfoText)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary> Holds information whether app is connected to web or not. </summary>
|
|
|
|
protected bool? isConnected = null;
|
|
|
|
|
|
|
|
/// <summary>Exposes the is connected state. </summary>
|
|
|
|
protected bool IsConnected
|
|
|
|
{
|
|
|
|
get => isConnected ?? false;
|
|
|
|
set
|
|
|
|
{
|
|
|
|
var statusInfoText = StatusInfoText;
|
|
|
|
isConnected = value;
|
|
|
|
if (statusInfoText == StatusInfoText)
|
|
|
|
{
|
|
|
|
// Nothing to do.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
OnPropertyChanged(new PropertyChangedEventArgs(nameof(StatusInfoText)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary> Holds the status information text. </summary>
|
|
|
|
public string StatusInfoText
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2023-08-31 12:20:06 +02:00
|
|
|
//if (Exception != null)
|
|
|
|
//{
|
|
|
|
// // An error occurred getting data from copri.
|
|
|
|
// return Exception.GetShortErrorInfoText(IsReportLevelVerbose);
|
|
|
|
//}
|
2023-03-08 13:18:54 +01:00
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
return ActionText ?? string.Empty;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Removes a bike view model by id.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="id">Id of bike to removed.</param>
|
|
|
|
public void Remove(string id)
|
|
|
|
{
|
|
|
|
foreach (var bike in BikeCollection)
|
|
|
|
{
|
|
|
|
if (bike.Id == id)
|
|
|
|
{
|
|
|
|
BikeCollection.Remove(bike);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets whether a bike is contained in collection of bikes.
|
|
|
|
/// </summary>
|
2023-04-19 12:14:14 +02:00
|
|
|
/// <param name="id">Id of bike to check existence.</param>
|
2022-09-06 16:08:19 +02:00
|
|
|
/// <returns>True if bike exists.</returns>
|
|
|
|
private bool Contains(string id)
|
|
|
|
{
|
|
|
|
foreach (var l_oBike in Items)
|
|
|
|
{
|
|
|
|
if (l_oBike.Id == id)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Transforms bikes view model object to string.
|
|
|
|
/// </summary>
|
|
|
|
/// <returns></returns>
|
|
|
|
public new string ToString()
|
|
|
|
{
|
|
|
|
var l_oToString = string.Empty;
|
|
|
|
foreach (var item in Items)
|
|
|
|
{
|
|
|
|
l_oToString += item.ToString();
|
|
|
|
}
|
|
|
|
|
|
|
|
return l_oToString;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
2022-10-17 18:45:38 +02:00
|
|
|
/// Invoked when page is shown and starts update process.
|
2022-09-06 16:08:19 +02:00
|
|
|
/// </summary>
|
2023-04-19 12:14:14 +02:00
|
|
|
/// <param name="updateAction"> Update function passed as argument by child class.</param>
|
2022-09-06 16:08:19 +02:00
|
|
|
protected async Task OnAppearing(Action updateAction)
|
2022-10-17 18:45:38 +02:00
|
|
|
=> await StartUpdateTask(updateAction);
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Starts update process.
|
|
|
|
/// </summary>
|
2023-04-19 12:14:14 +02:00
|
|
|
/// <param name="updateAction"> Update function passed as argument by child class.</param>
|
2022-10-17 18:45:38 +02:00
|
|
|
public async Task StartUpdateTask(Action updateAction)
|
2022-09-06 16:08:19 +02:00
|
|
|
{
|
|
|
|
m_oViewUpdateManager = new PollingUpdateTaskManager(updateAction);
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Update bikes at station or my bikes depending on context.
|
2023-08-31 12:20:06 +02:00
|
|
|
await m_oViewUpdateManager.StartAsync(m_oPolling);
|
2022-09-06 16:08:19 +02:00
|
|
|
}
|
|
|
|
catch (Exception l_oExcetion)
|
|
|
|
{
|
|
|
|
Exception = l_oExcetion;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Invoked when page is shutdown.
|
|
|
|
/// Currently invoked by code behind, would be nice if called by XAML in future versions.
|
|
|
|
/// </summary>
|
2022-10-17 18:45:38 +02:00
|
|
|
public virtual async Task OnDisappearing()
|
2023-08-31 12:20:06 +02:00
|
|
|
=> await m_oViewUpdateManager.StopAsync();
|
2022-09-06 16:08:19 +02:00
|
|
|
}
|
2023-07-04 11:06:38 +02:00
|
|
|
|
2022-10-17 18:45:38 +02:00
|
|
|
}
|