mirror of
https://dev.azure.com/TeilRad/sharee.bike%20App/_git/Code
synced 2025-04-19 11:37:28 +02:00
Manually merged.
This commit is contained in:
parent
c7c9f252af
commit
e5c09b9b8d
33 changed files with 39827 additions and 529 deletions
|
@ -551,39 +551,5 @@ namespace TINK.Model.Connector
|
|||
|
||||
return bookingFinished;
|
||||
}
|
||||
|
||||
/// <summary> Creates a survey object from response.</summary>
|
||||
/// <param name="response">Response to create survey object from.</param>
|
||||
public static MiniSurveyModel Create(this ReservationCancelReturnResponse response)
|
||||
{
|
||||
if (response?.user_miniquery == null)
|
||||
{
|
||||
return new MiniSurveyModel();
|
||||
}
|
||||
|
||||
var miniquery = response.user_miniquery;
|
||||
var survey = 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;
|
||||
}
|
||||
|
||||
survey.Questions.Add(
|
||||
question.Key,
|
||||
new MiniSurveyModel.QuestionModel());
|
||||
}
|
||||
|
||||
return survey;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
589
TINKLib/Model/Connector/Updater/UpdaterJSON.cs.bak
Normal file
589
TINKLib/Model/Connector/Updater/UpdaterJSON.cs.bak
Normal file
|
@ -0,0 +1,589 @@
|
|||
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 System.Globalization;
|
||||
using TINK.Model.Station.Operator;
|
||||
using Xamarin.Forms;
|
||||
using System.Linq;
|
||||
using TINK.Model.MiniSurvey;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
{
|
||||
/// <summary>
|
||||
/// Connects TINK app to copri using JSON as input data format.
|
||||
/// </summary>
|
||||
/// <todo>Rename to UpdateFromCopri.</todo>
|
||||
public static class UpdaterJSON
|
||||
{
|
||||
/// <summary> Loads a bike object from copri server cancel reservation/ booking update request.</summary>
|
||||
/// <param name="bike">Bike object to load response into.</param>
|
||||
/// <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)
|
||||
{
|
||||
|
||||
bike.State.Load(InUseStateEnum.Disposable, notifyLevel: notifyLevel);
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets all statsion for station provider and add them into station list.
|
||||
/// </summary>
|
||||
/// <param name="p_oStationList">List of stations to update.</param>
|
||||
public static StationDictionary GetStationsAllMutable(this StationsAvailableResponse stationsAllResponse)
|
||||
{
|
||||
// Get stations from Copri/ file/ memory, ....
|
||||
if (stationsAllResponse == null
|
||||
|| stationsAllResponse.stations == null)
|
||||
{
|
||||
// Latest list of stations could not be retrieved from provider.
|
||||
return new StationDictionary();
|
||||
}
|
||||
|
||||
Version.TryParse(stationsAllResponse.copri_version, out Version copriVersion);
|
||||
|
||||
var stations = new StationDictionary(p_oVersion: copriVersion);
|
||||
|
||||
foreach (var station in stationsAllResponse.stations)
|
||||
{
|
||||
if (stations.GetById(station.Value.station) != null)
|
||||
{
|
||||
// Can not add station to list of station. Id is not unique.
|
||||
throw new InvalidResponseException<StationsAvailableResponse>(
|
||||
string.Format("Station id {0} is not unique.", station.Value.station), stationsAllResponse);
|
||||
}
|
||||
|
||||
stations.Add(new Station.Station(
|
||||
station.Value.station,
|
||||
station.Value.GetGroup(),
|
||||
station.Value.GetPosition(),
|
||||
station.Value.description,
|
||||
new Data(station.Value.operator_data?.operator_name,
|
||||
station.Value.operator_data?.operator_phone,
|
||||
station.Value.operator_data?.operator_hours,
|
||||
station.Value.operator_data?.operator_email,
|
||||
!string.IsNullOrEmpty(station.Value.operator_data?.operator_color)
|
||||
? Color.FromHex(station.Value.operator_data?.operator_color)
|
||||
: (Color?)null)));
|
||||
}
|
||||
|
||||
return stations;
|
||||
}
|
||||
|
||||
/// <summary> Gets account object from login response.</summary>
|
||||
/// <param name="merchantId">Needed to extract cookie from autorization response.</param>
|
||||
/// <param name="loginResponse">Response to get session cookie and debug level from.</param>
|
||||
/// <param name="mail">Mail address needed to construct a complete account object (is not part of response).</param>
|
||||
/// <param name="password">Password needed to construct a complete account object (is not part of response).</param>
|
||||
public static IAccount GetAccount(
|
||||
this AuthorizationResponse loginResponse,
|
||||
string merchantId,
|
||||
string mail,
|
||||
string password)
|
||||
{
|
||||
if (loginResponse == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(loginResponse));
|
||||
}
|
||||
|
||||
return new Account(
|
||||
mail,
|
||||
password,
|
||||
loginResponse.authcookie?.Replace(merchantId, ""),
|
||||
loginResponse.GetGroup(),
|
||||
loginResponse.debuglevel == 1
|
||||
? Permissions.All :
|
||||
(Permissions)loginResponse.debuglevel) ;
|
||||
}
|
||||
|
||||
/// <summary> Load bike object from booking response. </summary>
|
||||
/// <param name="bike">Bike object to load from response.</param>
|
||||
/// <param name="bikeInfo">Booking response.</param>
|
||||
/// <param name="mailAddress">Mail address of user which books bike.</param>
|
||||
/// <param name="p_strSessionCookie">Session cookie of user which books bike.</param>
|
||||
/// <param name="notifyLevel">Controls whether notify property changed events are fired or not.</param>
|
||||
public static void Load(
|
||||
this IBikeInfoMutable bike,
|
||||
BikeInfoReservedOrBooked bikeInfo,
|
||||
string mailAddress,
|
||||
Func<DateTime> dateTimeProvider,
|
||||
Bikes.Bike.BC.NotifyPropertyChangedLevel notifyLevel = Bikes.Bike.BC.NotifyPropertyChangedLevel.All)
|
||||
{
|
||||
|
||||
var l_oDateTimeProvider = dateTimeProvider != null
|
||||
? dateTimeProvider
|
||||
: () => DateTime.Now;
|
||||
|
||||
if (bike is Bike.BluetoothLock.BikeInfoMutable btBikeInfo)
|
||||
{
|
||||
btBikeInfo.LockInfo.Load(
|
||||
bikeInfo.GetBluetoothLockId(),
|
||||
bikeInfo.GetBluetoothLockGuid(),
|
||||
bikeInfo.GetSeed(),
|
||||
bikeInfo.GetUserKey(),
|
||||
bikeInfo.GetAdminKey());
|
||||
}
|
||||
|
||||
var l_oState = bikeInfo.GetState();
|
||||
switch (l_oState)
|
||||
{
|
||||
case InUseStateEnum.Disposable:
|
||||
bike.State.Load(
|
||||
InUseStateEnum.Disposable,
|
||||
notifyLevel: notifyLevel);
|
||||
break;
|
||||
|
||||
case InUseStateEnum.Reserved:
|
||||
bike.State.Load(
|
||||
InUseStateEnum.Reserved,
|
||||
bikeInfo.GetFrom(),
|
||||
mailAddress,
|
||||
bikeInfo.timeCode,
|
||||
notifyLevel);
|
||||
break;
|
||||
|
||||
case InUseStateEnum.Booked:
|
||||
bike.State.Load(
|
||||
InUseStateEnum.Booked,
|
||||
bikeInfo.GetFrom(),
|
||||
mailAddress,
|
||||
bikeInfo.timeCode,
|
||||
notifyLevel);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception(string.Format("Unexpected bike state detected. state is {0}.", l_oState));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Gets bikes available from copri server response.</summary>
|
||||
/// <param name="bikesAvailableResponse">Response to create collection from.</param>
|
||||
/// <returns>New collection of available bikes.</returns>
|
||||
public static BikeCollection GetBikesAvailable(
|
||||
this BikesAvailableResponse bikesAvailableResponse)
|
||||
{
|
||||
return GetBikesAll(
|
||||
bikesAvailableResponse,
|
||||
new BikesReservedOccupiedResponse(), // 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>
|
||||
/// <returns>New collection of occupied bikes.</returns>
|
||||
public static BikeCollection GetBikesOccupied(
|
||||
this BikesReservedOccupiedResponse bikesOccupiedResponse,
|
||||
string mail,
|
||||
Func<DateTime> dateTimeProvider)
|
||||
{
|
||||
return GetBikesAll(
|
||||
new BikesAvailableResponse(),
|
||||
bikesOccupiedResponse,
|
||||
mail,
|
||||
dateTimeProvider);
|
||||
}
|
||||
|
||||
/// <summary> Gets bikes occupied from copri server response. </summary>
|
||||
/// <param name="p_oBikesAvailable">Response to create bikes from.</param>
|
||||
/// <returns>New collection of occupied bikes.</returns>
|
||||
public static BikeCollection GetBikesAll(
|
||||
BikesAvailableResponse bikesAvailableResponse,
|
||||
BikesReservedOccupiedResponse bikesOccupiedResponse,
|
||||
string mail,
|
||||
Func<DateTime> dateTimeProvider)
|
||||
{
|
||||
var bikesDictionary = new Dictionary<string, BikeInfo>();
|
||||
var duplicates = new Dictionary<string, BikeInfo>();
|
||||
|
||||
// Get bikes from Copri/ file/ memory, ....
|
||||
if (bikesAvailableResponse != null
|
||||
&& bikesAvailableResponse.bikes != null)
|
||||
{
|
||||
foreach (var bikeInfoResponse in bikesAvailableResponse.bikes.Values)
|
||||
{
|
||||
var bikeInfo = BikeInfoFactory.Create(bikeInfoResponse);
|
||||
if (bikeInfo == null)
|
||||
{
|
||||
// Response is not valid.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bikesDictionary.ContainsKey(bikeInfo.Id))
|
||||
{
|
||||
// Duplicates are not allowed.
|
||||
Log.Error($"Duplicate bike with id {bikeInfo.Id} detected evaluating bikes available. Bike status is {bikeInfo.State.Value}.");
|
||||
|
||||
if (!duplicates.ContainsKey(bikeInfo.Id))
|
||||
{
|
||||
duplicates.Add(bikeInfo.Id, bikeInfo);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
bikesDictionary.Add(bikeInfo.Id, bikeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// Get bikes from Copri/ file/ memory, ....
|
||||
if (bikesOccupiedResponse != null
|
||||
&& bikesOccupiedResponse.bikes_occupied != null)
|
||||
{
|
||||
foreach (var bikeInfoResponse in bikesOccupiedResponse.bikes_occupied.Values)
|
||||
{
|
||||
BikeInfo bikeInfo = BikeInfoFactory.Create(
|
||||
bikeInfoResponse,
|
||||
mail,
|
||||
dateTimeProvider);
|
||||
|
||||
if (bikeInfo == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bikesDictionary.ContainsKey(bikeInfo.Id))
|
||||
{
|
||||
// Duplicates are not allowed.
|
||||
Log.Error($"Duplicate bike with id {bikeInfo.Id} detected evaluating bikes occupied. Bike status is {bikeInfo.State.Value}.");
|
||||
if (!duplicates.ContainsKey(bikeInfo.Id))
|
||||
{
|
||||
duplicates.Add(bikeInfo.Id, bikeInfo);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
bikesDictionary.Add(bikeInfo.Id, bikeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove entries which are not unique.
|
||||
foreach (var l_oDuplicate in duplicates)
|
||||
{
|
||||
bikesDictionary.Remove(l_oDuplicate.Key);
|
||||
}
|
||||
|
||||
return new BikeCollection(bikesDictionary);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructs bike info instances/ bike info derived instances.
|
||||
/// </summary>
|
||||
public static class BikeInfoFactory
|
||||
{
|
||||
public static BikeInfo Create(BikeInfoAvailable bikeInfo)
|
||||
{
|
||||
if (bikeInfo.GetIsManualLockBike())
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return !bikeInfo.GetIsBluetoothLockBike()
|
||||
? new BikeInfo(
|
||||
bikeInfo.bike,
|
||||
bikeInfo.station,
|
||||
bikeInfo.GetOperatorUri(),
|
||||
#if !NOTARIFFDESCRIPTION
|
||||
Create(bikeInfo.tariff_description),
|
||||
#else
|
||||
Create((TINK.Repository.Response.TariffDescription) null),
|
||||
#endif
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup(),
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.description)
|
||||
: new Bike.BluetoothLock.BikeInfo(
|
||||
bikeInfo.bike,
|
||||
bikeInfo.GetBluetoothLockId(),
|
||||
bikeInfo.GetBluetoothLockGuid(),
|
||||
bikeInfo.station,
|
||||
bikeInfo.GetOperatorUri(),
|
||||
#if !NOTARIFFDESCRIPTION
|
||||
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(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>
|
||||
/// <returns></returns>
|
||||
public static BikeInfo Create(
|
||||
BikeInfoReservedOrBooked bikeInfo,
|
||||
string mailAddress,
|
||||
Func<DateTime> dateTimeProvider)
|
||||
{
|
||||
if (bikeInfo.GetIsManualLockBike())
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Check if bike is a bluetooth lock bike.
|
||||
var isBluetoothBike = bikeInfo.GetIsBluetoothLockBike();
|
||||
int lockSerial = bikeInfo.GetBluetoothLockId();
|
||||
Guid lockGuid = bikeInfo.GetBluetoothLockGuid();
|
||||
|
||||
switch (bikeInfo.GetState())
|
||||
{
|
||||
case InUseStateEnum.Reserved:
|
||||
try
|
||||
{
|
||||
return !isBluetoothBike
|
||||
? new BikeInfo(
|
||||
bikeInfo.bike,
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup(),
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.description,
|
||||
bikeInfo.station,
|
||||
bikeInfo.GetOperatorUri(),
|
||||
|
||||
#if !NOTARIFFDESCRIPTION
|
||||
Create(bikeInfo.tariff_description),
|
||||
#else
|
||||
Create((TINK.Repository.Response.TariffDescription)null),
|
||||
#endif
|
||||
bikeInfo.GetFrom(),
|
||||
mailAddress,
|
||||
bikeInfo.timeCode,
|
||||
dateTimeProvider)
|
||||
: new Bike.BluetoothLock.BikeInfo(
|
||||
bikeInfo.bike,
|
||||
lockSerial,
|
||||
lockGuid,
|
||||
bikeInfo.GetUserKey(),
|
||||
bikeInfo.GetAdminKey(),
|
||||
bikeInfo.GetSeed(),
|
||||
bikeInfo.GetFrom(),
|
||||
mailAddress,
|
||||
bikeInfo.station,
|
||||
bikeInfo.GetOperatorUri(),
|
||||
#if !NOTARIFFDESCRIPTION
|
||||
Create(bikeInfo.tariff_description),
|
||||
#else
|
||||
Create((TINK.Repository.Response.TariffDescription)null),
|
||||
#endif
|
||||
dateTimeProvider,
|
||||
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. Reserved bike with id {bikeInfo.bike} skipped. {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
|
||||
case InUseStateEnum.Booked:
|
||||
try
|
||||
{
|
||||
return !isBluetoothBike
|
||||
? new BikeInfo(
|
||||
bikeInfo.bike,
|
||||
bikeInfo.GetIsDemo(),
|
||||
bikeInfo.GetGroup(),
|
||||
bikeInfo.GetWheelType(),
|
||||
bikeInfo.GetTypeOfBike(),
|
||||
bikeInfo.description,
|
||||
bikeInfo.station,
|
||||
bikeInfo.GetOperatorUri(),
|
||||
#if !NOTARIFFDESCRIPTION
|
||||
Create(bikeInfo.tariff_description),
|
||||
#else
|
||||
Create((TINK.Repository.Response.TariffDescription)null),
|
||||
#endif
|
||||
bikeInfo.GetFrom(),
|
||||
mailAddress,
|
||||
bikeInfo.timeCode)
|
||||
: new Bike.BluetoothLock.BikeInfo(
|
||||
bikeInfo.bike,
|
||||
lockSerial,
|
||||
bikeInfo.GetBluetoothLockGuid(),
|
||||
bikeInfo.GetUserKey(),
|
||||
bikeInfo.GetAdminKey(),
|
||||
bikeInfo.GetSeed(),
|
||||
bikeInfo.GetFrom(),
|
||||
mailAddress,
|
||||
bikeInfo.station,
|
||||
bikeInfo.GetOperatorUri(),
|
||||
#if !NOTARIFFDESCRIPTION
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public static Bikes.Bike.TariffDescription Create(this TariffDescription tariffDesciption)
|
||||
{
|
||||
return new Bikes.Bike.TariffDescription
|
||||
{
|
||||
Name = tariffDesciption?.name,
|
||||
#if USCSHARP9
|
||||
Number = int.TryParse(tariffDesciption?.number, out int number) ? number : null,
|
||||
#else
|
||||
Number = int.TryParse(tariffDesciption?.number, out int number) ? number : (int?) null,
|
||||
#endif
|
||||
FreeTimePerSession = double.TryParse(tariffDesciption?.free_hours, NumberStyles.Any, CultureInfo.InvariantCulture, out double freeHours) ? TimeSpan.FromHours(freeHours) : TimeSpan.Zero,
|
||||
FeeEuroPerHour = double.TryParse(tariffDesciption?.eur_per_hour, NumberStyles.Any, CultureInfo.InvariantCulture, out double euroPerHour) ? euroPerHour : double.NaN,
|
||||
AboEuroPerMonth = double.TryParse(tariffDesciption?.abo_eur_per_month, NumberStyles.Any, CultureInfo.InvariantCulture, out double aboEuroPerMonth) ? aboEuroPerMonth : double.NaN,
|
||||
MaxFeeEuroPerDay = double.TryParse(tariffDesciption?.max_eur_per_day, NumberStyles.Any, CultureInfo.InvariantCulture, out double maxEuroPerDay) ? maxEuroPerDay : double.NaN,
|
||||
OperatorAgb = tariffDesciption?.operator_agb,
|
||||
TrackingInfo = tariffDesciption?.track_info
|
||||
};
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
|
||||
/// <summary> Creates a survey object from response.</summary>
|
||||
/// <param name="response">Response to create survey object from.</param>
|
||||
public static MiniSurveyModel Create(this ReservationCancelReturnResponse response)
|
||||
{
|
||||
if (response?.user_miniquery == null)
|
||||
{
|
||||
return new MiniSurveyModel();
|
||||
}
|
||||
|
||||
var miniquery = response.user_miniquery;
|
||||
var survey = 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;
|
||||
}
|
||||
|
||||
survey.Questions.Add(
|
||||
question.Key,
|
||||
new MiniSurveyModel.QuestionModel());
|
||||
}
|
||||
|
||||
return survey;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ using System.Threading;
|
|||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Model.Services.CopriApi.ServerUris;
|
||||
using Plugin.Permissions.Abstractions;
|
||||
using TINK.Services.BluetoothLock.Crypto;
|
||||
using TINK.ViewModel.Map;
|
||||
using TINK.ViewModel.Settings;
|
||||
|
@ -155,6 +156,7 @@ namespace TINK.Model
|
|||
ISmartDevice device,
|
||||
ISpecialFolder specialFolder,
|
||||
ICipher cipher,
|
||||
IPermissions permissions = null,
|
||||
object arendiCentral = null,
|
||||
Func<bool> isConnectedFunc = null,
|
||||
Action<SendOrPostCallback, object> postAction = null,
|
||||
|
|
419
TINKLib/Model/TinkApp.cs.bak
Normal file
419
TINKLib/Model/TinkApp.cs.bak
Normal file
|
@ -0,0 +1,419 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
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.Model.Services.Geolocation;
|
||||
using TINK.Model.Services.CopriApi.ServerUris;
|
||||
using TINK.Services.BluetoothLock.Crypto;
|
||||
using TINK.ViewModel.Map;
|
||||
using TINK.ViewModel.Settings;
|
||||
using TINK.Services;
|
||||
using TINK.Services.BluetoothLock.BLE;
|
||||
using Xamarin.Forms;
|
||||
using TINK.Model.Station;
|
||||
|
||||
namespace TINK.Model
|
||||
{
|
||||
[DataContract]
|
||||
public class TinkApp : ITinkApp
|
||||
{
|
||||
/// <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>
|
||||
/// <returns>True if setting credentials succeeded.</returns>
|
||||
public delegate bool SetCredentialsDelegate(string p_strMailAddress, string p_strPassword);
|
||||
|
||||
/// <summary>Returns the id of the app (sharee.bike) to be identified by copri.</summary>
|
||||
public static string MerchantId => "oiF2kahH";
|
||||
|
||||
/// <summary>
|
||||
/// Holds status about whants new page.
|
||||
/// </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; }
|
||||
|
||||
/// <summary> Holds the filters loaded from settings. </summary>
|
||||
public IGroupFilterSettings FilterGroupSetting { get; set; }
|
||||
|
||||
/// <summary> Holds the filter which is applied on the map view. Either TINK or Konrad stations are displayed. </summary>
|
||||
private IGroupFilterMapPage m_oFilterDictionaryMapPage;
|
||||
|
||||
/// <summary> Holds the filter which is applied on the map view. Either TINK or Konrad stations are displayed. </summary>
|
||||
public IGroupFilterMapPage GroupFilterMapPage
|
||||
{
|
||||
get => m_oFilterDictionaryMapPage;
|
||||
set => m_oFilterDictionaryMapPage = value ?? new GroupFilterMapPage();
|
||||
}
|
||||
|
||||
/// <summary> Value indicating whether map is centerted to current position or not. </summary>
|
||||
public bool CenterMapToCurrentLocation { get; set; }
|
||||
|
||||
/// <summary> Holds the map area to display. </summary>
|
||||
public Xamarin.Forms.GoogleMaps.MapSpan MapSpan { get; set; }
|
||||
|
||||
/// <summary> Gets the minimum logging level. </summary>
|
||||
public LogEventLevel MinimumLogEventLevel { get; set; }
|
||||
|
||||
/// <summary> Gets a value indicating whether reporting level is verbose or not.</summary>
|
||||
public bool IsReportLevelVerbose { get; set; }
|
||||
|
||||
/// <summary> Holds the uri which is applied after restart. </summary>
|
||||
public Uri NextActiveUri { get; set; }
|
||||
|
||||
/// <summary> Saves object to file. </summary>
|
||||
public void Save()
|
||||
=> JsonSettingsDictionary.Serialize(
|
||||
SettingsFileFolder,
|
||||
new Dictionary<string, string>()
|
||||
.SetGroupFilterMapPage(GroupFilterMapPage)
|
||||
.SetCopriHostUri(NextActiveUri.AbsoluteUri)
|
||||
.SetPollingParameters(Polling)
|
||||
.SetGroupFilterSettings(FilterGroupSetting)
|
||||
.SetAppVersion(AppVersion)
|
||||
.SetMinimumLoggingLevel(MinimumLogEventLevel)
|
||||
.SetIsReportLevelVerbose(IsReportLevelVerbose)
|
||||
.SetExpiresAfter(ExpiresAfter)
|
||||
.SetWhatsNew(AppVersion)
|
||||
.SetActiveLockService(LocksServices.Active.GetType().FullName)
|
||||
.SetActiveGeolocationService(GeolocationServices.Active.GetType().FullName)
|
||||
.SetCenterMapToCurrentLocation(CenterMapToCurrentLocation)
|
||||
.SetLogToExternalFolder(LogToExternalFolder)
|
||||
.SetConnectTimeout(LocksServices.Active.TimeOut.MultiConnect)
|
||||
.SetIsSiteCachingOn(IsSiteCachingOn)
|
||||
.SetActiveTheme(Themes.Active.GetType().FullName));
|
||||
|
||||
/// <summary>
|
||||
/// Update connector from filters when
|
||||
/// - login state changes
|
||||
/// - view is toggled (TINK to Kornrad and vice versa)
|
||||
/// </summary>
|
||||
public void UpdateConnector()
|
||||
{
|
||||
// Create filtered connector.
|
||||
m_oConnector = FilteredConnectorFactory.Create(
|
||||
FilterGroupSetting.DoFilter(ActiveUser.DoFilter(GroupFilterMapPage.DoFilter())),
|
||||
m_oConnector.Connector);
|
||||
}
|
||||
|
||||
/// <summary>Polling periode.</summary>
|
||||
public PollingParameters Polling { get; set; }
|
||||
|
||||
public TimeSpan ExpiresAfter { get; set; }
|
||||
|
||||
/// <summary> Holds the version of the app.</summary>
|
||||
public Version AppVersion { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds the default polling value.
|
||||
/// </summary>
|
||||
#if USCSHARP9
|
||||
public TimeSpan DefaultPolling => new (0, 0, 10);
|
||||
#else
|
||||
public TimeSpan DefaultPolling => new TimeSpan(0, 0, 10);
|
||||
#endif
|
||||
|
||||
/// <summary> Constructs TinkApp object. </summary>
|
||||
/// <param name="settings"></param>
|
||||
/// <param name="accountStore"></param>
|
||||
/// <param name="passwordValidator"></param>
|
||||
/// <param name="p_oConnectorFactory"></param>
|
||||
/// <param name="geolocationService">Null in productive context. Service to querry geoloation for testing purposes. Parameter can be made optional.</param>
|
||||
/// <param name="locksService">Null in productive context. Service to control locks/ get locks information for testing proposes. Parameter can be made optional.</param>
|
||||
/// <param name="device">Object allowing platform specific operations.</param>
|
||||
/// <param name="specialFolder"></param>
|
||||
/// <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="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
|
||||
/// - null if app is installed for the first time.
|
||||
/// /// </param>
|
||||
public TinkApp(
|
||||
Settings.Settings settings,
|
||||
IStore accountStore,
|
||||
Func<bool, Uri, string /* session cookie*/, string /* mail address*/, TimeSpan, IConnector> connectorFactory,
|
||||
IServicesContainer<IGeolocation> geolocationServicesContainer,
|
||||
ILocksService locksService,
|
||||
ISmartDevice device,
|
||||
ISpecialFolder specialFolder,
|
||||
ICipher cipher,
|
||||
object arendiCentral = null,
|
||||
Func<bool> isConnectedFunc = null,
|
||||
Action<SendOrPostCallback, object> postAction = null,
|
||||
Version currentVersion = null,
|
||||
Version lastVersion = null,
|
||||
Version whatsNewShownInVersion = null)
|
||||
{
|
||||
PostAction = postAction
|
||||
?? ((d, obj) => d(obj));
|
||||
|
||||
ConnectorFactory = connectorFactory
|
||||
?? throw new ArgumentException("Can not instantiate TinkApp- object. No connector factory object available.");
|
||||
|
||||
Cipher = cipher ?? new Cipher();
|
||||
|
||||
var locksServices = locksService != null
|
||||
? new HashSet<ILocksService> { locksService }
|
||||
: new HashSet<ILocksService> {
|
||||
new LockItByScanServiceEventBased(Cipher),
|
||||
new LockItByScanServicePolling(Cipher),
|
||||
new LockItByGuidService(Cipher),
|
||||
#if BLUETOOTHLE // Requires LockItBluetoothle library.
|
||||
new Bluetoothle.LockItByGuidService(Cipher),
|
||||
#endif
|
||||
#if ARENDI // Requires LockItArendi library.
|
||||
new Arendi.LockItByGuidService(Cipher, arendiCentral),
|
||||
new Arendi.LockItByScanService(Cipher, arendiCentral),
|
||||
#endif
|
||||
new LocksServiceInReach(),
|
||||
new LocksServiceOutOfReach(),
|
||||
};
|
||||
|
||||
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()
|
||||
},
|
||||
settings.ActiveTheme);
|
||||
|
||||
GeolocationServices = geolocationServicesContainer
|
||||
?? throw new ArgumentException($"Can not instantiate {nameof(TinkApp)}- object. No geolocation services container object available.");
|
||||
|
||||
FilterGroupSetting = settings.GroupFilterSettings;
|
||||
GroupFilterMapPage = settings.GroupFilterMapPage;
|
||||
|
||||
CenterMapToCurrentLocation = settings.CenterMapToCurrentLocation;
|
||||
|
||||
MapSpan = settings.MapSpan;
|
||||
|
||||
SmartDevice = device
|
||||
?? throw new ArgumentException("Can not instantiate TinkApp- object. No device information provider available.");
|
||||
|
||||
if (specialFolder == null)
|
||||
{
|
||||
throw new ArgumentException("Can not instantiate TinkApp- object. No special folder provider available.");
|
||||
}
|
||||
|
||||
// Set logging level.
|
||||
Level.MinimumLevel = settings.MinimumLogEventLevel;
|
||||
|
||||
LogToExternalFolder = settings.LogToExternalFolder;
|
||||
|
||||
IsSiteCachingOn = settings.IsSiteCachingOn;
|
||||
|
||||
ExternalFolder = specialFolder.GetExternalFilesDir();
|
||||
|
||||
SettingsFileFolder = specialFolder.GetInternalPersonalDir();
|
||||
|
||||
ActiveUser = new User.User(
|
||||
accountStore.GetType().Name == "StoreLegacy" ? new Store() : accountStore,
|
||||
accountStore.Load().Result,
|
||||
device.Identifier);
|
||||
|
||||
this.isConnectedFunc = isConnectedFunc ?? (() => CrossConnectivity.Current.IsConnected);
|
||||
|
||||
ExpiresAfter = settings.ExpiresAfter;
|
||||
|
||||
// Create filtered connector for offline mode.
|
||||
m_oConnector = FilteredConnectorFactory.Create(
|
||||
FilterGroupSetting.DoFilter(GroupFilterMapPage.DoFilter()),
|
||||
ConnectorFactory(GetIsConnected(), settings.ActiveUri, ActiveUser.SessionCookie, ActiveUser.Mail, ExpiresAfter));
|
||||
|
||||
// Get uris from file.
|
||||
// Initialize all settings to defaults
|
||||
// Process uris.
|
||||
Uris = new CopriServerUriList(settings.ActiveUri);
|
||||
|
||||
NextActiveUri = Uris.ActiveUri;
|
||||
|
||||
Polling = settings.PollingParameters ??
|
||||
throw new ArgumentException("Can not instantiate TinkApp- object. Polling parameters must never be null.");
|
||||
|
||||
AppVersion = currentVersion ?? new Version(3, 0, 122);
|
||||
|
||||
MinimumLogEventLevel = settings.MinimumLogEventLevel;
|
||||
|
||||
IsReportLevelVerbose = settings.IsReportLevelVerbose;
|
||||
|
||||
WhatsNew = new WhatsNew(AppVersion, lastVersion, whatsNewShownInVersion);
|
||||
|
||||
if (Themes.Active.GetType().FullName == typeof(Themes.ShareeBike).FullName)
|
||||
{
|
||||
// Nothing to do.
|
||||
// Theme to activate is default theme.
|
||||
return;
|
||||
}
|
||||
|
||||
// Set active app theme
|
||||
ICollection<ResourceDictionary> mergedDictionaries = Application.Current.Resources.MergedDictionaries;
|
||||
if (mergedDictionaries == 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.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Holds the user of the app. </summary>
|
||||
[DataMember]
|
||||
public User.User ActiveUser { get; }
|
||||
|
||||
/// <summary> Reference of object which provides device information. </summary>
|
||||
public ISmartDevice SmartDevice { get; }
|
||||
|
||||
/// <summary> Holds delegate to determine whether device is connected or not.</summary>
|
||||
private readonly Func<bool> isConnectedFunc;
|
||||
|
||||
/// <summary> Gets whether device is connected to internet or not. </summary>
|
||||
public bool GetIsConnected() => isConnectedFunc();
|
||||
|
||||
/// <summary> Holds the folder where settings files are stored. </summary>
|
||||
public string SettingsFileFolder { get; }
|
||||
|
||||
/// <summary> Holds folder parent of the folder where log files are stored. </summary>
|
||||
public string LogFileParentFolder => LogToExternalFolder && !string.IsNullOrEmpty(ExternalFolder) ? ExternalFolder : SettingsFileFolder;
|
||||
|
||||
/// <summary> Holds a value indicating whether to log to external or internal folder. </summary>
|
||||
public bool LogToExternalFolder { get; set; }
|
||||
|
||||
/// <summary> Holds a value indicating whether Site caching is on or off. </summary>
|
||||
public bool IsSiteCachingOn { get; set; }
|
||||
|
||||
/// <summary> External folder. </summary>
|
||||
public string ExternalFolder { get; }
|
||||
|
||||
public ICipher Cipher { get; }
|
||||
|
||||
/// <summary> Name of the station which is selected. </summary>
|
||||
public IStation SelectedStation { get; set; } = new NullStation();
|
||||
|
||||
/// <summary> Holds the stations availalbe. </summary>
|
||||
public IEnumerable<IStation> Stations { get; set; } = new List<Station.Station>();
|
||||
|
||||
/// <summary> Action to post to GUI thread.</summary>
|
||||
public Action<SendOrPostCallback, object> PostAction { get; }
|
||||
|
||||
/// <summary> Function which creates a connector depending on connected status.</summary>
|
||||
private Func<bool, Uri, string /*userAgent*/, string /*sessionCookie*/, TimeSpan, IConnector> ConnectorFactory { get; }
|
||||
|
||||
/// <summary> Holds the object which provides offline data.</summary>
|
||||
private IFilteredConnector m_oConnector;
|
||||
|
||||
/// <summary> Holds the system to copri.</summary>
|
||||
public IFilteredConnector GetConnector(bool isConnected)
|
||||
{
|
||||
if (m_oConnector.IsConnected == isConnected
|
||||
&& m_oConnector.Command.SessionCookie == ActiveUser.SessionCookie)
|
||||
{
|
||||
// Neither connection nor logged in stated changed.
|
||||
return m_oConnector;
|
||||
}
|
||||
|
||||
// Connected state changed. New connection object has to be created.
|
||||
m_oConnector = FilteredConnectorFactory.Create(
|
||||
FilterGroupSetting.DoFilter(ActiveUser.DoFilter(GroupFilterMapPage.DoFilter())),
|
||||
ConnectorFactory(
|
||||
isConnected,
|
||||
Uris.ActiveUri,
|
||||
ActiveUser.SessionCookie,
|
||||
ActiveUser.Mail,
|
||||
ExpiresAfter));
|
||||
|
||||
return m_oConnector;
|
||||
}
|
||||
|
||||
/// <summary> Manages the different types of LocksService objects.</summary>
|
||||
public LocksServicesContainerMutable LocksServices { get; set; }
|
||||
|
||||
/// <summary> Holds available app themes.</summary>
|
||||
public IServicesContainer<IGeolocation> GeolocationServices { get; }
|
||||
|
||||
/// <summary> Manages the different types of LocksService objects.</summary>
|
||||
public ServicesContainerMutable<object> Themes { get; }
|
||||
|
||||
/// <summary> Object to switch logging level. </summary>
|
||||
private LoggingLevelSwitch m_oLoggingLevelSwitch;
|
||||
|
||||
/// <summary>
|
||||
/// Object to allow swithing logging level
|
||||
/// </summary>
|
||||
public LoggingLevelSwitch Level
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_oLoggingLevelSwitch == null)
|
||||
{
|
||||
m_oLoggingLevelSwitch = new LoggingLevelSwitch
|
||||
{
|
||||
|
||||
// Set warning level to error.
|
||||
MinimumLevel = Settings.Settings.DEFAULTLOGGINLEVEL
|
||||
};
|
||||
}
|
||||
|
||||
return m_oLoggingLevelSwitch;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Updates logging level. </summary>
|
||||
/// <param name="p_oNewLevel">New level to set.</param>
|
||||
public void UpdateLoggingLevel(LogEventLevel p_oNewLevel)
|
||||
{
|
||||
if (Level.MinimumLevel == p_oNewLevel)
|
||||
{
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
Log.CloseAndFlush(); // Close before modifying logger configuration. Otherwise a sharing vialation occurs.
|
||||
|
||||
Level.MinimumLevel = p_oNewLevel;
|
||||
|
||||
// Update logging
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.MinimumLevel.ControlledBy(Level)
|
||||
.WriteTo.Debug()
|
||||
.WriteTo.File(LogFileParentFolder, Logging.RollingInterval.Session)
|
||||
.CreateLogger();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,8 +7,5 @@ namespace TINK.Repository.Response
|
|||
/// </summary>
|
||||
public class ReservationCancelReturnResponse : BikesReservedOccupiedResponse
|
||||
{
|
||||
/// <summary> Mini survey.</summary>
|
||||
[DataMember]
|
||||
public MiniSurveyResponse user_miniquery { get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
|
||||
namespace TINK.Repository.Response
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds the information about a cancel booking request and is used for deserialization of copri answer.
|
||||
/// </summary>
|
||||
public class ReservationCancelReturnResponse : BikesReservedOccupiedResponse
|
||||
{
|
||||
/// <summary> Mini survey.</summary>
|
||||
[DataMember]
|
||||
public MiniSurveyResponse user_miniquery { get; private set; }
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@
|
|||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="Plugin.BLE" Version="2.1.2" />
|
||||
<PackageReference Include="Plugin.BluetoothLE" Version="6.3.0.19" />
|
||||
<PackageReference Include="Plugin.Permissions" Version="6.0.1" />
|
||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
|
|
74
TINKLib/TINKLib.csproj.bak
Normal file
74
TINKLib/TINKLib.csproj.bak
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup Label="MultilingualAppToolkit">
|
||||
<MultilingualAppToolkitVersion>4.0</MultilingualAppToolkitVersion>
|
||||
<MultilingualFallbackLanguage>en-GB</MultilingualFallbackLanguage>
|
||||
<TranslationReport Condition="'$(Configuration)' == 'Release'">true</TranslationReport>
|
||||
<SuppressPseudoWarning Condition="'$(Configuration)' == 'Debug'">true</SuppressPseudoWarning>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RootNamespace>TINK</RootNamespace>
|
||||
<ReleaseVersion>3.0</ReleaseVersion>
|
||||
<NeutralLanguage>en-GB</NeutralLanguage>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DefineConstants>TRACE;USEFLYOUT</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DefineConstants>TRACE;USEFLYOUT</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\Multilingual App Toolkit\Microsoft.Multilingual.ResxResources.targets" Label="MultilingualAppToolkit" Condition="Exists('$(MSBuildExtensionsPath)\Microsoft\Multilingual App Toolkit\v$(MultilingualAppToolkitVersion)\Microsoft.Multilingual.ResxResources.targets')" />
|
||||
<Target Name="MATPrerequisite" BeforeTargets="PrepareForBuild" Condition="!Exists('$(MSBuildExtensionsPath)\Microsoft\Multilingual App Toolkit\Microsoft.Multilingual.ResxResources.targets')" Label="MultilingualAppToolkit">
|
||||
<Warning Text="$(MSBuildProjectFile) is Multilingual build enabled, but the Multilingual App Toolkit is unavailable during the build. If building with Visual Studio, please check to ensure that toolkit is properly installed." />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MonkeyCache" Version="1.5.2" />
|
||||
<PackageReference Include="MonkeyCache.FileStore" Version="1.5.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="Plugin.BLE" Version="2.1.2" />
|
||||
<PackageReference Include="Plugin.BluetoothLE" Version="6.3.0.19" />
|
||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="System.Collections" Version="4.3.0" />
|
||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||
<PackageReference Include="System.Net.Primitives" Version="4.3.1" />
|
||||
<PackageReference Include="System.Net.Sockets" Version="4.3.0" />
|
||||
<PackageReference Include="System.Private.DataContractSerialization" Version="4.3.0" />
|
||||
<PackageReference Include="System.Runtime.Serialization.Formatters" Version="4.3.0" />
|
||||
<PackageReference Include="System.Runtime.Serialization.Primitives" Version="4.3.0" />
|
||||
<PackageReference Include="System.Xml.XDocument" Version="4.3.0" />
|
||||
<PackageReference Include="Xam.Plugin.Connectivity" Version="3.2.0" />
|
||||
<PackageReference Include="Xam.Plugins.Messaging" Version="5.2.0" />
|
||||
<PackageReference Include="Xamarin.Essentials" Version="1.7.0" />
|
||||
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2196" />
|
||||
<PackageReference Include="Xamarin.Forms.GoogleMaps" Version="3.3.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Update="NETStandard.Library" Version="2.0.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Services\Permissions\Essentials\" />
|
||||
<Folder Include="Services\Permissions\Plugin\" />
|
||||
<Folder Include="ViewModel\Info\BikeInfo\" />
|
||||
<Folder Include="ViewModel\FeesAndBikes\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LockItBLE\LockItBLE.csproj" />
|
||||
<ProjectReference Include="..\LockItShared\LockItShared.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="MultilingualResources\AppResources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>AppResources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="MultilingualResources\AppResources.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>AppResources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -207,7 +207,7 @@ namespace TINK.ViewModel.Map
|
|||
|
||||
var l_oPin = new Pin
|
||||
{
|
||||
|
||||
|
||||
Position = new Xamarin.Forms.GoogleMaps.Position(station.Position.Latitude, station.Position.Longitude),
|
||||
Label = long.TryParse(station.Id, out long stationId) && stationId > CUSTOM_ICONS_COUNT
|
||||
? station.GetStationName()
|
||||
|
@ -231,13 +231,13 @@ namespace TINK.ViewModel.Map
|
|||
for (int pinIndex = 0; pinIndex < stationsColorList.Count; pinIndex++)
|
||||
{
|
||||
|
||||
var indexPartPrefix = int.TryParse(Pins[pinIndex].Tag.ToString(), out int stationId)
|
||||
var indexPartPrefix = int.TryParse(Pins[pinIndex].Tag.ToString(), out int stationId)
|
||||
&& stationId <= CUSTOM_ICONS_COUNT
|
||||
? $"{stationId}" // there is a station marker with index letter for given station id
|
||||
: "Open"; // there is no station marker. Use open marker.
|
||||
|
||||
var colorPartPrefix = GetRessourceNameColorPart(stationsColorList[pinIndex]);
|
||||
|
||||
|
||||
var l_iName = $"{indexPartPrefix.ToString().PadLeft(2, '0')}_{colorPartPrefix}{(DeviceInfo.Platform == DevicePlatform.Android ? ".png" : string.Empty)}";
|
||||
try
|
||||
{
|
||||
|
@ -292,7 +292,7 @@ namespace TINK.ViewModel.Map
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when page is shown.
|
||||
/// Invoked when page is shown.
|
||||
/// Starts update process.
|
||||
/// </summary>
|
||||
/// <param name="p_oFilterDictionaryMapPage">Holds map page filter settings.</param>
|
||||
|
@ -307,10 +307,10 @@ namespace TINK.ViewModel.Map
|
|||
Polling = TinkApp.Polling;
|
||||
|
||||
Log.ForContext<MapPageViewModel>().Information(
|
||||
$"{(Polling != null && Polling.IsActivated ? $"Map page is appearing. Update periode is {Polling.Periode.TotalSeconds} sec." : "Map page is appearing. Polling is off.")}" +
|
||||
$"{(Polling != null && Polling.IsActivated ? $"Map page is appearing. Update periode is {Polling.Periode.TotalSeconds} sec." : "Map page is appearing. Polling is off.")}" +
|
||||
$"Current UI language is {Thread.CurrentThread.CurrentUICulture.Name}.");
|
||||
|
||||
// Update map page filter
|
||||
// Update map page filter
|
||||
ActiveFilterMap = TinkApp.GroupFilterMapPage;
|
||||
|
||||
ActionText = AppResources.ActivityTextRequestingLocationPermissions;
|
||||
|
@ -383,9 +383,19 @@ namespace TINK.ViewModel.Map
|
|||
string.Format(AppResources.MessageAppVersionIsOutdated, ContactPageViewModel.GetAppName(TinkApp.Uris.ActiveUri)),
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
Result<StationsAndBikesContainer> resultStationsAndBikes = await TinkApp.GetConnector(IsConnected).Query.GetBikesAndStationsAsync();
|
||||
Log.ForContext<MapPageViewModel>().Error($"Outdated version of app detected. Version expected is {resultStationsAndBikes.Response.StationsAll.CopriVersion}.");
|
||||
}
|
||||
|
||||
TinkApp.Stations = resultStationsAndBikes.Response.StationsAll;
|
||||
// Set pins to their positions on map.
|
||||
InitializePins(resultStationsAndBikes.Response.StationsAll);
|
||||
|
||||
Log.ForContext<MapPageViewModel>().Verbose("Update of pins done.");
|
||||
}
|
||||
|
||||
|
||||
if (resultStationsAndBikes.Exception?.GetType() == typeof(AuthcookieNotDefinedException))
|
||||
{
|
||||
Log.ForContext<MapPageViewModel>().Error("Map page is shown (probable for the first time after startup of app) and COPRI auth cookie is not defined. {@l_oException}", resultStationsAndBikes.Exception);
|
||||
|
||||
// COPRI reports an auth cookie error.
|
||||
await ViewService.DisplayAlert(
|
||||
|
@ -393,6 +403,9 @@ namespace TINK.ViewModel.Map
|
|||
AppResources.MessageMapPageErrorAuthcookieUndefined,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
await TinkApp.GetConnector(IsConnected).Command.DoLogout();
|
||||
TinkApp.ActiveUser.Logout();
|
||||
}
|
||||
|
||||
// Update pin colors.
|
||||
Log.ForContext<MapPageViewModel>().Verbose("Starting update pins color...");
|
||||
|
@ -431,12 +444,6 @@ namespace TINK.ViewModel.Map
|
|||
|
||||
Log.ForContext<MapPageViewModel>().Verbose("Update pins color done.");
|
||||
|
||||
// Move and scale before getting stations and bikes which takes some time.
|
||||
ActionText = AppResources.ActivityTextCenterMap;
|
||||
await MoveMapToCurrentPositionOfUser(status);
|
||||
|
||||
m_oViewUpdateManager = CreateUpdateTask();
|
||||
|
||||
try
|
||||
{
|
||||
// Update bikes at station or my bikes depending on context.
|
||||
|
@ -510,7 +517,7 @@ namespace TINK.ViewModel.Map
|
|||
Log.ForContext<MapPageViewModel>().Error("Getting bikes and stations in polling context failed with exception {Exception}.", exception);
|
||||
}
|
||||
|
||||
// Check if there are alreay any pins to the map.
|
||||
// Check if there are alreay any pins to the map.
|
||||
// If no initialze pins.
|
||||
if (Pins.Count <= 0)
|
||||
{
|
||||
|
@ -555,7 +562,7 @@ namespace TINK.ViewModel.Map
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when pages is closed/ hidden.
|
||||
/// Invoked when pages is closed/ hidden.
|
||||
/// Stops update process.
|
||||
/// </summary>
|
||||
public async Task OnDisappearing()
|
||||
|
@ -576,7 +583,7 @@ namespace TINK.ViewModel.Map
|
|||
// Lock action to prevent multiple instances of "BikeAtStation" being opened.
|
||||
IsMapPageEnabled = false;
|
||||
|
||||
TinkApp.SelectedStation = TinkApp.Stations.FirstOrDefault(x => x.Id == selectedStationId)
|
||||
TinkApp.SelectedStation = TinkApp.Stations.FirstOrDefault(x => x.Id == selectedStationId)
|
||||
?? new Station(selectedStationId, new List<string>(), null); // Station might not be in list StationDictinaly because this list is not updatd in background task.
|
||||
|
||||
#if TRYNOTBACKSTYLE
|
||||
|
@ -847,14 +854,14 @@ namespace TINK.ViewModel.Map
|
|||
}
|
||||
}
|
||||
|
||||
// Do not use property .State to get bluetooth state due
|
||||
// to issue https://hausource.visualstudio.com/TINK/_workitems/edit/116 /
|
||||
// Do not use property .State to get bluetooth state due
|
||||
// to issue https://hausource.visualstudio.com/TINK/_workitems/edit/116 /
|
||||
// see https://github.com/xabre/xamarin-bluetooth-le/issues/112#issuecomment-380994887
|
||||
if (await BluetoothService.GetBluetoothState() != Plugin.BLE.Abstractions.Contracts.BluetoothState.On)
|
||||
{
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
AppResources.MessageBikesManagementBluetoothActivation,
|
||||
AppResources.MessageBikesManagementBluetoothActivation,
|
||||
AppResources.MessageAnswerOk);
|
||||
IsMapPageEnabled = true;
|
||||
ActionText = "";
|
||||
|
@ -932,4 +939,4 @@ namespace TINK.ViewModel.Map
|
|||
|
||||
public bool IsToggleVisible => tinkKonradToggleViewModel.IsToggleVisible;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue