mirror of
https://dev.azure.com/TeilRad/sharee.bike%20App/_git/Code
synced 2025-06-22 05:47:28 +02:00
Version 3.0.337
This commit is contained in:
parent
fd0e63cf10
commit
573fe77e12
2336 changed files with 33688 additions and 86082 deletions
|
@ -1,6 +1,4 @@
|
|||
using System.ComponentModel;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace System.Runtime.CompilerServices
|
||||
{
|
||||
#if USCSHARP9
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
namespace TINK.Model.Bikes.Bike.BluetoothLock
|
||||
{
|
||||
public interface IBikeInfoMutable : BC.IBikeInfoMutable
|
||||
{
|
||||
ILockInfoMutable LockInfo { get; }
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
using System;
|
||||
using TINK.Model.Bikes.Bike.CopriLock;
|
||||
|
||||
namespace TINK.Model.Bike.CopriLock
|
||||
{
|
||||
public class BikeInfoMutable : BC.BikeInfoMutable, IBikeInfoMutable
|
||||
{
|
||||
/// <summary> Constructs a bike object from source. </summary>
|
||||
public BikeInfoMutable(BikeInfo bike, string stationName) : base(
|
||||
bike?.Id ?? throw new ArgumentException(nameof(bike)),
|
||||
bike.LockModel,
|
||||
bike.IsDemo,
|
||||
bike.Group,
|
||||
bike.WheelType,
|
||||
bike.TypeOfBike,
|
||||
bike.Description,
|
||||
bike.StationId,
|
||||
stationName,
|
||||
bike.OperatorUri,
|
||||
bike.TariffDescription,
|
||||
() => DateTime.Now,
|
||||
bike.State)
|
||||
{
|
||||
LockInfo = new LockInfoMutable(bike.LockInfo.State);
|
||||
}
|
||||
|
||||
public LockInfoMutable LockInfo { get; }
|
||||
|
||||
ILockInfoMutable IBikeInfoMutable.LockInfo => LockInfo;
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
namespace TINK.Model.Bikes.Bike.CopriLock
|
||||
{
|
||||
public interface IBikeInfoMutable : BC.IBikeInfoMutable
|
||||
{
|
||||
ILockInfoMutable LockInfo { get; }
|
||||
}
|
||||
}
|
|
@ -4,14 +4,14 @@ using System.Collections.Generic;
|
|||
|
||||
using System.Linq;
|
||||
|
||||
using BikeInfo = TINK.Model.Bike.BC.BikeInfo;
|
||||
using BikeInfo = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfo;
|
||||
|
||||
namespace TINK.Model.Bike
|
||||
namespace TINK.Model.Bikes
|
||||
{
|
||||
public class BikeCollection : IBikeDictionary<BikeInfo>
|
||||
public class BikeCollection : IBikeDictionary<BikeInfo>
|
||||
{
|
||||
/// <summary> Holds the bike dictionary object.</summary>
|
||||
private Dictionary<string, BikeInfo> BikeDictionary { get; }
|
||||
private Dictionary<string, BikeInfo> BikeDictionary { get; }
|
||||
|
||||
/// <summary>Constructs an empty bike info dictionary object.</summary>
|
||||
public BikeCollection()
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TINK.Model.Bike;
|
||||
using TINK.Model.Bikes;
|
||||
|
||||
using BikeInfo = TINK.Model.Bike.BC.BikeInfo;
|
||||
using BikeInfo = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfo;
|
||||
|
||||
namespace TINK.Model
|
||||
{
|
||||
|
@ -18,7 +18,7 @@ namespace TINK.Model
|
|||
{
|
||||
return new BikeCollection(bikesAtAnyStation?
|
||||
.Where(bike => !string.IsNullOrEmpty(selectedStation) && bike.StationId == selectedStation)
|
||||
.ToDictionary(x => x.Id) ?? new Dictionary<string, BikeInfo>());
|
||||
.ToDictionary(bike => bike.Id) ?? new Dictionary<string, BikeInfo>());
|
||||
}
|
||||
|
||||
/// <summary> Filters bikes by bike type. </summary>
|
||||
|
@ -27,7 +27,7 @@ namespace TINK.Model
|
|||
public static BikeCollection GetLockIt(this BikeCollection bcAndLockItBikes)
|
||||
{
|
||||
return new BikeCollection(bcAndLockItBikes?
|
||||
.Where(bike => bike is Bike.BluetoothLock.BikeInfo)
|
||||
.Where(bike => bike is Bikes.BikeInfoNS.BluetoothLock.BikeInfo)
|
||||
.ToDictionary(x => x.Id) ?? new Dictionary<string, BikeInfo>());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
using Serilog;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using Serilog;
|
||||
using TINK.Model.Station;
|
||||
using BikeInfo = TINK.Model.Bike.BC.BikeInfo;
|
||||
using BikeInfoMutable = TINK.Model.Bike.BC.BikeInfoMutable;
|
||||
using BikeInfo = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfo;
|
||||
using BikeInfoMutable = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfoMutable;
|
||||
|
||||
namespace TINK.Model.Bike
|
||||
namespace TINK.Model.Bikes
|
||||
{
|
||||
/// <summary> Holds entity of bikes. </summary>
|
||||
public class BikeCollectionMutable : ObservableCollection<BikeInfoMutable>, IBikeDictionaryMutable<BikeInfoMutable>
|
||||
|
@ -26,7 +26,7 @@ namespace TINK.Model.Bike
|
|||
/// <param name="bikesAll"> Object holding bikes info from copri to update from. Holds station id but not station name.</param>
|
||||
/// <param name="stations"> All stations to get station names from.</param>
|
||||
/// <param name="p_oDateTimeProvider">Provices date time information.</param>
|
||||
public void Update(IEnumerable<BikeInfo> bikesAll,
|
||||
public void Update(IEnumerable<BikeInfo> bikesAll,
|
||||
IEnumerable<IStation> stations)
|
||||
{
|
||||
// Get list of current bikes by state(s) to update.
|
||||
|
@ -54,7 +54,7 @@ namespace TINK.Model.Bike
|
|||
}
|
||||
|
||||
// Update bike.
|
||||
GetById(bikeInfo.Id).State.Load(bikeInfo.State);
|
||||
GetById(bikeInfo.Id).State.Load(bikeInfo.State);
|
||||
|
||||
if (bikesToBeRemoved.Contains<string>(bikeInfo.Id))
|
||||
{
|
||||
|
@ -88,7 +88,7 @@ namespace TINK.Model.Bike
|
|||
|
||||
base.Add(newBike);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Bike selected by user for regerving or cancel reservation.
|
||||
/// </summary>
|
||||
|
@ -147,16 +147,16 @@ namespace TINK.Model.Bike
|
|||
public static class BikeInfoMutableFactory
|
||||
{
|
||||
public static BikeInfoMutable Create(
|
||||
BikeInfo bikeInfo,
|
||||
BikeInfo bikeInfo,
|
||||
string stationName)
|
||||
{
|
||||
if (bikeInfo is BluetoothLock.BikeInfo btBikeInfo)
|
||||
if (bikeInfo is Bikes.BikeInfoNS.BluetoothLock.BikeInfo btBikeInfo)
|
||||
{
|
||||
return new BluetoothLock.BikeInfoMutable(btBikeInfo, stationName);
|
||||
}
|
||||
else if (bikeInfo is CopriLock.BikeInfo copriBikeInfo)
|
||||
return new Bikes.BikeInfoNS.BluetoothLock.BikeInfoMutable(btBikeInfo, stationName);
|
||||
}
|
||||
else if (bikeInfo is BikeInfoNS.CopriLock.BikeInfo copriBikeInfo)
|
||||
{
|
||||
return new CopriLock.BikeInfoMutable(copriBikeInfo, stationName);
|
||||
return new BikeInfoNS.CopriLock.BikeInfoMutable(copriBikeInfo, stationName);
|
||||
}
|
||||
|
||||
// Unsupported type detected.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace TINK.Model.Bike
|
||||
namespace TINK.Model.Bikes
|
||||
{
|
||||
public static class BikeCollectionUpdater
|
||||
{
|
||||
|
@ -11,14 +11,14 @@ namespace TINK.Model.Bike
|
|||
/// <returns></returns>
|
||||
public static BikeCollection UpdateLockInfo(
|
||||
this BikeCollection bikes,
|
||||
IEnumerable<BluetoothLock.LockInfo> locksInfo)
|
||||
IEnumerable<Bikes.BikeInfoNS.BluetoothLock.LockInfo> locksInfo)
|
||||
{
|
||||
|
||||
var updatedBikesCollection = new Dictionary<string, BC.BikeInfo>();
|
||||
var updatedBikesCollection = new Dictionary<string, Bikes.BikeInfoNS.BC.BikeInfo>();
|
||||
|
||||
foreach (var bikeInfo in bikes)
|
||||
{
|
||||
if (!(bikeInfo is BluetoothLock.BikeInfo bluetoothBikeInfo))
|
||||
if (!(bikeInfo is BikeInfoNS.BluetoothLock.BikeInfo bluetoothBikeInfo))
|
||||
{
|
||||
// No processing needed because bike is not a bluetooth bike
|
||||
updatedBikesCollection.Add(bikeInfo.Id, bikeInfo);
|
||||
|
@ -29,7 +29,7 @@ namespace TINK.Model.Bike
|
|||
var currentLockInfo = locksInfo.FirstOrDefault(x => x.Id == bluetoothBikeInfo.LockInfo.Id) // Update bike info with latest info from bluethooth service if available
|
||||
?? bluetoothBikeInfo.LockInfo; // Use lock info state object from copri which holds a lock id and a state of value unknown.
|
||||
|
||||
updatedBikesCollection.Add(bluetoothBikeInfo.Id, new BluetoothLock.BikeInfo(bluetoothBikeInfo, currentLockInfo));
|
||||
updatedBikesCollection.Add(bluetoothBikeInfo.Id, new BikeInfoNS.BluetoothLock.BikeInfo(bluetoothBikeInfo, currentLockInfo));
|
||||
}
|
||||
|
||||
return new BikeCollection(updatedBikesCollection);
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TINK.Model.Bikes.Bike;
|
||||
using TINK.Model.Bikes.BikeInfoNS.BikeNS;
|
||||
using TINK.Model.Bikes.BikeInfoNS.DriveNS;
|
||||
using TINK.Model.State;
|
||||
|
||||
namespace TINK.Model.Bike.BC
|
||||
namespace TINK.Model.Bikes.BikeInfoNS.BC
|
||||
{
|
||||
public class BikeInfo : IBikeInfo
|
||||
{
|
||||
|
@ -11,30 +12,32 @@ namespace TINK.Model.Bike.BC
|
|||
public const bool DEFAULTVALUEISDEMO = false;
|
||||
|
||||
/// <summary> Holds the info about the bike state. </summary>
|
||||
private readonly IStateInfo m_oStateInfo;
|
||||
private readonly IStateInfo _StateInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Holds the bike object.
|
||||
/// </summary>
|
||||
private Bike Bike { get; }
|
||||
public BikeNS.Bike Bike { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds the drive object.
|
||||
/// </summary>
|
||||
public Drive Drive { get; }
|
||||
|
||||
/// <summary> Constructs a bike object.</summary>
|
||||
protected BikeInfo(
|
||||
IStateInfo stateInfo,
|
||||
string id,
|
||||
LockModel lockModel,
|
||||
BikeNS.Bike bike,
|
||||
Drive drive,
|
||||
bool? isDemo = DEFAULTVALUEISDEMO,
|
||||
IEnumerable<string> group = null,
|
||||
WheelType? wheelType = null,
|
||||
TypeOfBike? typeOfBike = null,
|
||||
string description = null,
|
||||
IEnumerable<string> group = null,
|
||||
string stationId = null,
|
||||
Uri operatorUri = null,
|
||||
RentalDescription tariffDescription = null)
|
||||
RentalDescription tariffDescription = null)
|
||||
{
|
||||
Bike = new Bike(id, lockModel, wheelType, typeOfBike, description);
|
||||
|
||||
m_oStateInfo = stateInfo;
|
||||
Bike = bike ?? throw new ArgumentNullException(nameof(bike));
|
||||
Drive = drive ?? throw new ArgumentNullException(nameof(drive));
|
||||
_StateInfo = stateInfo;
|
||||
|
||||
IsDemo = isDemo ?? DEFAULTVALUEISDEMO;
|
||||
Group = group ?? new List<string>();
|
||||
|
@ -44,90 +47,35 @@ namespace TINK.Model.Bike.BC
|
|||
}
|
||||
|
||||
public BikeInfo(BikeInfo bikeInfo) : this(
|
||||
bikeInfo?.State,
|
||||
bikeInfo?.Id ?? throw new ArgumentException($"Can not copy-construct {typeof(BikeInfo).Name}-object. Source must not be null."),
|
||||
bikeInfo.LockModel,
|
||||
bikeInfo != null ? bikeInfo?.State : throw new ArgumentNullException(nameof(bikeInfo)),
|
||||
bikeInfo.Bike,
|
||||
bikeInfo.Drive,
|
||||
bikeInfo.IsDemo,
|
||||
bikeInfo.Group,
|
||||
bikeInfo.WheelType,
|
||||
bikeInfo.TypeOfBike,
|
||||
bikeInfo.Description,
|
||||
bikeInfo.StationId,
|
||||
bikeInfo.OperatorUri,
|
||||
bikeInfo.TariffDescription) { }
|
||||
bikeInfo.TariffDescription)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a bike info object for a available bike.
|
||||
/// </summary>
|
||||
/// <param name="id">Unique id of bike.</param>
|
||||
/// <param name="stationId">Id of station where bike is located.</param>
|
||||
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||
/// <param name="tariffDescription">Hold tariff description of bike.</param>
|
||||
/// <param name="wheelType"></param>
|
||||
public BikeInfo(
|
||||
string id,
|
||||
LockModel lockModel,
|
||||
BikeNS.Bike bike,
|
||||
Drive drive,
|
||||
string stationId,
|
||||
Uri operatorUri = null,
|
||||
RentalDescription tariffDescription = null,
|
||||
bool? isDemo = DEFAULTVALUEISDEMO,
|
||||
IEnumerable<string> group = null,
|
||||
WheelType? wheelType = null,
|
||||
TypeOfBike? typeOfBike = null,
|
||||
string description = null) : this(
|
||||
IEnumerable<string> group = null) : this(
|
||||
new StateInfo(),
|
||||
id,
|
||||
lockModel,
|
||||
isDemo,
|
||||
group,
|
||||
wheelType,
|
||||
typeOfBike,
|
||||
description,
|
||||
stationId,
|
||||
operatorUri,
|
||||
tariffDescription)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a bike info object for a requested bike.
|
||||
/// </summary>
|
||||
/// <param name="wheelType"></param>
|
||||
/// <param name="id">Unique id of bike.</param>
|
||||
/// <param name="stationId">Name of station where bike is located, null if bike is on the road.</param>
|
||||
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||
/// <param name="tariffDescription">Hold tariff description of bike.</param>
|
||||
/// <param name="requestedAt">Date time when bike was requested</param>
|
||||
/// <param name="mailAddress">Mail address of user which requested bike.</param>
|
||||
/// <param name="code">Booking code.</param>
|
||||
/// <param name="dateTimeProvider">Date time provider to calculate reaining time.</param>
|
||||
public BikeInfo(
|
||||
string id,
|
||||
LockModel lockModel,
|
||||
bool? isDemo,
|
||||
IEnumerable<string> group,
|
||||
WheelType? wheelType,
|
||||
TypeOfBike? typeOfBike,
|
||||
string description,
|
||||
string stationId,
|
||||
Uri operatorUri,
|
||||
RentalDescription tariffDescription,
|
||||
DateTime requestedAt,
|
||||
string mailAddress,
|
||||
string code,
|
||||
Func<DateTime> dateTimeProvider = null) : this(
|
||||
new StateInfo(
|
||||
dateTimeProvider,
|
||||
requestedAt,
|
||||
mailAddress,
|
||||
code),
|
||||
id,
|
||||
lockModel,
|
||||
isDemo,
|
||||
group,
|
||||
wheelType,
|
||||
typeOfBike,
|
||||
description,
|
||||
bike,
|
||||
drive,
|
||||
isDemo,
|
||||
group,
|
||||
stationId,
|
||||
operatorUri,
|
||||
tariffDescription)
|
||||
|
@ -138,9 +86,6 @@ namespace TINK.Model.Bike.BC
|
|||
/// Constructs a bike info object for a booked bike.
|
||||
/// </summary>
|
||||
/// <param name="dateTimeProvider">Provider for current date time to calculate remainig time on demand for state of type reserved.</param>
|
||||
/// <param name="wheelType"></param>
|
||||
/// <param name="lockModel">Specifies the lock model.</param>
|
||||
/// <param name="id">Unique id of bike.</param>
|
||||
/// <param name="currentStationId">Name of station where bike is located, null if bike is on the road.</param>
|
||||
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||
/// <param name="tariffDescription">Hold tariff description of bike.</param>
|
||||
|
@ -148,13 +93,10 @@ namespace TINK.Model.Bike.BC
|
|||
/// <param name="mailAddress">Mail address of user which booked bike.</param>
|
||||
/// <param name="code">Booking code.</param>
|
||||
public BikeInfo(
|
||||
string id,
|
||||
LockModel lockModel,
|
||||
BikeNS.Bike bike,
|
||||
Drive drive,
|
||||
bool? isDemo,
|
||||
IEnumerable<string> group,
|
||||
WheelType? wheelType,
|
||||
TypeOfBike? typeOfBike,
|
||||
string description,
|
||||
string currentStationId,
|
||||
Uri operatorUri,
|
||||
RentalDescription tariffDescription,
|
||||
|
@ -165,13 +107,10 @@ namespace TINK.Model.Bike.BC
|
|||
bookedAt,
|
||||
mailAddress,
|
||||
code),
|
||||
id,
|
||||
lockModel,
|
||||
isDemo,
|
||||
group,
|
||||
wheelType,
|
||||
typeOfBike,
|
||||
description,
|
||||
bike,
|
||||
drive,
|
||||
isDemo,
|
||||
group,
|
||||
currentStationId,
|
||||
operatorUri,
|
||||
tariffDescription)
|
||||
|
@ -197,7 +136,7 @@ namespace TINK.Model.Bike.BC
|
|||
/// </summary>
|
||||
public IStateInfo State
|
||||
{
|
||||
get { return m_oStateInfo; }
|
||||
get { return _StateInfo; }
|
||||
}
|
||||
|
||||
public string Id => Bike.Id;
|
||||
|
@ -221,7 +160,7 @@ namespace TINK.Model.Bike.BC
|
|||
/// </summary>
|
||||
public new string ToString()
|
||||
{
|
||||
return $"Id={Bike.Id}{(Bike.WheelType != null ? $", wheel(s)={Bike.WheelType}" : string.Empty)}{(Bike.TypeOfBike != null ? $"type={Bike.TypeOfBike}" : "")}, state={State}, location={(!string.IsNullOrEmpty(StationId)? $"Station {StationId}" : "On the road")}, is demo={IsDemo}.";
|
||||
}
|
||||
return $"Id={Bike.Id}{(Bike.WheelType != null ? $", wheel(s)={Bike.WheelType}" : string.Empty)}{(Bike.TypeOfBike != null ? $"type={Bike.TypeOfBike}" : "")}, state={State}, location={(!string.IsNullOrEmpty(StationId) ? $"Station {StationId}" : "On the road")}, is demo={IsDemo}.";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,40 +2,38 @@
|
|||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.Serialization;
|
||||
using TINK.Model.Bikes.Bike;
|
||||
using TINK.Model.Bikes.Bike.BC;
|
||||
using TINK.Model.Bikes.BikeInfoNS.BikeNS;
|
||||
using TINK.Model.Bikes.BikeInfoNS.DriveNS;
|
||||
using TINK.Model.State;
|
||||
|
||||
namespace TINK.Model.Bike.BC
|
||||
namespace TINK.Model.Bikes.BikeInfoNS.BC
|
||||
{
|
||||
[DataContract]
|
||||
public class BikeInfoMutable : IBikeInfoMutable, INotifyPropertyChanged
|
||||
{
|
||||
/// <summary> Holds the bike. </summary>
|
||||
private readonly Bike m_oBike;
|
||||
private readonly BikeNS.Bike _Bike;
|
||||
|
||||
/// <summary> Holds the drive of the bike. </summary>
|
||||
private readonly Drive _Drive;
|
||||
|
||||
/// <summary> Holds the state info of the bike. </summary>
|
||||
private readonly StateInfoMutable m_oStateInfo;
|
||||
private readonly StateInfoMutable _StateInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a bike.
|
||||
/// </summary>
|
||||
/// <param name="id">Unique id of bike.</param>
|
||||
/// <param name="isDemo">True if device is demo device, false otherwise.</param>
|
||||
/// <param name="dateTimeProvider">Provider for current date time to calculate remainig time on demand for state of type reserved.</param>
|
||||
/// <param name="wheelType"></param>
|
||||
/// <param name="stationId">Name of station where bike is located, null if bike is on the road.</param>
|
||||
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||
/// <param name="tariffDescription">Hold tariff description of bike.</param>
|
||||
/// <param name="stateInfo">Bike state info.</param>
|
||||
protected BikeInfoMutable(
|
||||
string id,
|
||||
LockModel lockModel,
|
||||
BikeNS.Bike bike,
|
||||
Drive drive,
|
||||
bool isDemo = BikeInfo.DEFAULTVALUEISDEMO,
|
||||
IEnumerable<string> group = null,
|
||||
WheelType? wheelType = null,
|
||||
TypeOfBike? typeOfBike = null,
|
||||
string description = null,
|
||||
string stationId = null,
|
||||
string stationName = null,
|
||||
Uri operatorUri = null,
|
||||
|
@ -45,9 +43,10 @@ namespace TINK.Model.Bike.BC
|
|||
{
|
||||
IsDemo = isDemo;
|
||||
Group = group;
|
||||
m_oBike = new Bike(id, lockModel, wheelType, typeOfBike, description);
|
||||
m_oStateInfo = new StateInfoMutable(dateTimeProvider, stateInfo);
|
||||
m_oStateInfo.PropertyChanged += (sender, eventargs) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(eventargs.PropertyName));
|
||||
_Bike = bike;
|
||||
_Drive = drive;
|
||||
_StateInfo = new StateInfoMutable(dateTimeProvider, stateInfo);
|
||||
_StateInfo.PropertyChanged += (sender, eventargs) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(eventargs.PropertyName));
|
||||
StationId = stationId;
|
||||
StationName = stationName;
|
||||
OperatorUri = operatorUri;
|
||||
|
@ -56,18 +55,17 @@ namespace TINK.Model.Bike.BC
|
|||
|
||||
/// <summary> Constructs a bike object from source. </summary>
|
||||
public BikeInfoMutable(IBikeInfo bike, string stationName) : this(
|
||||
bike.Id,
|
||||
bike.LockModel,
|
||||
bike != null
|
||||
? bike.Bike
|
||||
: throw new ArgumentNullException(nameof(bike)),
|
||||
bike.Drive,
|
||||
bike.IsDemo,
|
||||
bike.Group,
|
||||
bike.WheelType,
|
||||
bike.TypeOfBike,
|
||||
bike.Description,
|
||||
bike.StationId,
|
||||
stationName,
|
||||
bike.OperatorUri,
|
||||
bike.TariffDescription,
|
||||
null,
|
||||
null /* date time provider */,
|
||||
bike.State)
|
||||
{
|
||||
}
|
||||
|
@ -90,7 +88,7 @@ namespace TINK.Model.Bike.BC
|
|||
[DataMember]
|
||||
public StateInfoMutable State
|
||||
{
|
||||
get { return m_oStateInfo; }
|
||||
get { return _StateInfo; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -99,22 +97,24 @@ namespace TINK.Model.Bike.BC
|
|||
public Uri OperatorUri { get; }
|
||||
|
||||
/// <summary> Unused member. </summary>
|
||||
IStateInfoMutable IBikeInfoMutable.State => m_oStateInfo;
|
||||
IStateInfoMutable IBikeInfoMutable.State => _StateInfo;
|
||||
|
||||
public string Id => m_oBike.Id;
|
||||
public string Id => _Bike.Id;
|
||||
|
||||
public bool IsDemo { get; }
|
||||
|
||||
/// <summary> Returns the group (TINK, Konrad, ...). </summary>
|
||||
public IEnumerable<string> Group { get; }
|
||||
|
||||
public WheelType? WheelType => m_oBike.WheelType;
|
||||
public WheelType? WheelType => _Bike.WheelType;
|
||||
|
||||
public TypeOfBike? TypeOfBike => m_oBike.TypeOfBike;
|
||||
public TypeOfBike? TypeOfBike => _Bike.TypeOfBike;
|
||||
|
||||
public LockModel LockModel => m_oBike.LockModel;
|
||||
public LockModel LockModel => _Bike.LockModel;
|
||||
|
||||
public string Description => m_oBike.Description;
|
||||
public string Description => _Bike.Description;
|
||||
|
||||
public Drive Drive => _Drive;
|
||||
|
||||
/// <summary>
|
||||
/// Fired whenever property of bike changes.
|
||||
|
@ -124,7 +124,6 @@ namespace TINK.Model.Bike.BC
|
|||
/// <summary>
|
||||
/// Converts the instance to text.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public new string ToString()
|
||||
{
|
||||
return $"Id={Id}{(WheelType != null ? $", wheel(s)={WheelType}" : string.Empty)}{(TypeOfBike != null ? $", type={TypeOfBike}" : "")}, demo={IsDemo}, state={State.ToString()}, location={(!string.IsNullOrEmpty(StationId) ? $"Station {StationId}" : "On the road")}.";
|
|
@ -1,9 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TINK.Model.Bikes.Bike;
|
||||
using TINK.Model.Bikes.BikeInfoNS.DriveNS;
|
||||
using TINK.Model.State;
|
||||
|
||||
namespace TINK.Model.Bike.BC
|
||||
namespace TINK.Model.Bikes.BikeInfoNS.BC
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows to access bike info.
|
||||
|
@ -11,9 +11,14 @@ namespace TINK.Model.Bike.BC
|
|||
public interface IBikeInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds the unique id of the bike;
|
||||
/// Holds the bike object.
|
||||
/// </summary>
|
||||
string Id { get; }
|
||||
BikeNS.Bike Bike { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds the drive.
|
||||
/// </summary>
|
||||
Drive Drive { get; }
|
||||
|
||||
/// <summary> True if bike is a demo bike. </summary>
|
||||
bool IsDemo { get; }
|
||||
|
@ -21,22 +26,6 @@ namespace TINK.Model.Bike.BC
|
|||
/// <summary> Returns the group (TINK, Konrad, ...). </summary>
|
||||
IEnumerable<string> Group { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds the count of wheels.
|
||||
/// </summary>
|
||||
WheelType? WheelType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds the type of bike.
|
||||
/// </summary>
|
||||
TypeOfBike? TypeOfBike { get; }
|
||||
|
||||
/// <summary> Gets the model of the lock. </summary>
|
||||
LockModel LockModel { get; }
|
||||
|
||||
/// <summary> Holds the description of the bike. </summary>
|
||||
string Description { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Station a which bike is located, null otherwise.
|
||||
/// </summary>
|
|
@ -1,10 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using TINK.Model.Bike;
|
||||
using TINK.Model.Bikes.BikeInfoNS.BikeNS;
|
||||
using TINK.Model.Bikes.BikeInfoNS.DriveNS;
|
||||
using TINK.Model.State;
|
||||
|
||||
namespace TINK.Model.Bikes.Bike.BC
|
||||
namespace TINK.Model.Bikes.BikeInfoNS.BC
|
||||
{
|
||||
public interface IBikeInfoMutable
|
||||
{
|
||||
|
@ -50,6 +51,11 @@ namespace TINK.Model.Bikes.Bike.BC
|
|||
/// </summary>
|
||||
Uri OperatorUri { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Hold the drive object.
|
||||
/// </summary>
|
||||
Drive Drive { get; }
|
||||
|
||||
event PropertyChangedEventHandler PropertyChanged;
|
||||
}
|
||||
|
|
@ -1,14 +1,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TINK.Model.Bike
|
||||
{
|
||||
namespace TINK.Model.Bikes.BikeInfoNS.BikeNS
|
||||
{
|
||||
/// <summary> Count of wheels. </summary>
|
||||
/// <remarks> Numeric values of enum must match count of wheels</remarks>
|
||||
public enum WheelType
|
||||
{
|
||||
Mono = 0,
|
||||
Two = 1,
|
||||
Trike = 2,
|
||||
Mono = 1,
|
||||
Two = 2,
|
||||
Trike = 3,
|
||||
Quad = 4
|
||||
}
|
||||
|
||||
/// <summary> Type of bike. </summary>
|
||||
|
@ -16,7 +18,7 @@ namespace TINK.Model.Bike
|
|||
{
|
||||
Allround = 0,
|
||||
Cargo = 1,
|
||||
Citybike = 2,
|
||||
City = 2,
|
||||
}
|
||||
|
||||
/// <summary> Holds the model of lock. </summary>
|
||||
|
@ -39,17 +41,18 @@ namespace TINK.Model.Bike
|
|||
/// <summary>
|
||||
/// Constructs a bike.
|
||||
/// </summary>
|
||||
/// <param name="id">Unique id of bike.</param>
|
||||
public Bike(
|
||||
string p_iId,
|
||||
string id,
|
||||
LockModel lockModel,
|
||||
WheelType? wheelType = null,
|
||||
TypeOfBike? typeOfBike = null,
|
||||
string description = null)
|
||||
{
|
||||
{
|
||||
WheelType = wheelType;
|
||||
TypeOfBike = typeOfBike;
|
||||
LockModel = lockModel;
|
||||
Id = p_iId;
|
||||
Id = id;
|
||||
Description = description;
|
||||
}
|
||||
|
||||
|
@ -92,7 +95,7 @@ namespace TINK.Model.Bike
|
|||
/// <summary> Converts the instance to text.</summary>
|
||||
public new string ToString()
|
||||
{
|
||||
return WheelType == null || TypeOfBike == null
|
||||
return WheelType == null || TypeOfBike == null
|
||||
? $"Id={Id}{(!string.IsNullOrEmpty(Description) ? $", {Description}" : "")}"
|
||||
: $"Id={Id}{(WheelType != null ? $", wheel(s)={WheelType}" : string.Empty)}{(TypeOfBike != null ? $"type={TypeOfBike}" : "")}.";
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using TINK.Model.Bike;
|
||||
|
||||
namespace TINK.Model.Bikes.Bike
|
||||
namespace TINK.Model.Bikes.BikeInfoNS.BikeNS
|
||||
{
|
||||
public static class BikeExtension
|
||||
{
|
|
@ -1,54 +1,55 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TINK.Model.Bikes.Bike;
|
||||
using TINK.Model.Bikes.BikeInfoNS.BikeNS;
|
||||
using TINK.Model.Bikes.BikeInfoNS.DriveNS;
|
||||
using TINK.Model.State;
|
||||
|
||||
namespace TINK.Model.Bike.BluetoothLock
|
||||
|
||||
namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
|
||||
{
|
||||
public class BikeInfo : BC.BikeInfo, IBikeInfo
|
||||
public class BikeInfo : Model.Bikes.BikeInfoNS.BC.BikeInfo, IBikeInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs a bike info object for a available bike.
|
||||
/// </summary>
|
||||
/// <param name="bikeId">Unique id of bike.</param>
|
||||
/// <param name="lockId">Id of the lock.</param>
|
||||
/// <param name="lockGuid">GUID specifying the lock.</param>
|
||||
/// <param name="currentStationId">Id of station where bike is located.</param>
|
||||
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||
/// <param name="tariffDescription">Hold tariff description of bike.</param>
|
||||
/// <param name="wheelType">Trike, two wheels, mono, ....</param>
|
||||
public BikeInfo(
|
||||
string bikeId,
|
||||
BikeNS.Bike bike,
|
||||
Drive drive,
|
||||
int lockId,
|
||||
Guid lockGuid,
|
||||
string currentStationId,
|
||||
Uri operatorUri = null,
|
||||
RentalDescription tariffDescription = null,
|
||||
bool? isDemo = DEFAULTVALUEISDEMO,
|
||||
IEnumerable<string> group = null,
|
||||
WheelType? wheelType = null,
|
||||
TypeOfBike? typeOfBike = null,
|
||||
string description = null) : base(
|
||||
IEnumerable<string> group = null) : base(
|
||||
new StateInfo(),
|
||||
bikeId,
|
||||
LockModel.ILockIt,
|
||||
bike != null
|
||||
? new BikeNS.Bike(
|
||||
bike.Id,
|
||||
LockModel.ILockIt /* Ensure consistend lock model value */,
|
||||
bike.WheelType,
|
||||
bike.TypeOfBike,
|
||||
bike.Description)
|
||||
: throw new ArgumentNullException(nameof(bike)),
|
||||
drive,
|
||||
isDemo,
|
||||
group,
|
||||
wheelType,
|
||||
typeOfBike,
|
||||
description,
|
||||
currentStationId,
|
||||
operatorUri,
|
||||
tariffDescription)
|
||||
{
|
||||
LockInfo = new LockInfo.Builder { Id = lockId, Guid = lockGuid }.Build();
|
||||
LockInfo = new Model.Bikes.BikeInfoNS.BluetoothLock.LockInfo.Builder { Id = lockId, Guid = lockGuid }.Build();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a bike info object for a requested bike.
|
||||
/// </summary>
|
||||
/// <param name="dateTimeProvider">Provider for current date time to calculate remainig time on demand for state of type reserved.</param>
|
||||
/// <param name="id">Unique id of bike.</param>
|
||||
/// <param name="lockId">Id of the lock.</param>
|
||||
/// <param name="lockGuid">GUID specifying the lock.</param>
|
||||
/// <param name="requestedAt">Date time when bike was requested</param>
|
||||
|
@ -56,10 +57,10 @@ namespace TINK.Model.Bike.BluetoothLock
|
|||
/// <param name="currentStationId">Name of station where bike is located, null if bike is on the road.</param>
|
||||
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||
/// <param name="tariffDescription">Hold tariff description of bike.</param>
|
||||
/// <param name="p_oDateTimeNowProvider">Date time provider to calculate reaining time.</param>
|
||||
/// <param name="wheelType"></param>
|
||||
/// <param name="dateTimeProvider">Date time provider to calculate reaining time.</param>
|
||||
public BikeInfo(
|
||||
string id,
|
||||
BikeNS.Bike bike,
|
||||
Drive drive,
|
||||
int lockId,
|
||||
Guid lockGuid,
|
||||
byte[] userKey,
|
||||
|
@ -72,27 +73,28 @@ namespace TINK.Model.Bike.BluetoothLock
|
|||
RentalDescription tariffDescription,
|
||||
Func<DateTime> dateTimeProvider,
|
||||
bool? isDemo = DEFAULTVALUEISDEMO,
|
||||
IEnumerable<string> group = null,
|
||||
WheelType? wheelType = null,
|
||||
TypeOfBike? typeOfBike = null,
|
||||
string description = null) : base(
|
||||
IEnumerable<string> group = null) : base(
|
||||
new StateInfo(
|
||||
dateTimeProvider,
|
||||
requestedAt,
|
||||
mailAddress,
|
||||
""),
|
||||
id,
|
||||
LockModel.ILockIt,
|
||||
bike != null
|
||||
? new BikeNS.Bike(
|
||||
bike.Id,
|
||||
LockModel.ILockIt /* Ensure consistend lock model value */,
|
||||
bike.WheelType,
|
||||
bike.TypeOfBike,
|
||||
bike.Description)
|
||||
: throw new ArgumentNullException(nameof(bike)),
|
||||
drive,
|
||||
isDemo,
|
||||
group,
|
||||
wheelType,
|
||||
typeOfBike,
|
||||
description,
|
||||
currentStationId,
|
||||
operatorUri,
|
||||
tariffDescription)
|
||||
{
|
||||
LockInfo = new LockInfo.Builder { Id = lockId, Guid = lockGuid, UserKey = userKey, AdminKey = adminKey, Seed = seed }.Build();
|
||||
LockInfo = new Model.Bikes.BikeInfoNS.BluetoothLock.LockInfo.Builder { Id = lockId, Guid = lockGuid, UserKey = userKey, AdminKey = adminKey, Seed = seed }.Build();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -108,7 +110,8 @@ namespace TINK.Model.Bike.BluetoothLock
|
|||
/// <param name="tariffDescription">Hold tariff description of bike.</param>
|
||||
/// <param name="wheelType"></param>
|
||||
public BikeInfo(
|
||||
string id,
|
||||
BikeNS.Bike bike,
|
||||
Drive drive,
|
||||
int lockId,
|
||||
Guid lockGuid,
|
||||
byte[] userKey,
|
||||
|
@ -120,35 +123,36 @@ namespace TINK.Model.Bike.BluetoothLock
|
|||
Uri operatorUri,
|
||||
RentalDescription tariffDescription = null,
|
||||
bool? isDemo = DEFAULTVALUEISDEMO,
|
||||
IEnumerable<string> group = null,
|
||||
WheelType? wheelType = null,
|
||||
TypeOfBike? typeOfBike = null,
|
||||
string description = null) : base(
|
||||
IEnumerable<string> group = null) : base(
|
||||
new StateInfo(
|
||||
bookedAt,
|
||||
mailAddress,
|
||||
""),
|
||||
id,
|
||||
LockModel.ILockIt,
|
||||
bike != null
|
||||
? new BikeNS.Bike(
|
||||
bike.Id,
|
||||
LockModel.ILockIt /* Ensure consistend lock model value */,
|
||||
bike.WheelType,
|
||||
bike.TypeOfBike,
|
||||
bike.Description)
|
||||
: throw new ArgumentNullException(),
|
||||
drive,
|
||||
isDemo,
|
||||
group,
|
||||
wheelType,
|
||||
typeOfBike,
|
||||
description,
|
||||
currentStationId,
|
||||
operatorUri,
|
||||
tariffDescription)
|
||||
{
|
||||
LockInfo = new LockInfo.Builder { Id = lockId, Guid = lockGuid, UserKey = userKey, AdminKey = adminKey, Seed = seed }.Build();
|
||||
LockInfo = new Model.Bikes.BikeInfoNS.BluetoothLock.LockInfo.Builder { Id = lockId, Guid = lockGuid, UserKey = userKey, AdminKey = adminKey, Seed = seed }.Build();
|
||||
}
|
||||
|
||||
public BikeInfo(BC.BikeInfo bikeInfo, LockInfo lockInfo) : base(
|
||||
public BikeInfo(Model.Bikes.BikeInfoNS.BC.BikeInfo bikeInfo, Model.Bikes.BikeInfoNS.BluetoothLock.LockInfo lockInfo) : base(
|
||||
bikeInfo ?? throw new ArgumentException($"Can not copy-construct {typeof(BikeInfo).Name}-object. Source bike info must not be null."))
|
||||
{
|
||||
LockInfo = lockInfo
|
||||
?? throw new ArgumentException($"Can not copy-construct {typeof(BikeInfo).Name}-object. Source lock object must not be null.");
|
||||
}
|
||||
|
||||
public LockInfo LockInfo { get; private set; }
|
||||
public Model.Bikes.BikeInfoNS.BluetoothLock.LockInfo LockInfo { get; private set; }
|
||||
}
|
||||
}
|
|
@ -1,19 +1,17 @@
|
|||
using System;
|
||||
using TINK.Model.Bikes.Bike.BluetoothLock;
|
||||
|
||||
namespace TINK.Model.Bike.BluetoothLock
|
||||
namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
|
||||
{
|
||||
public class BikeInfoMutable : BC.BikeInfoMutable, IBikeInfoMutable
|
||||
public class BikeInfoMutable : Model.Bikes.BikeInfoNS.BC.BikeInfoMutable, IBikeInfoMutable
|
||||
{
|
||||
/// <summary> Constructs a bike object from source. </summary>
|
||||
public BikeInfoMutable(BikeInfo bike, string stationName) : base(
|
||||
bike.Id,
|
||||
bike.LockModel,
|
||||
bike != null
|
||||
? bike.Bike
|
||||
: throw new ArgumentNullException(nameof(bike)),
|
||||
bike.Drive,
|
||||
bike.IsDemo,
|
||||
bike.Group,
|
||||
bike.WheelType,
|
||||
bike.TypeOfBike,
|
||||
bike.Description,
|
||||
bike.StationId,
|
||||
stationName,
|
||||
bike.OperatorUri,
|
||||
|
@ -22,7 +20,7 @@ namespace TINK.Model.Bike.BluetoothLock
|
|||
bike.State)
|
||||
{
|
||||
LockInfo = new LockInfoMutable(
|
||||
bike.LockInfo.Id,
|
||||
bike.LockInfo.Id,
|
||||
bike.LockInfo.Guid,
|
||||
bike.LockInfo.UserKey,
|
||||
bike.LockInfo.AdminKey,
|
|
@ -1,4 +1,4 @@
|
|||
namespace TINK.Model.Bike.BluetoothLock
|
||||
namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
|
||||
{
|
||||
public interface IBikeInfo : BC.IBikeInfo
|
||||
{
|
|
@ -0,0 +1,7 @@
|
|||
namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
|
||||
{
|
||||
public interface IBikeInfoMutable : BikeInfoNS.BC.IBikeInfoMutable
|
||||
{
|
||||
ILockInfoMutable LockInfo { get; }
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using TINK.Model.Bike.BluetoothLock;
|
||||
|
||||
namespace TINK.Model.Bikes.Bike.BluetoothLock
|
||||
namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
|
||||
{
|
||||
public interface ILockInfoMutable
|
||||
{
|
|
@ -1,12 +1,11 @@
|
|||
using System;
|
||||
using TINK.Model.Bikes.Bike.BluetoothLock;
|
||||
|
||||
namespace TINK.Model.Bike.BluetoothLock
|
||||
namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
|
||||
{
|
||||
public class LockInfoMutable : ILockInfoMutable
|
||||
public class LockInfoMutable : TINK.Model.Bikes.BikeInfoNS.BluetoothLock.ILockInfoMutable
|
||||
{
|
||||
/// <summary> Lock info object. </summary>
|
||||
private LockInfo LockInfo { get; set; }
|
||||
private Model.Bikes.BikeInfoNS.BluetoothLock.LockInfo LockInfo { get; set; }
|
||||
|
||||
/// <summary> Constructs a bluetooth lock info object. </summary>
|
||||
/// <param name="id">Id of lock must always been known when constructing an lock info object.</param>
|
||||
|
@ -16,9 +15,9 @@ namespace TINK.Model.Bike.BluetoothLock
|
|||
byte[] userKey,
|
||||
byte[] adminKey,
|
||||
byte[] seed,
|
||||
LockingState state)
|
||||
Model.Bikes.BikeInfoNS.BluetoothLock.LockingState state)
|
||||
{
|
||||
LockInfo = new LockInfo.Builder() { Id = id, Guid = guid, UserKey = userKey, AdminKey = adminKey, Seed = seed, State = state }.Build();
|
||||
LockInfo = new Model.Bikes.BikeInfoNS.BluetoothLock.LockInfo.Builder() { Id = id, Guid = guid, UserKey = userKey, AdminKey = adminKey, Seed = seed, State = state }.Build();
|
||||
}
|
||||
|
||||
public int Id => LockInfo.Id;
|
||||
|
@ -27,8 +26,8 @@ namespace TINK.Model.Bike.BluetoothLock
|
|||
public Guid Guid
|
||||
{
|
||||
get => LockInfo.Guid;
|
||||
set => LockInfo = new LockInfo.Builder(LockInfo) { Guid = value }.Build();
|
||||
}
|
||||
set => LockInfo = new Model.Bikes.BikeInfoNS.BluetoothLock.LockInfo.Builder(LockInfo) { Guid = value }.Build();
|
||||
}
|
||||
|
||||
public byte[] Seed => LockInfo.Seed;
|
||||
|
||||
|
@ -36,10 +35,10 @@ namespace TINK.Model.Bike.BluetoothLock
|
|||
|
||||
public byte[] AdminKey => LockInfo.AdminKey;
|
||||
|
||||
public LockingState State
|
||||
public Model.Bikes.BikeInfoNS.BluetoothLock.LockingState State
|
||||
{
|
||||
get => LockInfo.State;
|
||||
set => LockInfo = new LockInfo.Builder(LockInfo) { State = value }.Build();
|
||||
set => LockInfo = new Model.Bikes.BikeInfoNS.BluetoothLock.LockInfo.Builder(LockInfo) { State = value }.Build();
|
||||
}
|
||||
|
||||
/// <summary> Holds the percentage of lock battery.</summary>
|
||||
|
@ -48,7 +47,7 @@ namespace TINK.Model.Bike.BluetoothLock
|
|||
/// <summary> Loads lock info object from values. </summary>
|
||||
public void Load(int id, Guid guid, byte[] seed, byte[] userKey, byte[] adminKey)
|
||||
{
|
||||
LockInfo = new LockInfo.Builder(LockInfo) { Id = id, Guid = guid, Seed = seed, UserKey = userKey, AdminKey = adminKey}.Build();
|
||||
LockInfo = new Model.Bikes.BikeInfoNS.BluetoothLock.LockInfo.Builder(LockInfo) { Id = id, Guid = guid, Seed = seed, UserKey = userKey, AdminKey = adminKey }.Build();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,52 +1,60 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TINK.Model.Bikes.Bike;
|
||||
using TINK.Model.Bikes.Bike.CopriLock;
|
||||
using TINK.Model.Bikes.BikeInfoNS.BikeNS;
|
||||
using TINK.Model.Bikes.BikeInfoNS.DriveNS;
|
||||
using TINK.Model.MiniSurvey;
|
||||
using TINK.Model.State;
|
||||
|
||||
namespace TINK.Model.Bike.CopriLock
|
||||
namespace TINK.Model.Bikes.BikeInfoNS.CopriLock
|
||||
{
|
||||
public class BikeInfo : BC.BikeInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs a bike info object for a available bike.
|
||||
/// Constructs a bike info object for a available bike or bike for which feed back is pending.
|
||||
/// </summary>
|
||||
/// <param name="bikeId">Unique id of bike.</param>
|
||||
/// <param name="bike">Bike object.</param>
|
||||
/// <param name="currentStationId">Id of station where bike is located.</param>
|
||||
/// <param name="lockInfo">Lock info.</param>
|
||||
/// <param name="isFeedbackPending">If true user has not yet given feedback after returning bike.</param>
|
||||
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||
/// <param name="tariffDescription">Hold tariff description of bike.</param>
|
||||
/// <param name="wheelType">Trike, two wheels, mono, ....</param>
|
||||
public BikeInfo(
|
||||
string bikeId,
|
||||
BikeNS.Bike bike,
|
||||
Drive drive,
|
||||
string currentStationId,
|
||||
LockInfo lockInfo,
|
||||
bool isFeedbackPending = false,
|
||||
Uri operatorUri = null,
|
||||
RentalDescription tariffDescription = null,
|
||||
bool? isDemo = DEFAULTVALUEISDEMO,
|
||||
IEnumerable<string> group = null,
|
||||
WheelType? wheelType = null,
|
||||
TypeOfBike? typeOfBike = null,
|
||||
string description = null) : base(
|
||||
new StateInfo(),
|
||||
bikeId,
|
||||
LockModel.Sigo,
|
||||
IMiniSurveyModel miniSurvey = null,
|
||||
string co2Saving = null) : base(
|
||||
new StateInfo(isFeedbackPending),
|
||||
bike != null
|
||||
? new Bike(
|
||||
bike.Id,
|
||||
LockModel.Sigo,
|
||||
bike.WheelType /* Ensure consistend lock model value */,
|
||||
bike.TypeOfBike,
|
||||
bike.Description)
|
||||
: throw new ArgumentNullException(nameof(bike)),
|
||||
drive,
|
||||
isDemo,
|
||||
group,
|
||||
wheelType,
|
||||
typeOfBike,
|
||||
description,
|
||||
currentStationId,
|
||||
operatorUri,
|
||||
tariffDescription)
|
||||
{
|
||||
LockInfo = lockInfo;
|
||||
MiniSurvey = miniSurvey;
|
||||
Co2Saving = co2Saving;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a bike info object for a requested bike.
|
||||
/// </summary>
|
||||
/// <param name="id">Unique id of bike.</param>
|
||||
/// <param name="bike">Bike object.</param>
|
||||
/// <param name="requestedAt">Date time when bike was requested</param>
|
||||
/// <param name="mailAddress">Mail address of user which requested bike.</param>
|
||||
/// <param name="currentStationId">Name of station where bike is located, null if bike is on the road.</param>
|
||||
|
@ -54,9 +62,9 @@ namespace TINK.Model.Bike.CopriLock
|
|||
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||
/// <param name="tariffDescription">Hold tariff description of bike.</param>
|
||||
/// <param name="dateTimeProvider">Provider for current date time to calculate remainig time on demand for state of type reserved.</param>
|
||||
/// <param name="wheelType"></param>
|
||||
public BikeInfo(
|
||||
string id,
|
||||
BikeNS.Bike bike,
|
||||
Drive drive,
|
||||
DateTime requestedAt,
|
||||
string mailAddress,
|
||||
string currentStationId,
|
||||
|
@ -65,41 +73,45 @@ namespace TINK.Model.Bike.CopriLock
|
|||
RentalDescription tariffDescription,
|
||||
Func<DateTime> dateTimeProvider,
|
||||
bool? isDemo = DEFAULTVALUEISDEMO,
|
||||
IEnumerable<string> group = null,
|
||||
WheelType? wheelType = null,
|
||||
TypeOfBike? typeOfBike = null,
|
||||
string description = null) : base(
|
||||
IEnumerable<string> group = null) : base(
|
||||
new StateInfo(
|
||||
dateTimeProvider,
|
||||
requestedAt,
|
||||
mailAddress,
|
||||
""),
|
||||
id,
|
||||
LockModel.ILockIt,
|
||||
bike != null
|
||||
? new BikeNS.Bike(
|
||||
bike.Id,
|
||||
LockModel.Sigo /* Ensure consistend lock model value */,
|
||||
bike.WheelType,
|
||||
bike.TypeOfBike,
|
||||
bike.Description)
|
||||
: throw new ArgumentNullException(nameof(bike)),
|
||||
drive,
|
||||
isDemo,
|
||||
group,
|
||||
wheelType,
|
||||
typeOfBike,
|
||||
description,
|
||||
currentStationId,
|
||||
operatorUri,
|
||||
tariffDescription)
|
||||
{
|
||||
LockInfo = lockInfo;
|
||||
MiniSurvey = new MiniSurveyModel();
|
||||
Co2Saving = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a bike info object for a booked bike.
|
||||
/// </summary>
|
||||
/// <param name="bike">Bike object.</param>
|
||||
/// <param name="bookedAt">Date time when bike was booked</param>
|
||||
/// <param name="mailAddress">Mail address of user which booked bike.</param>
|
||||
/// <param name="currentStationId">Name of station where bike is located, null if bike is on the road.</param>
|
||||
/// <param name="lockInfo">Lock info.</param>
|
||||
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||
/// <param name="tariffDescription">Hold tariff description of bike.</param>
|
||||
/// <param name="wheelType"></param>
|
||||
public BikeInfo(
|
||||
string id,
|
||||
BikeNS.Bike bike,
|
||||
Drive drive,
|
||||
DateTime bookedAt,
|
||||
string mailAddress,
|
||||
string currentStationId,
|
||||
|
@ -107,26 +119,29 @@ namespace TINK.Model.Bike.CopriLock
|
|||
Uri operatorUri,
|
||||
RentalDescription tariffDescription = null,
|
||||
bool? isDemo = DEFAULTVALUEISDEMO,
|
||||
IEnumerable<string> group = null,
|
||||
WheelType? wheelType = null,
|
||||
TypeOfBike? typeOfBike = null,
|
||||
string description = null) : base(
|
||||
IEnumerable<string> group = null) : base(
|
||||
new StateInfo(
|
||||
bookedAt,
|
||||
mailAddress,
|
||||
""),
|
||||
id,
|
||||
LockModel.ILockIt,
|
||||
bike != null
|
||||
? new BikeNS.Bike(
|
||||
bike.Id,
|
||||
LockModel.Sigo /* Ensure consistend lock model value */,
|
||||
bike.WheelType,
|
||||
bike.TypeOfBike,
|
||||
bike.Description)
|
||||
: throw new ArgumentNullException(nameof(bike)),
|
||||
drive,
|
||||
isDemo,
|
||||
group,
|
||||
wheelType,
|
||||
typeOfBike,
|
||||
description,
|
||||
currentStationId,
|
||||
operatorUri,
|
||||
tariffDescription)
|
||||
{
|
||||
LockInfo = lockInfo;
|
||||
MiniSurvey = new MiniSurveyModel();
|
||||
Co2Saving = string.Empty;
|
||||
}
|
||||
|
||||
public BikeInfo(BC.BikeInfo bikeInfo, LockInfo lockInfo) : base(
|
||||
|
@ -136,6 +151,11 @@ namespace TINK.Model.Bike.CopriLock
|
|||
?? throw new ArgumentException($"Can not copy-construct {typeof(BikeInfo).Name}-object. Source lock object must not be null.");
|
||||
}
|
||||
|
||||
/// <summary> Holds the lock info.</summary>
|
||||
public LockInfo LockInfo { get; private set; }
|
||||
|
||||
public IMiniSurveyModel MiniSurvey { get; private set; }
|
||||
|
||||
public string Co2Saving { get; private set; }
|
||||
}
|
||||
}
|
47
TINKLib/Model/Bikes/BikeInfoNS/CopriLock/BikeInfoMutable.cs
Normal file
47
TINKLib/Model/Bikes/BikeInfoNS/CopriLock/BikeInfoMutable.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
|
||||
namespace TINK.Model.Bikes.BikeInfoNS.CopriLock
|
||||
{
|
||||
public class BikeInfoMutable : BC.BikeInfoMutable, IBikeInfoMutable
|
||||
{
|
||||
/// <summary> Constructs a bike object from source. </summary>
|
||||
public BikeInfoMutable(BikeInfo bike, string stationName) : base(
|
||||
bike != null
|
||||
? bike.Bike
|
||||
: throw new ArgumentNullException(nameof(bike)),
|
||||
bike.Drive,
|
||||
bike.IsDemo,
|
||||
bike.Group,
|
||||
bike.StationId,
|
||||
stationName,
|
||||
bike.OperatorUri,
|
||||
bike.TariffDescription,
|
||||
() => DateTime.Now,
|
||||
bike.State)
|
||||
{
|
||||
LockInfo = new LockInfoMutable(bike.LockInfo.State);
|
||||
|
||||
BookingFinishedModel = new BookingFinishedModel
|
||||
{
|
||||
Co2Saving = bike.Co2Saving,
|
||||
MiniSurvey = new MiniSurvey.MiniSurveyModel()
|
||||
};
|
||||
|
||||
if ((bike?.MiniSurvey?.Questions) == null
|
||||
|| bike.MiniSurvey.Questions.Count <= 0)
|
||||
{
|
||||
// No querries to add.
|
||||
return;
|
||||
}
|
||||
|
||||
// Add a dummy querry. Querries are not yet read from COPRI but compiled into the app.
|
||||
BookingFinishedModel.MiniSurvey.Questions.Add("q1", new MiniSurvey.QuestionModel());
|
||||
}
|
||||
|
||||
public LockInfoMutable LockInfo { get; }
|
||||
|
||||
ILockInfoMutable IBikeInfoMutable.LockInfo => LockInfo;
|
||||
|
||||
public IBookingFinishedModel BookingFinishedModel { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
namespace TINK.Model.Bikes.BikeInfoNS.CopriLock
|
||||
{
|
||||
public interface IBikeInfoMutable : BikeInfoNS.BC.IBikeInfoMutable
|
||||
{
|
||||
ILockInfoMutable LockInfo { get; }
|
||||
|
||||
IBookingFinishedModel BookingFinishedModel { get; }
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
namespace TINK.Model.Bikes.Bike.CopriLock
|
||||
namespace TINK.Model.Bikes.BikeInfoNS.CopriLock
|
||||
{
|
||||
public interface ILockInfoMutable
|
||||
{
|
|
@ -1,7 +1,4 @@
|
|||
using System;
|
||||
using TINK.Model.Bikes.Bike.CopriLock;
|
||||
|
||||
namespace TINK.Model.Bike.CopriLock
|
||||
namespace TINK.Model.Bikes.BikeInfoNS.CopriLock
|
||||
{
|
||||
public class LockInfoMutable : ILockInfoMutable
|
||||
{
|
110
TINKLib/Model/Bikes/BikeInfoNS/DriveNS/BatteryNS/Battery.cs
Normal file
110
TINKLib/Model/Bikes/BikeInfoNS/DriveNS/BatteryNS/Battery.cs
Normal file
|
@ -0,0 +1,110 @@
|
|||
using Serilog;
|
||||
|
||||
namespace TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS
|
||||
{
|
||||
public class Battery : IBattery
|
||||
{
|
||||
private Battery() { }
|
||||
|
||||
/// <summary>
|
||||
/// Holds the current charging level of the battery in percent, double.NaN if unknown.
|
||||
/// </summary>
|
||||
public double CurrentChargePercent { get; private set; } = double.NaN;
|
||||
|
||||
/// <summary>
|
||||
/// Holds the current chargeing level of the battery in bars, null if unkonwn.
|
||||
/// </summary>
|
||||
public int? CurrentChargeBars { get; private set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Holds the maximum chargeing level of the battery in bars, null if unkonwn.
|
||||
/// </summary>
|
||||
public int? MaxChargeBars { get; private set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Holds whether backend is aware of battery charging level.
|
||||
/// </summary>
|
||||
public bool? IsBackendAccessible { get; private set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Holds whether to display battery level or not.
|
||||
/// </summary>
|
||||
public bool? IsHidden { get; private set; } = null;
|
||||
|
||||
public class Builder
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds the current chargeing level of the battery in bars.
|
||||
/// </summary>
|
||||
public int? CurrentChargeBars { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Holds the maximum chargeing level of the battery in bars.
|
||||
/// </summary>
|
||||
public int? MaxChargeBars { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Holds the current charging level of the battery in percent.
|
||||
/// </summary>
|
||||
public double CurrentChargePercent { get; set; } = double.NaN;
|
||||
|
||||
/// <summary>
|
||||
/// Holds whether backend is aware of battery charging level.
|
||||
/// </summary>
|
||||
public bool? IsBackendAccessible { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Holds whether to display battery level or not.
|
||||
/// </summary>
|
||||
public bool? IsHidden { get; set; } = null;
|
||||
|
||||
public Battery Build()
|
||||
{
|
||||
if (!double.IsNaN(CurrentChargePercent)
|
||||
&& (CurrentChargePercent < 0 || 100 < CurrentChargePercent))
|
||||
{
|
||||
// Invalid filling level detected
|
||||
CurrentChargePercent = double.NaN;
|
||||
}
|
||||
|
||||
if (CurrentChargeBars < 0)
|
||||
{
|
||||
// Current value of bars must never be smaller zero.
|
||||
CurrentChargeBars = null;
|
||||
}
|
||||
|
||||
if (MaxChargeBars < 0)
|
||||
{
|
||||
// Max value of bars must never be smaller zero.
|
||||
MaxChargeBars = null;
|
||||
}
|
||||
|
||||
if (CurrentChargeBars != null
|
||||
&& MaxChargeBars == null)
|
||||
{
|
||||
// If current charge bars is set, max charge must be set as well.
|
||||
Log.ForContext<Battery>().Error($"Current bars value can not be set to {CurrentChargeBars} if max bars is not se.");
|
||||
CurrentChargeBars = null;
|
||||
}
|
||||
|
||||
if (CurrentChargeBars != null
|
||||
&& MaxChargeBars != null
|
||||
&& CurrentChargeBars > MaxChargeBars)
|
||||
{
|
||||
// If current charge bars must never be larger than max charge bars.
|
||||
Log.ForContext<Battery>().Error($"Invalid current bars value {CurrentChargeBars} detected. Value must never be largen than max value bars {MaxChargeBars}.");
|
||||
CurrentChargeBars = null;
|
||||
}
|
||||
|
||||
return new Battery
|
||||
{
|
||||
CurrentChargeBars = CurrentChargeBars,
|
||||
MaxChargeBars = MaxChargeBars,
|
||||
CurrentChargePercent = CurrentChargePercent,
|
||||
IsBackendAccessible = IsBackendAccessible,
|
||||
IsHidden = IsHidden
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
31
TINKLib/Model/Bikes/BikeInfoNS/DriveNS/BatteryNS/IBattery.cs
Normal file
31
TINKLib/Model/Bikes/BikeInfoNS/DriveNS/BatteryNS/IBattery.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
|
||||
namespace TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS
|
||||
{
|
||||
public interface IBattery
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds the current charging level of the battery in percent, double.NaN if unknown.
|
||||
/// </summary>
|
||||
double CurrentChargePercent { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds the current chargeing level of the battery in bars. Must not be arger than MaxChargeBars, null if unkonwn.
|
||||
/// </summary>
|
||||
int? CurrentChargeBars { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds the maximum chargeing level of the battery in bars, null if unkonwn.
|
||||
/// </summary>
|
||||
int? MaxChargeBars { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds whether backend is aware of battery charging level.
|
||||
/// </summary>
|
||||
bool? IsBackendAccessible { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds whether to display battery level or not.
|
||||
/// </summary>
|
||||
bool? IsHidden { get; }
|
||||
}
|
||||
}
|
62
TINKLib/Model/Bikes/BikeInfoNS/DriveNS/Drive.cs
Normal file
62
TINKLib/Model/Bikes/BikeInfoNS/DriveNS/Drive.cs
Normal file
|
@ -0,0 +1,62 @@
|
|||
using TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
|
||||
using TINK.Model.Bikes.BikeInfoNS.DriveNS.EngineNS;
|
||||
|
||||
namespace TINK.Model.Bikes.BikeInfoNS.DriveNS
|
||||
{
|
||||
public enum DriveType
|
||||
{
|
||||
/// <summary>
|
||||
/// Bike without pedalling aid.
|
||||
/// </summary>
|
||||
SoleHumanPowered,
|
||||
|
||||
/// <summary>
|
||||
/// pedal electric cycle: Pedalling is assisted by an electric engine.
|
||||
/// </summary>
|
||||
Pedelec
|
||||
}
|
||||
|
||||
public class Drive
|
||||
{
|
||||
public Drive(
|
||||
IEngine engine = null,
|
||||
IBattery battery = null)
|
||||
{
|
||||
if (engine == null)
|
||||
{
|
||||
Engine = new Engine();
|
||||
Battery = new Battery.Builder().Build();
|
||||
Type = DriveType.SoleHumanPowered;
|
||||
return;
|
||||
}
|
||||
|
||||
Engine = engine;
|
||||
Battery = battery ?? new Battery.Builder().Build();
|
||||
Type = DriveType.Pedelec;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the drive.
|
||||
/// </summary>
|
||||
public DriveType Type { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Engine driving the bike.
|
||||
/// </summary>
|
||||
public IEngine Engine { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Battery powering the engine.
|
||||
/// </summary>
|
||||
public IBattery _Battery = new Battery.Builder().Build();
|
||||
|
||||
/// <summary>
|
||||
/// Battery powering the engine.
|
||||
/// </summary>
|
||||
public IBattery Battery
|
||||
{
|
||||
get => _Battery;
|
||||
set => _Battery = value ?? new Battery.Builder().Build();
|
||||
}
|
||||
}
|
||||
}
|
13
TINKLib/Model/Bikes/BikeInfoNS/DriveNS/EngineNS/Engine.cs
Normal file
13
TINKLib/Model/Bikes/BikeInfoNS/DriveNS/EngineNS/Engine.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
namespace TINK.Model.Bikes.BikeInfoNS.DriveNS.EngineNS
|
||||
{
|
||||
public class Engine : IEngine
|
||||
{
|
||||
public Engine(string manufacturer = null)
|
||||
=> Manufacturer = !string.IsNullOrEmpty(manufacturer) ? manufacturer : null;
|
||||
|
||||
/// <summary>
|
||||
/// Manufacturer of the engine.
|
||||
/// </summary>
|
||||
public string Manufacturer { get; private set; } = null;
|
||||
}
|
||||
}
|
10
TINKLib/Model/Bikes/BikeInfoNS/DriveNS/EngineNS/IEngine.cs
Normal file
10
TINKLib/Model/Bikes/BikeInfoNS/DriveNS/EngineNS/IEngine.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace TINK.Model.Bikes.BikeInfoNS.DriveNS.EngineNS
|
||||
{
|
||||
public interface IEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// Manufacturer of the engine.
|
||||
/// </summary>
|
||||
string Manufacturer { get; }
|
||||
}
|
||||
}
|
23
TINKLib/Model/Bikes/BikeInfoNS/DriveNS/IDrive.cs
Normal file
23
TINKLib/Model/Bikes/BikeInfoNS/DriveNS/IDrive.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
|
||||
using TINK.Model.Bikes.BikeInfoNS.DriveNS.EngineNS;
|
||||
|
||||
namespace TINK.Model.Bikes.BikeInfoNS
|
||||
{
|
||||
public interface IDrive
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the type of the drive.
|
||||
/// </summary>
|
||||
DriveNS.DriveType Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Engine driving the bike.
|
||||
/// </summary>
|
||||
IEngine Engine { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Battery powering the engine.
|
||||
/// </summary>
|
||||
IBattery Battery { get; }
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace TINK.Model.Bikes.Bike
|
||||
namespace TINK.Model.Bikes.BikeInfoNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Successor of TarifDescription- object.
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
|
||||
namespace TINK.Model.Bikes.Bike
|
||||
namespace TINK.Model.Bikes.BikeInfoNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds tariff info for a single bike.
|
|
@ -1,6 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace TINK.Model.Bike
|
||||
namespace TINK.Model.Bikes
|
||||
{
|
||||
public interface IBikeDictionary<T> : IReadOnlyCollection<T>
|
||||
{
|
||||
|
|
|
@ -5,16 +5,12 @@ namespace TINK.Model
|
|||
/// <summary>
|
||||
/// Holds tasks to be accoumplished/ information shown to user after booking has finished.
|
||||
/// </summary>
|
||||
public class BookingFinishedModel
|
||||
public class BookingFinishedModel : IBookingFinishedModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Minisurvey to query user.
|
||||
/// </summary>
|
||||
public MiniSurveyModel MiniSurvey { get; set; } = new MiniSurveyModel();
|
||||
/// <summary> Minisurvey to query user.</summary>
|
||||
public IMiniSurveyModel MiniSurvey { get; set; } = new MiniSurveyModel();
|
||||
|
||||
/// <summary>
|
||||
/// Holds info about co2 saving accomplished by using cargo bike.
|
||||
/// </summary>
|
||||
/// <summary> Holds info about co2 saving accomplished by using cargo bike. </summary>
|
||||
public string Co2Saving { get; set; }
|
||||
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
using Serilog;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Serilog;
|
||||
using TINK.Model.Connector.Updater;
|
||||
using TINK.Model.Device;
|
||||
using TINK.Model.User.Account;
|
||||
using TINK.Repository;
|
||||
using TINK.Repository.Request;
|
||||
using TINK.Repository.Response;
|
||||
using TINK.Model.User.Account;
|
||||
using TINK.Model.Device;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
{
|
||||
|
@ -84,7 +85,7 @@ namespace TINK.Model.Connector
|
|||
/// </summary>
|
||||
/// <param name="bike">Bike to book.</param>
|
||||
public async Task DoReserve(
|
||||
Bikes.Bike.BC.IBikeInfoMutable bike)
|
||||
Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
|
||||
{
|
||||
Log.ForContext<Command>().Error("Unexpected booking request detected. No user logged in.");
|
||||
await Task.CompletedTask;
|
||||
|
@ -92,7 +93,7 @@ namespace TINK.Model.Connector
|
|||
|
||||
/// <summary> Request to cancel a reservation.</summary>
|
||||
/// <param name="p_oBike">Bike to book.</param>
|
||||
public async Task DoCancelReservation(Bikes.Bike.BC.IBikeInfoMutable bike)
|
||||
public async Task DoCancelReservation(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
|
||||
{
|
||||
Log.ForContext<Command>().Error("Unexpected cancel reservation request detected. No user logged in.");
|
||||
await Task.CompletedTask;
|
||||
|
@ -100,7 +101,7 @@ namespace TINK.Model.Connector
|
|||
|
||||
/// <summary> Get authentication keys.</summary>
|
||||
/// <param name="bike">Bike to book.</param>
|
||||
public async Task CalculateAuthKeys(Bikes.Bike.BluetoothLock.IBikeInfoMutable bike)
|
||||
public async Task CalculateAuthKeys(Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable bike)
|
||||
{
|
||||
Log.ForContext<Command>().Error("Unexpected request to get authenticatin keys detected. No user logged in.");
|
||||
await Task.CompletedTask;
|
||||
|
@ -110,7 +111,7 @@ namespace TINK.Model.Connector
|
|||
/// <param name="bike">Bike to update locking state for.</param>
|
||||
/// <param name="location">Location where lock was opened/ changed.</param>
|
||||
/// <returns>Response on updating locking state.</returns>
|
||||
public async Task StartReturningBike(Bikes.Bike.BC.IBikeInfoMutable bike)
|
||||
public async Task StartReturningBike(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
|
||||
{
|
||||
Log.ForContext<Command>().Error("Unexpected request to notify about start of returning bike. No user logged in.");
|
||||
await Task.CompletedTask;
|
||||
|
@ -120,26 +121,26 @@ namespace TINK.Model.Connector
|
|||
/// <remarks> Operator specific call.</remarks>
|
||||
/// <param name="bike">Bike to return.</param>
|
||||
/// <returns>Response on notification about start of returning sequence.</returns>
|
||||
public async Task UpdateLockingStateAsync(Bikes.Bike.BluetoothLock.IBikeInfoMutable bike, LocationDto location)
|
||||
public async Task UpdateLockingStateAsync(Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable bike, LocationDto location)
|
||||
{
|
||||
Log.ForContext<Command>().Error("Unexpected request to update locking state detected. No user logged in.");
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task DoBook(Bikes.Bike.BC.IBikeInfoMutable bike)
|
||||
public async Task DoBook(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
|
||||
{
|
||||
Log.ForContext<Command>().Error("Unexpected booking request detected. No user logged in.");
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task BookAndOpenAync(Bikes.Bike.CopriLock.IBikeInfoMutable bike)
|
||||
public async Task BookAndOpenAync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike)
|
||||
{
|
||||
Log.ForContext<Command>().Error("Unexpected request to book and open bike detected. No user logged in.");
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task<BookingFinishedModel> DoReturn(
|
||||
Bikes.Bike.BC.IBikeInfoMutable bike,
|
||||
Bikes.BikeInfoNS.BC.IBikeInfoMutable bike,
|
||||
LocationDto location,
|
||||
ISmartDevice smartDevice)
|
||||
{
|
||||
|
@ -148,7 +149,7 @@ namespace TINK.Model.Connector
|
|||
}
|
||||
|
||||
public async Task<BookingFinishedModel> ReturnAndCloseAsync(
|
||||
Bikes.Bike.CopriLock.IBikeInfoMutable bike,
|
||||
Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike,
|
||||
ISmartDevice smartDevice)
|
||||
{
|
||||
Log.ForContext<Command>().Error("Unexpected close lock and return request detected. No user logged in.");
|
||||
|
@ -177,10 +178,10 @@ namespace TINK.Model.Connector
|
|||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task OpenLockAsync(Bikes.Bike.CopriLock.IBikeInfoMutable bike)
|
||||
public Task OpenLockAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike)
|
||||
=> throw new NotImplementedException();
|
||||
|
||||
public Task CloseLockAsync(Bikes.Bike.CopriLock.IBikeInfoMutable bike)
|
||||
public Task CloseLockAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike)
|
||||
=> throw new NotImplementedException();
|
||||
}
|
||||
}
|
|
@ -1,13 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using TINK.Model.Bike.BluetoothLock;
|
||||
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using TINK.Model.Connector.Updater;
|
||||
using TINK.Model.Device;
|
||||
using TINK.Model.User.Account;
|
||||
using TINK.Repository;
|
||||
using TINK.Repository.Exception;
|
||||
using TINK.Repository.Request;
|
||||
using TINK.Repository.Response;
|
||||
using TINK.Model.User.Account;
|
||||
using TINK.Model.Device;
|
||||
using System.Collections.Generic;
|
||||
using TINK.Services.CopriApi;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
|
@ -25,7 +26,7 @@ namespace TINK.Model.Connector
|
|||
public CommandLoggedIn(ICopriServerBase p_oCopriServer,
|
||||
string sessionCookie,
|
||||
string mail,
|
||||
Func<DateTime> dateTimeProvider) : base(p_oCopriServer, sessionCookie, mail, dateTimeProvider)
|
||||
Func<DateTime> dateTimeProvider) : base(p_oCopriServer, sessionCookie, mail, dateTimeProvider)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -75,7 +76,7 @@ namespace TINK.Model.Connector
|
|||
/// Request to reserve a bike.
|
||||
/// </summary>
|
||||
/// <param name="bike">Bike to book.</param>
|
||||
public async Task DoReserve(Bikes.Bike.BC.IBikeInfoMutable bike)
|
||||
public async Task DoReserve(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
|
||||
{
|
||||
if (bike == null)
|
||||
{
|
||||
|
@ -93,13 +94,13 @@ namespace TINK.Model.Connector
|
|||
throw;
|
||||
}
|
||||
|
||||
bike.Load(response, Mail, Bikes.Bike.BC.NotifyPropertyChangedLevel.None);
|
||||
bike.Load(response, Mail, Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.None);
|
||||
}
|
||||
|
||||
/// <summary> Request to cancel a reservation.</summary>
|
||||
/// <param name="bike">Bike to cancel reservation.</param>
|
||||
public async Task DoCancelReservation(
|
||||
Bikes.Bike.BC.IBikeInfoMutable bike)
|
||||
Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
|
||||
{
|
||||
if (bike == null)
|
||||
{
|
||||
|
@ -117,12 +118,12 @@ namespace TINK.Model.Connector
|
|||
throw;
|
||||
}
|
||||
|
||||
bike.Load(Bikes.Bike.BC.NotifyPropertyChangedLevel.None);
|
||||
bike.Load(Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.None);
|
||||
}
|
||||
|
||||
/// <summary> Get authentication keys.</summary>
|
||||
/// <param name="bike">Bike to get new keys for.</param>
|
||||
public async Task CalculateAuthKeys(Bikes.Bike.BluetoothLock.IBikeInfoMutable bike)
|
||||
public async Task CalculateAuthKeys(Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable bike)
|
||||
{
|
||||
if (bike == null)
|
||||
{
|
||||
|
@ -152,17 +153,17 @@ namespace TINK.Model.Connector
|
|||
}
|
||||
|
||||
UpdaterJSON.Load(
|
||||
bike,
|
||||
response,
|
||||
Mail,
|
||||
Bikes.Bike.BC.NotifyPropertyChangedLevel.None);
|
||||
bike,
|
||||
response,
|
||||
Mail,
|
||||
Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.None);
|
||||
}
|
||||
|
||||
/// <summary> Notifies COPRI about start of returning sequence. </summary>
|
||||
/// <remarks> Operator specific call.</remarks>
|
||||
/// <param name="bike">Bike to return.</param>
|
||||
/// <returns>Response on notification about start of returning sequence.</returns>
|
||||
public async Task StartReturningBike(Bikes.Bike.BC.IBikeInfoMutable bike)
|
||||
public async Task StartReturningBike(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
|
||||
{
|
||||
if (bike == null)
|
||||
{
|
||||
|
@ -188,7 +189,7 @@ namespace TINK.Model.Connector
|
|||
/// <param name="location">Location of the bike.</param>
|
||||
/// <returns>Response on updating locking state.</returns>
|
||||
public async Task UpdateLockingStateAsync(
|
||||
Bikes.Bike.BluetoothLock.IBikeInfoMutable bike,
|
||||
IBikeInfoMutable bike,
|
||||
LocationDto location)
|
||||
{
|
||||
if (bike == null)
|
||||
|
@ -221,10 +222,10 @@ namespace TINK.Model.Connector
|
|||
try
|
||||
{
|
||||
(await CopriServer.UpdateLockingStateAsync(
|
||||
bike.Id,
|
||||
bike.Id,
|
||||
state.Value,
|
||||
bike.OperatorUri,
|
||||
location,
|
||||
location,
|
||||
bike.LockInfo.BatteryPercentage)).GetIsBookingResponseOk(bike.Id);
|
||||
}
|
||||
catch (Exception)
|
||||
|
@ -236,7 +237,7 @@ namespace TINK.Model.Connector
|
|||
|
||||
/// <summary> Request to book a bike. </summary>
|
||||
/// <param name="bike">Bike to book.</param>
|
||||
public async Task DoBook(Bikes.Bike.BC.IBikeInfoMutable bike)
|
||||
public async Task DoBook(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
|
||||
{
|
||||
if (bike == null)
|
||||
{
|
||||
|
@ -249,22 +250,22 @@ namespace TINK.Model.Connector
|
|||
double batteryPercentage = btBike != null ? btBike.LockInfo.BatteryPercentage : double.NaN;
|
||||
|
||||
response = (await CopriServer.DoBookAsync(
|
||||
bike.Id,
|
||||
guid,
|
||||
bike.Id,
|
||||
guid,
|
||||
batteryPercentage,
|
||||
bike.OperatorUri)).GetIsBookingResponseOk(bike.Id);
|
||||
|
||||
bike.Load(
|
||||
response,
|
||||
response,
|
||||
Mail,
|
||||
Bikes.Bike.BC.NotifyPropertyChangedLevel.None);
|
||||
Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.None);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Books a bike and opens the lock.
|
||||
/// </summary>
|
||||
/// <param name="bike">Bike to book and open.</param>
|
||||
public async Task BookAndOpenAync(Bikes.Bike.CopriLock.IBikeInfoMutable bike)
|
||||
public async Task BookAndOpenAync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike)
|
||||
=> await Polling.BookAndOpenAync(CopriServer, bike, Mail);
|
||||
|
||||
/// <summary> Request to return a bike.</summary>
|
||||
|
@ -272,7 +273,7 @@ namespace TINK.Model.Connector
|
|||
/// <param name="locaton">Position of the bike for bluetooth locks.</param>
|
||||
/// <param name="smartDevice">Provides info about hard and software.</param>
|
||||
public async Task<BookingFinishedModel> DoReturn(
|
||||
Bikes.Bike.BC.IBikeInfoMutable bike,
|
||||
Bikes.BikeInfoNS.BC.IBikeInfoMutable bike,
|
||||
LocationDto location = null,
|
||||
ISmartDevice smartDevice = null)
|
||||
{
|
||||
|
@ -282,16 +283,16 @@ namespace TINK.Model.Connector
|
|||
}
|
||||
|
||||
DoReturnResponse response
|
||||
= (await CopriServer.DoReturn(bike.Id, location, smartDevice, bike.OperatorUri)).GetIsReturnBikeResponseOk(bike.Id);
|
||||
= (await CopriServer.DoReturn(bike.Id, location, smartDevice, bike.OperatorUri)).GetIsReturnBikeResponseOk(bike.Id);
|
||||
|
||||
bike.Load(Bikes.Bike.BC.NotifyPropertyChangedLevel.None);
|
||||
bike.Load(Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.None);
|
||||
return response?.Create() ?? new BookingFinishedModel();
|
||||
}
|
||||
|
||||
/// <summary> Request to return bike and close the lock.</summary>
|
||||
/// <param name="bike">Bike to return.</param>
|
||||
/// <param name="smartDevice">Provides info about hard and software.</param>
|
||||
public async Task<BookingFinishedModel> ReturnAndCloseAsync(Bikes.Bike.CopriLock.IBikeInfoMutable bike, ISmartDevice smartDevice = null)
|
||||
public async Task<BookingFinishedModel> ReturnAndCloseAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike, ISmartDevice smartDevice = null)
|
||||
=> await Polling.ReturnAndCloseAync(CopriServer, smartDevice, bike);
|
||||
|
||||
/// <summary>
|
||||
|
@ -302,8 +303,11 @@ namespace TINK.Model.Connector
|
|||
public async Task DoSubmitFeedback(ICommand.IUserFeedback userFeedback, Uri opertorUri)
|
||||
=> await CopriServer.DoSubmitFeedback(userFeedback.BikeId, userFeedback.Message, userFeedback.IsBikeBroken, opertorUri);
|
||||
#else
|
||||
public async Task DoSubmitFeedback(IUserFeedback userFeedback, Uri opertorUri)
|
||||
=> await CopriServer.DoSubmitFeedback(userFeedback.BikeId, userFeedback.Message, userFeedback.IsBikeBroken, opertorUri);
|
||||
/// <summary> Submits feedback for a renting operation.</summary>
|
||||
public async Task DoSubmitFeedback(
|
||||
IUserFeedback userFeedback,
|
||||
Uri opertorUri)
|
||||
=> await CopriServer.DoSubmitFeedback(userFeedback.BikeId, userFeedback.CurrentChargeBars, userFeedback.Message, userFeedback.IsBikeBroken, opertorUri);
|
||||
#endif
|
||||
|
||||
/// <summary> Submits mini survey to copri server. </summary>
|
||||
|
@ -311,9 +315,9 @@ namespace TINK.Model.Connector
|
|||
public async Task DoSubmitMiniSurvey(IDictionary<string, string> answers)
|
||||
=> await CopriServer.DoSubmitMiniSurvey(answers);
|
||||
|
||||
public async Task OpenLockAsync(Bikes.Bike.CopriLock.IBikeInfoMutable bike)
|
||||
public async Task OpenLockAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike)
|
||||
=> await CopriServer.OpenAync(bike);
|
||||
public async Task CloseLockAsync(Bikes.Bike.CopriLock.IBikeInfoMutable bike)
|
||||
public async Task CloseLockAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike)
|
||||
=> await CopriServer.CloseAync(bike);
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using TINK.Repository.Request;
|
||||
using TINK.Model.User.Account;
|
||||
using TINK.Model.Device;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using TINK.Model.Device;
|
||||
using TINK.Model.User.Account;
|
||||
using TINK.Repository.Request;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
{
|
||||
|
@ -25,54 +25,54 @@ namespace TINK.Model.Connector
|
|||
|
||||
/// <summary> Request to reserve a bike.</summary>
|
||||
/// <param name="bike">Bike to book.</param>
|
||||
Task DoReserve(Bikes.Bike.BC.IBikeInfoMutable bike);
|
||||
Task DoReserve(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike);
|
||||
|
||||
/// <summary> Request to cancel a reservation.</summary>
|
||||
/// <param name="bike">Bike to book.</param>
|
||||
Task DoCancelReservation(Bikes.Bike.BC.IBikeInfoMutable bike);
|
||||
Task DoCancelReservation(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike);
|
||||
|
||||
/// <summary> Get authentication keys to connect to lock.</summary>
|
||||
/// <param name="bike">Bike to book.</param>
|
||||
Task CalculateAuthKeys(Bikes.Bike.BluetoothLock.IBikeInfoMutable bike);
|
||||
Task CalculateAuthKeys(Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable bike);
|
||||
|
||||
/// <summary> Notifies COPRI about start of returning sequence. </summary>
|
||||
/// <remarks> Operator specific call.</remarks>
|
||||
/// <param name="bike">Bike to return.</param>
|
||||
/// <returns>Response on notification about start of returning sequence.</returns>
|
||||
Task StartReturningBike(Bikes.Bike.BC.IBikeInfoMutable bike);
|
||||
Task StartReturningBike(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike);
|
||||
|
||||
/// <summary> Updates COPRI lock state for a booked bike. </summary>
|
||||
/// <param name="bike">Bike to update locking state for.</param>
|
||||
/// <param name="location">Geolocation of lock when returning bike.</param>
|
||||
/// <returns>Response on updating locking state.</returns>
|
||||
Task UpdateLockingStateAsync(Bikes.Bike.BluetoothLock.IBikeInfoMutable bike, LocationDto location = null);
|
||||
Task UpdateLockingStateAsync(Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable bike, LocationDto location = null);
|
||||
|
||||
/// <summary> Request to book a bike.</summary>
|
||||
/// <param name="bike">Bike to book.</param>
|
||||
Task DoBook(Bikes.Bike.BC.IBikeInfoMutable bike);
|
||||
Task DoBook(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike);
|
||||
|
||||
/// <summary> Request to book a bike and open its lock.</summary>
|
||||
/// <param name="bike">Bike to book and to open lock for.</param>
|
||||
Task BookAndOpenAync(Bikes.Bike.CopriLock.IBikeInfoMutable bike);
|
||||
Task BookAndOpenAync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike);
|
||||
|
||||
/// <summary> Request to open lock.</summary>
|
||||
/// <param name="bike">Bike for which lock has to be opened.</param>
|
||||
Task OpenLockAsync(Bikes.Bike.CopriLock.IBikeInfoMutable bike);
|
||||
Task OpenLockAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike);
|
||||
|
||||
/// <summary> Request to close lock.</summary>
|
||||
/// <param name="bike">Bike for which lock has to be closed.</param>
|
||||
Task CloseLockAsync(Bikes.Bike.CopriLock.IBikeInfoMutable bike);
|
||||
Task CloseLockAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike);
|
||||
|
||||
/// <summary> Request to return a bike.</summary>
|
||||
/// <param name="bike">Bike to return.</param>
|
||||
/// <param name="location">Geolocation of lock when returning bike.</param>
|
||||
/// <param name="smartDevice">Provides info about hard and software.</param>
|
||||
Task<BookingFinishedModel> DoReturn(Bikes.Bike.BC.IBikeInfoMutable bike, LocationDto geolocation = null, ISmartDevice smartDevice = null);
|
||||
Task<BookingFinishedModel> DoReturn(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike, LocationDto geolocation = null, ISmartDevice smartDevice = null);
|
||||
|
||||
/// <summary> Request to return bike and close the lock.</summary>
|
||||
/// <param name="bike">Bike to return.</param>
|
||||
/// <param name="smartDevice">Provides info about hard and software.</param>
|
||||
Task<BookingFinishedModel> ReturnAndCloseAsync(Bikes.Bike.CopriLock.IBikeInfoMutable bike, ISmartDevice smartDevice = null);
|
||||
Task<BookingFinishedModel> ReturnAndCloseAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike, ISmartDevice smartDevice = null);
|
||||
|
||||
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
|
||||
bool IsConnected { get; }
|
||||
|
@ -80,7 +80,10 @@ namespace TINK.Model.Connector
|
|||
/// <summary> True if user is logged in false if not. </summary>
|
||||
string SessionCookie { get; }
|
||||
|
||||
Task DoSubmitFeedback(IUserFeedback userFeedback, Uri opertorUri);
|
||||
/// <summary> Submits feedback for a renting operation.</summary>
|
||||
Task DoSubmitFeedback(
|
||||
IUserFeedback userFeedback,
|
||||
Uri opertorUri);
|
||||
|
||||
/// <summary> Submits mini survey to copri server. </summary>
|
||||
/// <param name="answers">Collection of answers.</param>
|
||||
|
@ -124,6 +127,11 @@ namespace TINK.Model.Connector
|
|||
/// <summary> Id of the bike to which the feedback is related to.</summary>
|
||||
string BikeId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds the current chargeing level of the battery in bars, null if unkonwn.
|
||||
/// </summary>
|
||||
int? CurrentChargeBars { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds whether bike is broken or not.
|
||||
/// </summary>
|
||||
|
|
|
@ -17,9 +17,16 @@ namespace TINK.Model.Connector
|
|||
{
|
||||
public string BikeId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds the current chargeing level of the battery in bars, null if unkonwn.
|
||||
/// </summary>
|
||||
public int? CurrentChargeBars { get; set; }
|
||||
|
||||
public bool IsBikeBroken { get; set; }
|
||||
|
||||
public string Message { get; set; }
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -5,33 +5,46 @@ using TINK.Repository;
|
|||
namespace TINK.Model.Connector
|
||||
{
|
||||
/// <summary>
|
||||
/// Connects tink app to copri by getting data from copri and updating tink app model (i.e. bikes, user, ...)
|
||||
/// Connects app to copri data by getting data from copri.
|
||||
/// </summary>
|
||||
public class Connector : IConnector
|
||||
{
|
||||
/// <summary>Constructs a copri connector object.</summary>
|
||||
/// <param name="activeUri"> Uri to connect to.</param>
|
||||
/// <param name="appContextInfo">Provides app related info (app name and version, merchantid) to pass to COPRI.</param>
|
||||
/// /// <param name="sessionCookie"> Holds the session cookie.</param>
|
||||
/// <param name="p_strMail">Mail of user.</param>
|
||||
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
|
||||
/// <param name="sessionCookie"> Holds the session cookie.</param>
|
||||
/// <param name="mail">Mail of user.</param>
|
||||
/// <param name="expiresAfter">Timespan which holds value after which cache expires.</param>
|
||||
/// <param name="server"> Provides cached addess to copri.</param>
|
||||
/// <param name="server"> Is null in production and migh be a mock in testing context.</param>
|
||||
public Connector(
|
||||
Uri activeUri,
|
||||
AppContextInfo appContextInfo,
|
||||
string uiIsoLangugageName,
|
||||
string sessionCookie,
|
||||
string mail,
|
||||
TimeSpan? expiresAfter = null,
|
||||
ICachedCopriServer server = null )
|
||||
ICachedCopriServer server = null)
|
||||
{
|
||||
Command = GetCommand(
|
||||
server ?? new CopriProviderHttps(activeUri, appContextInfo.MerchantId, appContextInfo, sessionCookie),
|
||||
sessionCookie,
|
||||
server ?? new CopriProviderHttps(
|
||||
activeUri,
|
||||
appContextInfo.MerchantId,
|
||||
appContextInfo,
|
||||
uiIsoLangugageName,
|
||||
sessionCookie),
|
||||
sessionCookie,
|
||||
mail);
|
||||
|
||||
Query = GetQuery(
|
||||
server ?? new CopriProviderHttps(activeUri, appContextInfo.MerchantId, appContextInfo, sessionCookie, expiresAfter),
|
||||
sessionCookie,
|
||||
server ?? new CopriProviderHttps(
|
||||
activeUri,
|
||||
appContextInfo.MerchantId,
|
||||
appContextInfo,
|
||||
uiIsoLangugageName,
|
||||
sessionCookie,
|
||||
expiresAfter),
|
||||
sessionCookie,
|
||||
mail);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,28 +5,30 @@ using TINK.Repository;
|
|||
namespace TINK.Model.Connector
|
||||
{
|
||||
/// <summary>
|
||||
/// Connects tink app to copri by getting data from copri and updating tink app model (i.e. bikes, user, ...)
|
||||
/// Connects app to copri data by getting data from cache.
|
||||
/// </summary>
|
||||
public class ConnectorCache : IConnector
|
||||
{
|
||||
/// <summary>Constructs a copri connector object.</summary>
|
||||
/// <param name="p_strSessionCookie"> Holds the session cookie.</param>
|
||||
/// <param name="p_strMail">Mail of user.</param>
|
||||
/// <param name="server"> Provides addess to copri.</param>
|
||||
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
|
||||
/// <param name="sessionCookie"> Holds the session cookie.</param>
|
||||
/// <param name="mail">Mail of user.</param>
|
||||
/// <param name="server"> Is null in production and migh be a mock in testing context.</param>
|
||||
public ConnectorCache(
|
||||
AppContextInfo appContextInfo,
|
||||
string uiIsoLangugageName,
|
||||
string sessionCookie,
|
||||
string mail,
|
||||
ICopriServer server = null)
|
||||
{
|
||||
|
||||
Command = Connector.GetCommand(
|
||||
server ?? new CopriProviderMonkeyStore(appContextInfo.MerchantId, sessionCookie),
|
||||
server ?? new CopriProviderMonkeyStore(appContextInfo.MerchantId, uiIsoLangugageName, sessionCookie),
|
||||
sessionCookie,
|
||||
mail);
|
||||
|
||||
Query = GetQuery(
|
||||
server ?? new CopriProviderMonkeyStore(appContextInfo.MerchantId, sessionCookie),
|
||||
server ?? new CopriProviderMonkeyStore(appContextInfo.MerchantId, uiIsoLangugageName, sessionCookie),
|
||||
sessionCookie,
|
||||
mail);
|
||||
}
|
||||
|
|
|
@ -10,18 +10,20 @@ namespace TINK.Model.Connector
|
|||
/// </summary>
|
||||
/// <param name="isConnected">True if online, false if offline. If offline cache connector is returned.</param>
|
||||
/// <param name="appContextInfo">Provides app related info (app name and version, merchantid) to pass to COPRI.</param>
|
||||
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
|
||||
/// <returns></returns>
|
||||
public static IConnector Create(
|
||||
bool isConnected,
|
||||
bool isConnected,
|
||||
Uri activeUri,
|
||||
AppContextInfo appContextInfo,
|
||||
string sessionCookie,
|
||||
string mail,
|
||||
AppContextInfo appContextInfo,
|
||||
string uiIsoLangugageName,
|
||||
string sessionCookie,
|
||||
string mail,
|
||||
TimeSpan? expiresAfter = null)
|
||||
{
|
||||
return isConnected
|
||||
? new Connector(activeUri, appContextInfo, sessionCookie, mail, expiresAfter: expiresAfter) as IConnector
|
||||
: new ConnectorCache(appContextInfo, sessionCookie, mail);
|
||||
? new Connector(activeUri, appContextInfo, uiIsoLangugageName, sessionCookie, mail, expiresAfter: expiresAfter) as IConnector
|
||||
: new ConnectorCache(appContextInfo, uiIsoLangugageName, sessionCookie, mail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace TINK.Model.Connector.Filter
|
||||
|
@ -18,8 +17,8 @@ namespace TINK.Model.Connector.Filter
|
|||
/// </remarks>
|
||||
public static IGroupFilter Create(IEnumerable<string> group)
|
||||
{
|
||||
return group != null && group.Count() > 0
|
||||
? (IGroupFilter) new IntersectGroupFilter(group) :
|
||||
return group != null && group.Count() > 0
|
||||
? (IGroupFilter)new IntersectGroupFilter(group) :
|
||||
new NullGroupFilter();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace TINK.Model.Connector.Filter
|
|||
/// <param name="group">Group to transform.</param>
|
||||
/// <returns>Enumeration of numeric bike categories.</returns>
|
||||
public static IEnumerable<string> ToBikeCategory(this IEnumerable<string> group)
|
||||
=> group?.Select(x => x.GetBikeCategory())?.Where(x => !string.IsNullOrEmpty(x))
|
||||
=> group?.Select(x => x.GetBikeCategory())?.Where(x => !string.IsNullOrEmpty(x))
|
||||
?? new List<string>();
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using TINK.Model.Bike;
|
||||
using TINK.Model.Bikes;
|
||||
using TINK.Model.Connector.Filter;
|
||||
using TINK.Model.Services.CopriApi;
|
||||
using TINK.Model.Station;
|
||||
|
||||
using BikeInfo = TINK.Model.Bike.BC.BikeInfo;
|
||||
using BikeInfo = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfo;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
{
|
||||
|
@ -48,7 +48,7 @@ namespace TINK.Model.Connector
|
|||
private class QueryProvider : IQuery
|
||||
{
|
||||
/// <summary> Holds the filter. </summary>
|
||||
private IGroupFilter Filter { get; }
|
||||
private IGroupFilter Filter { get; }
|
||||
|
||||
/// <summary> Holds the reference to object which performs copry queries.</summary>
|
||||
private IQuery m_oInnerQuery;
|
||||
|
@ -67,7 +67,7 @@ namespace TINK.Model.Connector
|
|||
{
|
||||
var result = await m_oInnerQuery.GetBikesAsync();
|
||||
return new Result<BikeCollection>(
|
||||
result.Source,
|
||||
result.Source,
|
||||
new BikeCollection(DoFilter(result.Response, Filter)),
|
||||
result.GeneralData,
|
||||
result.Exception);
|
||||
|
@ -78,7 +78,7 @@ namespace TINK.Model.Connector
|
|||
{
|
||||
var result = await m_oInnerQuery.GetBikesOccupiedAsync();
|
||||
return new Result<BikeCollection>(
|
||||
result.Source,
|
||||
result.Source,
|
||||
new BikeCollection(result.Response.ToDictionary(x => x.Id)),
|
||||
result.GeneralData,
|
||||
result.Exception);
|
||||
|
@ -98,7 +98,7 @@ namespace TINK.Model.Connector
|
|||
providerBikesAndStations.Source,
|
||||
new StationsAndBikesContainer(filteredStationsDictionary, filteredBikesDictionary),
|
||||
providerBikesAndStations.GeneralData,
|
||||
providerBikesAndStations.Exception);
|
||||
providerBikesAndStations.Exception);
|
||||
|
||||
return filteredBikesAndStations;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace TINK.Model.Connector
|
|||
public static IFilteredConnector Create(IEnumerable<string> group, IConnector connector)
|
||||
{
|
||||
return group != null
|
||||
? (IFilteredConnector) new FilteredConnector(group, connector)
|
||||
? (IFilteredConnector)new FilteredConnector(group, connector)
|
||||
: new NullFilterConnector(connector); // Do not apply filtering.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using TINK.Model.Bike;
|
||||
using TINK.Model.Bikes;
|
||||
using TINK.Model.Services.CopriApi;
|
||||
using TINK.Model.Station;
|
||||
|
||||
using BikeInfo = TINK.Model.Bike.BC.BikeInfo;
|
||||
using BikeInfo = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfo;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
{
|
||||
|
@ -50,7 +50,7 @@ namespace TINK.Model.Connector
|
|||
/// <summary> Constructs a query object.</summary>
|
||||
/// <param name="p_oInnerQuery"></param>
|
||||
/// <param name="p_oFilter"></param>
|
||||
public QueryProvider(IQuery p_oInnerQuery)
|
||||
public QueryProvider(IQuery p_oInnerQuery)
|
||||
{
|
||||
m_oInnerQuery = p_oInnerQuery;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace TINK.Model.Connector
|
|||
|
||||
/// <summary> Gets the merchant id.</summary>
|
||||
protected string MerchantId => CopriServer.MerchantId;
|
||||
|
||||
|
||||
/// <summary> Constructs a query base object.</summary>
|
||||
/// <param name="p_oCopriServer">Server which implements communication.</param>
|
||||
/// <param name="p_oErrorStack">Object which hold communication objects.</param>
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
using Serilog;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using TINK.Model.Bike;
|
||||
using Serilog;
|
||||
using TINK.Model.Bikes;
|
||||
using TINK.Model.Connector.Updater;
|
||||
using TINK.Model.Services.CopriApi;
|
||||
using TINK.Repository;
|
||||
using TINK.Services.CopriApi;
|
||||
using BikeInfo = TINK.Model.Bike.BC.BikeInfo;
|
||||
using BikeInfo = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfo;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
{
|
||||
|
@ -16,14 +17,14 @@ namespace TINK.Model.Connector
|
|||
private readonly ICachedCopriServer server;
|
||||
|
||||
/// <summary>Constructs a copri query object.</summary>
|
||||
/// <param name="p_oCopriServer">Server which implements communication.</param>
|
||||
/// <param name="copriServer">Server which implements communication.</param>
|
||||
public CachedQuery(
|
||||
ICopriServerBase p_oCopriServer) : base(p_oCopriServer)
|
||||
ICopriServerBase copriServer) : base(copriServer)
|
||||
{
|
||||
server = p_oCopriServer as ICachedCopriServer;
|
||||
server = copriServer as ICachedCopriServer;
|
||||
if (server == null)
|
||||
{
|
||||
throw new ArgumentException($"Copri server is not of expected typ. Type detected is {p_oCopriServer.GetType()}.");
|
||||
throw new ArgumentException($"Copri server is not of expected typ. Type detected is {copriServer.GetType()}.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using TINK.Model.Bike;
|
||||
using Serilog;
|
||||
using TINK.Model.Bikes;
|
||||
using TINK.Model.Connector.Updater;
|
||||
using TINK.Model.Services.CopriApi;
|
||||
using TINK.Repository;
|
||||
|
||||
|
@ -11,26 +13,26 @@ namespace TINK.Model.Connector
|
|||
public class CachedQueryLoggedIn : BaseLoggedIn, IQuery
|
||||
{
|
||||
/// <summary> Cached copri server. </summary>
|
||||
private readonly ICachedCopriServer server;
|
||||
private ICachedCopriServer Server { get; }
|
||||
|
||||
/// <summary>Constructs a copri query object.</summary>
|
||||
/// <param name="p_oCopriServer">Server which implements communication.</param>
|
||||
public CachedQueryLoggedIn(ICopriServerBase p_oCopriServer,
|
||||
string p_strSessionCookie,
|
||||
string p_strMail,
|
||||
Func<DateTime> p_oDateTimeProvider) : base(p_oCopriServer, p_strSessionCookie, p_strMail, p_oDateTimeProvider)
|
||||
/// <param name="copriServer">Server which implements communication.</param>
|
||||
public CachedQueryLoggedIn(ICopriServerBase copriServer,
|
||||
string sessionCookie,
|
||||
string mail,
|
||||
Func<DateTime> dateTimeProvider) : base(copriServer, sessionCookie, mail, dateTimeProvider)
|
||||
{
|
||||
server = p_oCopriServer as ICachedCopriServer;
|
||||
if (server == null)
|
||||
Server = copriServer as ICachedCopriServer;
|
||||
if (Server == null)
|
||||
{
|
||||
throw new ArgumentException($"Copri server is not of expected typ. Type detected is {p_oCopriServer.GetType()}.");
|
||||
throw new ArgumentException($"Copri server is not of expected typ. Type detected is {copriServer.GetType()}.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Gets all stations including postions.</summary>
|
||||
public async Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync()
|
||||
{
|
||||
var stationsResponse = await server.GetStations();
|
||||
var stationsResponse = await Server.GetStations();
|
||||
|
||||
if (stationsResponse.Source == typeof(CopriCallsMonkeyStore)
|
||||
|| stationsResponse.Exception != null)
|
||||
|
@ -41,15 +43,15 @@ namespace TINK.Model.Connector
|
|||
new StationsAndBikesContainer(
|
||||
stationsResponse.Response.GetStationsAllMutable(),
|
||||
UpdaterJSON.GetBikesAll(
|
||||
(await server.GetBikesAvailable(true)).Response,
|
||||
(await server.GetBikesOccupied(true)).Response,
|
||||
(await Server.GetBikesAvailable(true)).Response?.bikes?.Values,
|
||||
(await Server.GetBikesOccupied(true)).Response?.bikes_occupied?.Values,
|
||||
Mail,
|
||||
DateTimeProvider)),
|
||||
stationsResponse.GeneralData,
|
||||
stationsResponse.Exception);
|
||||
}
|
||||
|
||||
var bikesAvailableResponse = await server.GetBikesAvailable();
|
||||
var bikesAvailableResponse = await Server.GetBikesAvailable();
|
||||
if (bikesAvailableResponse.Source == typeof(CopriCallsMonkeyStore)
|
||||
|| bikesAvailableResponse.Exception != null)
|
||||
{
|
||||
|
@ -57,16 +59,16 @@ namespace TINK.Model.Connector
|
|||
return new Result<StationsAndBikesContainer>(
|
||||
bikesAvailableResponse.Source,
|
||||
new StationsAndBikesContainer(
|
||||
(await server.GetStations(true)).Response.GetStationsAllMutable(),
|
||||
UpdaterJSON.GetBikesAll(bikesAvailableResponse.Response,
|
||||
(await server.GetBikesOccupied(true)).Response,
|
||||
(await Server.GetStations(true)).Response.GetStationsAllMutable(),
|
||||
UpdaterJSON.GetBikesAll(bikesAvailableResponse.Response?.bikes?.Values,
|
||||
(await Server.GetBikesOccupied(true)).Response?.bikes_occupied?.Values,
|
||||
Mail,
|
||||
DateTimeProvider)),
|
||||
bikesAvailableResponse.GeneralData,
|
||||
bikesAvailableResponse.Exception);
|
||||
}
|
||||
|
||||
var bikesOccupiedResponse = await server.GetBikesOccupied();
|
||||
var bikesOccupiedResponse = await Server.GetBikesOccupied();
|
||||
if (bikesOccupiedResponse.Source == typeof(CopriCallsMonkeyStore)
|
||||
|| bikesOccupiedResponse.Exception != null)
|
||||
{
|
||||
|
@ -74,10 +76,10 @@ namespace TINK.Model.Connector
|
|||
return new Result<StationsAndBikesContainer>(
|
||||
bikesOccupiedResponse.Source,
|
||||
new StationsAndBikesContainer(
|
||||
(await server.GetStations(true)).Response.GetStationsAllMutable(),
|
||||
(await Server.GetStations(true)).Response.GetStationsAllMutable(),
|
||||
UpdaterJSON.GetBikesAll(
|
||||
(await server.GetBikesAvailable(true)).Response,
|
||||
bikesOccupiedResponse.Response,
|
||||
(await Server.GetBikesAvailable(true)).Response?.bikes?.Values,
|
||||
bikesOccupiedResponse.Response?.bikes_occupied?.Values,
|
||||
Mail,
|
||||
DateTimeProvider)),
|
||||
bikesOccupiedResponse.GeneralData,
|
||||
|
@ -85,16 +87,16 @@ namespace TINK.Model.Connector
|
|||
}
|
||||
|
||||
// Both types bikes could read from copri => update cache
|
||||
server.AddToCache(stationsResponse);
|
||||
server.AddToCache(bikesAvailableResponse);
|
||||
server.AddToCache(bikesOccupiedResponse);
|
||||
Server.AddToCache(stationsResponse);
|
||||
Server.AddToCache(bikesAvailableResponse);
|
||||
Server.AddToCache(bikesOccupiedResponse);
|
||||
|
||||
var exceptions = new[] { stationsResponse?.Exception, bikesAvailableResponse?.Exception, bikesOccupiedResponse?.Exception }.Where(x => x != null).ToArray();
|
||||
|
||||
var stationsMutable = stationsResponse.Response.GetStationsAllMutable();
|
||||
var bikesMutable = UpdaterJSON.GetBikesAll(
|
||||
bikesAvailableResponse.Response,
|
||||
bikesOccupiedResponse.Response,
|
||||
bikesAvailableResponse.Response?.bikes?.Values,
|
||||
bikesOccupiedResponse.Response?.bikes_occupied?.Values,
|
||||
Mail,
|
||||
DateTimeProvider);
|
||||
|
||||
|
@ -109,58 +111,108 @@ namespace TINK.Model.Connector
|
|||
/// <returns>Collection of bikes.</returns>
|
||||
public async Task<Result<BikeCollection>> GetBikesOccupiedAsync()
|
||||
{
|
||||
var result = await server.GetBikesOccupied();
|
||||
server.AddToCache(result);
|
||||
return new Result<BikeCollection>(result.Source, result.Response.GetBikesOccupied(Mail, DateTimeProvider), result.GeneralData, result.Exception);
|
||||
var bikesAvailableResponse = await Server.GetBikesAvailable(false);
|
||||
if (bikesAvailableResponse.Source == typeof(CopriCallsMonkeyStore)
|
||||
|| bikesAvailableResponse.Exception != null)
|
||||
{
|
||||
// Bikes available were read from cache ==> get bikes occupied from cache as well to avoid inconsistencies.
|
||||
Log.ForContext<CachedQueryLoggedIn>().Debug("Bikes available read from cache. Reading bikes occupied from cache as well.");
|
||||
return new Result<BikeCollection>(
|
||||
bikesAvailableResponse.Source,
|
||||
UpdaterJSON.GetBikesAll(
|
||||
bikesAvailableResponse.Response?.bikes?.Values?.Where(bike => bike.GetState() == State.InUseStateEnum.FeedbackPending),
|
||||
(await Server.GetBikesOccupied(true))?.Response?.bikes_occupied?.Values,
|
||||
Mail,
|
||||
DateTimeProvider),
|
||||
bikesAvailableResponse.GeneralData,
|
||||
bikesAvailableResponse.Exception);
|
||||
}
|
||||
|
||||
var bikesOccupiedResponse = await Server.GetBikesOccupied(false);
|
||||
if (bikesOccupiedResponse.Source == typeof(CopriCallsMonkeyStore)
|
||||
|| bikesOccupiedResponse.Exception != null)
|
||||
{
|
||||
// Bikes occupied were read from cache ==> get bikes available from cache as well to avoid inconsistencies
|
||||
Log.ForContext<CachedQueryLoggedIn>().Debug("Bikes occupied read from cache. Reread bikes available from cache as well.");
|
||||
return new Result<BikeCollection>(
|
||||
bikesOccupiedResponse.Source,
|
||||
UpdaterJSON.GetBikesAll(
|
||||
(await Server.GetBikesAvailable(true)).Response?.bikes?.Values?.Where(bike => bike.GetState() == State.InUseStateEnum.FeedbackPending),
|
||||
bikesOccupiedResponse.Response?.bikes_occupied?.Values,
|
||||
Mail,
|
||||
DateTimeProvider),
|
||||
bikesOccupiedResponse.GeneralData,
|
||||
bikesOccupiedResponse.Exception);
|
||||
}
|
||||
|
||||
// Both types bikes could read from copri => update bikes occupied cache.
|
||||
// // Do not add bikes available to cache because this might lead to conflicts calls GetBikesAsync() and bikes with FeedbackPending state are of no use offline.
|
||||
Server.AddToCache(bikesOccupiedResponse);
|
||||
|
||||
return new Result<BikeCollection>(
|
||||
bikesOccupiedResponse.Source,
|
||||
UpdaterJSON.GetBikesAll(
|
||||
bikesAvailableResponse?.Response.bikes?.Values?.Select(bike => bike)?.Where(bike => bike.GetState() == State.InUseStateEnum.FeedbackPending),
|
||||
bikesOccupiedResponse?.Response?.bikes_occupied?.Values,
|
||||
Mail,
|
||||
DateTimeProvider),
|
||||
bikesOccupiedResponse.GeneralData,
|
||||
bikesOccupiedResponse.Exception);
|
||||
}
|
||||
|
||||
/// <summary> Gets bikes available and bikes occupied. </summary>
|
||||
/// <returns>Collection of bikes.</returns>
|
||||
public async Task<Result<BikeCollection>> GetBikesAsync()
|
||||
{
|
||||
var l_oBikesAvailableResponse = await server.GetBikesAvailable();
|
||||
var bikesAvailableResponse = await Server.GetBikesAvailable();
|
||||
|
||||
if (l_oBikesAvailableResponse.Source == typeof(CopriCallsMonkeyStore)
|
||||
|| l_oBikesAvailableResponse.Exception != null)
|
||||
if (bikesAvailableResponse.Source == typeof(CopriCallsMonkeyStore)
|
||||
|| bikesAvailableResponse.Exception != null)
|
||||
{
|
||||
// Bikes avilable were read from cache ==> get bikes occupied from cache as well to avoid inconsistencies
|
||||
// Bikes available were read from cache ==> get bikes occupied from cache as well to avoid inconsistencies.
|
||||
Log.ForContext<CachedQueryLoggedIn>().Debug("Bikes available read from cache. Reading bikes occupied from cache as well.");
|
||||
return new Result<BikeCollection>(
|
||||
l_oBikesAvailableResponse.Source,
|
||||
bikesAvailableResponse.Source,
|
||||
UpdaterJSON.GetBikesAll(
|
||||
l_oBikesAvailableResponse.Response,
|
||||
(await server.GetBikesOccupied(true)).Response,
|
||||
bikesAvailableResponse.Response?.bikes?.Values,
|
||||
(await Server.GetBikesOccupied(true)).Response?.bikes_occupied?.Values,
|
||||
Mail,
|
||||
DateTimeProvider),
|
||||
l_oBikesAvailableResponse.GeneralData,
|
||||
l_oBikesAvailableResponse.Exception);
|
||||
bikesAvailableResponse.GeneralData,
|
||||
bikesAvailableResponse.Exception);
|
||||
}
|
||||
|
||||
var l_oBikesOccupiedResponse = await server.GetBikesOccupied();
|
||||
if (l_oBikesOccupiedResponse.Source == typeof(CopriCallsMonkeyStore)
|
||||
|| l_oBikesOccupiedResponse.Exception != null)
|
||||
var bikesOccupiedResponse = await Server.GetBikesOccupied();
|
||||
if (bikesOccupiedResponse.Source == typeof(CopriCallsMonkeyStore)
|
||||
|| bikesOccupiedResponse.Exception != null)
|
||||
{
|
||||
// Bikes occupied were read from cache ==> get bikes available from cache as well to avoid inconsistencies
|
||||
Log.ForContext<CachedQueryLoggedIn>().Debug("Bikes occupied read from cache. Reread bikes available from cache as well.");
|
||||
return new Result<BikeCollection>(
|
||||
l_oBikesOccupiedResponse.Source,
|
||||
bikesOccupiedResponse.Source,
|
||||
UpdaterJSON.GetBikesAll(
|
||||
(await server.GetBikesAvailable(true)).Response,
|
||||
l_oBikesOccupiedResponse.Response,
|
||||
(await Server.GetBikesAvailable(true)).Response?.bikes?.Values,
|
||||
bikesOccupiedResponse.Response?.bikes_occupied?.Values,
|
||||
Mail,
|
||||
DateTimeProvider),
|
||||
l_oBikesOccupiedResponse.GeneralData,
|
||||
l_oBikesOccupiedResponse.Exception);
|
||||
|
||||
bikesOccupiedResponse.GeneralData,
|
||||
bikesOccupiedResponse.Exception);
|
||||
}
|
||||
|
||||
// Both types bikes could read from copri => update cache
|
||||
server.AddToCache(l_oBikesAvailableResponse);
|
||||
server.AddToCache(l_oBikesOccupiedResponse);
|
||||
Server.AddToCache(bikesAvailableResponse);
|
||||
Server.AddToCache(bikesOccupiedResponse);
|
||||
|
||||
Log.ForContext<CachedQueryLoggedIn>().Debug("Bikes available and occupied read successfully from server.");
|
||||
return new Result<BikeCollection>(
|
||||
l_oBikesAvailableResponse.Source,
|
||||
UpdaterJSON.GetBikesAll(l_oBikesAvailableResponse.Response, l_oBikesOccupiedResponse.Response, Mail, DateTimeProvider),
|
||||
l_oBikesAvailableResponse.GeneralData,
|
||||
l_oBikesAvailableResponse.Exception != null || l_oBikesOccupiedResponse.Exception != null ? new AggregateException(new[] { l_oBikesAvailableResponse.Exception, l_oBikesOccupiedResponse.Exception }) : null);
|
||||
}
|
||||
bikesAvailableResponse.Source,
|
||||
UpdaterJSON.GetBikesAll(
|
||||
bikesAvailableResponse.Response?.bikes?.Values,
|
||||
bikesOccupiedResponse.Response?.bikes_occupied?.Values,
|
||||
Mail,
|
||||
DateTimeProvider),
|
||||
bikesAvailableResponse.GeneralData,
|
||||
bikesAvailableResponse.Exception != null || bikesOccupiedResponse.Exception != null ? new AggregateException(new[] { bikesAvailableResponse.Exception, bikesOccupiedResponse.Exception }) : null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using System.Threading.Tasks;
|
||||
using TINK.Model.Bike;
|
||||
using TINK.Model.Bikes;
|
||||
using TINK.Model.Services.CopriApi;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
using Serilog;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using TINK.Model.Bike;
|
||||
using Serilog;
|
||||
using TINK.Model.Bikes;
|
||||
using TINK.Model.Connector.Updater;
|
||||
using TINK.Model.Services.CopriApi;
|
||||
using TINK.Repository;
|
||||
using TINK.Services.CopriApi;
|
||||
using BikeInfo = TINK.Model.Bike.BC.BikeInfo;
|
||||
using BikeInfo = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfo;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
{
|
||||
|
@ -20,7 +21,7 @@ namespace TINK.Model.Connector
|
|||
/// <param name="p_oCopriServer">Server which implements communication.</param>
|
||||
public Query(ICopriServerBase p_oCopriServer) : base(p_oCopriServer)
|
||||
{
|
||||
server = p_oCopriServer as ICopriServer;
|
||||
server = p_oCopriServer as ICopriServer;
|
||||
if (server == null)
|
||||
{
|
||||
throw new ArgumentException($"Copri server is not of expected typ. Type detected is {p_oCopriServer.GetType()}.");
|
||||
|
@ -30,11 +31,11 @@ namespace TINK.Model.Connector
|
|||
/// <summary> Gets all stations including postions.</summary>
|
||||
public async Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync()
|
||||
{
|
||||
var stationsAllResponse = await server.GetStationsAsync();
|
||||
var stationsAllResponse = await server.GetStationsAsync();
|
||||
var bikesAvailableResponse = await server.GetBikesAvailableAsync();
|
||||
|
||||
return new Result<StationsAndBikesContainer>(
|
||||
typeof(CopriCallsMonkeyStore),
|
||||
typeof(CopriCallsMonkeyStore),
|
||||
new StationsAndBikesContainer(stationsAllResponse.GetStationsAllMutable(), bikesAvailableResponse.GetBikesAvailable()),
|
||||
stationsAllResponse.GetGeneralData());
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using TINK.Model.Bike;
|
||||
using TINK.Model.Bikes;
|
||||
using TINK.Model.Connector.Updater;
|
||||
using TINK.Model.Services.CopriApi;
|
||||
using TINK.Repository;
|
||||
|
||||
|
@ -9,23 +11,23 @@ namespace TINK.Model.Connector
|
|||
/// <summary> Provides query functionality for a logged in user. </summary>
|
||||
public class QueryLoggedIn : BaseLoggedIn, IQuery
|
||||
{
|
||||
/// <summary> Cached copri server. </summary>
|
||||
/// <summary> Copri server. </summary>
|
||||
private readonly ICopriServer server;
|
||||
|
||||
/// <summary>Constructs a copri query object.</summary>
|
||||
/// <param name="p_oCopriServer">Server which implements communication.</param>
|
||||
public QueryLoggedIn(ICopriServerBase p_oCopriServer,
|
||||
string p_strSessionCookie,
|
||||
string p_strMail,
|
||||
Func<DateTime> p_oDateTimeProvider) : base(p_oCopriServer, p_strSessionCookie, p_strMail, p_oDateTimeProvider)
|
||||
/// <param name="copriServer">Server which implements communication.</param>
|
||||
public QueryLoggedIn(ICopriServerBase copriServer,
|
||||
string sessionCookie,
|
||||
string mail,
|
||||
Func<DateTime> dateTimeProvider) : base(copriServer, sessionCookie, mail, dateTimeProvider)
|
||||
{
|
||||
server = p_oCopriServer as ICopriServer;
|
||||
server = copriServer as ICopriServer;
|
||||
if (server == null)
|
||||
{
|
||||
throw new ArgumentException($"Copri server is not of expected typ. Type detected is {p_oCopriServer.GetType()}.");
|
||||
throw new ArgumentException($"Copri server is not of expected typ. Type detected is {copriServer.GetType()}.");
|
||||
}
|
||||
|
||||
server = p_oCopriServer as ICopriServer;
|
||||
server = copriServer as ICopriServer;
|
||||
}
|
||||
|
||||
/// <summary> Gets all stations including postions.</summary>
|
||||
|
@ -39,30 +41,45 @@ namespace TINK.Model.Connector
|
|||
typeof(CopriCallsMonkeyStore),
|
||||
new StationsAndBikesContainer(
|
||||
stationResponse.GetStationsAllMutable(),
|
||||
UpdaterJSON.GetBikesAll(bikesAvailableResponse, bikesOccupiedResponse, Mail, DateTimeProvider)),
|
||||
UpdaterJSON.GetBikesAll(
|
||||
bikesAvailableResponse?.bikes?.Values,
|
||||
bikesOccupiedResponse?.bikes_occupied?.Values,
|
||||
Mail,
|
||||
DateTimeProvider)),
|
||||
stationResponse.GetGeneralData());
|
||||
}
|
||||
|
||||
/// <summary> Gets bikes occupied. </summary>
|
||||
/// <summary> Gets bikes occupied and bikes for which feedback is required. </summary>
|
||||
/// <returns>Collection of bikes.</returns>
|
||||
public async Task<Result<BikeCollection>> GetBikesOccupiedAsync()
|
||||
{
|
||||
var bikesOccupiedResponse = (await server.GetBikesOccupiedAsync());
|
||||
var bikesFeedbackRequired = await server.GetBikesAvailableAsync();
|
||||
var bikesOccupiedResponse = await server.GetBikesOccupiedAsync();
|
||||
|
||||
return new Result<BikeCollection>(
|
||||
typeof(CopriCallsMonkeyStore),
|
||||
bikesOccupiedResponse.GetBikesOccupied(Mail, DateTimeProvider),
|
||||
UpdaterJSON.GetBikesAll(
|
||||
bikesFeedbackRequired.bikes?.Values?.Select(bike => bike)?.Where(bike => bike.GetState() == State.InUseStateEnum.FeedbackPending),
|
||||
bikesOccupiedResponse?.bikes_occupied?.Values,
|
||||
Mail,
|
||||
DateTimeProvider),
|
||||
bikesOccupiedResponse.GetGeneralData());
|
||||
}
|
||||
|
||||
/// <summary> Gets bikes available and bikes occupied. </summary>
|
||||
/// <returns>Collection of bikes.</returns>
|
||||
public async Task<Result<BikeCollection>> GetBikesAsync()
|
||||
{
|
||||
var bikesAvailableResponse = await server.GetBikesAvailableAsync();
|
||||
var bikesOccupiedResponse = await server.GetBikesOccupiedAsync();
|
||||
|
||||
|
||||
return new Result<BikeCollection>(
|
||||
typeof(CopriCallsMonkeyStore),
|
||||
UpdaterJSON.GetBikesAll(bikesAvailableResponse, bikesOccupiedResponse, Mail, DateTimeProvider),
|
||||
typeof(CopriCallsMonkeyStore),
|
||||
UpdaterJSON.GetBikesAll(
|
||||
bikesAvailableResponse?.bikes?.Values,
|
||||
bikesOccupiedResponse?.bikes_occupied?.Values,
|
||||
Mail,
|
||||
DateTimeProvider),
|
||||
bikesAvailableResponse.GetGeneralData());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,26 @@
|
|||
using Serilog;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using TINK.Model.Bike;
|
||||
using TINK.Repository.Exception;
|
||||
using TINK.Repository.Response;
|
||||
using Serilog;
|
||||
using TINK.Model.Bikes.BikeInfoNS.BikeNS;
|
||||
using TINK.Model.Services.CopriApi.ServerUris;
|
||||
using TINK.Model.State;
|
||||
using TINK.Repository.Exception;
|
||||
using TINK.Repository.Response;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
{
|
||||
/// <summary>
|
||||
/// Conversion helper functionality.
|
||||
/// Converts weak typed JSON data (mostly string) to strong typed c# data (base types, enumerations, objects, ...).
|
||||
/// JSON is received from COPRI and deserialized using Json.NET.
|
||||
/// </summary>
|
||||
public static class TextToTypeHelper
|
||||
{
|
||||
/// <summary> Holds the text for demo bikes. </summary>
|
||||
private const string DEMOBIKEMARKER = "DEMO";
|
||||
|
||||
/// <summary> Part text denoting two wheel cargo bike.. </summary>
|
||||
private const string TWOWHEELCARGOMARKERFRAGMENT = "LONG";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the position from StationInfo object.
|
||||
/// </summary>
|
||||
|
@ -30,7 +28,7 @@ namespace TINK.Model.Connector
|
|||
/// <returns>Position information.</returns>
|
||||
public static IPosition GetPosition(this StationsAvailableResponse.StationInfo stationInfo)
|
||||
=> GetPosition(stationInfo.gps);
|
||||
|
||||
|
||||
/// <summary> Gets the position from StationInfo object. </summary>
|
||||
/// <param name="authorizationResponse">Object to get information from.</param>
|
||||
/// <returns>Position information.</returns>
|
||||
|
@ -83,7 +81,7 @@ namespace TINK.Model.Connector
|
|||
{
|
||||
try
|
||||
{
|
||||
return stationInfo.station_group.GetGroup();
|
||||
return stationInfo.station_group.GetGroup();
|
||||
}
|
||||
catch (Exception l_oException)
|
||||
{
|
||||
|
@ -92,48 +90,67 @@ namespace TINK.Model.Connector
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the position from StationInfo object.
|
||||
/// Gets the position from BikeInfoBase object.
|
||||
/// </summary>
|
||||
/// <param name="bikeInfo">Object to get information from.</param>
|
||||
/// <returns>Position information.</returns>
|
||||
/// <returns>Rental state.</returns>
|
||||
public static InUseStateEnum GetState(this BikeInfoBase bikeInfo)
|
||||
{
|
||||
var l_oState = bikeInfo.state;
|
||||
var stateText = bikeInfo.state?.ToLower()?.Trim();
|
||||
|
||||
if (string.IsNullOrEmpty(l_oState))
|
||||
if (string.IsNullOrEmpty(stateText))
|
||||
{
|
||||
throw new InvalidResponseException<BikeInfoBase>(
|
||||
string.Format("Unknown reservation state detected. Member {0}.{1}.", typeof(BikeInfoBase), nameof(BikeInfoBase.state)),
|
||||
"Bike state must not be empty.",
|
||||
bikeInfo);
|
||||
}
|
||||
|
||||
if (l_oState == "available")
|
||||
if (Enum.TryParse(stateText, out InUseStateEnum state))
|
||||
return state;
|
||||
|
||||
if (stateText == "available")
|
||||
{
|
||||
return InUseStateEnum.Disposable;
|
||||
}
|
||||
else if (l_oState == "reserved" ||
|
||||
l_oState == "requested")
|
||||
else if (stateText == "reserved" ||
|
||||
stateText == "requested")
|
||||
{
|
||||
return InUseStateEnum.Reserved;
|
||||
}
|
||||
else if (l_oState == "booked" ||
|
||||
l_oState == "occupied")
|
||||
else if (stateText == "booked" ||
|
||||
stateText == "occupied")
|
||||
{
|
||||
return InUseStateEnum.Booked;
|
||||
}
|
||||
|
||||
throw new CommunicationException(string.Format("Unknown bike state detected. State is {0}.", l_oState));
|
||||
throw new CommunicationException(string.Format("Unknown bike state detected. State is {0}.", stateText));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the position from BikeInfoAvailable object.
|
||||
/// </summary>
|
||||
/// <param name="bikeInfo">Object to get information from.</param>
|
||||
/// <returns>Rental state.</returns>
|
||||
public static InUseStateEnum GetState(this BikeInfoAvailable bikeInfo)
|
||||
{
|
||||
var state = GetState((BikeInfoBase)bikeInfo);
|
||||
|
||||
if (state != InUseStateEnum.Disposable)
|
||||
return state;
|
||||
|
||||
return bikeInfo.GetIsFeedbackPending()
|
||||
? InUseStateEnum.FeedbackPending
|
||||
: InUseStateEnum.Disposable;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the from date information from JSON.
|
||||
/// </summary>
|
||||
/// <param name="bikeInfo">JSON to get information from..</param>
|
||||
/// <returns>From information.</returns>
|
||||
/// <returns>From information if bike hold this information 0001-01-01 (DateTime.MinValue) otherwise.</returns>
|
||||
public static DateTime GetFrom(this BikeInfoReservedOrBooked bikeInfo)
|
||||
{
|
||||
return DateTime.Parse(bikeInfo.start_time);
|
||||
}
|
||||
=> DateTime.TryParse(bikeInfo?.start_time, out DateTime dateFrom) ? dateFrom : DateTime.MinValue;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the bike is a trike or not.
|
||||
|
@ -144,7 +161,7 @@ namespace TINK.Model.Connector
|
|||
{
|
||||
return bikeInfo?.description != null
|
||||
? bikeInfo.description.ToUpper().Contains(DEMOBIKEMARKER)
|
||||
: (bool?) null;
|
||||
: (bool?)null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -178,7 +195,7 @@ namespace TINK.Model.Connector
|
|||
/// <returns>From information.</returns>
|
||||
public static bool GetIsBluetoothLockBike(this BikeInfoBase bikeInfo)
|
||||
{
|
||||
return !string.IsNullOrEmpty(bikeInfo.system)
|
||||
return !string.IsNullOrEmpty(bikeInfo.system)
|
||||
&& bikeInfo.system.ToUpper().StartsWith("ILOCKIT");
|
||||
}
|
||||
|
||||
|
@ -208,7 +225,7 @@ namespace TINK.Model.Connector
|
|||
/// <summary> Gets whether the bike has a bord computer or not. </summary>
|
||||
/// <param name="bikeInfo">JSON to get information from..</param>
|
||||
/// <returns>From information.</returns>
|
||||
public static int GetBluetoothLockId(this BikeInfoAvailable bikeInfo)
|
||||
public static int GetBluetoothLockId(this BikeInfoBase bikeInfo)
|
||||
{
|
||||
return TextToLockItTypeHelper.GetBluetoothLockId(bikeInfo?.Ilockit_ID);
|
||||
}
|
||||
|
@ -216,7 +233,7 @@ namespace TINK.Model.Connector
|
|||
/// <summary> Gets whether the bike has a bord computer or not. </summary>
|
||||
/// <param name="bikeInfo">JSON to get information from..</param>
|
||||
/// <returns>From information.</returns>
|
||||
public static Guid GetBluetoothLockGuid(this BikeInfoAvailable bikeInfo)
|
||||
public static Guid GetBluetoothLockGuid(this BikeInfoBase bikeInfo)
|
||||
{
|
||||
// return new Guid("00000000-0000-0000-0000-e57e6b9aee16");
|
||||
return Guid.TryParse(bikeInfo?.Ilockit_GUID, out Guid lockGuid)
|
||||
|
@ -266,38 +283,9 @@ namespace TINK.Model.Connector
|
|||
/// <param name="bikeInfo">JSON to get information from..</param>
|
||||
/// <returns>From information.</returns>
|
||||
public static WheelType? GetWheelType(this BikeInfoBase bikeInfo)
|
||||
{
|
||||
var l_oDescription = bikeInfo.description;
|
||||
|
||||
if (l_oDescription == null)
|
||||
{
|
||||
// Can not get type of wheel if description text is empty.
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach (WheelType l_oWheelType in Enum.GetValues(typeof(WheelType)))
|
||||
{
|
||||
|
||||
if (l_oDescription.ToUpper().Contains(l_oWheelType.ToString().ToUpper()))
|
||||
{
|
||||
return l_oWheelType;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for custom value "Long".
|
||||
if (l_oDescription.ToUpper().Contains(TWOWHEELCARGOMARKERFRAGMENT))
|
||||
{
|
||||
return WheelType.Two;
|
||||
}
|
||||
|
||||
// Check for Stadrad.
|
||||
if (GetTypeOfBike(bikeInfo) == TypeOfBike.Citybike)
|
||||
{
|
||||
return WheelType.Two;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
=> Enum.TryParse(bikeInfo?.bike_type?.wheels, true, out WheelType wheelType)
|
||||
? wheelType
|
||||
: (WheelType?)null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of bike.
|
||||
|
@ -305,25 +293,9 @@ namespace TINK.Model.Connector
|
|||
/// <param name="bikeInfo">Object to get bike type from.</param>
|
||||
/// <returns>Type of bike.</returns>
|
||||
public static TypeOfBike? GetTypeOfBike(this BikeInfoBase bikeInfo)
|
||||
{
|
||||
var l_oDescription = bikeInfo?.description;
|
||||
|
||||
if (l_oDescription == null)
|
||||
{
|
||||
// Can not get type of wheel if description text is empty.
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach (TypeOfBike l_oTypeOfBike in Enum.GetValues(typeof(TypeOfBike)))
|
||||
{
|
||||
if (l_oDescription.ToUpper().Contains(l_oTypeOfBike.GetCopriText().ToUpper()))
|
||||
{
|
||||
return l_oTypeOfBike;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
=> Enum.TryParse(bikeInfo?.bike_type?.category, true, out TypeOfBike typeOfBike)
|
||||
? typeOfBike
|
||||
: (TypeOfBike?)null;
|
||||
|
||||
/// <summary> Get position from a ,- separated string. </summary>
|
||||
/// <param name="gps">Text to extract positon from.</param>
|
||||
|
@ -338,48 +310,33 @@ namespace TINK.Model.Connector
|
|||
/// <returns>Position object.</returns>
|
||||
public static Map.IMapSpan GetMapSpan(this MapSpan mapSpan)
|
||||
=> Map.MapSpanFactory.Create(
|
||||
GetPosition(mapSpan?.center),
|
||||
double.TryParse(mapSpan?.radius, NumberStyles.Float, CultureInfo.InvariantCulture, out double radius) ? radius: double.NaN);
|
||||
GetPosition(mapSpan?.center),
|
||||
double.TryParse(mapSpan?.radius, NumberStyles.Float, CultureInfo.InvariantCulture, out double radius) ? radius : double.NaN);
|
||||
|
||||
|
||||
/// <summary> Gets text of bike from. </summary>
|
||||
/// <param name="p_eType">Type to get text for.</param>
|
||||
/// <returns></returns>
|
||||
public static string GetCopriText(this TypeOfBike p_eType)
|
||||
{
|
||||
switch (p_eType)
|
||||
{
|
||||
case TypeOfBike.Citybike:
|
||||
return "Stadtrad";
|
||||
|
||||
default:
|
||||
return p_eType.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the locking state from response.
|
||||
/// </summary>
|
||||
/// <param name="bikeInfo"> Response locking state from.</param>
|
||||
/// <returns>Locking state</returns>
|
||||
public static Bikes.Bike.CopriLock.LockingState GetCopriLockingState(this BikeInfoBase bikeInfo)
|
||||
public static Bikes.BikeInfoNS.CopriLock.LockingState GetCopriLockingState(this BikeInfoBase bikeInfo)
|
||||
{
|
||||
if (string.IsNullOrEmpty(bikeInfo?.lock_state))
|
||||
return Bikes.Bike.CopriLock.LockingState.UnknownDisconnected;
|
||||
return Bikes.BikeInfoNS.CopriLock.LockingState.UnknownDisconnected;
|
||||
|
||||
if (bikeInfo.lock_state.ToUpper().Trim() == "locked".ToUpper())
|
||||
return Bikes.Bike.CopriLock.LockingState.Closed;
|
||||
return Bikes.BikeInfoNS.CopriLock.LockingState.Closed;
|
||||
|
||||
if (bikeInfo.lock_state.ToUpper().Trim() == "locking".ToUpper())
|
||||
return Bikes.Bike.CopriLock.LockingState.Closing;
|
||||
return Bikes.BikeInfoNS.CopriLock.LockingState.Closing;
|
||||
|
||||
if (bikeInfo.lock_state.ToUpper().Trim() == "unlocked".ToUpper())
|
||||
return Bikes.Bike.CopriLock.LockingState.Open;
|
||||
return Bikes.BikeInfoNS.CopriLock.LockingState.Open;
|
||||
|
||||
if (bikeInfo.lock_state.ToUpper().Trim() == "unlocking".ToUpper())
|
||||
return Bikes.Bike.CopriLock.LockingState.Opening;
|
||||
return Bikes.BikeInfoNS.CopriLock.LockingState.Opening;
|
||||
|
||||
return Bikes.Bike.CopriLock.LockingState.UnknownDisconnected;
|
||||
return Bikes.BikeInfoNS.CopriLock.LockingState.UnknownDisconnected;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -409,8 +366,15 @@ namespace TINK.Model.Connector
|
|||
/// <param name="response">Response to get version info from.</param>
|
||||
/// <returns>COPRI version</returns>
|
||||
public static Version GetCopriVersion(this CopriVersion response)
|
||||
=> response.TryGetCopriVersion(out Version copriVersion)
|
||||
=> response.TryGetCopriVersion(out Version copriVersion)
|
||||
? copriVersion
|
||||
: throw new InvalidResponseException($"Can not get version info from copri response {response?.copri_version}.");
|
||||
|
||||
/// <summary>
|
||||
/// Gets bike advanced bike state. If entry Co2Saving exists feedback is required.
|
||||
/// </summary>
|
||||
/// <param name="bike">Bike get to state from.</param>
|
||||
public static bool GetIsFeedbackPending(this BikeInfoAvailable bike)
|
||||
=> bike.co2saving != null;
|
||||
}
|
||||
}
|
||||
|
|
330
TINKLib/Model/Connector/Updater/BikeInfoFactory.cs
Normal file
330
TINKLib/Model/Connector/Updater/BikeInfoFactory.cs
Normal file
|
@ -0,0 +1,330 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Serilog;
|
||||
using TINK.Model.Bikes.BikeInfoNS.BikeNS;
|
||||
using TINK.Model.MiniSurvey;
|
||||
using TINK.Model.State;
|
||||
using TINK.Repository.Response;
|
||||
using BikeExtension = TINK.Model.Bikes.BikeInfoNS.BikeNS.BikeExtension;
|
||||
using BikeInfo = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfo;
|
||||
|
||||
namespace TINK.Model.Connector.Updater
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs bike info instances/ bike info derived instances.
|
||||
/// </summary>
|
||||
public static class BikeInfoFactory
|
||||
{
|
||||
/// <summary> Set default lock type to . </summary>
|
||||
public static LockModel DEFAULTLOCKMODEL = LockModel.Sigo;
|
||||
|
||||
/// <summary> Creates a bike info object from copri response. </summary>
|
||||
/// <param name="bikeInfo">Copri response for a disposable bike. </param>
|
||||
public static BikeInfo Create(BikeInfoAvailable bikeInfo)
|
||||
{
|
||||
if (bikeInfo == null) throw new ArgumentNullException(nameof(bikeInfo));
|
||||
|
||||
var lockModel = bikeInfo.GetLockModel();
|
||||
|
||||
if (lockModel.HasValue
|
||||
&& lockModel.Value == LockModel.BordComputer)
|
||||
{
|
||||
// Manual lock bikes are no more supported.
|
||||
Log.Error(
|
||||
$"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. " +
|
||||
"Manual lock bikes are no more supported." +
|
||||
$"Bike number: {bikeInfo.bike}{(bikeInfo.station != null ? $"station number {bikeInfo.station}" : string.Empty)}."
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (bikeInfo.GetState())
|
||||
{
|
||||
case InUseStateEnum.Disposable:
|
||||
case InUseStateEnum.FeedbackPending:
|
||||
break;
|
||||
|
||||
default:
|
||||
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. Unexpected state {bikeInfo.GetState()} detected.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(bikeInfo.station))
|
||||
{
|
||||
// Bike available must always have a station id because bikes can only be returned at a station.
|
||||
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. No station info set.");
|
||||
return null;
|
||||
}
|
||||
|
||||
var lockType = lockModel.HasValue
|
||||
? BikeExtension.GetLockType(lockModel.Value)
|
||||
: BikeExtension.GetLockType(DEFAULTLOCKMODEL); // Map bikes without "system"- entry in response to backend- locks.
|
||||
|
||||
try
|
||||
{
|
||||
switch (lockType)
|
||||
{
|
||||
case LockType.Backend:
|
||||
return new Bikes.BikeInfoNS.CopriLock.BikeInfo(
|
||||
new Bike(
|
||||
bikeInfo.bike,
|
||||
LockModel.Sigo,
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.description),
|
||||
DriveFactory.Create(bikeInfo?.bike_type),
|
||||
bikeInfo.station,
|
||||
new Bikes.BikeInfoNS.CopriLock.LockInfo.Builder { State = bikeInfo.GetCopriLockingState() }.Build(),
|
||||
bikeInfo.GetState() == InUseStateEnum.FeedbackPending,
|
||||
bikeInfo.GetOperatorUri(),
|
||||
#if !NOTARIFFDESCRIPTION
|
||||
bikeInfo.rental_description != null
|
||||
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
|
||||
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
|
||||
#else
|
||||
Create((TINK.Repository.Response.TariffDescription) null),
|
||||
#endif
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup(),
|
||||
miniSurvey: bikeInfo.user_miniquery != null
|
||||
? new MiniSurveyModel(new Dictionary<string, IQuestionModel> {
|
||||
{ "q1", new QuestionModel()} // Add a dummy querry. Querries are not yet read from COPRI but compiled into the app.
|
||||
})
|
||||
: new MiniSurveyModel(),
|
||||
co2Saving: bikeInfo.co2saving);
|
||||
|
||||
case LockType.Bluethooth:
|
||||
return new Bikes.BikeInfoNS.BluetoothLock.BikeInfo(
|
||||
new Bike(
|
||||
bikeInfo.bike,
|
||||
LockModel.ILockIt,
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.description),
|
||||
DriveFactory.Create(bikeInfo?.bike_type),
|
||||
bikeInfo.GetBluetoothLockId(),
|
||||
bikeInfo.GetBluetoothLockGuid(),
|
||||
bikeInfo.station,
|
||||
bikeInfo.GetOperatorUri(),
|
||||
#if !NOTARIFFDESCRIPTION
|
||||
bikeInfo.rental_description != null
|
||||
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
|
||||
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
|
||||
#else
|
||||
Create((TINK.Repository.Response.TariffDescription)null),
|
||||
#endif
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup());
|
||||
|
||||
default:
|
||||
throw new ArgumentException($"Unsupported lock type {lockType} detected.");
|
||||
}
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
// Contructor reported invalid arguemts (missing lock id, ....).
|
||||
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. Invalid response detected. Available bike with id {bikeInfo.bike} skipped. {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Creates a bike info object from copri response. </summary>
|
||||
/// <param name="bikeInfo">Copri response. </param>
|
||||
/// <param name="mailAddress">Mail address of user.</param>
|
||||
/// <param name="dateTimeProvider">Date and time provider function.</param>
|
||||
public static BikeInfo Create(
|
||||
BikeInfoReservedOrBooked bikeInfo,
|
||||
string mailAddress,
|
||||
Func<DateTime> dateTimeProvider)
|
||||
{
|
||||
if (bikeInfo == null) throw new ArgumentNullException(nameof(bikeInfo));
|
||||
|
||||
var lockModel = bikeInfo.GetLockModel();
|
||||
|
||||
if (lockModel.HasValue
|
||||
&& lockModel.Value == LockModel.BordComputer)
|
||||
{
|
||||
// Manual lock bikes are no more supported.
|
||||
Log.Error(
|
||||
$"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. " +
|
||||
"Manual lock bikes are no more supported." +
|
||||
$"Bike number: {bikeInfo.bike}{(bikeInfo.station != null ? $", station number {bikeInfo.station}" : string.Empty)}."
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
var lockType = lockModel.HasValue
|
||||
? BikeExtension.GetLockType(lockModel.Value)
|
||||
: BikeExtension.GetLockType(DEFAULTLOCKMODEL); // Map bikes without "system"- entry in response to backend- locks.
|
||||
|
||||
// Check if bike is a bluetooth lock bike.
|
||||
int lockSerial = bikeInfo.GetBluetoothLockId();
|
||||
Guid lockGuid = bikeInfo.GetBluetoothLockGuid();
|
||||
|
||||
switch (bikeInfo.GetState())
|
||||
{
|
||||
case InUseStateEnum.Reserved:
|
||||
try
|
||||
{
|
||||
switch (lockType)
|
||||
{
|
||||
case LockType.Bluethooth:
|
||||
return new Bikes.BikeInfoNS.BluetoothLock.BikeInfo(
|
||||
new Bike(
|
||||
bikeInfo.bike,
|
||||
LockModel.ILockIt,
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.description),
|
||||
DriveFactory.Create(bikeInfo?.bike_type),
|
||||
lockSerial,
|
||||
lockGuid,
|
||||
bikeInfo.GetUserKey(),
|
||||
bikeInfo.GetAdminKey(),
|
||||
bikeInfo.GetSeed(),
|
||||
bikeInfo.GetFrom(),
|
||||
mailAddress,
|
||||
bikeInfo.station,
|
||||
bikeInfo.GetOperatorUri(),
|
||||
#if !NOTARIFFDESCRIPTION
|
||||
bikeInfo.rental_description != null
|
||||
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
|
||||
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
|
||||
#else
|
||||
Create((TINK.Repository.Response.TariffDescription)null),
|
||||
#endif
|
||||
dateTimeProvider,
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup());
|
||||
|
||||
case LockType.Backend:
|
||||
return new Bikes.BikeInfoNS.CopriLock.BikeInfo(
|
||||
new Bike(
|
||||
bikeInfo.bike,
|
||||
LockModel.Sigo,
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.description),
|
||||
DriveFactory.Create(bikeInfo?.bike_type),
|
||||
bikeInfo.GetFrom(),
|
||||
mailAddress,
|
||||
bikeInfo.station,
|
||||
new Bikes.BikeInfoNS.CopriLock.LockInfo.Builder { State = bikeInfo.GetCopriLockingState() }.Build(),
|
||||
bikeInfo.GetOperatorUri(),
|
||||
#if !NOTARIFFDESCRIPTION
|
||||
bikeInfo.rental_description != null
|
||||
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
|
||||
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
|
||||
#else
|
||||
Create((TINK.Repository.Response.TariffDescription)null),
|
||||
#endif
|
||||
dateTimeProvider,
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup());
|
||||
default:
|
||||
throw new ArgumentException($"Unsupported lock type {lockType} detected.");
|
||||
}
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
// Contructor reported invalid arguemts (missing lock id, ....).
|
||||
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoReservedOrBooked)} argument. Invalid response detected. Reserved bike with id {bikeInfo.bike} skipped. {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
|
||||
case InUseStateEnum.Booked:
|
||||
try
|
||||
{
|
||||
switch (lockModel)
|
||||
{
|
||||
case LockModel.ILockIt:
|
||||
return new Bikes.BikeInfoNS.BluetoothLock.BikeInfo(
|
||||
new Bike(
|
||||
bikeInfo.bike,
|
||||
LockModel.ILockIt,
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.description),
|
||||
DriveFactory.Create(bikeInfo?.bike_type),
|
||||
lockSerial,
|
||||
bikeInfo.GetBluetoothLockGuid(),
|
||||
bikeInfo.GetUserKey(),
|
||||
bikeInfo.GetAdminKey(),
|
||||
bikeInfo.GetSeed(),
|
||||
bikeInfo.GetFrom(),
|
||||
mailAddress,
|
||||
bikeInfo.station,
|
||||
bikeInfo.GetOperatorUri(),
|
||||
#if !NOTARIFFDESCRIPTION
|
||||
bikeInfo.rental_description != null
|
||||
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
|
||||
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
|
||||
#else
|
||||
Create((TINK.Repository.Response.TariffDescription)null),
|
||||
#endif
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup());
|
||||
|
||||
case LockModel.BordComputer:
|
||||
return new BikeInfo(
|
||||
new Bike(
|
||||
bikeInfo.bike,
|
||||
LockModel.BordComputer,
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.description),
|
||||
DriveFactory.Create(bikeInfo?.bike_type),
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup(),
|
||||
bikeInfo.station,
|
||||
bikeInfo.GetOperatorUri(),
|
||||
#if !NOTARIFFDESCRIPTION
|
||||
bikeInfo.rental_description != null
|
||||
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
|
||||
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
|
||||
#else
|
||||
Create((TINK.Repository.Response.TariffDescription)null),
|
||||
#endif
|
||||
bikeInfo.GetFrom(),
|
||||
mailAddress,
|
||||
bikeInfo.timeCode);
|
||||
default:
|
||||
return new Bikes.BikeInfoNS.CopriLock.BikeInfo(
|
||||
new Bike(
|
||||
bikeInfo.bike,
|
||||
LockModel.Sigo,
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.description),
|
||||
DriveFactory.Create(bikeInfo?.bike_type),
|
||||
bikeInfo.GetFrom(),
|
||||
mailAddress,
|
||||
bikeInfo.station,
|
||||
new Bikes.BikeInfoNS.CopriLock.LockInfo.Builder { State = bikeInfo.GetCopriLockingState() }.Build(),
|
||||
bikeInfo.GetOperatorUri(),
|
||||
#if !NOTARIFFDESCRIPTION
|
||||
bikeInfo.rental_description != null
|
||||
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
|
||||
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
|
||||
#else
|
||||
Create((TINK.Repository.Response.TariffDescription)null),
|
||||
#endif
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup());
|
||||
}
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
// Contructor reported invalid arguemts (missing lock id, ....).
|
||||
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoReservedOrBooked)} argument. Invalid response detected. Booked bike with id {bikeInfo.bike} skipped. {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
|
||||
default:
|
||||
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. Unexpected state {bikeInfo.GetState()} detected.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TINK.Model.MiniSurvey;
|
||||
using TINK.Repository.Response;
|
||||
|
||||
namespace TINK.Model.Connector.Updater
|
||||
{
|
||||
public static class BookingFinishedModelFactory
|
||||
{
|
||||
/// <summary> Creates a booking finished object from response.</summary>
|
||||
/// <param name="response">Response to create survey object from.</param>
|
||||
public static BookingFinishedModel Create(this DoReturnResponse response)
|
||||
{
|
||||
var bookingFinished = new BookingFinishedModel
|
||||
{
|
||||
Co2Saving = response?.co2saving
|
||||
};
|
||||
|
||||
if (response?.user_miniquery == null)
|
||||
|
||||
{
|
||||
return bookingFinished;
|
||||
}
|
||||
|
||||
var miniquery = response.user_miniquery;
|
||||
bookingFinished.MiniSurvey = new MiniSurveyModel
|
||||
{
|
||||
Title = miniquery.title,
|
||||
Subtitle = miniquery.subtitle,
|
||||
Footer = miniquery.footer
|
||||
};
|
||||
|
||||
foreach (var question in miniquery?.questions?.OrderBy(x => x.Key) ?? new Dictionary<string, MiniSurveyResponse.Question>().OrderBy(x => x.Key))
|
||||
{
|
||||
if (string.IsNullOrEmpty(question.Key.Trim())
|
||||
|| question.Value.query == null)
|
||||
{
|
||||
// Skip invalid entries.
|
||||
continue;
|
||||
}
|
||||
|
||||
bookingFinished.MiniSurvey.Questions.Add(
|
||||
question.Key,
|
||||
new QuestionModel());
|
||||
}
|
||||
|
||||
return bookingFinished;
|
||||
}
|
||||
}
|
||||
}
|
45
TINKLib/Model/Connector/Updater/DriveFactory.cs
Normal file
45
TINKLib/Model/Connector/Updater/DriveFactory.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
using TINK.Model.Bikes.BikeInfoNS.DriveNS;
|
||||
using TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
|
||||
using TINK.Model.Bikes.BikeInfoNS.DriveNS.EngineNS;
|
||||
using TINK.Repository.Response;
|
||||
|
||||
namespace TINK.Model.Connector.Updater
|
||||
{
|
||||
public static class DriveFactory
|
||||
{
|
||||
public static Drive Create(this BikeType bikeType)
|
||||
{
|
||||
if (string.IsNullOrEmpty(bikeType?.engine?.manufacturer))
|
||||
{
|
||||
// Bike is has no engine
|
||||
return new Drive();
|
||||
}
|
||||
|
||||
// Bike is a pedelec.
|
||||
return new Drive(
|
||||
new Engine(bikeType?.engine?.manufacturer),
|
||||
new Battery.Builder
|
||||
{
|
||||
CurrentChargePercent = double.TryParse(bikeType?.battery?.charge_current_percent, out double currentChargePercent)
|
||||
? currentChargePercent
|
||||
: double.NaN,
|
||||
|
||||
CurrentChargeBars = int.TryParse(bikeType?.battery?.charge_current_bars, out int currentChargeBars)
|
||||
? (int?)currentChargeBars
|
||||
: null,
|
||||
|
||||
MaxChargeBars = int.TryParse(bikeType?.battery?.charge_max_bars, out int maxChargeBars)
|
||||
? (int?)maxChargeBars
|
||||
: null,
|
||||
|
||||
IsBackendAccessible = bikeType?.battery?.backend_accessible != null && int.TryParse(bikeType.battery.backend_accessible, out int accessible)
|
||||
? (bool?)(accessible > 0)
|
||||
: null,
|
||||
|
||||
IsHidden = bikeType?.battery?.hidden != null && int.TryParse(bikeType.battery.hidden, out int hidden)
|
||||
? (bool?)(hidden > 0)
|
||||
: null
|
||||
}.Build());
|
||||
}
|
||||
}
|
||||
}
|
63
TINKLib/Model/Connector/Updater/RentalDescriptionFactory.cs
Normal file
63
TINKLib/Model/Connector/Updater/RentalDescriptionFactory.cs
Normal file
|
@ -0,0 +1,63 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace TINK.Model.Connector.Updater
|
||||
{
|
||||
public static class RentalDescriptionFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates rental description object from JSON- tarif description object.
|
||||
/// </summary>
|
||||
/// <param name="rentalDesciption">Source JSON object.</param>
|
||||
/// <returns>Tariff description object.</returns>
|
||||
|
||||
public static Bikes.BikeInfoNS.RentalDescription Create(this Repository.Response.RentalDescription rentalDesciption)
|
||||
{
|
||||
Bikes.BikeInfoNS.RentalDescription.TariffElement CreateTarifEntry(string[] elementValue)
|
||||
{
|
||||
return new Bikes.BikeInfoNS.RentalDescription.TariffElement
|
||||
{
|
||||
Description = elementValue != null && elementValue.Length > 0 ? elementValue[0] : string.Empty,
|
||||
Value = elementValue != null && elementValue.Length > 1 ? elementValue[1] : string.Empty,
|
||||
};
|
||||
}
|
||||
|
||||
Bikes.BikeInfoNS.RentalDescription.InfoElement CreateInfoElement(string[] elementValue)
|
||||
{
|
||||
return new Bikes.BikeInfoNS.RentalDescription.InfoElement
|
||||
{
|
||||
Key = elementValue != null && elementValue.Length > 0 ? elementValue[0] : string.Empty,
|
||||
Value = elementValue != null && elementValue.Length > 1 ? elementValue[1] : string.Empty,
|
||||
};
|
||||
}
|
||||
|
||||
// Read tariff elements.
|
||||
var tarifEntries = rentalDesciption?.tarif_elements != null
|
||||
? rentalDesciption.tarif_elements.Select(x => new
|
||||
{
|
||||
Key = x.Key,
|
||||
Value = CreateTarifEntry(x.Value)
|
||||
}).ToLookup(x => x.Key, x => x.Value).ToDictionary(x => x.Key, x => x.First())
|
||||
: new Dictionary<string, Bikes.BikeInfoNS.RentalDescription.TariffElement>();
|
||||
|
||||
// Read info elements.
|
||||
var InfoEntries = rentalDesciption?.rental_info != null
|
||||
? rentalDesciption.rental_info.Select(x => new
|
||||
{
|
||||
Key = x.Key,
|
||||
Value = CreateInfoElement(x.Value)
|
||||
}).ToLookup(x => x.Key, x => x.Value).ToDictionary(x => x.Key, x => x.First())
|
||||
: new Dictionary<string, Bikes.BikeInfoNS.RentalDescription.InfoElement>();
|
||||
|
||||
var bike = new Bikes.BikeInfoNS.RentalDescription
|
||||
{
|
||||
Name = rentalDesciption?.name ?? string.Empty,
|
||||
Id = int.TryParse(rentalDesciption?.id ?? string.Empty, out int number) ? number : (int?)null,
|
||||
TariffEntries = tarifEntries,
|
||||
InfoEntries = InfoEntries
|
||||
};
|
||||
|
||||
return bike;
|
||||
}
|
||||
}
|
||||
}
|
80
TINKLib/Model/Connector/Updater/TariffDescriptionFactory.cs
Normal file
80
TINKLib/Model/Connector/Updater/TariffDescriptionFactory.cs
Normal file
|
@ -0,0 +1,80 @@
|
|||
using System.Globalization;
|
||||
using TINK.MultilingualResources;
|
||||
using TINK.Repository.Response;
|
||||
|
||||
namespace TINK.Model.Connector.Updater
|
||||
{
|
||||
public static class TariffDescriptionFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates rental description object from JSON- tarif description object.
|
||||
/// </summary>
|
||||
/// <param name="tariffDesciption">Source JSON object.</param>
|
||||
/// <returns>Tariff description object.</returns>
|
||||
public static Bikes.BikeInfoNS.RentalDescription Create(this TariffDescription tariffDesciption)
|
||||
{
|
||||
var bike = new Bikes.BikeInfoNS.RentalDescription
|
||||
{
|
||||
Name = tariffDesciption?.name,
|
||||
#if USCSHARP9
|
||||
Number = int.TryParse(tariffDesciption?.number, out int number) ? number : null,
|
||||
#else
|
||||
Id = int.TryParse(tariffDesciption?.number, out int number) ? number : (int?)null,
|
||||
#endif
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(tariffDesciption?.free_hours)
|
||||
&& double.TryParse(tariffDesciption?.free_hours, NumberStyles.Any, CultureInfo.InvariantCulture, out double freeHours))
|
||||
{
|
||||
// Free time. Unit hours,format floating point number.
|
||||
bike.TariffEntries.Add("1", new Bikes.BikeInfoNS.RentalDescription.TariffElement
|
||||
{
|
||||
Description = AppResources.MessageBikesManagementTariffDescriptionFreeTimePerSession,
|
||||
Value = string.Format("{0} {1}", freeHours.ToString("0.00"), AppResources.MessageBikesManagementTariffDescriptionHour)
|
||||
});
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(tariffDesciption?.eur_per_hour)
|
||||
&& double.TryParse(tariffDesciption?.eur_per_hour, NumberStyles.Any, CultureInfo.InvariantCulture, out double euroPerHour))
|
||||
{
|
||||
// Euro per hour. Format floating point.
|
||||
bike.TariffEntries.Add("2", new Bikes.BikeInfoNS.RentalDescription.TariffElement
|
||||
{
|
||||
Description = AppResources.MessageBikesManagementTariffDescriptionFeeEuroPerHour,
|
||||
Value = string.Format("{0} {1}", euroPerHour.ToString("0.00"), AppResources.MessageBikesManagementTariffDescriptionEuroPerHour)
|
||||
});
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(tariffDesciption?.max_eur_per_day)
|
||||
&& double.TryParse(tariffDesciption.max_eur_per_day, NumberStyles.Any, CultureInfo.InvariantCulture, out double maxEuroPerDay))
|
||||
{
|
||||
// Max euro per day. Format floating point.
|
||||
bike.TariffEntries.Add("3", new Bikes.BikeInfoNS.RentalDescription.TariffElement
|
||||
{
|
||||
Description = AppResources.MessageBikesManagementTariffDescriptionMaxFeeEuroPerDay,
|
||||
Value = string.Format("{0} {1}", maxEuroPerDay.ToString("0.00"), AppResources.MessageBikesManagementMaxFeeEuroPerDay)
|
||||
});
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(tariffDesciption?.abo_eur_per_month)
|
||||
&& double.TryParse(tariffDesciption.abo_eur_per_month, NumberStyles.Any, CultureInfo.InvariantCulture, out double aboEuroPerMonth))
|
||||
{
|
||||
// Abo per month
|
||||
bike.TariffEntries.Add("4", new Bikes.BikeInfoNS.RentalDescription.TariffElement
|
||||
{
|
||||
Description = AppResources.MessageBikesManagementTariffDescriptionAboEuroPerMonth,
|
||||
Value = string.Format("{0} {1}", aboEuroPerMonth.ToString("0.00"), AppResources.MessageBikesManagementTariffDescriptionEuroPerMonth)
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(tariffDesciption?.operator_agb ?? string.Empty))
|
||||
{
|
||||
bike.InfoEntries.Add("1", new Bikes.BikeInfoNS.RentalDescription.InfoElement { Key = "AGB", Value = tariffDesciption.operator_agb });
|
||||
}
|
||||
|
||||
return bike;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,26 +1,19 @@
|
|||
using System;
|
||||
using TINK.Model.Bike;
|
||||
using TINK.Model.Station;
|
||||
using TINK.Repository.Response;
|
||||
using TINK.Model.User.Account;
|
||||
using System.Collections.Generic;
|
||||
using TINK.Model.State;
|
||||
using TINK.Repository.Exception;
|
||||
using Serilog;
|
||||
|
||||
using BikeInfo = TINK.Model.Bike.BC.BikeInfo;
|
||||
using IBikeInfoMutable = TINK.Model.Bikes.Bike.BC.IBikeInfoMutable;
|
||||
using BikeExtension = TINK.Model.Bikes.Bike.BikeExtension;
|
||||
|
||||
using System.Globalization;
|
||||
using TINK.Model.Bikes;
|
||||
using TINK.Model.State;
|
||||
using TINK.Model.Station;
|
||||
using TINK.Model.Station.Operator;
|
||||
using Xamarin.Forms;
|
||||
using System.Linq;
|
||||
using TINK.Model.MiniSurvey;
|
||||
using TINK.Model.User.Account;
|
||||
using TINK.Repository.Exception;
|
||||
using TINK.Repository.Response;
|
||||
using TINK.Services.CopriApi;
|
||||
using TINK.MultilingualResources;
|
||||
using Xamarin.Forms;
|
||||
using BikeInfo = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfo;
|
||||
using IBikeInfoMutable = TINK.Model.Bikes.BikeInfoNS.BC.IBikeInfoMutable;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
namespace TINK.Model.Connector.Updater
|
||||
{
|
||||
/// <summary>
|
||||
/// Connects TINK app to copri using JSON as input data format.
|
||||
|
@ -33,11 +26,12 @@ namespace TINK.Model.Connector
|
|||
/// <param name="notifyLevel">Controls whether notify property changed events are fired or not.</param>
|
||||
public static void Load(
|
||||
this IBikeInfoMutable bike,
|
||||
Bikes.Bike.BC.NotifyPropertyChangedLevel notifyLevel)
|
||||
Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel notifyLevel)
|
||||
{
|
||||
|
||||
bike.State.Load(InUseStateEnum.Disposable, notifyLevel: notifyLevel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all statsion for station provider and add them into station list.
|
||||
/// </summary>
|
||||
|
@ -132,9 +126,9 @@ namespace TINK.Model.Connector
|
|||
this IBikeInfoMutable bike,
|
||||
BikeInfoReservedOrBooked bikeInfo,
|
||||
string mailAddress,
|
||||
Bikes.Bike.BC.NotifyPropertyChangedLevel notifyLevel = Bikes.Bike.BC.NotifyPropertyChangedLevel.All)
|
||||
Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel notifyLevel = Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.All)
|
||||
{
|
||||
if (bike is Bike.BluetoothLock.BikeInfoMutable btBikeInfo)
|
||||
if (bike is Bikes.BikeInfoNS.BluetoothLock.BikeInfoMutable btBikeInfo)
|
||||
{
|
||||
btBikeInfo.LockInfo.Load(
|
||||
bikeInfo.GetBluetoothLockId(),
|
||||
|
@ -181,13 +175,11 @@ namespace TINK.Model.Connector
|
|||
/// <returns>New collection of available bikes.</returns>
|
||||
public static BikeCollection GetBikesAvailable(
|
||||
this BikesAvailableResponse bikesAvailableResponse)
|
||||
{
|
||||
return GetBikesAll(
|
||||
bikesAvailableResponse,
|
||||
new BikesReservedOccupiedResponse(), // There are no occupied bikes.
|
||||
=> GetBikesAll(
|
||||
bikesAvailableResponse?.bikes?.Values,
|
||||
new BikesReservedOccupiedResponse()?.bikes_occupied?.Values, // There are no occupied bikes.
|
||||
string.Empty,
|
||||
() => DateTime.Now);
|
||||
}
|
||||
|
||||
/// <summary> Gets bikes occupied from copri server response. </summary>
|
||||
/// <param name="p_oBikesAvailable">Response to create bikes from.</param>
|
||||
|
@ -198,18 +190,19 @@ namespace TINK.Model.Connector
|
|||
Func<DateTime> dateTimeProvider)
|
||||
{
|
||||
return GetBikesAll(
|
||||
new BikesAvailableResponse(),
|
||||
bikesOccupiedResponse,
|
||||
new BikesAvailableResponse()?.bikes?.Values,
|
||||
bikesOccupiedResponse?.bikes_occupied?.Values,
|
||||
mail,
|
||||
dateTimeProvider);
|
||||
}
|
||||
|
||||
/// <summary> Gets bikes occupied from copri server response. </summary>
|
||||
/// <param name="p_oBikesAvailable">Response to create bikes from.</param>
|
||||
/// <param name="bikesAvailable">Response to create bikes available from.</param>
|
||||
/// <param name="bikesOccupied">Response to create bikes occupied from.</param>
|
||||
/// <returns>New collection of occupied bikes.</returns>
|
||||
public static BikeCollection GetBikesAll(
|
||||
BikesAvailableResponse bikesAvailableResponse,
|
||||
BikesReservedOccupiedResponse bikesOccupiedResponse,
|
||||
IEnumerable<BikeInfoAvailable> bikesAvailable,
|
||||
IEnumerable<BikeInfoReservedOrBooked> bikesOccupied,
|
||||
string mail,
|
||||
Func<DateTime> dateTimeProvider)
|
||||
{
|
||||
|
@ -217,10 +210,9 @@ namespace TINK.Model.Connector
|
|||
var duplicates = new Dictionary<string, BikeInfo>();
|
||||
|
||||
// Get bikes from Copri/ file/ memory, ....
|
||||
if (bikesAvailableResponse != null
|
||||
&& bikesAvailableResponse.bikes != null)
|
||||
if (bikesAvailable != null)
|
||||
{
|
||||
foreach (var bikeInfoResponse in bikesAvailableResponse.bikes.Values)
|
||||
foreach (var bikeInfoResponse in bikesAvailable)
|
||||
{
|
||||
var bikeInfo = BikeInfoFactory.Create(bikeInfoResponse);
|
||||
if (bikeInfo == null)
|
||||
|
@ -247,10 +239,9 @@ namespace TINK.Model.Connector
|
|||
}
|
||||
|
||||
// Get bikes from Copri/ file/ memory, ....
|
||||
if (bikesOccupiedResponse != null
|
||||
&& bikesOccupiedResponse.bikes_occupied != null)
|
||||
if (bikesOccupied != null)
|
||||
{
|
||||
foreach (var bikeInfoResponse in bikesOccupiedResponse.bikes_occupied.Values)
|
||||
foreach (var bikeInfoResponse in bikesOccupied)
|
||||
{
|
||||
BikeInfo bikeInfo = BikeInfoFactory.Create(
|
||||
bikeInfoResponse,
|
||||
|
@ -288,437 +279,4 @@ namespace TINK.Model.Connector
|
|||
return new BikeCollection(bikesDictionary);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs bike info instances/ bike info derived instances.
|
||||
/// </summary>
|
||||
public static class BikeInfoFactory
|
||||
{
|
||||
/// <summary> Set default lock type to . </summary>
|
||||
public static LockModel DEFAULTLOCKMODEL = LockModel.Sigo;
|
||||
|
||||
/// <summary> Creates a bike info object from copri response. </summary>
|
||||
/// <param name="bikeInfo">Copri response for a disposable bike. </param>
|
||||
public static BikeInfo Create(BikeInfoAvailable bikeInfo)
|
||||
{
|
||||
var lockModel = bikeInfo.GetLockModel();
|
||||
|
||||
if (lockModel.HasValue
|
||||
&& lockModel.Value == LockModel.BordComputer)
|
||||
{
|
||||
// Manual lock bikes are no more supported.
|
||||
Log.Error(
|
||||
$"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. " +
|
||||
"Manual lock bikes are no more supported." +
|
||||
$"Bike number: {bikeInfo.bike}{(bikeInfo.station != null ? $"station number {bikeInfo.station}" : string.Empty)}."
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (bikeInfo.GetState())
|
||||
{
|
||||
case InUseStateEnum.Disposable:
|
||||
break;
|
||||
|
||||
default:
|
||||
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. Unexpected state {bikeInfo.GetState()} detected.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(bikeInfo.station))
|
||||
{
|
||||
// Bike available must always have a station id because bikes can only be returned at a station.
|
||||
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. No station info set.");
|
||||
return null;
|
||||
}
|
||||
|
||||
var lockType = lockModel.HasValue
|
||||
? BikeExtension.GetLockType(lockModel.Value)
|
||||
: BikeExtension.GetLockType(DEFAULTLOCKMODEL); // Map bikes without "system"- entry in response to backend- locks.
|
||||
|
||||
try
|
||||
{
|
||||
switch (lockType)
|
||||
{
|
||||
case LockType.Backend:
|
||||
return new Bike.CopriLock.BikeInfo(
|
||||
bikeInfo.bike,
|
||||
bikeInfo.station,
|
||||
new Bikes.Bike.CopriLock.LockInfo.Builder { State = bikeInfo.GetCopriLockingState()}.Build(),
|
||||
bikeInfo.GetOperatorUri(),
|
||||
#if !NOTARIFFDESCRIPTION
|
||||
bikeInfo.rental_description != null ? Create(bikeInfo.rental_description) : Create(bikeInfo.tariff_description),
|
||||
#else
|
||||
Create((TINK.Repository.Response.TariffDescription) null),
|
||||
#endif
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup(),
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.description);
|
||||
|
||||
case LockType.Bluethooth:
|
||||
return new Bike.BluetoothLock.BikeInfo(
|
||||
bikeInfo.bike,
|
||||
bikeInfo.GetBluetoothLockId(),
|
||||
bikeInfo.GetBluetoothLockGuid(),
|
||||
bikeInfo.station,
|
||||
bikeInfo.GetOperatorUri(),
|
||||
#if !NOTARIFFDESCRIPTION
|
||||
bikeInfo.rental_description != null ? Create(bikeInfo.rental_description) : Create(bikeInfo.tariff_description),
|
||||
#else
|
||||
Create((TINK.Repository.Response.TariffDescription)null),
|
||||
#endif
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup(),
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.description);
|
||||
|
||||
default:
|
||||
throw new ArgumentException($"Unsupported lock type {lockType} detected.");
|
||||
}
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
// Contructor reported invalid arguemts (missing lock id, ....).
|
||||
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. Invalid response detected. Available bike with id {bikeInfo.bike} skipped. {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Creates a bike info object from copri response. </summary>
|
||||
/// <param name="bikeInfo">Copri response. </param>
|
||||
/// <param name="mailAddress">Mail address of user.</param>
|
||||
/// <param name="dateTimeProvider">Date and time provider function.</param>
|
||||
public static BikeInfo Create(
|
||||
BikeInfoReservedOrBooked bikeInfo,
|
||||
string mailAddress,
|
||||
Func<DateTime> dateTimeProvider)
|
||||
{
|
||||
var lockModel = bikeInfo.GetLockModel();
|
||||
|
||||
if (lockModel.HasValue
|
||||
&& lockModel.Value == LockModel.BordComputer)
|
||||
{
|
||||
// Manual lock bikes are no more supported.
|
||||
Log.Error(
|
||||
$"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. " +
|
||||
"Manual lock bikes are no more supported." +
|
||||
$"Bike number: {bikeInfo.bike}{(bikeInfo.station != null ? $", station number {bikeInfo.station}" : string.Empty)}."
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
var lockType = lockModel.HasValue
|
||||
? BikeExtension.GetLockType(lockModel.Value)
|
||||
: BikeExtension.GetLockType(DEFAULTLOCKMODEL); // Map bikes without "system"- entry in response to backend- locks.
|
||||
|
||||
// Check if bike is a bluetooth lock bike.
|
||||
int lockSerial = bikeInfo.GetBluetoothLockId();
|
||||
Guid lockGuid = bikeInfo.GetBluetoothLockGuid();
|
||||
|
||||
switch (bikeInfo.GetState())
|
||||
{
|
||||
case InUseStateEnum.Reserved:
|
||||
try
|
||||
{
|
||||
switch (lockType)
|
||||
{
|
||||
case LockType.Bluethooth:
|
||||
return new Bike.BluetoothLock.BikeInfo(
|
||||
bikeInfo.bike,
|
||||
lockSerial,
|
||||
lockGuid,
|
||||
bikeInfo.GetUserKey(),
|
||||
bikeInfo.GetAdminKey(),
|
||||
bikeInfo.GetSeed(),
|
||||
bikeInfo.GetFrom(),
|
||||
mailAddress,
|
||||
bikeInfo.station,
|
||||
bikeInfo.GetOperatorUri(),
|
||||
#if !NOTARIFFDESCRIPTION
|
||||
bikeInfo.rental_description != null ? Create(bikeInfo.rental_description) : Create(bikeInfo.tariff_description),
|
||||
#else
|
||||
Create((TINK.Repository.Response.TariffDescription)null),
|
||||
#endif
|
||||
dateTimeProvider,
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup(),
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.description);
|
||||
|
||||
case LockType.Backend:
|
||||
return new Bike.CopriLock.BikeInfo(
|
||||
bikeInfo.bike,
|
||||
bikeInfo.GetFrom(),
|
||||
mailAddress,
|
||||
bikeInfo.station,
|
||||
new Bikes.Bike.CopriLock.LockInfo.Builder { State = bikeInfo.GetCopriLockingState() }.Build(),
|
||||
bikeInfo.GetOperatorUri(),
|
||||
#if !NOTARIFFDESCRIPTION
|
||||
bikeInfo.rental_description != null ? Create(bikeInfo.rental_description) : Create(bikeInfo.tariff_description),
|
||||
#else
|
||||
Create((TINK.Repository.Response.TariffDescription)null),
|
||||
#endif
|
||||
dateTimeProvider,
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup(),
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.description);
|
||||
default:
|
||||
throw new ArgumentException($"Unsupported lock type {lockType} detected.");
|
||||
}
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
// Contructor reported invalid arguemts (missing lock id, ....).
|
||||
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoReservedOrBooked)} argument. Invalid response detected. Reserved bike with id {bikeInfo.bike} skipped. {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
|
||||
case InUseStateEnum.Booked:
|
||||
try
|
||||
{
|
||||
switch (lockModel)
|
||||
{
|
||||
case LockModel.ILockIt:
|
||||
return new Bike.BluetoothLock.BikeInfo(
|
||||
bikeInfo.bike,
|
||||
lockSerial,
|
||||
bikeInfo.GetBluetoothLockGuid(),
|
||||
bikeInfo.GetUserKey(),
|
||||
bikeInfo.GetAdminKey(),
|
||||
bikeInfo.GetSeed(),
|
||||
bikeInfo.GetFrom(),
|
||||
mailAddress,
|
||||
bikeInfo.station,
|
||||
bikeInfo.GetOperatorUri(),
|
||||
#if !NOTARIFFDESCRIPTION
|
||||
bikeInfo.rental_description != null ? Create(bikeInfo.rental_description) : Create(bikeInfo.tariff_description),
|
||||
#else
|
||||
Create((TINK.Repository.Response.TariffDescription)null),
|
||||
#endif
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup(),
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.description);
|
||||
|
||||
case LockModel.BordComputer:
|
||||
return new BikeInfo(
|
||||
bikeInfo.bike,
|
||||
LockModel.BordComputer,
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup(),
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.description,
|
||||
bikeInfo.station,
|
||||
bikeInfo.GetOperatorUri(),
|
||||
#if !NOTARIFFDESCRIPTION
|
||||
bikeInfo.rental_description != null ? Create(bikeInfo.rental_description) : Create(bikeInfo.tariff_description),
|
||||
#else
|
||||
Create((TINK.Repository.Response.TariffDescription)null),
|
||||
#endif
|
||||
bikeInfo.GetFrom(),
|
||||
mailAddress,
|
||||
bikeInfo.timeCode);
|
||||
default:
|
||||
return new Bike.CopriLock.BikeInfo(
|
||||
bikeInfo.bike,
|
||||
bikeInfo.GetFrom(),
|
||||
mailAddress,
|
||||
bikeInfo.station,
|
||||
new Bikes.Bike.CopriLock.LockInfo.Builder { State = bikeInfo.GetCopriLockingState() }.Build(),
|
||||
bikeInfo.GetOperatorUri(),
|
||||
#if !NOTARIFFDESCRIPTION
|
||||
bikeInfo.rental_description != null ? Create(bikeInfo.rental_description) : Create(bikeInfo.tariff_description),
|
||||
#else
|
||||
Create((TINK.Repository.Response.TariffDescription)null),
|
||||
#endif
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup(),
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.description);
|
||||
}
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
// Contructor reported invalid arguemts (missing lock id, ....).
|
||||
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoReservedOrBooked)} argument. Invalid response detected. Booked bike with id {bikeInfo.bike} skipped. {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
|
||||
default:
|
||||
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. Unexpected state {bikeInfo.GetState()} detected.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates rental description object from JSON- tarif description object.
|
||||
/// </summary>
|
||||
/// <param name="tariffDesciption">Source JSON object.</param>
|
||||
/// <returns>Tariff description object.</returns>
|
||||
public static Bikes.Bike.RentalDescription Create(this TariffDescription tariffDesciption)
|
||||
{
|
||||
var bike = new Bikes.Bike.RentalDescription
|
||||
{
|
||||
Name = tariffDesciption?.name,
|
||||
#if USCSHARP9
|
||||
Number = int.TryParse(tariffDesciption?.number, out int number) ? number : null,
|
||||
#else
|
||||
Id = int.TryParse(tariffDesciption?.number, out int number) ? number : (int?)null,
|
||||
#endif
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(tariffDesciption?.free_hours)
|
||||
&& double.TryParse(tariffDesciption?.free_hours, NumberStyles.Any, CultureInfo.InvariantCulture, out double freeHours))
|
||||
{
|
||||
// Free time. Unit hours,format floating point number.
|
||||
bike.TariffEntries.Add("1", new Bikes.Bike.RentalDescription.TariffElement {
|
||||
Description = AppResources.MessageBikesManagementTariffDescriptionFreeTimePerSession,
|
||||
Value =string.Format("{0} {1}", freeHours.ToString("0.00"), AppResources.MessageBikesManagementTariffDescriptionHour)
|
||||
});
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(tariffDesciption?.eur_per_hour)
|
||||
&& double.TryParse(tariffDesciption?.eur_per_hour, NumberStyles.Any, CultureInfo.InvariantCulture, out double euroPerHour))
|
||||
{
|
||||
// Euro per hour. Format floating point.
|
||||
bike.TariffEntries.Add("2", new Bikes.Bike.RentalDescription.TariffElement {
|
||||
Description = AppResources.MessageBikesManagementTariffDescriptionFeeEuroPerHour,
|
||||
Value = string.Format("{0} {1}", euroPerHour.ToString("0.00"), AppResources.MessageBikesManagementTariffDescriptionEuroPerHour)
|
||||
});
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(tariffDesciption?.max_eur_per_day)
|
||||
&& double.TryParse(tariffDesciption.max_eur_per_day, NumberStyles.Any, CultureInfo.InvariantCulture, out double maxEuroPerDay))
|
||||
{
|
||||
// Max euro per day. Format floating point.
|
||||
bike.TariffEntries.Add("3", new Bikes.Bike.RentalDescription.TariffElement {
|
||||
Description = AppResources.MessageBikesManagementTariffDescriptionMaxFeeEuroPerDay,
|
||||
Value = string.Format("{0} {1}", maxEuroPerDay.ToString("0.00"), AppResources.MessageBikesManagementMaxFeeEuroPerDay)
|
||||
});
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(tariffDesciption?.abo_eur_per_month)
|
||||
&& double.TryParse(tariffDesciption.abo_eur_per_month, NumberStyles.Any, CultureInfo.InvariantCulture, out double aboEuroPerMonth))
|
||||
{
|
||||
// Abo per month
|
||||
bike.TariffEntries.Add("4", new Bikes.Bike.RentalDescription.TariffElement {
|
||||
Description = AppResources.MessageBikesManagementTariffDescriptionAboEuroPerMonth,
|
||||
Value = string.Format("{0} {1}", aboEuroPerMonth.ToString("0.00"), AppResources.MessageBikesManagementTariffDescriptionEuroPerMonth)
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(tariffDesciption?.operator_agb ?? string.Empty))
|
||||
{
|
||||
bike.InfoEntries.Add("1", new Bikes.Bike.RentalDescription.InfoElement { Key = "AGB", Value = tariffDesciption.operator_agb });
|
||||
}
|
||||
|
||||
return bike;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates rental description object from JSON- tarif description object.
|
||||
/// </summary>
|
||||
/// <param name="rentalDesciption">Source JSON object.</param>
|
||||
/// <returns>Tariff description object.</returns>
|
||||
|
||||
public static Bikes.Bike.RentalDescription Create(this RentalDescription rentalDesciption)
|
||||
{
|
||||
Bikes.Bike.RentalDescription.TariffElement CreateTarifEntry(string[] elementValue)
|
||||
{
|
||||
return new Bikes.Bike.RentalDescription.TariffElement
|
||||
{
|
||||
Description = elementValue != null && elementValue.Length > 0 ? elementValue[0] : string.Empty,
|
||||
Value = elementValue != null && elementValue.Length > 1 ? elementValue[1] : string.Empty,
|
||||
};
|
||||
}
|
||||
|
||||
Bikes.Bike.RentalDescription.InfoElement CreateInfoElement(string[] elementValue)
|
||||
{
|
||||
return new Bikes.Bike.RentalDescription.InfoElement
|
||||
{
|
||||
Key = elementValue != null && elementValue.Length > 0 ? elementValue[0] : string.Empty,
|
||||
Value = elementValue != null && elementValue.Length > 1 ? elementValue[1] : string.Empty,
|
||||
};
|
||||
}
|
||||
|
||||
// Read tariff elements.
|
||||
var tarifEntries = rentalDesciption?.tarif_elements != null
|
||||
? rentalDesciption.tarif_elements.Select(x => new
|
||||
{
|
||||
Key = x.Key,
|
||||
Value = CreateTarifEntry(x.Value)
|
||||
}).ToLookup(x => x.Key, x => x.Value).ToDictionary(x => x.Key, x => x.First())
|
||||
: new Dictionary<string, Bikes.Bike.RentalDescription.TariffElement>();
|
||||
|
||||
// Read info elements.
|
||||
var InfoEntries = rentalDesciption?.rental_info != null
|
||||
? rentalDesciption.rental_info.Select(x => new
|
||||
{
|
||||
Key = x.Key,
|
||||
Value = CreateInfoElement(x.Value)
|
||||
}).ToLookup(x => x.Key, x => x.Value).ToDictionary(x => x.Key, x => x.First())
|
||||
: new Dictionary<string, Bikes.Bike.RentalDescription.InfoElement>();
|
||||
|
||||
var bike = new Bikes.Bike.RentalDescription
|
||||
{
|
||||
Name = rentalDesciption?.name ?? string.Empty,
|
||||
Id = int.TryParse(rentalDesciption?.id ?? string.Empty, out int number) ? number : (int?)null,
|
||||
TariffEntries = tarifEntries,
|
||||
InfoEntries = InfoEntries
|
||||
};
|
||||
|
||||
return bike;
|
||||
}
|
||||
|
||||
/// <summary> Creates a booking finished object from response.</summary>
|
||||
/// <param name="response">Response to create survey object from.</param>
|
||||
public static BookingFinishedModel Create(this DoReturnResponse response)
|
||||
{
|
||||
var bookingFinished = new BookingFinishedModel
|
||||
{
|
||||
Co2Saving = response?.co2saving
|
||||
};
|
||||
|
||||
if (response?.user_miniquery == null)
|
||||
|
||||
{
|
||||
return bookingFinished;
|
||||
}
|
||||
|
||||
var miniquery = response.user_miniquery;
|
||||
bookingFinished.MiniSurvey = new MiniSurveyModel
|
||||
{
|
||||
Title = miniquery.title,
|
||||
Subtitle = miniquery.subtitle,
|
||||
Footer = miniquery.footer
|
||||
};
|
||||
|
||||
foreach (var question in miniquery?.questions?.OrderBy(x => x.Key) ?? new Dictionary<string, MiniSurveyResponse.Question>().OrderBy(x => x.Key))
|
||||
{
|
||||
if (string.IsNullOrEmpty(question.Key.Trim())
|
||||
|| question.Value.query == null)
|
||||
{
|
||||
// Skip invalid entries.
|
||||
continue;
|
||||
}
|
||||
|
||||
bookingFinished.MiniSurvey.Questions.Add(
|
||||
question.Key,
|
||||
new MiniSurveyModel.QuestionModel());
|
||||
}
|
||||
|
||||
return bookingFinished;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
namespace TINK.Model.Device
|
||||
using Xamarin.Essentials;
|
||||
|
||||
namespace TINK.Model.Device
|
||||
{
|
||||
public interface ISmartDevice
|
||||
{
|
||||
|
@ -10,10 +12,9 @@
|
|||
string Manufacturer { get; }
|
||||
|
||||
/// <summary> Device Model (SMG-950U, iPhone10,6). </summary>
|
||||
string Model { get; }
|
||||
string Model { get; }
|
||||
|
||||
/// <summary> Platform (Android). </summary>
|
||||
string PlatformText { get; }
|
||||
DevicePlatform Platform { get; }
|
||||
|
||||
/// <summary> Operating System Version Number (7.0) as text</summary>
|
||||
string VersionText { get; }
|
||||
|
|
34
TINKLib/Model/EnumExtensions.cs
Normal file
34
TINKLib/Model/EnumExtensions.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Reflection;
|
||||
|
||||
namespace TINK.Model
|
||||
{
|
||||
public static class EnumExtensions
|
||||
{
|
||||
public static string GetDisplayName(this Enum enu)
|
||||
{
|
||||
var attr = GetDisplayAttribute(enu);
|
||||
return attr != null ? attr.Name : enu.ToString();
|
||||
}
|
||||
|
||||
public static string GetDescription(this Enum enu)
|
||||
{
|
||||
var attr = GetDisplayAttribute(enu);
|
||||
return attr != null ? attr.Description : enu.ToString();
|
||||
}
|
||||
|
||||
private static DisplayAttribute GetDisplayAttribute(object value)
|
||||
{
|
||||
Type type = value?.GetType() ?? typeof(object);
|
||||
if (!type.IsEnum)
|
||||
{
|
||||
throw new ArgumentException(string.Format("Type {0} is not an enum", type));
|
||||
}
|
||||
|
||||
// Get the enum field.
|
||||
var field = type.GetField(value.ToString());
|
||||
return field == null ? null : field.GetCustomAttribute<DisplayAttribute>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace TINK.Model
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace TINK.Model
|
|||
{
|
||||
/// <summary> Holds collecion of filters to filter options (TINK, Konrad, ....). </summary>
|
||||
/// <remarks> Former name: FilterCollection.</remarks>
|
||||
public static class GroupFilterHelper
|
||||
public static class GroupFilterHelper
|
||||
{
|
||||
/// <summary> Gets default filter set.</summary>
|
||||
public static IGroupFilterSettings GetSettingsFilterDefaults
|
||||
|
|
13
TINKLib/Model/IBookingFinishedModel.cs
Normal file
13
TINKLib/Model/IBookingFinishedModel.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using TINK.Model.MiniSurvey;
|
||||
|
||||
namespace TINK.Model
|
||||
{
|
||||
public interface IBookingFinishedModel
|
||||
{
|
||||
/// <summary> Minisurvey to query user.</summary>
|
||||
IMiniSurveyModel MiniSurvey { get; set; }
|
||||
|
||||
/// <summary> Holds info about co2 saving accomplished by using cargo bike. </summary>
|
||||
string Co2Saving { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,19 +1,30 @@
|
|||
using Serilog.Events;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Threading;
|
||||
using Serilog.Events;
|
||||
using TINK.Model.Connector;
|
||||
using TINK.Model.Device;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Model.Services.CopriApi.ServerUris;
|
||||
using TINK.Model.Station;
|
||||
using TINK.Services;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Settings;
|
||||
using TINK.ViewModel.Map;
|
||||
using TINK.ViewModel.Settings;
|
||||
using TINK.Services;
|
||||
using TINK.Model.Station;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TINK.Model
|
||||
{
|
||||
public enum AppFlavor
|
||||
{
|
||||
[Display(Name = "sharee.bike")]
|
||||
ShareeBike,
|
||||
[Display(Name = "Lastenrad Bayern")]
|
||||
LastenradBayern,
|
||||
[Display(Name = "Mein konrad")]
|
||||
MeinKonrad,
|
||||
}
|
||||
|
||||
public interface ITinkApp
|
||||
{
|
||||
/// <summary> Update connector from depending on whether user is logged in or not.</summary>
|
||||
|
@ -28,9 +39,6 @@ namespace TINK.Model
|
|||
/// <summary> Holds the user of the app. </summary>
|
||||
User.User ActiveUser { get; }
|
||||
|
||||
/// <summary>Sets flag whats new page was already shown to true. </summary>
|
||||
void SetWhatsNewWasShown();
|
||||
|
||||
/// <summary> Holds the system to copri.</summary>
|
||||
IFilteredConnector GetConnector(bool isConnected);
|
||||
|
||||
|
@ -88,7 +96,7 @@ namespace TINK.Model
|
|||
LocksServicesContainerMutable LocksServices { get; }
|
||||
|
||||
/// <summary> Holds available app themes.</summary>
|
||||
ServicesContainerMutable<object> Themes { get; }
|
||||
ServicesContainerMutable Themes { get; }
|
||||
|
||||
/// <summary> Reference of object which provides device information. </summary>
|
||||
ISmartDevice SmartDevice { get; }
|
||||
|
@ -107,7 +115,7 @@ namespace TINK.Model
|
|||
}
|
||||
|
||||
public interface IResourceUrls
|
||||
{
|
||||
{
|
||||
string FeesResourcePath { get; }
|
||||
|
||||
string BikesResourcePath { get; }
|
||||
|
@ -117,5 +125,5 @@ namespace TINK.Model
|
|||
string PrivacyResourcePath { get; }
|
||||
|
||||
string ImpressResourcePath { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,6 @@ namespace TINK.Model.Logging
|
|||
|
||||
/// <summary> Gets path where log files are located. </summary>
|
||||
/// <returns>Path to log files.</returns>
|
||||
public string LogFilePath { get { return string.Empty; } }
|
||||
public string LogFilePath { get { return string.Empty; } }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using Serilog;
|
||||
using System;
|
||||
using System;
|
||||
using Serilog;
|
||||
using TINK.Repository.Exception;
|
||||
|
||||
namespace TINK.Model.Logging
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
using Serilog;
|
||||
using Serilog.Configuration;
|
||||
using Serilog.Formatting.Json;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Serilog;
|
||||
using Serilog.Configuration;
|
||||
using Serilog.Formatting.Json;
|
||||
|
||||
namespace TINK.Model.Logging
|
||||
{
|
||||
|
@ -17,6 +17,12 @@ namespace TINK.Model.Logging
|
|||
/// <summary> Provides logging file name helper functionality.</summary>
|
||||
public static class LoggerConfigurationHelper
|
||||
{
|
||||
// Max count of retained logs count.
|
||||
private const int RETAINEDFILECOUNT = 10;
|
||||
|
||||
// Max size of logging file.
|
||||
private const int MAXLOGFILESSIZEBYTESBYTES = 1024 * 1024 * 8; // 8MB
|
||||
|
||||
/// <summary> Holds the log file name. </summary>
|
||||
private static ILoggingDirectoryManager DirectoryManager { get; set; } = new EmptyDirectoryLoggingManger();
|
||||
|
||||
|
@ -30,7 +36,7 @@ namespace TINK.Model.Logging
|
|||
this LoggerSinkConfiguration loggerConfiguration,
|
||||
string logFileFolder,
|
||||
RollingInterval rollingInterval = RollingInterval.Session,
|
||||
int retainedFilesCountLimit = 10)
|
||||
int retainedFilesCountLimit = RETAINEDFILECOUNT)
|
||||
{
|
||||
if (DirectoryManager is EmptyDirectoryLoggingManger)
|
||||
{
|
||||
|
@ -67,9 +73,10 @@ namespace TINK.Model.Logging
|
|||
return null;
|
||||
}
|
||||
|
||||
return loggerConfiguration.File(
|
||||
return loggerConfiguration.File(
|
||||
new JsonFormatter(),
|
||||
DirectoryManager.LogFileName,
|
||||
fileSizeLimitBytes: MAXLOGFILESSIZEBYTESBYTES / RETAINEDFILECOUNT,
|
||||
/*shared: true, // Leads to exception if activated.*/
|
||||
rollingInterval: Serilog.RollingInterval.Infinite,
|
||||
retainedFileCountLimit: retainedFilesCountLimit);
|
||||
|
@ -78,7 +85,7 @@ namespace TINK.Model.Logging
|
|||
/// <summary> Gets all log files in logging directory. </summary>
|
||||
/// <param name="p_oLogger"></param>
|
||||
/// <returns>List of log files.</returns>
|
||||
public static IList<string> GetLogFiles(this ILogger p_oLogger)
|
||||
public static IList<string> GetLogFiles(this ILogger p_oLogger)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
@ -13,34 +13,34 @@ namespace TINK.Model.Logging
|
|||
private LoggingDirectoryManager() { }
|
||||
|
||||
public LoggingDirectoryManager(
|
||||
Func<string, IList<string>> p_oFileListProvider,
|
||||
Func<string, bool> p_oDirectoryExistsChecker,
|
||||
Action<string> p_oDirectoryCreator,
|
||||
Action<string> p_oFileEraser,
|
||||
string p_oLogFilePath,
|
||||
char p_strDirectorySeparatorChar,
|
||||
Func<string, IList<string>> fileListProvider,
|
||||
Func<string, bool> directoryExistsChecker,
|
||||
Action<string> directoryCreator,
|
||||
Action<string> fileEraser,
|
||||
string logFilePath,
|
||||
char directorySeparatorChar,
|
||||
int p_iRetainedFilesCountLimit)
|
||||
{
|
||||
m_oFileListProvider = p_oFileListProvider ?? throw new ArgumentException($"Can not instantiate {nameof(LoggingDirectoryManager)}- object. File list provider delegate can not be null.");
|
||||
m_oFileListProvider = fileListProvider ?? throw new ArgumentException($"Can not instantiate {nameof(LoggingDirectoryManager)}- object. File list provider delegate can not be null.");
|
||||
|
||||
if (p_oDirectoryExistsChecker == null)
|
||||
if (directoryExistsChecker == null)
|
||||
{
|
||||
throw new ArgumentException($"Can not instantiate {nameof(LoggingDirectoryManager)}- object. Directory existance checker delegate can not be null.");
|
||||
}
|
||||
|
||||
if (p_oDirectoryCreator == null)
|
||||
if (directoryCreator == null)
|
||||
{
|
||||
throw new ArgumentException($"Can not instantiate {nameof(LoggingDirectoryManager)}- object. Directory creator delegate can not be null.");
|
||||
}
|
||||
|
||||
m_oFileEraser = p_oFileEraser ?? throw new ArgumentException($"Can not instantiate {nameof(LoggingDirectoryManager)}- object. File eraser delegate can not be null.");
|
||||
m_oFileEraser = fileEraser ?? throw new ArgumentException($"Can not instantiate {nameof(LoggingDirectoryManager)}- object. File eraser delegate can not be null.");
|
||||
|
||||
if (string.IsNullOrEmpty(p_oLogFilePath))
|
||||
if (string.IsNullOrEmpty(logFilePath))
|
||||
{
|
||||
throw new ArgumentException($"Can not instantiate {nameof(LoggingDirectoryManager)}- object. Log file path can not be null or empty.");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(p_strDirectorySeparatorChar.ToString()))
|
||||
if (string.IsNullOrEmpty(directorySeparatorChar.ToString()))
|
||||
{
|
||||
throw new ArgumentException($"Can not instantiate {nameof(LoggingDirectoryManager)}- object. Directory separtor character can not be null or empty.");
|
||||
}
|
||||
|
@ -50,9 +50,9 @@ namespace TINK.Model.Logging
|
|||
throw new ArgumentException($"Can not instantiate {nameof(LoggingDirectoryManager)}- object. Count of retained log files is {p_iRetainedFilesCountLimit} but must be equal or larger one.");
|
||||
}
|
||||
|
||||
DirectorySeparatorChar = p_strDirectorySeparatorChar.ToString();
|
||||
DirectorySeparatorChar = directorySeparatorChar.ToString();
|
||||
|
||||
LogFilePath = $"{p_oLogFilePath}{DirectorySeparatorChar}{LOGDIRECTORYTITLE}";
|
||||
LogFilePath = $"{logFilePath}{DirectorySeparatorChar}{LOGDIRECTORYTITLE}";
|
||||
|
||||
|
||||
m_iRetainedFilesCountLimit = p_iRetainedFilesCountLimit;
|
||||
|
@ -63,11 +63,11 @@ namespace TINK.Model.Logging
|
|||
}
|
||||
|
||||
// Create directory if direcotry does not exist.
|
||||
if (p_oDirectoryExistsChecker(LogFilePath) == false)
|
||||
if (directoryExistsChecker(LogFilePath) == false)
|
||||
{
|
||||
try
|
||||
{
|
||||
p_oDirectoryCreator(LogFilePath);
|
||||
directoryCreator(LogFilePath);
|
||||
}
|
||||
catch (Exception l_oException)
|
||||
{
|
||||
|
@ -83,9 +83,9 @@ namespace TINK.Model.Logging
|
|||
var l_oExceptions = new List<Exception>();
|
||||
var l_oSortedFileArray = m_oFileListProvider(LogFilePath).OrderByDescending(x => x).ToArray();
|
||||
|
||||
for (int l_iIndex = l_oSortedFileArray.Length - 1;
|
||||
l_iIndex >= m_iRetainedFilesCountLimit - 1; /* files remaining count must be m_iRetainedFilesCountLimit - 1 because new log file will be added afterwards */
|
||||
l_iIndex --)
|
||||
for (int l_iIndex = l_oSortedFileArray.Length - 1;
|
||||
l_iIndex >= m_iRetainedFilesCountLimit - 1; /* files remaining count must be m_iRetainedFilesCountLimit - 1 because new log file will be added afterwards */
|
||||
l_iIndex--)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
@ -23,8 +23,8 @@ namespace TINK.Model.Map
|
|||
public bool IsValid => GetIsValid(Center, Radius);
|
||||
|
||||
public static bool GetIsValid(IPosition center, double radius)
|
||||
=> center != null
|
||||
&& center.IsValid
|
||||
=> center != null
|
||||
&& center.IsValid
|
||||
&& !double.IsNaN(radius);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace TINK.Model.Map
|
|||
{
|
||||
public static IMapSpan Create(IPosition position = null, double radius = double.NaN)
|
||||
=> MapSpan.GetIsValid(position, radius)
|
||||
? new MapSpan(position, radius) as IMapSpan
|
||||
? new MapSpan(position, radius) as IMapSpan
|
||||
: new NullMapSpan();
|
||||
}
|
||||
}
|
||||
|
|
19
TINKLib/Model/MiniSurvey/IMiniSurveyModel.cs
Normal file
19
TINKLib/Model/MiniSurvey/IMiniSurveyModel.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace TINK.Model.MiniSurvey
|
||||
{
|
||||
public interface IMiniSurveyModel
|
||||
{
|
||||
/// <summary> Holds the title of the mini survey. </summary>
|
||||
string Title { get; set; }
|
||||
|
||||
/// <summary> Holds the sub title of the mini survey. </summary>
|
||||
string Subtitle { get; set; }
|
||||
|
||||
/// <summary> Holds the footer of the mini survey. </summary>
|
||||
string Footer { get; set; }
|
||||
|
||||
/// <summary> Holds the questions. </summary>
|
||||
IDictionary<string, IQuestionModel> Questions { get; }
|
||||
}
|
||||
}
|
16
TINKLib/Model/MiniSurvey/IQuestionModel.cs
Normal file
16
TINKLib/Model/MiniSurvey/IQuestionModel.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace TINK.Model.MiniSurvey
|
||||
{
|
||||
public interface IQuestionModel
|
||||
{
|
||||
/// <summary> Holds the query description. </summary>
|
||||
string Text { get; set; }
|
||||
|
||||
/// <summary> Holds the type of the question. </summary>
|
||||
MiniSurveyModel.Type Type { get; set; }
|
||||
|
||||
/// <summary>Holds the collection of possible answers.</summary>
|
||||
Dictionary<string, string> PossibleAnswers { get; }
|
||||
}
|
||||
}
|
|
@ -6,34 +6,29 @@ namespace TINK.Model.MiniSurvey
|
|||
/// <summary>
|
||||
/// Holds mini survey.
|
||||
/// </summary>
|
||||
public class MiniSurveyModel
|
||||
public class MiniSurveyModel : IMiniSurveyModel
|
||||
{
|
||||
public MiniSurveyModel(Dictionary<string, IQuestionModel> questions = null)
|
||||
{
|
||||
Questions = questions ?? new Dictionary<string, IQuestionModel>();
|
||||
}
|
||||
|
||||
public enum Type
|
||||
{
|
||||
SingleAnswer,
|
||||
CustomText
|
||||
}
|
||||
public class QuestionModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds the query description.
|
||||
/// </summary>
|
||||
public string Text { get; set; }
|
||||
|
||||
public Type Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds the collection of possible answers.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> PossibleAnswers { get; private set; } = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
/// <summary> Holds the title of the mini survey. </summary>
|
||||
public string Title { get; set; }
|
||||
|
||||
/// <summary> Holds the sub title of the mini survey. </summary>
|
||||
public string Subtitle { get; set; }
|
||||
|
||||
/// <summary> Holds the footer of the mini survey. </summary>
|
||||
public string Footer { get; set; }
|
||||
|
||||
public Dictionary<string, QuestionModel> Questions { get; } = new Dictionary<string, QuestionModel>();
|
||||
/// <summary> Holds the questions. </summary>
|
||||
public IDictionary<string, IQuestionModel> Questions { get; }
|
||||
}
|
||||
}
|
||||
|
|
16
TINKLib/Model/MiniSurvey/QuestionModel.cs
Normal file
16
TINKLib/Model/MiniSurvey/QuestionModel.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace TINK.Model.MiniSurvey
|
||||
{
|
||||
public class QuestionModel : IQuestionModel
|
||||
{
|
||||
/// <summary> Holds the query description. </summary>
|
||||
public string Text { get; set; }
|
||||
|
||||
/// <summary> Holds the type of the question. </summary>
|
||||
public MiniSurveyModel.Type Type { get; set; }
|
||||
|
||||
/// <summary>Holds the collection of possible answers.</summary>
|
||||
public Dictionary<string, string> PossibleAnswers { get; private set; } = new Dictionary<string, string>();
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ namespace TINK.Model
|
|||
{
|
||||
public static IPosition Create(double latitude = double.NaN, double longitude = double.NaN)
|
||||
=> Position.GetIsValid(longitude, latitude)
|
||||
? new Position(latitude, longitude) as IPosition
|
||||
? new Position(latitude, longitude) as IPosition
|
||||
: new NullPostion();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace TINK.ViewModel.Settings
|
|||
FilterDictionary = filterDictionary ?? new Dictionary<string, FilterState>();
|
||||
|
||||
Filter = filterDictionary != null
|
||||
? (IGroupFilter) new IntersectGroupFilter(FilterDictionary.Where(x => x.Value == FilterState.On).Select(x => x.Key))
|
||||
? (IGroupFilter)new IntersectGroupFilter(FilterDictionary.Where(x => x.Value == FilterState.On).Select(x => x.Key))
|
||||
: new NullGroupFilter();
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ namespace TINK.ViewModel.Settings
|
|||
private IGroupFilter Filter { get; }
|
||||
|
||||
/// <summary> Performs filtering on response -group. </summary>
|
||||
public IEnumerable<string> DoFilter(IEnumerable<string> filter = null) => Filter.DoFilter(filter);
|
||||
public IEnumerable<string> DoFilter(IEnumerable<string> filter = null) => Filter.DoFilter(filter);
|
||||
|
||||
public FilterState this[string key] { get => FilterDictionary[key]; set => FilterDictionary[key] = value; }
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Serilog.Events;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Serilog.Events;
|
||||
using TINK.Model.Services.CopriApi.ServerUris;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Settings;
|
||||
using TINK.ViewModel.Map;
|
||||
|
@ -65,16 +65,21 @@ namespace TINK.Model.Settings
|
|||
/// <param name="settingsJSON">Dictionary to get value from.</param>
|
||||
public static T GetEntry<T>(
|
||||
string keyName,
|
||||
Dictionary<string, string> settingsJSON) where T : class
|
||||
Dictionary<string, string> settingsJSON,
|
||||
Func<string, string> legacyValueConverter = null) where T : class
|
||||
{
|
||||
if (!settingsJSON.TryGetValue(keyName, out string boolText)
|
||||
|| string.IsNullOrEmpty(boolText))
|
||||
if (string.IsNullOrEmpty(keyName)
|
||||
|| settingsJSON == null
|
||||
|| !settingsJSON.TryGetValue(keyName, out string valueJSON)
|
||||
|| string.IsNullOrEmpty(valueJSON))
|
||||
{
|
||||
// File holds no entry.
|
||||
return null;
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<T>(boolText);
|
||||
return JsonConvert.DeserializeObject<T>(legacyValueConverter != null
|
||||
? legacyValueConverter(valueJSON)
|
||||
: valueJSON);
|
||||
}
|
||||
|
||||
/// <summary> Sets a nullable.</summary>
|
||||
|
@ -97,7 +102,7 @@ namespace TINK.Model.Settings
|
|||
/// <param name="targetDictionary">Dictionary to write information to.</param>
|
||||
/// <param name="connectTimeout">Connect timeout value.</param>
|
||||
public static Dictionary<string, string> SetConnectTimeout(
|
||||
this IDictionary<string, string> targetDictionary,
|
||||
this IDictionary<string, string> targetDictionary,
|
||||
TimeSpan connectTimeout)
|
||||
{
|
||||
if (targetDictionary == null)
|
||||
|
@ -154,10 +159,12 @@ namespace TINK.Model.Settings
|
|||
|
||||
/// <summary> Sets the version of the app. </summary>
|
||||
/// <param name="settingsJSON">Dictionary holding parameters from JSON.</param>
|
||||
public static Dictionary<string, string> SetAppVersion(this IDictionary<string, string> targetDictionary, Version appVersion)
|
||||
public static Dictionary<string, string> SetAppVersion(
|
||||
this IDictionary<string, string> targetDictionary,
|
||||
Version appVersion)
|
||||
{
|
||||
if (targetDictionary == null)
|
||||
throw new Exception("Writing copri host uri to dictionary failed. Dictionary must not be null.");
|
||||
throw new Exception("Writing app version to dictionary failed. Dictionary must not be null.");
|
||||
|
||||
return targetDictionary.Union(new Dictionary<string, string>
|
||||
{
|
||||
|
@ -204,15 +211,14 @@ namespace TINK.Model.Settings
|
|||
public static PollingParameters GetPollingParameters(this IDictionary<string, string> settingsJSON)
|
||||
{
|
||||
// Check if dictionary contains entry for periode.
|
||||
if (settingsJSON.TryGetValue($"{typeof(PollingParameters).Name}_{typeof(TimeSpan).Name}", out string l_strPeriode)
|
||||
&& settingsJSON.TryGetValue($"{typeof(PollingParameters).Name}_{typeof(bool).Name}", out string l_strIsActive)
|
||||
&& !string.IsNullOrEmpty(l_strPeriode)
|
||||
&& !string.IsNullOrEmpty(l_strIsActive))
|
||||
if (settingsJSON.TryGetValue($"{typeof(PollingParameters).Name}_{typeof(TimeSpan).Name}", out string periode)
|
||||
&& settingsJSON.TryGetValue($"{typeof(PollingParameters).Name}_{typeof(bool).Name}", out string active)
|
||||
&& !string.IsNullOrEmpty(periode)
|
||||
&& !string.IsNullOrEmpty(active))
|
||||
{
|
||||
return new PollingParameters(
|
||||
JsonConvert.DeserializeObject<TimeSpan>(l_strPeriode),
|
||||
JsonConvert.DeserializeObject<bool>(l_strIsActive));
|
||||
|
||||
JsonConvert.DeserializeObject<TimeSpan>(periode),
|
||||
JsonConvert.DeserializeObject<bool>(active));
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -260,14 +266,14 @@ namespace TINK.Model.Settings
|
|||
Dictionary<string, string> settingsJSON)
|
||||
{
|
||||
// Get logging level.
|
||||
if (!settingsJSON.TryGetValue(MINLOGGINGLEVELKEY, out string l_strLevel)
|
||||
|| string.IsNullOrEmpty(l_strLevel))
|
||||
if (!settingsJSON.TryGetValue(MINLOGGINGLEVELKEY, out string level)
|
||||
|| string.IsNullOrEmpty(level))
|
||||
{
|
||||
// File holds no entry.
|
||||
return null;
|
||||
}
|
||||
|
||||
return (LogEventLevel)int.Parse(JsonConvert.DeserializeObject<string>(l_strLevel));
|
||||
return (LogEventLevel)int.Parse(JsonConvert.DeserializeObject<string>(level));
|
||||
}
|
||||
|
||||
/// <summary> Gets a value indicating whether report level is verbose or not.</summary>
|
||||
|
@ -300,14 +306,14 @@ namespace TINK.Model.Settings
|
|||
public static Version GetWhatsNew(Dictionary<string, string> settingsJSON)
|
||||
{
|
||||
// Get logging level.
|
||||
if (!settingsJSON.TryGetValue(SHOWWHATSNEWKEY, out string l_strWhatsNewVersion)
|
||||
|| string.IsNullOrEmpty(l_strWhatsNewVersion))
|
||||
if (!settingsJSON.TryGetValue(SHOWWHATSNEWKEY, out string whatsNewVersion)
|
||||
|| string.IsNullOrEmpty(whatsNewVersion))
|
||||
{
|
||||
// File holds no entry.
|
||||
return null;
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<Version>(l_strWhatsNewVersion, new VersionConverter());
|
||||
return JsonConvert.DeserializeObject<Version>(whatsNewVersion, new VersionConverter());
|
||||
}
|
||||
|
||||
/// <summary> Sets the version of app when whats new was shown.</summary>
|
||||
|
@ -354,7 +360,7 @@ namespace TINK.Model.Settings
|
|||
|
||||
/// <summary> Sets the active lock service name. </summary>
|
||||
/// <param name="targetDictionary">Dictionary holding parameters from JSON.</param>
|
||||
public static Dictionary<string, string> SetActiveLockService(this IDictionary<string, string> targetDictionary, string activeLockService)
|
||||
public static Dictionary<string, string> SetActiveLockService(this IDictionary<string, string> targetDictionary, string activeLockService)
|
||||
{
|
||||
if (targetDictionary == null)
|
||||
throw new Exception("Writing active lock service name to dictionary failed. Dictionary must not be null.");
|
||||
|
@ -433,7 +439,26 @@ namespace TINK.Model.Settings
|
|||
|
||||
/// <summary> Gets full class name of active theme.</summary>
|
||||
/// <param name="settingsJSON">Dictionary to get value from.</param>
|
||||
public static string GetActiveTheme(Dictionary<string, string> settingsJSON) => GetEntry<string>(THEMEKEY, settingsJSON);
|
||||
public static string GetActiveTheme(Dictionary<string, string> settingsJSON)
|
||||
=> GetEntry<string>(THEMEKEY, settingsJSON, (value) =>
|
||||
{
|
||||
if (value == JsonConvert.SerializeObject(typeof(Themes.Konrad).FullName))
|
||||
{
|
||||
return JsonConvert.SerializeObject(TINK.Services.ThemeNS.ThemeSet.Konrad.ToString());
|
||||
}
|
||||
else if (value == JsonConvert.SerializeObject(typeof(Themes.LastenradBayern).FullName))
|
||||
{
|
||||
return JsonConvert.SerializeObject(TINK.Services.ThemeNS.ThemeSet.LastenradBayern.ToString());
|
||||
}
|
||||
else if (value == JsonConvert.SerializeObject(typeof(Themes.ShareeBike).FullName))
|
||||
{
|
||||
return JsonConvert.SerializeObject(TINK.Services.ThemeNS.ThemeSet.ShareeBike.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
return value;
|
||||
}
|
||||
});
|
||||
|
||||
/// <summary> Gets a value indicating whether site caching is on or off.</summary>
|
||||
/// <param name="settingsJSON">Dictionary to get value from.</param>
|
||||
|
@ -445,23 +470,26 @@ namespace TINK.Model.Settings
|
|||
|
||||
/// <summary> Sets active theme.</summary>
|
||||
/// <param name="targetDictionary">Dictionary to set value to.</param>
|
||||
public static Dictionary<string, string> SetActiveTheme(this IDictionary<string, string> targetDictionary, string theme) => SetEntry(theme, THEMEKEY, targetDictionary);
|
||||
public static Dictionary<string, string> SetActiveTheme(
|
||||
this IDictionary<string, string> targetDictionary,
|
||||
string theme)
|
||||
=> SetEntry(theme, THEMEKEY, targetDictionary);
|
||||
|
||||
/// <summary> Sets whether site caching is on or off.</summary>
|
||||
/// <param name="settingsJSON">Dictionary to get value from.</param>
|
||||
public static Dictionary<string, string> SetIsSiteCachingOn(this IDictionary<string, string> targetDictionary, bool useSdCard) => SetEntry(useSdCard, ISSITECACHINGON, targetDictionary);
|
||||
|
||||
|
||||
/// <summary> Gets the map page filter. </summary>
|
||||
/// <param name="settings">Settings objet to load from.</param>
|
||||
public static IGroupFilterMapPage GetGroupFilterMapPage(this IDictionary<string, string> settings)
|
||||
{
|
||||
var l_oKeyName = "FilterCollection_MapPageFilter";
|
||||
if (settings == null || !settings.ContainsKey(l_oKeyName))
|
||||
var keyName = "FilterCollection_MapPageFilter";
|
||||
if (settings == null || !settings.ContainsKey(keyName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new GroupFilterMapPage(JsonConvert.DeserializeObject<IDictionary<string, FilterState>>(settings[l_oKeyName]));
|
||||
return new GroupFilterMapPage(JsonConvert.DeserializeObject<IDictionary<string, FilterState>>(settings[keyName]));
|
||||
}
|
||||
|
||||
public static IDictionary<string, string> SetGroupFilterMapPage(
|
||||
|
@ -483,13 +511,13 @@ namespace TINK.Model.Settings
|
|||
/// <param name="settings">Settings objet to load from.</param>
|
||||
public static IGroupFilterSettings GetGoupFilterSettings(this IDictionary<string, string> settings)
|
||||
{
|
||||
var l_oKeyName = "FilterCollection";
|
||||
if (settings == null || !settings.ContainsKey(l_oKeyName))
|
||||
var keyName = "FilterCollection";
|
||||
if (settings == null || !settings.ContainsKey(keyName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var legacyFilterCollection = new GroupFilterSettings(JsonConvert.DeserializeObject<IDictionary<string, FilterState>>(settings[l_oKeyName]));
|
||||
var legacyFilterCollection = new GroupFilterSettings(JsonConvert.DeserializeObject<IDictionary<string, FilterState>>(settings[keyName]));
|
||||
|
||||
// Process legacy entries.
|
||||
var updatedFilterCollection = legacyFilterCollection.Where(x => x.Key.ToUpper() != "TINK.SMS" && x.Key.ToUpper() != "TINK.COPRI").ToDictionary(x => x.Key, x => x.Value);
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace TINK.Settings
|
|||
{
|
||||
/// <summary> Holds polling parameters.</summary>
|
||||
public sealed class PollingParameters : IEquatable<PollingParameters>
|
||||
{
|
||||
{
|
||||
/// <summary> Holds default polling parameters. </summary>
|
||||
public static PollingParameters Default { get; } = new PollingParameters(
|
||||
new TimeSpan(0, 0, 0, 10 /*secs*/, 0),// Default polling interval.
|
||||
|
@ -28,7 +28,7 @@ namespace TINK.Settings
|
|||
public TimeSpan Periode { get; }
|
||||
|
||||
/// <summary> Holds value whether polling is activated or not.</summary>
|
||||
public bool IsActivated { get; }
|
||||
public bool IsActivated { get; }
|
||||
|
||||
/// <summary> Checks equallity.</summary>
|
||||
/// <param name="other">Object to compare with.</param>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
using Serilog.Events;
|
||||
using System;
|
||||
using TINK.Services.Geolocation;
|
||||
using System;
|
||||
using Serilog.Events;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Services.CopriApi.ServerUris;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Settings;
|
||||
using TINK.ViewModel.Map;
|
||||
using TINK.ViewModel.Settings;
|
||||
|
@ -20,7 +20,7 @@ namespace TINK.Model.Settings
|
|||
/// <summary> Gets the type of the default geolocation service. </summary>
|
||||
/// <remarks> Swtiched from GeolocationService (GeolocationAccuracyMediumService) to GeolocationAccuracyHighService in app version 3.0.290.</remarks>
|
||||
public static Type DefaultLocationService => typeof(GeolocationAccuracyHighService);
|
||||
|
||||
|
||||
// Default value of the expires after entry. Controls the expiration time of the cache values.
|
||||
private TimeSpan DEFAULTEXPIRESAFTER = TimeSpan.FromSeconds(1);
|
||||
|
||||
|
@ -66,7 +66,7 @@ namespace TINK.Model.Settings
|
|||
MapSpan = mapSpan;
|
||||
LogToExternalFolder = logToExternalFolder ?? false;
|
||||
IsSiteCachingOn = isSiteCachingOn ?? true;
|
||||
ActiveTheme = activeTheme ?? typeof(Themes.ShareeBike).FullName;
|
||||
ActiveTheme = activeTheme ?? typeof(Themes.ShareeBike).Name;
|
||||
}
|
||||
|
||||
/// <summary> Holds the filter which is applied on the map view. Either TINK or Konrad stations are displayed. </summary>
|
||||
|
|
|
@ -6,15 +6,16 @@ namespace TINK.Model.State
|
|||
/// Base type for serialization purposes.
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
[KnownType(typeof(StateFeedbackPendingInfo))]
|
||||
[KnownType(typeof(StateAvailableInfo))]
|
||||
[KnownType(typeof(StateRequestedInfo))]
|
||||
[KnownType(typeof(StateOccupiedInfo))]
|
||||
public abstract class BaseState
|
||||
{
|
||||
/// <summary> Constructor for Json serialization. </summary>
|
||||
/// <param name="p_eValue">State value.</param>
|
||||
protected BaseState(InUseStateEnum p_eValue) {}
|
||||
|
||||
/// <param name="value">State value.</param>
|
||||
protected BaseState(InUseStateEnum value) { }
|
||||
|
||||
/// <summary>
|
||||
/// Holds the state value.
|
||||
/// </summary>
|
||||
|
|
|
@ -17,6 +17,6 @@ namespace TINK.Model.State
|
|||
DateTime? from = null,
|
||||
string mailAddress = null,
|
||||
string code = null,
|
||||
Bikes.Bike.BC.NotifyPropertyChangedLevel notifyLevel = Bikes.Bike.BC.NotifyPropertyChangedLevel.All);
|
||||
Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel notifyLevel = Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.All);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace TINK.Model.State
|
||||
{
|
||||
|
@ -13,27 +12,17 @@ namespace TINK.Model.State
|
|||
/// <summary>
|
||||
/// Constructs state info object representing state available.
|
||||
/// </summary>
|
||||
public StateAvailableInfo() : base(InUseStateEnum.Disposable)
|
||||
{
|
||||
}
|
||||
public StateAvailableInfo() : base(InUseStateEnum.Disposable) { }
|
||||
|
||||
/// <summary> Constructor for Json serialization. </summary>
|
||||
/// <param name="p_eValue">Unused value.</param>
|
||||
/// <param name="value">Unused value.</param>
|
||||
[JsonConstructor]
|
||||
private StateAvailableInfo (InUseStateEnum p_eValue) : base(InUseStateEnum.Disposable)
|
||||
{
|
||||
}
|
||||
private StateAvailableInfo(InUseStateEnum value) : base(InUseStateEnum.Disposable) { }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the info that state is disposable.
|
||||
/// Setter exists only for serialization purposes.
|
||||
/// </summary>
|
||||
public override InUseStateEnum Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return InUseStateEnum.Disposable;
|
||||
}
|
||||
}
|
||||
public override InUseStateEnum Value => InUseStateEnum.Disposable;
|
||||
}
|
||||
}
|
||||
|
|
28
TINKLib/Model/State/StateFeedbackPendingInfo.cs
Normal file
28
TINKLib/Model/State/StateFeedbackPendingInfo.cs
Normal file
|
@ -0,0 +1,28 @@
|
|||
using System.Runtime.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace TINK.Model.State
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the state feedback pending.
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
public sealed class StateFeedbackPendingInfo : BaseState, IBaseState
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs state info object representing feedback pending.
|
||||
/// </summary>
|
||||
public StateFeedbackPendingInfo() : base(InUseStateEnum.FeedbackPending) { }
|
||||
|
||||
/// <summary> Constructor for Json serialization. </summary>
|
||||
/// <param name="value">Unused value.</param>
|
||||
[JsonConstructor]
|
||||
private StateFeedbackPendingInfo(InUseStateEnum value) : base(InUseStateEnum.FeedbackPending) { }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the info that state is disposable.
|
||||
/// Setter exists only for serialization purposes.
|
||||
/// </summary>
|
||||
public override InUseStateEnum Value => InUseStateEnum.FeedbackPending;
|
||||
}
|
||||
}
|
|
@ -7,6 +7,12 @@ namespace TINK.Model.State
|
|||
/// </summary>
|
||||
public enum InUseStateEnum
|
||||
{
|
||||
/// <summary>
|
||||
/// Bike was returned but no feedback given.
|
||||
/// This applies to COPRI locks only because returning of bike is not done using app (Status: Supported locks are ILockIt and COPRI).
|
||||
/// </summary>
|
||||
FeedbackPending,
|
||||
|
||||
/// <summary>
|
||||
/// Bike is not in use. Corresponding COPRI state is "available".
|
||||
/// </summary>
|
||||
|
@ -29,37 +35,39 @@ namespace TINK.Model.State
|
|||
public class StateInfo : IStateInfo
|
||||
{
|
||||
// Holds the current disposable state value.
|
||||
private readonly BaseState m_oInUseState;
|
||||
private readonly BaseState _InUseState;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a state info object when state is available.
|
||||
/// </summary>
|
||||
/// <param name="p_oDateTimeNowProvider">Provider for current date time to calculate remainig time on demand for state of type reserved.</param>
|
||||
public StateInfo()
|
||||
/// <param name="isFeedbackPending">Specifieds whether feedback is pending or not.</param>
|
||||
public StateInfo(bool isFeedbackPending = false)
|
||||
{
|
||||
m_oInUseState = new StateAvailableInfo();
|
||||
_InUseState = isFeedbackPending
|
||||
? (BaseState)new StateFeedbackPendingInfo()
|
||||
: new StateAvailableInfo();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a state info object when state is requested.
|
||||
/// </summary>
|
||||
/// <param name="p_oRequestedAt">Date time when bike was requested</param>
|
||||
/// <param name="p_strMailAddress">Mail address of user which requested bike.</param>
|
||||
/// <param name="p_strCode">Booking code.</param>
|
||||
/// <param name="p_oDateTimeNowProvider">Date time provider to calculate reaining time.</param>
|
||||
/// <param name="requestedAt">Date time when bike was requested</param>
|
||||
/// <param name="mailAddress">Mail address of user which requested bike.</param>
|
||||
/// <param name="code">Booking code.</param>
|
||||
/// <param name="dateTimeNowProvider">Date time provider to calculate reaining time.</param>
|
||||
public StateInfo(
|
||||
Func<DateTime> p_oDateTimeNowProvider,
|
||||
DateTime p_oRequestedAt,
|
||||
string p_strMailAddress,
|
||||
string p_strCode)
|
||||
Func<DateTime> dateTimeNowProvider,
|
||||
DateTime requestedAt,
|
||||
string mailAddress,
|
||||
string code)
|
||||
{
|
||||
// Todo: Handle p_oFrom == null here.
|
||||
// Todo: Handle p_oDuration == null here.
|
||||
m_oInUseState = new StateRequestedInfo(
|
||||
p_oDateTimeNowProvider ?? (() => DateTime.Now),
|
||||
p_oRequestedAt,
|
||||
p_strMailAddress,
|
||||
p_strCode);
|
||||
_InUseState = new StateRequestedInfo(
|
||||
dateTimeNowProvider ?? (() => DateTime.Now),
|
||||
requestedAt,
|
||||
mailAddress,
|
||||
code);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -76,7 +84,7 @@ namespace TINK.Model.State
|
|||
// Todo: Handle p_oFrom == null here.
|
||||
// Todo: Clearify question: What to do if code changes form one value to another? This should never happen.
|
||||
// Todo: Clearify question: What to do if from time changes form one value to another? This should never happen.
|
||||
m_oInUseState = new StateOccupiedInfo(
|
||||
_InUseState = new StateOccupiedInfo(
|
||||
p_oBookedAt,
|
||||
p_strMailAddress,
|
||||
p_strCode);
|
||||
|
@ -87,7 +95,7 @@ namespace TINK.Model.State
|
|||
/// </summary>
|
||||
public InUseStateEnum Value
|
||||
{
|
||||
get { return m_oInUseState.Value; }
|
||||
get { return _InUseState.Value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -95,14 +103,14 @@ namespace TINK.Model.State
|
|||
/// </summary>
|
||||
internal BaseState StateInfoObject
|
||||
{
|
||||
get { return m_oInUseState; }
|
||||
get { return _InUseState; }
|
||||
}
|
||||
/// Transforms object to string.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public new string ToString()
|
||||
{
|
||||
return m_oInUseState.Value.ToString("g");
|
||||
return _InUseState.Value.ToString("g");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -112,7 +120,7 @@ namespace TINK.Model.State
|
|||
{
|
||||
get
|
||||
{
|
||||
var l_oNotDisposableInfo = m_oInUseState as INotAvailableState;
|
||||
var l_oNotDisposableInfo = _InUseState as INotAvailableState;
|
||||
return l_oNotDisposableInfo != null ? l_oNotDisposableInfo.From : (DateTime?)null;
|
||||
}
|
||||
}
|
||||
|
@ -124,7 +132,7 @@ namespace TINK.Model.State
|
|||
{
|
||||
get
|
||||
{
|
||||
var l_oNotDisposableInfo = m_oInUseState as INotAvailableState;
|
||||
var l_oNotDisposableInfo = _InUseState as INotAvailableState;
|
||||
return l_oNotDisposableInfo?.MailAddress;
|
||||
}
|
||||
}
|
||||
|
@ -136,7 +144,7 @@ namespace TINK.Model.State
|
|||
{
|
||||
get
|
||||
{
|
||||
var l_oNotDisposableInfo = m_oInUseState as INotAvailableState;
|
||||
var l_oNotDisposableInfo = _InUseState as INotAvailableState;
|
||||
return l_oNotDisposableInfo?.Code;
|
||||
}
|
||||
}
|
||||
|
@ -148,7 +156,7 @@ namespace TINK.Model.State
|
|||
/// <todo>Implement logging of time stamps.</todo>
|
||||
public bool GetIsStillReserved(out TimeSpan? p_oRemainingTime)
|
||||
{
|
||||
var l_oReservedInfo = m_oInUseState as StateRequestedInfo;
|
||||
var l_oReservedInfo = _InUseState as StateRequestedInfo;
|
||||
if (l_oReservedInfo == null)
|
||||
{
|
||||
p_oRemainingTime = null;
|
||||
|
|
13
TINKLib/Model/State/StateInfoHelper.cs
Normal file
13
TINKLib/Model/State/StateInfoHelper.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
namespace TINK.Model.State
|
||||
{
|
||||
public static class StateInfoHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets whether bike is available or occupied, i.e. reserved or booked.
|
||||
/// </summary>
|
||||
/// <param name="state">State to be info from.</param>
|
||||
/// <returns>True if bike is reserved to booked.</returns>
|
||||
public static bool IsOccupied(this InUseStateEnum state)
|
||||
=> state != InUseStateEnum.Disposable && state != InUseStateEnum.FeedbackPending;
|
||||
}
|
||||
}
|
|
@ -14,15 +14,15 @@ namespace TINK.Model.State
|
|||
/// <summary>
|
||||
/// Provider for current date time to calculate remainig time on demand for state of type reserved.
|
||||
/// </summary>
|
||||
private readonly Func<DateTime> m_oDateTimeNowProvider;
|
||||
private readonly Func<DateTime> _DateTimeNowProvider;
|
||||
|
||||
// Holds the current disposable state value
|
||||
private StateInfo m_oStateInfo;
|
||||
private StateInfo _StateInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Backs up remaining time of child object.
|
||||
/// </summary>
|
||||
private TimeSpan? m_oRemainingTime = null;
|
||||
private TimeSpan? _RemainingTime = null;
|
||||
|
||||
/// <summary> Notifies clients about state changes. </summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
@ -30,26 +30,26 @@ namespace TINK.Model.State
|
|||
/// <summary>
|
||||
/// Constructs a state object from source.
|
||||
/// </summary>
|
||||
/// <param name="p_oState">State info to load from.</param>
|
||||
/// <param name="state">State info to load from.</param>
|
||||
public StateInfoMutable(
|
||||
Func<DateTime> p_oDateTimeNowProvider = null,
|
||||
IStateInfo p_oState = null)
|
||||
Func<DateTime> dateTimeNowProvider = null,
|
||||
IStateInfo state = null)
|
||||
{
|
||||
// Back up date time provider to be able to pass this to requested- object if state changes to requested.
|
||||
m_oDateTimeNowProvider = p_oDateTimeNowProvider != null
|
||||
? p_oDateTimeNowProvider
|
||||
_DateTimeNowProvider = dateTimeNowProvider != null
|
||||
? dateTimeNowProvider
|
||||
: () => DateTime.Now;
|
||||
|
||||
m_oStateInfo = Create(p_oState, p_oDateTimeNowProvider);
|
||||
_StateInfo = Create(state, dateTimeNowProvider);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads state from immutable source.
|
||||
/// </summary>
|
||||
/// <param name="p_oState">State to load from.</param>
|
||||
public void Load(IStateInfo p_oState)
|
||||
/// <param name="state">State to load from.</param>
|
||||
public void Load(IStateInfo state)
|
||||
{
|
||||
if (p_oState == null)
|
||||
if (state == null)
|
||||
{
|
||||
throw new ArgumentException("Can not load state info, object must not be null.");
|
||||
}
|
||||
|
@ -57,20 +57,20 @@ namespace TINK.Model.State
|
|||
// Back up last state value and remaining time value
|
||||
// to be able to check whether an event has to be fired or not.
|
||||
var l_oLastState = Value;
|
||||
var l_oLastRemainingTime = m_oRemainingTime;
|
||||
var l_oLastRemainingTime = _RemainingTime;
|
||||
|
||||
// Create new state info object from source.
|
||||
m_oStateInfo = Create(p_oState, m_oDateTimeNowProvider);
|
||||
_StateInfo = Create(state, _DateTimeNowProvider);
|
||||
|
||||
// Update remaining time value.
|
||||
m_oStateInfo.GetIsStillReserved(out m_oRemainingTime);
|
||||
_StateInfo.GetIsStillReserved(out _RemainingTime);
|
||||
|
||||
if (l_oLastState == m_oStateInfo.Value
|
||||
&& l_oLastRemainingTime == m_oRemainingTime)
|
||||
if (l_oLastState == _StateInfo.Value
|
||||
&& l_oLastRemainingTime == _RemainingTime)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// State has changed, notify clients.
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(State)));
|
||||
}
|
||||
|
@ -78,24 +78,25 @@ namespace TINK.Model.State
|
|||
/// <summary>
|
||||
/// Creates a state info object.
|
||||
/// </summary>
|
||||
/// <param name="p_oState">State to load from.</param>
|
||||
/// <param name="state">State to load from.</param>
|
||||
private static StateInfo Create(
|
||||
IStateInfo p_oState,
|
||||
Func<DateTime> p_oDateTimeNowProvider)
|
||||
IStateInfo state,
|
||||
Func<DateTime> dateTimeNowProvider)
|
||||
{
|
||||
switch (p_oState != null ? p_oState.Value : InUseStateEnum.Disposable)
|
||||
switch (state != null ? state.Value : InUseStateEnum.Disposable)
|
||||
{
|
||||
case InUseStateEnum.Disposable:
|
||||
return new StateInfo();
|
||||
case InUseStateEnum.FeedbackPending:
|
||||
return new StateInfo(state != null ? state.Value == InUseStateEnum.FeedbackPending : false);
|
||||
|
||||
case InUseStateEnum.Reserved:
|
||||
// Todo: Handle p_oFrom == null here.
|
||||
// Todo: Handle p_oDuration == null here.
|
||||
return new StateInfo(
|
||||
p_oDateTimeNowProvider,
|
||||
p_oState.From.Value,
|
||||
p_oState.MailAddress,
|
||||
p_oState.Code);
|
||||
dateTimeNowProvider,
|
||||
state.From.Value,
|
||||
state.MailAddress,
|
||||
state.Code);
|
||||
|
||||
|
||||
case InUseStateEnum.Booked:
|
||||
|
@ -103,13 +104,13 @@ namespace TINK.Model.State
|
|||
// Todo: Clearify question: What to do if code changes form one value to another? This should never happen.
|
||||
// Todo: Clearify question: What to do if from time changes form one value to another? This should never happen.
|
||||
return new StateInfo(
|
||||
p_oState.From.Value,
|
||||
p_oState.MailAddress,
|
||||
p_oState.Code);
|
||||
state.From.Value,
|
||||
state.MailAddress,
|
||||
state.Code);
|
||||
|
||||
default:
|
||||
// Todo: New state Busy has to be defined.
|
||||
throw new Exception(string.Format("Can not create new state info object. Unknown state {0} detected.", p_oState.Value));
|
||||
throw new Exception(string.Format("Can not create new state info object. Unknown state {0} detected.", state.Value));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,9 +118,7 @@ namespace TINK.Model.State
|
|||
/// Gets the state value of object.
|
||||
/// </summary>
|
||||
public InUseStateEnum Value
|
||||
{
|
||||
get { return m_oStateInfo.Value; }
|
||||
}
|
||||
=> _StateInfo.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Member for serialization purposes.
|
||||
|
@ -127,24 +126,24 @@ namespace TINK.Model.State
|
|||
[DataMember]
|
||||
private BaseState StateInfoObject
|
||||
{
|
||||
get { return m_oStateInfo.StateInfoObject; }
|
||||
get { return _StateInfo.StateInfoObject; }
|
||||
set
|
||||
{
|
||||
var l_oStateOccupied = value as StateOccupiedInfo;
|
||||
if (l_oStateOccupied != null)
|
||||
{
|
||||
m_oStateInfo = new StateInfo(l_oStateOccupied.From, l_oStateOccupied.MailAddress, l_oStateOccupied.Code);
|
||||
_StateInfo = new StateInfo(l_oStateOccupied.From, l_oStateOccupied.MailAddress, l_oStateOccupied.Code);
|
||||
return;
|
||||
}
|
||||
|
||||
var l_oStateRequested = value as StateRequestedInfo;
|
||||
if (l_oStateRequested != null)
|
||||
{
|
||||
m_oStateInfo = new StateInfo(m_oDateTimeNowProvider, l_oStateRequested.From, l_oStateRequested.MailAddress, l_oStateRequested.Code);
|
||||
_StateInfo = new StateInfo(_DateTimeNowProvider, l_oStateRequested.From, l_oStateRequested.MailAddress, l_oStateRequested.Code);
|
||||
return;
|
||||
}
|
||||
|
||||
m_oStateInfo = new StateInfo();
|
||||
_StateInfo = new StateInfo();
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -153,7 +152,7 @@ namespace TINK.Model.State
|
|||
/// <returns></returns>
|
||||
public new string ToString()
|
||||
{
|
||||
return m_oStateInfo.ToString();
|
||||
return _StateInfo.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -162,7 +161,7 @@ namespace TINK.Model.State
|
|||
/// <returns>Value indicating wheter state has changed</returns>
|
||||
public void UpdateOnTimeElapsed()
|
||||
{
|
||||
switch (m_oStateInfo.Value )
|
||||
switch (_StateInfo.Value)
|
||||
{
|
||||
// State is disposable or booked. No need to update "OnTimeElapsed"
|
||||
case InUseStateEnum.Disposable:
|
||||
|
@ -171,10 +170,10 @@ namespace TINK.Model.State
|
|||
}
|
||||
|
||||
// Check if maximum reserved time has elapsed.
|
||||
if (!m_oStateInfo.GetIsStillReserved(out m_oRemainingTime))
|
||||
if (!_StateInfo.GetIsStillReserved(out _RemainingTime))
|
||||
{
|
||||
// Time has elapsed, switch state to disposable and notfiy client
|
||||
m_oStateInfo = new StateInfo();
|
||||
_StateInfo = new StateInfo();
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(State)));
|
||||
return;
|
||||
}
|
||||
|
@ -183,54 +182,53 @@ namespace TINK.Model.State
|
|||
}
|
||||
|
||||
/// <summary> Updates state from webserver. </summary>
|
||||
/// <param name="p_oState">State of the bike.</param>
|
||||
/// <param name="p_oFrom">Date time when bike was reserved/ booked.</param>
|
||||
/// <param name="p_oDuration">Lenght of time span for which bike remains booked.</param>
|
||||
/// <param name="p_strMailAddress">Mailaddress of the one which reserved/ booked.</param>
|
||||
/// <param name="p_strCode">Booking code if bike is booked or reserved.</param>
|
||||
/// <param name="state">State of the bike.</param>
|
||||
/// <param name="from">Date time when bike was reserved/ booked.</param>
|
||||
/// <param name="mailAddress">Mailaddress of the one which reserved/ booked.</param>
|
||||
/// <param name="code">Booking code if bike is booked or reserved.</param>
|
||||
/// <param name="supressNotifyPropertyChanged">Controls whether notify property changed events are fired or not.</param>
|
||||
public void Load(
|
||||
InUseStateEnum p_oState,
|
||||
DateTime? p_oFrom = null,
|
||||
string p_strMailAddress = null,
|
||||
string p_strCode = null,
|
||||
Bikes.Bike.BC.NotifyPropertyChangedLevel notifyLevel = Bikes.Bike.BC.NotifyPropertyChangedLevel.All)
|
||||
InUseStateEnum state,
|
||||
DateTime? from = null,
|
||||
string mailAddress = null,
|
||||
string code = null,
|
||||
Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel notifyLevel = Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.All)
|
||||
{
|
||||
var l_oLastState = m_oStateInfo.Value;
|
||||
var lastState = _StateInfo.Value;
|
||||
|
||||
switch (p_oState)
|
||||
switch (state)
|
||||
{
|
||||
case InUseStateEnum.Disposable:
|
||||
m_oStateInfo = new StateInfo();
|
||||
_StateInfo = new StateInfo();
|
||||
|
||||
// Set value to null. Otherwise potentially obsolete value will be taken remaining time.
|
||||
m_oRemainingTime = null;
|
||||
_RemainingTime = null;
|
||||
break;
|
||||
|
||||
case InUseStateEnum.Reserved:
|
||||
// Todo: Handle p_oFrom == null here.
|
||||
// Todo: Handle p_oDuration == null here.
|
||||
m_oStateInfo = new StateInfo(
|
||||
m_oDateTimeNowProvider,
|
||||
p_oFrom.Value,
|
||||
p_strMailAddress,
|
||||
p_strCode);
|
||||
_StateInfo = new StateInfo(
|
||||
_DateTimeNowProvider,
|
||||
from.Value,
|
||||
mailAddress,
|
||||
code);
|
||||
|
||||
// Set value to null. Otherwise potentially obsolete value will be taken remaining time.
|
||||
m_oRemainingTime = null;
|
||||
_RemainingTime = null;
|
||||
break;
|
||||
|
||||
case InUseStateEnum.Booked:
|
||||
// Todo: Handle p_oFrom == null here.
|
||||
// Todo: Clearify question: What to do if code changes form one value to another? This should never happen.
|
||||
// Todo: Clearify question: What to do if from time changes form one value to another? This should never happen.
|
||||
m_oStateInfo = new StateInfo(
|
||||
p_oFrom.Value,
|
||||
p_strMailAddress,
|
||||
p_strCode);
|
||||
_StateInfo = new StateInfo(
|
||||
from.Value,
|
||||
mailAddress,
|
||||
code);
|
||||
|
||||
// Set value to null. Otherwise potentially obsolete value will be taken remaining time.
|
||||
m_oRemainingTime = null;
|
||||
_RemainingTime = null;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -238,8 +236,8 @@ namespace TINK.Model.State
|
|||
break;
|
||||
}
|
||||
|
||||
if (l_oLastState != m_oStateInfo.Value
|
||||
&& notifyLevel == Bikes.Bike.BC.NotifyPropertyChangedLevel.All)
|
||||
if (lastState != _StateInfo.Value
|
||||
&& notifyLevel == Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.All)
|
||||
{
|
||||
// State has changed, notify clients.
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(State)));
|
||||
|
@ -252,23 +250,23 @@ namespace TINK.Model.State
|
|||
public TimeSpan? RemainingTime
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (m_oStateInfo.Value)
|
||||
{
|
||||
switch (_StateInfo.Value)
|
||||
{
|
||||
// State is either available or occupied.
|
||||
case InUseStateEnum.Disposable:
|
||||
case InUseStateEnum.Booked:
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (m_oRemainingTime.HasValue == false)
|
||||
if (_RemainingTime.HasValue == false)
|
||||
{
|
||||
// Value was not yet querried.
|
||||
// Do querry before returning object.
|
||||
m_oStateInfo.GetIsStillReserved(out m_oRemainingTime);
|
||||
_StateInfo.GetIsStillReserved(out _RemainingTime);
|
||||
}
|
||||
|
||||
return m_oRemainingTime;
|
||||
return _RemainingTime;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -276,7 +274,7 @@ namespace TINK.Model.State
|
|||
{
|
||||
get
|
||||
{
|
||||
return m_oStateInfo.From;
|
||||
return _StateInfo.From;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -284,7 +282,7 @@ namespace TINK.Model.State
|
|||
{
|
||||
get
|
||||
{
|
||||
return m_oStateInfo.MailAddress;
|
||||
return _StateInfo.MailAddress;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -292,7 +290,7 @@ namespace TINK.Model.State
|
|||
{
|
||||
get
|
||||
{
|
||||
return m_oStateInfo.Code;
|
||||
return _StateInfo.Code;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace TINK.Model.State
|
||||
{
|
||||
|
@ -41,7 +41,7 @@ namespace TINK.Model.State
|
|||
[JsonConstructor]
|
||||
private StateOccupiedInfo(
|
||||
InUseStateEnum Value,
|
||||
DateTime From,
|
||||
DateTime From,
|
||||
string MailAddress,
|
||||
string Code) : this(From, MailAddress, Code)
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace TINK.Model.State
|
||||
{
|
||||
|
@ -14,7 +14,7 @@ namespace TINK.Model.State
|
|||
public static readonly TimeSpan MaximumReserveTime = new TimeSpan(0, 15, 0); // 15 mins
|
||||
|
||||
// Reference to date time provider.
|
||||
private Func<DateTime> m_oDateTimeNowProvider;
|
||||
private Func<DateTime> _DateTimeNowProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Prevents an invalid instance to be created.
|
||||
|
@ -23,7 +23,7 @@ namespace TINK.Model.State
|
|||
private StateRequestedInfo() : base(InUseStateEnum.Reserved)
|
||||
{
|
||||
// Is called in context of JSON deserialization.
|
||||
m_oDateTimeNowProvider = () => DateTime.Now;
|
||||
_DateTimeNowProvider = () => DateTime.Now;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -44,21 +44,20 @@ namespace TINK.Model.State
|
|||
/// Reservation performed with other device/ before start of app.
|
||||
/// Date time info when bike was reserved has been received from webserver.
|
||||
/// </summary>
|
||||
/// <param name="p_oDateTimeNowProvider">
|
||||
/// <param name="dateTimeNowProvider">
|
||||
/// Used to to provide current date time information for potential calls of <seealso cref="GetIsStillReserved"/>.
|
||||
/// Not used to calculate remaining time because this duration whould always be shorter as the one received from webserver.
|
||||
/// </param>
|
||||
/// <param name="p_oRemainingTime">Time span which holds duration how long bike still will be reserved.</param>
|
||||
public StateRequestedInfo(
|
||||
Func<DateTime> p_oDateTimeNowProvider,
|
||||
DateTime p_oFrom,
|
||||
string p_strMailAddress,
|
||||
string p_strCode) : base(InUseStateEnum.Reserved)
|
||||
Func<DateTime> dateTimeNowProvider,
|
||||
DateTime from,
|
||||
string mailAddress,
|
||||
string code) : base(InUseStateEnum.Reserved)
|
||||
{
|
||||
m_oDateTimeNowProvider = p_oDateTimeNowProvider ?? (() => DateTime.Now);
|
||||
From = p_oFrom;
|
||||
MailAddress = p_strMailAddress;
|
||||
Code = p_strCode;
|
||||
_DateTimeNowProvider = dateTimeNowProvider ?? (() => DateTime.Now);
|
||||
From = from;
|
||||
MailAddress = mailAddress;
|
||||
Code = code;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -68,7 +67,7 @@ namespace TINK.Model.State
|
|||
/// <todo>Implement logging of time stamps.</todo>
|
||||
public bool GetIsStillReserved(out TimeSpan? p_oRemainingTime)
|
||||
{
|
||||
var l_oTimeReserved = m_oDateTimeNowProvider().Subtract(From);
|
||||
var l_oTimeReserved = _DateTimeNowProvider().Subtract(From);
|
||||
if (l_oTimeReserved > MaximumReserveTime)
|
||||
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace TINK.Model.Station.Operator
|
|||
public Data(
|
||||
string name = null,
|
||||
string phoneNumberText = null,
|
||||
string hours = null,
|
||||
string hours = null,
|
||||
string mailAddressText = null, Color? color = null)
|
||||
{
|
||||
Name = name ?? string.Empty;
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace TINK.Model.Station
|
|||
|
||||
/// <summary> Gets the name of the station.</summary>
|
||||
public string StationName { get; }
|
||||
|
||||
|
||||
/// <summary> Holds the gps- position of the station.</summary>
|
||||
public IPosition Position { get; }
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace TINK.Model.Station
|
|||
/// <summary> Count of stations. </summary>
|
||||
public int Count { get { return m_oStationDictionary.Count; } }
|
||||
|
||||
public Version CopriVersion { get; }
|
||||
public Version CopriVersion { get; }
|
||||
|
||||
/// <summary> Constructs a station dictionary object. </summary>
|
||||
/// <param name="p_oVersion">Version of copri- service.</param>
|
||||
|
|
|
@ -1,37 +1,37 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading;
|
||||
using Plugin.BLE.Abstractions.Contracts;
|
||||
using Plugin.Connectivity;
|
||||
using Serilog;
|
||||
using Serilog.Core;
|
||||
using Serilog.Events;
|
||||
using Serilog.Filters;
|
||||
using TINK.Model.Connector;
|
||||
using TINK.Model.Device;
|
||||
using TINK.Settings;
|
||||
using TINK.Model.User.Account;
|
||||
using TINK.Model.Settings;
|
||||
using TINK.Model.Logging;
|
||||
using Serilog.Events;
|
||||
using Serilog.Core;
|
||||
using Serilog;
|
||||
using Plugin.Connectivity;
|
||||
using System.Threading;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Model.Services.CopriApi.ServerUris;
|
||||
using TINK.Model.Settings;
|
||||
using TINK.Model.Station;
|
||||
using TINK.Model.User.Account;
|
||||
using TINK.Services;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Services.BluetoothLock.BLE;
|
||||
using TINK.Services.BluetoothLock.Crypto;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Services.Logging;
|
||||
using TINK.Services.Permissions;
|
||||
using TINK.Services.ThemeNS;
|
||||
using TINK.Settings;
|
||||
using TINK.ViewModel.Map;
|
||||
using TINK.ViewModel.Settings;
|
||||
using TINK.Services;
|
||||
using TINK.Services.BluetoothLock.BLE;
|
||||
using Xamarin.Forms;
|
||||
using TINK.Model.Station;
|
||||
using TINK.Services.Permissions;
|
||||
using Plugin.BLE.Abstractions.Contracts;
|
||||
|
||||
namespace TINK.Model
|
||||
{
|
||||
[DataContract]
|
||||
public class TinkApp : ITinkApp
|
||||
{
|
||||
private const string PLATFORMANDROID = "ANDROID";
|
||||
|
||||
/// <summary> Delegate used by login view to commit user name and password. </summary>
|
||||
/// <param name="p_strMailAddress">Mail address used as id login.</param>
|
||||
/// <param name="p_strPassword">Password for login.</param>
|
||||
|
@ -46,9 +46,6 @@ namespace TINK.Model
|
|||
/// </summary>
|
||||
public WhatsNew WhatsNew { get; private set; }
|
||||
|
||||
/// <summary>Sets flag whats new page was already shown to true. </summary>
|
||||
public void SetWhatsNewWasShown() => WhatsNew = WhatsNew.SetWasShown();
|
||||
|
||||
/// <summary>Holds uris of copri servers. </summary>
|
||||
public CopriServerUriList Uris { get; private set; }
|
||||
|
||||
|
@ -75,8 +72,8 @@ namespace TINK.Model
|
|||
public Xamarin.Forms.GoogleMaps.MapSpan UserMapSpan { get; set; } = null;
|
||||
|
||||
/// <summary> Holds the map span to display either default span or span centered to current position depending on option <see cref="CenterMapToCurrentLocation"/>.</summary>
|
||||
public Xamarin.Forms.GoogleMaps.MapSpan ActiveMapSpan
|
||||
=> CenterMapToCurrentLocation
|
||||
public Xamarin.Forms.GoogleMaps.MapSpan ActiveMapSpan
|
||||
=> CenterMapToCurrentLocation
|
||||
? UserMapSpan ?? HomeMapSpan
|
||||
: HomeMapSpan;
|
||||
|
||||
|
@ -109,7 +106,7 @@ namespace TINK.Model
|
|||
.SetLogToExternalFolder(LogToExternalFolder)
|
||||
.SetConnectTimeout(LocksServices.Active.TimeOut.MultiConnect)
|
||||
.SetIsSiteCachingOn(IsSiteCachingOn)
|
||||
.SetActiveTheme(Themes.Active.GetType().FullName));
|
||||
.SetActiveTheme(Themes.Active));
|
||||
|
||||
/// <summary>
|
||||
/// Update connector from filters when
|
||||
|
@ -153,7 +150,7 @@ namespace TINK.Model
|
|||
/// <param name="p_oDateTimeProvider"></param>
|
||||
/// <param name="isConnectedFunc">True if connector has access to copri server, false if cached values are used.</param>
|
||||
/// <param name="currentVersion">Version of the app. If null version is set to a fixed dummy value (3.0.122) for testing purposes.</param>
|
||||
/// <param name="lastVersion">Version of app which was used before this session.</param>
|
||||
/// <param name="lastVersion">Version of app which was used before this session, null if app is installed for the first time.</param>
|
||||
/// <param name="whatsNewShownInVersion"> Holds
|
||||
/// - the version when whats new info was shown last or
|
||||
/// - version of application used last if whats new functionality was not implemented in this version or
|
||||
|
@ -172,11 +169,13 @@ namespace TINK.Model
|
|||
ISmartDevice device,
|
||||
ISpecialFolder specialFolder,
|
||||
ICipher cipher,
|
||||
ITheme theme,
|
||||
object arendiCentral = null,
|
||||
Action<SendOrPostCallback, object> postAction = null,
|
||||
Version currentVersion = null,
|
||||
Version lastVersion = null,
|
||||
Version whatsNewShownInVersion = null)
|
||||
Version whatsNewShownInVersion = null,
|
||||
AppFlavor appFlavor = AppFlavor.ShareeBike)
|
||||
{
|
||||
PostAction = postAction
|
||||
?? ((d, obj) => d(obj));
|
||||
|
@ -189,21 +188,19 @@ namespace TINK.Model
|
|||
|
||||
Cipher = cipher ?? new Cipher();
|
||||
|
||||
bool GetIsAndroid(string platformText) => platformText.ToUpper().Contains(PLATFORMANDROID);
|
||||
|
||||
var locksServices = locksService != null
|
||||
? new HashSet<ILocksService> { locksService }
|
||||
: new HashSet<ILocksService> {
|
||||
new LockItByScanServiceEventBased(
|
||||
Cipher,
|
||||
bluetoothService,
|
||||
async () => GetIsAndroid(device.PlatformText) && await locationPermissionsService.CheckStatusAsync() != Status.Granted,
|
||||
() => GetIsAndroid(device.PlatformText) && !locationServicesContainer.Active.IsGeolcationEnabled),
|
||||
bluetoothService,
|
||||
async () => device.Platform == Xamarin.Essentials.DevicePlatform.Android && await locationPermissionsService.CheckStatusAsync() != Status.Granted,
|
||||
() => device.Platform == Xamarin.Essentials.DevicePlatform.Android && !locationServicesContainer.Active.IsGeolcationEnabled),
|
||||
new LockItByScanServicePolling(
|
||||
Cipher,
|
||||
bluetoothService,
|
||||
async () => GetIsAndroid(device.PlatformText) && await locationPermissionsService.CheckStatusAsync() != Status.Granted,
|
||||
() => GetIsAndroid(device.PlatformText) && !locationServicesContainer.Active.IsGeolcationEnabled),
|
||||
bluetoothService,
|
||||
async () => device.Platform == Xamarin.Essentials.DevicePlatform.Android && await locationPermissionsService.CheckStatusAsync() != Status.Granted,
|
||||
() => device.Platform == Xamarin.Essentials.DevicePlatform.Android && !locationServicesContainer.Active.IsGeolcationEnabled),
|
||||
new LockItByGuidService(Cipher),
|
||||
#if BLUETOOTHLE // Requires LockItBluetoothle library.
|
||||
new Bluetoothle.LockItByGuidService(Cipher),
|
||||
|
@ -216,19 +213,19 @@ namespace TINK.Model
|
|||
new LocksServiceOutOfReach(),
|
||||
};
|
||||
|
||||
LocksServices = new LocksServicesContainerMutable(
|
||||
LocksServices = new LocksServicesContainerMutable(
|
||||
lastVersion >= new Version(3, 0, 173) ? settings.ActiveLockService : LocksServicesContainerMutable.DefaultLocksservice,
|
||||
locksServices);
|
||||
|
||||
LocksServices.SetTimeOut(settings.ConnectTimeout);
|
||||
|
||||
Themes = new ServicesContainerMutable<object>(
|
||||
new HashSet<object> {
|
||||
new Themes.Konrad(),
|
||||
new Themes.ShareeBike(),
|
||||
new Themes.LastenradBayern()
|
||||
Themes = new ServicesContainerMutable(
|
||||
new HashSet<string> {
|
||||
ThemeSet.Konrad.ToString(),
|
||||
ThemeSet.ShareeBike.ToString(),
|
||||
ThemeSet.LastenradBayern.ToString()
|
||||
},
|
||||
settings.ActiveTheme);
|
||||
Enum.TryParse(settings.ActiveTheme, true, out ThemeSet active) ? active.ToString() : ThemeSet.ShareeBike.ToString());
|
||||
|
||||
GeolocationServices = locationServicesContainer
|
||||
?? throw new ArgumentException($"Can not instantiate {nameof(TinkApp)}- object. No geolocation services container object available.");
|
||||
|
@ -250,7 +247,7 @@ namespace TINK.Model
|
|||
|
||||
// Set logging level.
|
||||
Level.MinimumLevel = settings.MinimumLogEventLevel;
|
||||
|
||||
|
||||
LogToExternalFolder = settings.LogToExternalFolder;
|
||||
|
||||
IsSiteCachingOn = settings.IsSiteCachingOn;
|
||||
|
@ -289,7 +286,7 @@ namespace TINK.Model
|
|||
|
||||
IsReportLevelVerbose = settings.IsReportLevelVerbose;
|
||||
|
||||
WhatsNew = new WhatsNew(AppVersion, lastVersion, whatsNewShownInVersion);
|
||||
WhatsNew = new WhatsNew(AppVersion, lastVersion, whatsNewShownInVersion, appFlavor, SmartDevice.Platform);
|
||||
|
||||
if (Themes.Active.GetType().FullName == typeof(Themes.ShareeBike).FullName)
|
||||
{
|
||||
|
@ -300,27 +297,13 @@ namespace TINK.Model
|
|||
|
||||
// Set active app theme from settings.
|
||||
// Value might differ from default scheme value defined in ResourceDictionary.MergedDictionaries (App.xaml)
|
||||
ICollection<ResourceDictionary> mergedDictionaries = Application.Current.Resources.MergedDictionaries;
|
||||
if (mergedDictionaries == null)
|
||||
if (theme == null)
|
||||
{
|
||||
Log.ForContext<TinkApp>().Error("No merged dictionary available.");
|
||||
return;
|
||||
}
|
||||
|
||||
mergedDictionaries.Clear();
|
||||
|
||||
if (Themes.Active.GetType().FullName == typeof(Themes.Konrad).FullName)
|
||||
{
|
||||
mergedDictionaries.Add(new Themes.Konrad());
|
||||
}
|
||||
else if (Themes.Active.GetType().FullName == typeof(Themes.LastenradBayern).FullName)
|
||||
{
|
||||
mergedDictionaries.Add(new Themes.LastenradBayern());
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<TinkApp>().Debug($"No theme {Themes.Active} found.");
|
||||
}
|
||||
theme.SetActiveTheme(Themes.Active);
|
||||
}
|
||||
|
||||
/// <summary> Holds the user of the app. </summary>
|
||||
|
@ -375,7 +358,7 @@ namespace TINK.Model
|
|||
{
|
||||
if (m_oConnector.IsConnected == isConnected
|
||||
&& m_oConnector.Command.SessionCookie == ActiveUser.SessionCookie)
|
||||
{
|
||||
{
|
||||
// Neither connection nor logged in stated changed.
|
||||
return m_oConnector;
|
||||
}
|
||||
|
@ -384,9 +367,9 @@ namespace TINK.Model
|
|||
m_oConnector = FilteredConnectorFactory.Create(
|
||||
FilterGroupSetting.DoFilter(ActiveUser.DoFilter(GroupFilterMapPage.DoFilter())),
|
||||
ConnectorFactory(
|
||||
isConnected,
|
||||
isConnected,
|
||||
Uris.ActiveUri,
|
||||
ActiveUser.SessionCookie,
|
||||
ActiveUser.SessionCookie,
|
||||
ActiveUser.Mail,
|
||||
ExpiresAfter));
|
||||
|
||||
|
@ -400,7 +383,7 @@ namespace TINK.Model
|
|||
public IServicesContainer<IGeolocation> GeolocationServices { get; }
|
||||
|
||||
/// <summary> Manages the different types of LocksService objects.</summary>
|
||||
public ServicesContainerMutable<object> Themes { get; private set; }
|
||||
public ServicesContainerMutable Themes { get; private set; }
|
||||
|
||||
/// <summary> Object to switch logging level. </summary>
|
||||
private LoggingLevelSwitch m_oLoggingLevelSwitch;
|
||||
|
@ -427,10 +410,10 @@ namespace TINK.Model
|
|||
}
|
||||
|
||||
/// <summary> Updates logging level. </summary>
|
||||
/// <param name="p_oNewLevel">New level to set.</param>
|
||||
public void UpdateLoggingLevel(LogEventLevel p_oNewLevel)
|
||||
/// <param name="minimumLevel">New level to set.</param>
|
||||
public void UpdateLoggingLevel(LogEventLevel minimumLevel)
|
||||
{
|
||||
if (Level.MinimumLevel == p_oNewLevel)
|
||||
if (Level.MinimumLevel == minimumLevel)
|
||||
{
|
||||
// Nothing to do.
|
||||
return;
|
||||
|
@ -438,13 +421,29 @@ namespace TINK.Model
|
|||
|
||||
Log.CloseAndFlush(); // Close before modifying logger configuration. Otherwise a sharing vialation occurs.
|
||||
|
||||
Level.MinimumLevel = p_oNewLevel;
|
||||
Level.MinimumLevel = minimumLevel;
|
||||
|
||||
// Update logging
|
||||
SetupLogging(Level, LogFileParentFolder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets up logging.
|
||||
/// </summary>
|
||||
/// <param name="levelSwitch">Logging level to use.</param>
|
||||
/// <param name="logFilePath">Path to logging file.</param>
|
||||
public static void SetupLogging(
|
||||
LoggingLevelSwitch levelSwitch,
|
||||
string logFilePath)
|
||||
{
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.MinimumLevel.ControlledBy(Level)
|
||||
.MinimumLevel.ControlledBy(levelSwitch)
|
||||
.WriteTo.Debug()
|
||||
.WriteTo.File(LogFileParentFolder, Logging.RollingInterval.Session)
|
||||
.WriteTo.File(logFilePath, Logging.RollingInterval.Session)
|
||||
.WriteTo.Logger(lg => lg
|
||||
.MinimumLevel.ControlledBy(new LoggingLevelSwitch(LogEventLevel.Debug))
|
||||
.Filter.ByIncludingOnly(Matching.FromSource("TINK.Services.BluetoothLock.BLE"))
|
||||
.WriteTo.MemoryQueueSink()
|
||||
)
|
||||
.CreateLogger();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,8 +60,8 @@ namespace TINK.Model.User.Account
|
|||
/// <param name="bikeGroup">Group holdig info about Group (TINK, Konrad, ...)</param>
|
||||
/// <param name="p_iDebugLevel">Flag which controls display of debug settings.</param>
|
||||
public Account(
|
||||
string mail,
|
||||
string password,
|
||||
string mail,
|
||||
string password,
|
||||
bool isAgbAcknowledged,
|
||||
string sessionCookie,
|
||||
IEnumerable<string> bikeGroup,
|
||||
|
@ -73,7 +73,7 @@ namespace TINK.Model.User.Account
|
|||
SessionCookie = sessionCookie;
|
||||
DebugLevel = debugLevel;
|
||||
Group = bikeGroup != null
|
||||
? new HashSet<string>(bikeGroup).ToList()
|
||||
? new HashSet<string>(bikeGroup).ToList()
|
||||
: throw new ArgumentException("Can not instantiate account object. Reference to group list must not be empty.");
|
||||
}
|
||||
|
||||
|
|
|
@ -22,11 +22,11 @@ namespace TINK.Model.User.Account
|
|||
/// <param name="filter">Groups to filter.</param>
|
||||
/// <returns>Filtered bike groups.</returns>
|
||||
public static IEnumerable<string> DoFilter(
|
||||
this IAccount account,
|
||||
this IAccount account,
|
||||
IEnumerable<string> filter)
|
||||
{
|
||||
|
||||
return GetIsLoggedIn(account)
|
||||
return GetIsLoggedIn(account)
|
||||
? GroupFilterFactory.Create(account.Group).DoFilter(filter) // Filter if user is logged in.
|
||||
: new NullGroupFilter().DoFilter(filter); // Do not filter if no user is logged in.
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace TINK.Model.User.Account
|
|||
public string Mail
|
||||
{
|
||||
get { return m_oAccount.Mail; }
|
||||
set { m_oAccount = new Account(value, m_oAccount.Pwd, m_oAccount.IsAgbAcknowledged, m_oAccount.SessionCookie, m_oAccount.Group, m_oAccount.DebugLevel); }
|
||||
set { m_oAccount = new Account(value, m_oAccount.Pwd, m_oAccount.IsAgbAcknowledged, m_oAccount.SessionCookie, m_oAccount.Group, m_oAccount.DebugLevel); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using Serilog;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Serilog;
|
||||
using Xamarin.Essentials;
|
||||
|
||||
namespace TINK.Model.User.Account
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace TINK.Model.User.Account
|
|||
case Elements.Account:
|
||||
case Elements.None:
|
||||
continue;
|
||||
|
||||
|
||||
}
|
||||
|
||||
m_oDescription.Add(l_oElement, string.Empty);
|
||||
|
@ -94,7 +94,7 @@ namespace TINK.Model.User.Account
|
|||
}
|
||||
|
||||
l_oUserFriendlyDescription.Add(
|
||||
l_oElement,
|
||||
l_oElement,
|
||||
m_oDescription.ContainsKey(l_oElement) ? m_oDescription[l_oElement] : string.Empty);
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ namespace TINK.Model.User.Account
|
|||
Elements.Account,
|
||||
string.Join(";", l_oUserFriendlyDescription.Where(x => x.Value.Length > 0).Select(x => x.Value).ToArray()));
|
||||
|
||||
return l_oUserFriendlyDescription ;
|
||||
return l_oUserFriendlyDescription;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ namespace TINK.Model.User.Account
|
|||
{
|
||||
var l_oElements = Elements.None;
|
||||
var l_oDescription = new Dictionary<Elements, string>();
|
||||
|
||||
|
||||
// Validate mail address.
|
||||
if (string.IsNullOrEmpty(p_strMail))
|
||||
{
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace TINK.Model.User
|
|||
IAccount account,
|
||||
string deviceId)
|
||||
{
|
||||
Store = accountStore
|
||||
Store = accountStore
|
||||
?? throw new ArgumentException("Can not instantiate user- object. No store functionality available.");
|
||||
DeviceId = deviceId;
|
||||
Account = new AccountMutable(account);
|
||||
|
@ -44,7 +44,7 @@ namespace TINK.Model.User
|
|||
/// <summary>
|
||||
/// Holds a value indicating whether user is logged in or not.
|
||||
/// </summary>
|
||||
public bool IsLoggedIn => Account.GetIsLoggedIn();
|
||||
public bool IsLoggedIn => Account.GetIsLoggedIn();
|
||||
|
||||
/// <summary>
|
||||
/// Holds the mail address.
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue