Version 3.0.290

This commit is contained in:
Oliver Hauff 2022-04-10 17:38:34 +02:00
parent af3c20ea1c
commit ad3cdbcadf
231 changed files with 14555 additions and 7798 deletions

View file

@ -111,6 +111,16 @@ 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.BluetoothLock.IBikeInfoMutable bike)
{
Log.ForContext<Command>().Error("Unexpected request to notify about start of returning bike. No user logged in.");
await Task.CompletedTask;
}
/// <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 UpdateLockingStateAsync(Bikes.Bike.BluetoothLock.IBikeInfoMutable bike, LocationDto location)
{
Log.ForContext<Command>().Error("Unexpected request to update locking state detected. No user logged in.");

View file

@ -159,15 +159,42 @@ namespace TINK.Model.Connector
Bikes.Bike.BC.NotifyPropertyChangedLevel.None);
}
/// <summary> Updates COPRI lock state for a booked bike. </summary>
/// <param name="bike">Bike to update locking state for.</param>
/// <returns>Response on updating locking state.</returns>
public async Task UpdateLockingStateAsync(
Bikes.Bike.BluetoothLock.IBikeInfoMutable bike, LocationDto location)
/// <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.BluetoothLock.IBikeInfoMutable bike)
{
if (bike == null)
{
throw new ArgumentNullException("Can not book bike. No bike object available.");
throw new ArgumentNullException("Can not notify about start returning bike. No bike object available.");
}
try
{
(await CopriServer.StartReturningBike(
bike.Id,
bike.OperatorUri)).GetIsResponseOk("Start returning bike");
}
catch (Exception)
{
// Exception was not expected or too many subsequent excepitons detected.
throw;
}
}
/// <summary> Updates COPRI lock state for a booked bike. </summary>
/// <param name="bike">Bike to update locking state for.</param>
/// <param name="location">Location of the bike.</param>
/// <returns>Response on updating locking state.</returns>
public async Task UpdateLockingStateAsync(
Bikes.Bike.BluetoothLock.IBikeInfoMutable bike,
LocationDto location)
{
if (bike == null)
{
throw new ArgumentNullException("Can not update locking state of bike. No bike object available.");
}
if (bike.State.Value != State.InUseStateEnum.Booked)

View file

@ -25,19 +25,25 @@ namespace TINK.Model.Connector
Task DoLogout();
/// <summary> Request to reserve a bike.</summary>
/// <param name="p_oBike">Bike to book.</param>
Task DoReserve(Bikes.Bike.BC.IBikeInfoMutable p_oBike);
/// <param name="bike">Bike to book.</param>
Task DoReserve(Bikes.Bike.BC.IBikeInfoMutable bike);
/// <summary> Request to cancel a reservation.</summary>
/// <param name="p_oBike">Bike to book.</param>
Task DoCancelReservation(Bikes.Bike.BC.IBikeInfoMutable p_oBike);
/// <param name="bike">Bike to book.</param>
Task DoCancelReservation(Bikes.Bike.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);
/// <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.BluetoothLock.IBikeInfoMutable bike);
/// <summary> Updates COPRI lock state for a booked bike. </summary>
/// <param name="bikeId">Id of the bike to update locking state for.</param>
/// <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);
@ -90,8 +96,8 @@ namespace TINK.Model.Connector
}
/// <summary>Defines delegate to be raised whenever login state changes.</summary>
/// <param name="p_oEventArgs">Holds session cookie and mail address if user logged in successfully.</param>
public delegate void LoginStateChangedEventHandler(object p_oSender, LoginStateChangedEventArgs p_oEventArgs);
/// <param name="eventArgs">Holds session cookie and mail address if user logged in successfully.</param>
public delegate void LoginStateChangedEventHandler(object sender, LoginStateChangedEventArgs eventArgs);
#if !USCSHARP9
/// <summary>
@ -123,10 +129,10 @@ namespace TINK.Model.Connector
public LoginStateChangedEventArgs() : this(string.Empty, string.Empty)
{ }
public LoginStateChangedEventArgs(string p_strSessionCookie, string p_strMail)
public LoginStateChangedEventArgs(string sessionCookie, string mail)
{
SessionCookie = p_strSessionCookie;
Mail = p_strMail;
SessionCookie = sessionCookie;
Mail = mail;
}
public string SessionCookie { get; }

