2022-11-17 10:05:05 +01:00
using Xamarin.Forms ;
2021-07-22 22:41:35 +02:00
using TINK.View ;
2023-04-19 12:14:14 +02:00
using TINK.Model.Stations ;
2021-07-22 22:41:35 +02:00
using System ;
using System.Linq ;
2022-08-30 15:42:25 +02:00
using TINK.Model.Bikes ;
2021-07-22 22:41:35 +02:00
using TINK.Repository.Exception ;
using TINK.Model ;
using Serilog ;
using System.Collections.Generic ;
using System.Threading.Tasks ;
using System.ComponentModel ;
using Xamarin.Forms.GoogleMaps ;
using System.Collections.ObjectModel ;
2021-08-28 10:04:10 +02:00
#if USEFLYOUT
2021-07-22 22:41:35 +02:00
using TINK.View.MasterDetail ;
#endif
2021-11-07 19:42:59 +01:00
using TINK.Services.Permissions ;
2021-07-22 22:41:35 +02:00
using Xamarin.Essentials ;
using System.Threading ;
using TINK.MultilingualResources ;
using TINK.Repository ;
2022-04-10 17:38:34 +02:00
using TINK.Services.Geolocation ;
2022-08-30 15:42:25 +02:00
using TINK.Model.State ;
2023-07-19 10:10:36 +02:00
using TINK.ViewModel.Map ;
using TINK.Model.Stations.StationNS ;
using TINK.Model.Bikes.BikeInfoNS.BC ;
2021-07-22 22:41:35 +02:00
namespace TINK.ViewModel.Contact
{
2022-09-06 16:08:19 +02:00
public class SelectStationPageViewModel : INotifyPropertyChanged
{
2023-04-19 12:14:14 +02:00
/// <summary> Holds the count of custom icons centered.</summary>
2022-09-06 16:08:19 +02:00
private const int CUSTOM_ICONS_COUNT = 30 ;
2021-07-22 22:41:35 +02:00
2022-09-06 16:08:19 +02:00
/// <summary> Reference on view service to show modal notifications and to perform navigation. </summary>
private IViewService ViewService { get ; }
2021-07-22 22:41:35 +02:00
2022-09-06 16:08:19 +02:00
/// <summary>
/// Holds the exception which occurred getting bikes occupied information.
/// </summary>
private Exception m_oException ;
2021-07-22 22:41:35 +02:00
2022-09-06 16:08:19 +02:00
/// <summary>
/// Service to query/ manage permissions (location) of the app.
/// </summary>
private ILocationPermission PermissionsService { get ; }
2021-07-22 22:41:35 +02:00
2022-09-06 16:08:19 +02:00
/// <summary>
/// Service to manage bluetooth stack.
/// </summary>
private Plugin . BLE . Abstractions . Contracts . IBluetoothLE BluetoothService { get ; set ; }
2021-07-22 22:41:35 +02:00
2022-09-06 16:08:19 +02:00
/// <summary> Notifies view about changes. </summary>
public event PropertyChangedEventHandler PropertyChanged ;
2021-07-22 22:41:35 +02:00
2022-09-06 16:08:19 +02:00
/// <summary> Reference on the tink app instance. </summary>
private ITinkApp TinkApp { get ; }
2021-07-22 22:41:35 +02:00
2022-09-06 16:08:19 +02:00
/// <summary>Delegate to perform navigation.</summary>
private INavigation m_oNavigation ;
2021-07-22 22:41:35 +02:00
2021-08-28 10:04:10 +02:00
#if USEFLYOUT
2021-07-22 22:41:35 +02:00
/// <summary>Delegate to perform navigation.</summary>
private INavigationMasterDetail m_oNavigationMasterDetail ;
#endif
2022-09-06 16:08:19 +02:00
private ObservableCollection < Pin > pins ;
public ObservableCollection < Pin > Pins
{
get
{
if ( pins = = null )
pins = new ObservableCollection < Pin > ( ) ; // If view model is not binding context pins collection must be set programmatically.
return pins ;
}
set = > pins = value ;
}
/// <summary>Delegate to move map to region.</summary>
private Action < MapSpan > m_oMoveToRegionDelegate ;
/// <summary> False if user tabed on station marker to show bikes at a given station.</summary>
private bool isMapPageEnabled = false ;
2023-04-05 15:02:10 +02:00
IGeolocationService GeolocationService { get ; }
2022-09-06 16:08:19 +02:00
/// <summary> False if user tabed on station marker to show bikes at a given station.</summary>
public bool IsMapPageEnabled
{
get = > isMapPageEnabled ;
private set
{
if ( isMapPageEnabled = = value )
return ;
isMapPageEnabled = value ;
PropertyChanged ? . Invoke ( this , new PropertyChangedEventArgs ( nameof ( IsMapPageEnabled ) ) ) ;
}
}
/// <summary> Prevents an invalid instane to be created. </summary>
/// <param name="tinkApp"> Reference to tink app model.</param>
/// <param name="moveToRegionDelegate">Delegate to center map and set zoom level.</param>
/// <param name="viewService">View service to notify user.</param>
/// <param name="navigation">Interface to navigate.</param>
public SelectStationPageViewModel (
ITinkApp tinkApp ,
ILocationPermission permissionsService ,
Plugin . BLE . Abstractions . Contracts . IBluetoothLE bluetoothService ,
2023-04-05 15:02:10 +02:00
IGeolocationService geolocationService ,
2022-09-06 16:08:19 +02:00
Action < MapSpan > moveToRegionDelegate ,
IViewService viewService ,
INavigation navigation )
{
TinkApp = tinkApp
? ? throw new ArgumentException ( "Can not instantiate map page view model- object. No tink app object available." ) ;
PermissionsService = permissionsService ? ?
throw new ArgumentException ( $"Can not instantiate {nameof(SelectStationPageViewModel)}. Permissions service object must never be null." ) ;
BluetoothService = bluetoothService ? ?
throw new ArgumentException ( $"Can not instantiate {nameof(SelectStationPageViewModel)}. Bluetooth service object must never be null." ) ;
GeolocationService = geolocationService ? ?
throw new ArgumentException ( $"Can not instantiate {nameof(SelectStationPageViewModel)}. Geolocation service object must never be null." ) ;
m_oMoveToRegionDelegate = moveToRegionDelegate
? ? throw new ArgumentException ( "Can not instantiate map page view model- object. No move delegate available." ) ;
ViewService = viewService
? ? throw new ArgumentException ( "Can not instantiate map page view model- object. No view available." ) ;
m_oNavigation = navigation
? ? throw new ArgumentException ( "Can not instantiate map page view model- object. No navigation service available." ) ;
2021-07-22 22:41:35 +02:00
2021-08-28 10:04:10 +02:00
#if USEFLYOUT
2021-07-22 22:41:35 +02:00
m_oNavigationMasterDetail = new EmptyNavigationMasterDetail ( ) ;
#endif
2022-09-06 16:08:19 +02:00
IsConnected = TinkApp . GetIsConnected ( ) ;
}
2021-07-22 22:41:35 +02:00
2021-08-28 10:04:10 +02:00
#if USEFLYOUT
2021-07-22 22:41:35 +02:00
/// <summary> Delegate to perform navigation.</summary>
public INavigationMasterDetail NavigationMasterDetail
{
set { m_oNavigationMasterDetail = value ; }
}
#endif
2022-09-06 16:08:19 +02:00
public Command < PinClickedEventArgs > PinClickedCommand = > new Command < PinClickedEventArgs > (
args = >
{
OnStationClicked ( args . Pin . Tag . ToString ( ) ) ;
args . Handled = true ; // Prevents map to be centered to selected pin.
} ) ;
/// <summary>
/// One time setup: Sets pins into map and connects to events.
/// </summary>
2023-04-05 15:02:10 +02:00
private void InitializePins ( StationDictionary stations )
2022-09-06 16:08:19 +02:00
{
// Add pins to stations.
Log . ForContext < SelectStationPageViewModel > ( ) . Debug ( $"Request to draw {stations.Count} pins." ) ;
foreach ( var station in stations )
{
if ( station . Position = = null )
{
2023-04-19 12:14:14 +02:00
// There should be no reason for a position object to be null but this already occurred in past.
Log . ForContext < SelectStationPageViewModel > ( ) . Error ( "Position object of station {@l_oStation} is null." , station ) ;
2022-09-06 16:08:19 +02:00
continue ;
}
var l_oPin = new Pin
{
Position = new Xamarin . Forms . GoogleMaps . Position ( station . Position . Latitude , station . Position . Longitude ) ,
Label = long . TryParse ( station . Id , out long stationId ) & & stationId > CUSTOM_ICONS_COUNT
? station . GetStationName ( )
: string . Empty , // Stations with custom icons have already a id marker. No need for a label.
Tag = station . Id ,
IsVisible = false , // Set to false to prevent showing default icons (flickering).
} ;
Pins . Add ( l_oPin ) ;
}
}
/// <summary> Update all stations from TINK. </summary>
/// <param name="stationsColorList">List of colors to apply.</param>
private void UpdatePinsColor ( IList < Color > stationsColorList )
{
Log . ForContext < SelectStationPageViewModel > ( ) . Debug ( $"Starting update of stations pins color for {stationsColorList.Count} stations..." ) ;
// Update colors of pins.
for ( int pinIndex = 0 ; pinIndex < stationsColorList . Count ; pinIndex + + )
{
2022-11-17 10:05:05 +01:00
var indexPartPrefix = int . TryParse ( Pins [ pinIndex ] . Tag . ToString ( ) , out int stationId )
& & stationId < = CUSTOM_ICONS_COUNT
? $"{stationId}" // there is a station marker with index letter for given station id
: "Open" ; // there is no station marker. Use open marker.
2023-05-09 08:47:52 +02:00
var colorPartPrefix = GetResourceNameColorPart ( stationsColorList [ pinIndex ] ) ;
2022-11-17 10:05:05 +01:00
var l_iName = $"{indexPartPrefix.ToString().PadLeft(2, '0')}_{colorPartPrefix}{(DeviceInfo.Platform == DevicePlatform.Android ? " . png " : string.Empty)}" ;
try
{
Pins [ pinIndex ] . Icon = BitmapDescriptorFactory . FromBundle ( l_iName ) ;
}
catch ( Exception l_oException )
{
Log . ForContext < SelectStationPageViewModel > ( ) . Error ( "Station icon {l_strName} can not be loaded. {@l_oException}." , l_oException ) ;
Pins [ pinIndex ] . Label = stationId . ToString ( ) ;
Pins [ pinIndex ] . Icon = BitmapDescriptorFactory . DefaultMarker ( stationsColorList [ pinIndex ] ) ;
}
2022-09-06 16:08:19 +02:00
Pins [ pinIndex ] . IsVisible = true ;
}
var pinsCount = Pins . Count ;
for ( int pinIndex = stationsColorList . Count ; pinIndex < pinsCount ; pinIndex + + )
{
Log . ForContext < SelectStationPageViewModel > ( ) . Error ( $"Unexpected count of pins detected. Expected {stationsColorList.Count} but is {pinsCount}." ) ;
Pins [ pinIndex ] . IsVisible = false ;
}
Log . ForContext < SelectStationPageViewModel > ( ) . Debug ( "Update of stations pins color done." ) ;
}
/// <summary> Gets the color related part of the ressrouce name.</summary>
/// <param name="color">Color to get name for.</param>
/// <returns>Resource name.</returns>
2023-05-09 08:47:52 +02:00
private static string GetResourceNameColorPart ( Color color )
2022-09-06 16:08:19 +02:00
{
if ( color = = Color . Blue )
{
return "Blue" ;
}
if ( color = = Color . Green )
{
return "Green" ;
}
if ( color = = Color . LightBlue )
{
return "LightBlue" ;
}
if ( color = = Color . Red )
{
return "Red" ;
}
return color . ToString ( ) ;
}
/// <summary>
/// Invoked when page is shown.
/// Starts update process.
/// </summary>
/// <param name="p_oFilterDictionaryMapPage">Holds map page filter settings.</param>
/// <param name="p_oPolling">Holds polling management object.</param>
/// <param name="p_bIsShowWhatsNewRequired">If true whats new page will be shown.</param>
public async Task OnAppearing ( )
{
try
{
2023-01-18 14:22:51 +01:00
IsProcessWithRunningProcessView = true ;
2022-09-06 16:08:19 +02:00
// Process map page.
Log . ForContext < SelectStationPageViewModel > ( ) . Information (
$"Current UI language is {Thread.CurrentThread.CurrentUICulture.Name}." ) ;
if ( Pins . Count < = 0 )
{
2022-12-07 16:54:52 +01:00
// Move and scale before getting stations and bikes which takes some time.
if ( TinkApp . CenterMapToCurrentLocation )
2022-09-06 16:08:19 +02:00
{
2022-12-07 16:54:52 +01:00
ActionText = AppResources . ActivityTextRequestingLocationPermissions ;
2022-09-06 16:08:19 +02:00
2022-12-07 16:54:52 +01:00
// Check location permission
var status = await PermissionsService . CheckStatusAsync ( ) ;
if ( ! GeolocationService . IsSimulation
& & status ! = Status . Granted )
2022-09-06 16:08:19 +02:00
{
var dialogResult = await ViewService . DisplayAlert (
2023-08-31 12:20:06 +02:00
AppResources . MessageHintTitle ,
AppResources . ErrorMapCenterNoLocationPermissionOpenDialog ,
2022-09-06 16:08:19 +02:00
AppResources . MessageAnswerYes ,
AppResources . MessageAnswerNo ) ;
if ( dialogResult )
{
// User decided to give access to locations permissions.
PermissionsService . OpenAppSettings ( ) ;
2023-02-22 14:03:35 +01:00
ActionText = string . Empty ;
2023-01-18 14:22:51 +01:00
IsProcessWithRunningProcessView = false ;
2022-09-06 16:08:19 +02:00
IsMapPageEnabled = true ;
return ;
}
}
2022-12-07 16:54:52 +01:00
if ( status = = Status . Granted )
{
ActionText = AppResources . ActivityTextCenterMap ;
2022-09-06 16:08:19 +02:00
2023-04-05 15:02:10 +02:00
IGeolocation currentLocation = null ;
2022-12-07 16:54:52 +01:00
try
{
currentLocation = TinkApp . CenterMapToCurrentLocation
? await GeolocationService . GetAsync ( )
: null ;
}
catch ( Exception ex )
{
Log . ForContext < SelectStationPageViewModel > ( ) . Error ( "Getting location failed. {Exception}" , ex ) ;
}
2022-09-06 16:08:19 +02:00
2022-12-07 16:54:52 +01:00
MoveAndScale ( m_oMoveToRegionDelegate , TinkApp . Uris . ActiveUri , currentLocation ) ;
}
}
2022-09-06 16:08:19 +02:00
}
ActionText = AppResources . ActivityTextMapLoadingStationsAndBikes ;
IsConnected = TinkApp . GetIsConnected ( ) ;
var resultStationsAndBikes = await TinkApp . GetConnector ( IsConnected ) . Query . GetBikesAndStationsAsync ( ) ;
TinkApp . Stations = resultStationsAndBikes . Response . StationsAll ;
TinkApp . ResourceUrls = resultStationsAndBikes . GeneralData . ResourceUrls ;
if ( Pins . Count > 0 & & Pins . Count ! = resultStationsAndBikes . Response . StationsAll . Count )
{
// Either
// - user logged in/ logged out which might lead to more/ less stations beeing available
// - new stations were added/ existing ones remove
Pins . Clear ( ) ;
}
2023-04-19 12:14:14 +02:00
// Check if there are already any pins to the map
// i.e detects first call of member OnAppearing after construction
2022-09-06 16:08:19 +02:00
if ( Pins . Count < = 0 )
{
// Map was not yet initialized.
// Get stations from Copri
Log . ForContext < SelectStationPageViewModel > ( ) . Verbose ( "No pins detected on page." ) ;
if ( resultStationsAndBikes . Response . StationsAll . CopriVersion < CopriCallsStatic . UnsupportedVersionLower )
{
await ViewService . DisplayAlert (
AppResources . MessageWaring ,
string . Format ( AppResources . MessageCopriVersionIsOutdated , TinkApp . Flavor . GetDisplayName ( ) ) ,
AppResources . MessageAnswerOk ) ;
Log . ForContext < SelectStationPageViewModel > ( ) . Error ( $"Outdated version of app detected. Version expected is {resultStationsAndBikes.Response.StationsAll.CopriVersion}." ) ;
}
if ( resultStationsAndBikes . Response . StationsAll . CopriVersion > = CopriCallsStatic . UnsupportedVersionUpper )
{
await ViewService . DisplayAlert (
AppResources . MessageWaring ,
string . Format ( AppResources . MessageAppVersionIsOutdated , TinkApp . Flavor . GetDisplayName ( ) ) ,
AppResources . MessageAnswerOk ) ;
Log . ForContext < SelectStationPageViewModel > ( ) . Error ( $"Outdated version of app detected. Version expected is {resultStationsAndBikes.Response.StationsAll.CopriVersion}." ) ;
}
// Set pins to their positions on map.
InitializePins ( resultStationsAndBikes . Response . StationsAll ) ;
Log . ForContext < SelectStationPageViewModel > ( ) . Verbose ( "Update of pins done." ) ;
}
if ( resultStationsAndBikes . Exception ? . GetType ( ) = = typeof ( AuthcookieNotDefinedException ) )
{
Log . ForContext < SelectStationPageViewModel > ( ) . Error ( "Map page is shown (probable for the first time after startup of app) and COPRI auth cookie is not defined. {@l_oException}" , resultStationsAndBikes . Exception ) ;
// COPRI reports an auth cookie error.
await ViewService . DisplayAlert (
AppResources . MessageWaring ,
2023-08-31 12:20:06 +02:00
AppResources . ErrorMapPageAuthcookieUndefined ,
2022-09-06 16:08:19 +02:00
AppResources . MessageAnswerOk ) ;
IsConnected = TinkApp . GetIsConnected ( ) ;
await TinkApp . GetConnector ( IsConnected ) . Command . DoLogout ( ) ;
TinkApp . ActiveUser . Logout ( ) ;
}
// Update pin colors.
Log . ForContext < SelectStationPageViewModel > ( ) . Verbose ( "Starting update pins color..." ) ;
var colors = GetStationColors (
Pins . Select ( x = > x . Tag . ToString ( ) ) . ToList ( ) ,
2023-07-19 10:10:36 +02:00
resultStationsAndBikes . Response . StationsAll ,
2023-05-09 08:47:52 +02:00
resultStationsAndBikes . Response . BikesOccupied ) ;
2022-09-06 16:08:19 +02:00
// Update pins color form count of bikes located at station.
UpdatePinsColor ( colors ) ;
Log . ForContext < SelectStationPageViewModel > ( ) . Verbose ( "Update pins color done." ) ;
Exception = resultStationsAndBikes . Exception ;
2023-02-22 14:03:35 +01:00
ActionText = string . Empty ;
2023-01-18 14:22:51 +01:00
IsProcessWithRunningProcessView = false ;
2022-09-06 16:08:19 +02:00
IsMapPageEnabled = true ;
}
catch ( Exception l_oException )
{
Log . ForContext < SelectStationPageViewModel > ( ) . Error ( $"An error occurred opening select station page.\r\n{l_oException.Message}" ) ;
2023-01-18 14:22:51 +01:00
IsProcessWithRunningProcessView = false ;
2022-09-06 16:08:19 +02:00
await ViewService . DisplayAlert (
2023-08-31 12:20:06 +02:00
AppResources . ErrorPageNotLoadedTitle ,
$"{AppResources.ErrorPageNotLoaded}\r\n{l_oException.Message}" ,
AppResources . MessageAnswerOk ) ;
2022-09-06 16:08:19 +02:00
IsMapPageEnabled = true ;
}
}
/// <summary> Moves map and scales visible region depending on active filter. </summary>
public static void MoveAndScale (
Action < MapSpan > moveToRegionDelegate ,
Uri activeUri ,
2023-04-05 15:02:10 +02:00
IGeolocation currentLocation = null )
2022-09-06 16:08:19 +02:00
{
if ( currentLocation ! = null )
{
// Move to current location.
moveToRegionDelegate ( MapSpan . FromCenterAndRadius (
new Xamarin . Forms . GoogleMaps . Position ( currentLocation . Latitude , currentLocation . Longitude ) ,
Distance . FromKilometers ( 1.0 ) ) ) ;
return ;
}
// Center map to Freiburg
moveToRegionDelegate ( MapSpan . FromCenterAndRadius (
new Xamarin . Forms . GoogleMaps . Position ( 47.995865 , 7.815086 ) ,
Distance . FromKilometers ( 2.9 ) ) ) ;
}
/// <summary> User clicked on a bike. </summary>
/// <param name="selectedStationId">Id of station user clicked on.</param>
public async void OnStationClicked ( string selectedStationId )
{
2022-11-17 10:05:05 +01:00
try
{
Log . ForContext < SelectStationPageViewModel > ( ) . Information ( $"User taped station {selectedStationId}." ) ;
2022-09-06 16:08:19 +02:00
2022-11-17 10:05:05 +01:00
// Lock action to prevent multiple instances of "BikeAtStation" being opened.
IsMapPageEnabled = false ;
TinkApp . SelectedStation = TinkApp . Stations . FirstOrDefault ( x = > x . Id = = selectedStationId )
2023-04-19 12:14:14 +02:00
? ? new Model . Stations . StationNS . Station ( selectedStationId , new List < string > ( ) , null ) ; // Station might not be in list StationDictinaly because this list is not updated in background task.
2021-07-22 22:41:35 +02:00
#if TRYNOTBACKSTYLE
m_oNavigation . ShowPage (
typeof ( BikesAtStationPage ) ,
p_strStationName ) ;
#else
2022-01-22 18:32:22 +01:00
#if USEFLYOUT
2021-07-22 22:41:35 +02:00
// Show page.
ViewService . ShowPage ( ViewTypes . ContactPage , AppResources . MarkingContactPageTitle ) ;
2022-01-22 18:32:22 +01:00
#else
2022-11-17 10:05:05 +01:00
await ViewService . ShowPage ( "//ContactPage" ) ;
#endif
IsMapPageEnabled = true ;
2023-02-22 14:03:35 +01:00
ActionText = string . Empty ;
2022-11-17 10:05:05 +01:00
}
catch ( Exception exception )
{
IsMapPageEnabled = true ;
2023-02-22 14:03:35 +01:00
ActionText = string . Empty ;
2022-11-17 10:05:05 +01:00
Log . ForContext < SelectStationPageViewModel > ( ) . Error ( "Fehler beim Öffnen der Ansicht \"Fahrräder an Station\" aufgetreten. {Exception}" , exception ) ;
2023-08-31 12:20:06 +02:00
await ViewService . DisplayAlert (
AppResources . ErrorPageNotLoadedTitle ,
$"{AppResources.ErrorPageNotLoaded}\r\n{exception.Message}" ,
AppResources . MessageAnswerOk ) ;
2022-11-17 10:05:05 +01:00
}
2022-01-22 18:32:22 +01:00
#endif
2022-09-06 16:08:19 +02:00
}
/// <summary>
/// Gets the list of station color for all stations.
/// </summary>
/// <param name="stationsId">Station id list to get color for.</param>
2023-07-19 10:10:36 +02:00
/// <param name="stations">Station object dictionary to get count of available bike from for each station.</param>
/// <param name="bikesReserved">Bike collection to get count of reserved/ rented bikes from for each station.</param>
2022-09-06 16:08:19 +02:00
/// <returns></returns>
2023-07-19 10:10:36 +02:00
internal static IList < Color > GetStationColors (
IEnumerable < string > stationsId ,
IEnumerable < IStation > stations ,
IEnumerable < BikeInfo > bikesReserved )
2022-09-06 16:08:19 +02:00
{
if ( stationsId = = null )
{
Log . ForContext < SelectStationPageViewModel > ( ) . Debug ( "No stations available to update color for." ) ;
return new List < Color > ( ) ;
}
2023-07-19 10:10:36 +02:00
if ( stations = = null )
2022-09-06 16:08:19 +02:00
{
2023-07-19 10:10:36 +02:00
Log . ForContext < SelectStationPageViewModel > ( ) . Error ( "No stations info available to get count of bikes available to determine whether a pin is green or not." ) ;
}
if ( bikesReserved = = null )
{
Log . ForContext < SelectStationPageViewModel > ( ) . Error ( "No bikes info available to determine whether a pins is light blue or not." ) ;
2022-09-06 16:08:19 +02:00
}
// Get state for each station.
var colors = new List < Color > ( ) ;
foreach ( var stationId in stationsId )
{
2022-12-13 10:53:08 +01:00
// Get color of given station.
2023-07-19 10:10:36 +02:00
if ( bikesReserved ? . Where ( x = > x . StationId = = stationId ) . Count ( ) > 0 )
2022-09-06 16:08:19 +02:00
{
2022-12-13 10:53:08 +01:00
// There is at least one requested or booked bike
colors . Add ( Color . LightBlue ) ;
continue ;
}
2022-09-06 16:08:19 +02:00
2023-07-19 10:10:36 +02:00
if ( stations ? . FirstOrDefault ( x = > x . Id = = stationId ) ? . AvailableBikesCount > 0 )
2022-12-13 10:53:08 +01:00
{
// There is at least one bike available
colors . Add ( Color . Green ) ;
continue ;
2022-11-17 10:05:05 +01:00
}
2022-12-13 10:53:08 +01:00
colors . Add ( Color . Red ) ;
2022-09-06 16:08:19 +02:00
}
return colors ;
}
/// <summary>
/// Exception which occurred getting bike information.
/// </summary>
public Exception Exception
{
get
{
return m_oException ;
}
private set
{
var statusInfoText = StatusInfoText ;
m_oException = value ;
if ( statusInfoText = = StatusInfoText )
{
// Nothing to do because value did not change.
return ;
}
PropertyChanged ? . Invoke ( this , new PropertyChangedEventArgs ( nameof ( StatusInfoText ) ) ) ;
}
}
/// <summary> Holds info about current action. </summary>
private string actionText ;
/// <summary> Holds info about current action. </summary>
private string ActionText
{
get = > actionText ;
set
{
var statusInfoText = StatusInfoText ;
actionText = value ;
if ( statusInfoText = = StatusInfoText )
{
// Nothing to do because value did not change.
return ;
}
PropertyChanged ? . Invoke ( this , new PropertyChangedEventArgs ( nameof ( StatusInfoText ) ) ) ;
}
}
/// <summary> Used to block more than on copri requests at a given time.</summary>
2023-01-18 14:22:51 +01:00
private bool isProcessWithRunningProcessView = false ;
2022-09-06 16:08:19 +02:00
/// <summary>
/// True if any action can be performed (request and cancel request)
/// </summary>
2023-01-18 14:22:51 +01:00
public bool IsProcessWithRunningProcessView
2022-09-06 16:08:19 +02:00
{
2023-01-18 14:22:51 +01:00
get = > isProcessWithRunningProcessView ;
2022-09-06 16:08:19 +02:00
set
{
2023-01-18 14:22:51 +01:00
if ( value = = isProcessWithRunningProcessView )
2022-09-06 16:08:19 +02:00
return ;
2023-01-18 14:22:51 +01:00
Log . ForContext < SelectStationPageViewModel > ( ) . Debug ( $"Switch value of {nameof(isProcessWithRunningProcessView)} to {value}." ) ;
isProcessWithRunningProcessView = value ;
PropertyChanged ? . Invoke ( this , new PropertyChangedEventArgs ( nameof ( IsProcessWithRunningProcessView ) ) ) ;
2022-09-06 16:08:19 +02:00
}
}
/// <summary> Holds information whether app is connected to web or not. </summary>
private bool? isConnected = null ;
/// <summary>Exposes the is connected state. </summary>
private bool IsConnected
{
get = > isConnected ? ? false ;
set
{
var statusInfoText = StatusInfoText ;
isConnected = value ;
if ( statusInfoText = = StatusInfoText )
{
// Nothing to do.
return ;
}
PropertyChanged ? . Invoke ( this , 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(TinkApp.IsReportLevelVerbose);
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
//}
2022-09-06 16:08:19 +02:00
return ActionText ? ? string . Empty ;
}
}
}
2021-07-22 22:41:35 +02:00
}