View file

@ -4,10 +4,9 @@ using Serilog.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using TINK.Model.Connector;
using TINK.Services.BluetoothLock;
using TINK.Model.Services.CopriApi.ServerUris;
using TINK.Model.Services.Geolocation;
using TINK.Services.Geolocation;
using TINK.Settings;
using TINK.ViewModel.Map;
using TINK.ViewModel.Settings;
@ -155,14 +154,14 @@ 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> p_oTargetDictionary, Version p_strAppVersion)
public static Dictionary<string, string> SetAppVersion(this IDictionary<string, string> targetDictionary, Version appVersion)
{
if (p_oTargetDictionary == null)
if (targetDictionary == null)
throw new Exception("Writing copri host uri to dictionary failed. Dictionary must not be null.");
return p_oTargetDictionary.Union(new Dictionary<string, string>
return targetDictionary.Union(new Dictionary<string, string>
{
{APPVERIONKEY , JsonConvert.SerializeObject(p_strAppVersion, new VersionConverter()) },
{APPVERIONKEY , JsonConvert.SerializeObject(appVersion, new VersionConverter()) },
}).ToDictionary(key => key.Key, value => value.Value);
}
@ -172,16 +171,16 @@ namespace TINK.Model.Settings
public static Version GetAppVersion(this IDictionary<string, string> settingsJSON)
{
// Get the version of the app which wrote the settings file.
if (!settingsJSON.TryGetValue(APPVERIONKEY, out string l_oAppVersion)
|| string.IsNullOrEmpty(l_oAppVersion))
if (!settingsJSON.TryGetValue(APPVERIONKEY, out string appVersion)
|| string.IsNullOrEmpty(appVersion))
{
// File holds no entry.
return null;
}
return l_oAppVersion.TrimStart().StartsWith("\"")
? JsonConvert.DeserializeObject<Version>(l_oAppVersion, new VersionConverter())
: Version.Parse(l_oAppVersion); // Format used up to version 3.0.0.115
return appVersion.TrimStart().StartsWith("\"")
? JsonConvert.DeserializeObject<Version>(appVersion, new VersionConverter())
: Version.Parse(appVersion); // Format used up to version 3.0.0.115
}
@ -220,21 +219,21 @@ namespace TINK.Model.Settings
}
/// <summary> Saves object to file. </summary>
/// <param name="p_SettingsList">Settings to save.</param>
public static void Serialize(string p_strSettingsFileFolder, IDictionary<string, string> p_SettingsList)
/// <param name="settingsList">Settings to save.</param>
public static void Serialize(string settingsFileFolder, IDictionary<string, string> settingsList)
{
// Save settings to file.
var l_oText = JsonConvert.SerializeObject(p_SettingsList, Formatting.Indented);
var l_oFolder = p_strSettingsFileFolder;
var l_oText = JsonConvert.SerializeObject(settingsList, Formatting.Indented);
var l_oFolder = settingsFileFolder;
System.IO.File.WriteAllText($"{l_oFolder}{System.IO.Path.DirectorySeparatorChar}{SETTINGSFILETITLE}", l_oText);
}
/// <summary> Gets TINK app settings form xml- file. </summary>
/// <param name="p_strSettingsDirectory">Directory to read settings from.</param>
/// <param name="settingsDirectory">Directory to read settings from.</param>
/// <returns>Dictionary of settings.</returns>
public static Dictionary<string, string> Deserialize(string p_strSettingsDirectory)
public static Dictionary<string, string> Deserialize(string settingsDirectory)
{
var l_oFileName = $"{p_strSettingsDirectory}{System.IO.Path.DirectorySeparatorChar}{SETTINGSFILETITLE}";
var l_oFileName = $"{settingsDirectory}{System.IO.Path.DirectorySeparatorChar}{SETTINGSFILETITLE}";
if (!System.IO.File.Exists(l_oFileName))
{

View file

@ -1,6 +1,6 @@
using Serilog.Events;
using System;
using TINK.Model.Services.Geolocation;
using TINK.Services.Geolocation;
using TINK.Services.BluetoothLock;
using TINK.Services.CopriApi.ServerUris;
using TINK.Settings;
@ -18,7 +18,8 @@ namespace TINK.Model.Settings
public const bool DEFAULTREPOTLEVEL = false;
/// <summary> Gets the type of the default geolocation service. </summary>
public static Type DefaultLocationService => typeof(GeolocationService);
/// <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);

View file

@ -13,9 +13,8 @@ using Serilog;
using Plugin.Connectivity;
using System.Threading;
using TINK.Services.BluetoothLock;
using TINK.Model.Services.Geolocation;
using TINK.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;
@ -23,12 +22,16 @@ 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>
@ -159,16 +162,17 @@ namespace TINK.Model
public TinkApp(
Settings.Settings settings,
IStore accountStore,
Func<bool> isConnectedFunc,
Func<bool, Uri, string /* session cookie*/, string /* mail address*/, TimeSpan, IConnector> connectorFactory,
string merchantId,
IServicesContainer<IGeolocation> geolocationServicesContainer,
IBluetoothLE bluetoothService,
ILocationPermission locationPermissionsService,
IServicesContainer<IGeolocation> locationServicesContainer,
ILocksService locksService,
ISmartDevice device,
ISpecialFolder specialFolder,
ICipher cipher,
IPermissions permissions = null,
object arendiCentral = null,
Func<bool> isConnectedFunc = null,
Action<SendOrPostCallback, object> postAction = null,
Version currentVersion = null,
Version lastVersion = null,
@ -185,11 +189,21 @@ 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),
new LockItByScanServicePolling(Cipher),
new LockItByScanServiceEventBased(
Cipher,
bluetoothService,
async () => GetIsAndroid(device.PlatformText) && await locationPermissionsService.CheckStatusAsync() != Status.Granted,
() => GetIsAndroid(device.PlatformText) && !locationServicesContainer.Active.IsGeolcationEnabled),
new LockItByScanServicePolling(
Cipher,
bluetoothService,
async () => GetIsAndroid(device.PlatformText) && await locationPermissionsService.CheckStatusAsync() != Status.Granted,
() => GetIsAndroid(device.PlatformText) && !locationServicesContainer.Active.IsGeolcationEnabled),
new LockItByGuidService(Cipher),
#if BLUETOOTHLE // Requires LockItBluetoothle library.
new Bluetoothle.LockItByGuidService(Cipher),
@ -216,7 +230,7 @@ namespace TINK.Model
},
settings.ActiveTheme);
GeolocationServices = geolocationServicesContainer
GeolocationServices = locationServicesContainer
?? throw new ArgumentException($"Can not instantiate {nameof(TinkApp)}- object. No geolocation services container object available.");
FilterGroupSetting = settings.GroupFilterSettings;

View file

@ -477,11 +477,43 @@ namespace TINK.Model
},
{
new Version(3, 0, 276),
AppResources.ChangeLog3_0_276
AppResources.ChangeLog3_0_276
},
{
new Version(3, 0, 277),
AppResources.ChangeLog3_0_277
},
{
new Version(3, 0, 279),
AppResources.ChangeLog3_0_278 // Addition spelling corrected and missing translation added.
},
{
new Version(3, 0, 280),
AppResources.ChangeLog3_0_280
},
{
new Version(3, 0, 281),
AppResources.ChangeLog3_0_280
},
{
new Version(3, 0, 283),
AppResources.ChangeLog3_0_282
},
{
new Version(3, 0, 284),
AppResources.ChangeLog3_0_284
},
{
new Version(3, 0, 285),
AppResources.ChangeLog3_0_285
},
{
new Version(3, 0, 289),
AppResources.ChangeLog3_0_289
},
{
new Version(3, 0, 290),
AppResources.ChangeLog3_0_290
}
};