mirror of
https://dev.azure.com/TeilRad/sharee.bike%20App/_git/Code
synced 2025-06-21 21:46:27 +02:00
Version 3.0.290
This commit is contained in:
parent
af3c20ea1c
commit
ad3cdbcadf
231 changed files with 14555 additions and 7798 deletions
|
@ -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.");
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
};
|
||||
|
||||
|
|
338
TINKLib/MultilingualResources/AppResources.Designer.cs
generated
338
TINKLib/MultilingualResources/AppResources.Designer.cs
generated
|
@ -195,6 +195,15 @@ namespace TINK.MultilingualResources {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Auth. expired.
|
||||
/// </summary>
|
||||
public static string ActivityTextAuthcookieNotDefinedException {
|
||||
get {
|
||||
return ResourceManager.GetString("ActivityTextAuthcookieNotDefinedException", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Loading bikes located at station....
|
||||
/// </summary>
|
||||
|
@ -411,6 +420,24 @@ namespace TINK.MultilingualResources {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Lock out of reach.
|
||||
/// </summary>
|
||||
public static string ActivityTextLockIsOutOfReach {
|
||||
get {
|
||||
return ResourceManager.GetString("ActivityTextLockIsOutOfReach", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Lock not found.
|
||||
/// </summary>
|
||||
public static string ActivityTextLockNotFound {
|
||||
get {
|
||||
return ResourceManager.GetString("ActivityTextLockNotFound", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Loading Stations and Bikes....
|
||||
/// </summary>
|
||||
|
@ -564,6 +591,15 @@ namespace TINK.MultilingualResources {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Starting bike return....
|
||||
/// </summary>
|
||||
public static string ActivityTextStartReturningBike {
|
||||
get {
|
||||
return ResourceManager.GetString("ActivityTextStartReturningBike", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Updateing.....
|
||||
/// </summary>
|
||||
|
@ -930,7 +966,75 @@ namespace TINK.MultilingualResources {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Lock of rented bike can not be found..
|
||||
/// Looks up a localized string similar to Hints added to ease closing of lock in case closing does not succeed on first try..
|
||||
/// </summary>
|
||||
public static string ChangeLog3_0_278 {
|
||||
get {
|
||||
return ResourceManager.GetString("ChangeLog3_0_278", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Errormessages improved for szenarios when
|
||||
///- bluetooth is off,
|
||||
///- location permission is not granted or
|
||||
///- location is off..
|
||||
/// </summary>
|
||||
public static string ChangeLog3_0_280 {
|
||||
get {
|
||||
return ResourceManager.GetString("ChangeLog3_0_280", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Permission requests messages on iOS formulated in more detail.
|
||||
///Hints to ease connecting to lock in case connecting does not succeed on first try improved..
|
||||
/// </summary>
|
||||
public static string ChangeLog3_0_282 {
|
||||
get {
|
||||
return ResourceManager.GetString("ChangeLog3_0_282", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to User friendly message is shown if authentication expired..
|
||||
/// </summary>
|
||||
public static string ChangeLog3_0_284 {
|
||||
get {
|
||||
return ResourceManager.GetString("ChangeLog3_0_284", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Framework updated.
|
||||
///Activity indicator added account management pages and logging extended..
|
||||
/// </summary>
|
||||
public static string ChangeLog3_0_285 {
|
||||
get {
|
||||
return ResourceManager.GetString("ChangeLog3_0_285", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Flyout menu header improved..
|
||||
/// </summary>
|
||||
public static string ChangeLog3_0_289 {
|
||||
get {
|
||||
return ResourceManager.GetString("ChangeLog3_0_289", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Geolocation is queried with higher accuracy..
|
||||
/// </summary>
|
||||
public static string ChangeLog3_0_290 {
|
||||
get {
|
||||
return ResourceManager.GetString("ChangeLog3_0_290", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Lock of rented bike cannot be be connected right now..
|
||||
/// </summary>
|
||||
public static string ErrorBookedSearchMessage {
|
||||
get {
|
||||
|
@ -938,6 +1042,40 @@ namespace TINK.MultilingualResources {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Lock of rented bike cannot be be connected right now.
|
||||
///If the bike is nearby:
|
||||
///- restart app and repeat action
|
||||
///- restart phone and repeat action
|
||||
///to connect the lock..
|
||||
/// </summary>
|
||||
public static string ErrorBookedSearchMessageEscalationLevel1 {
|
||||
get {
|
||||
return ResourceManager.GetString("ErrorBookedSearchMessageEscalationLevel1", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Lock of rented bike cannot be be connected right now.
|
||||
///If the bike is nearby:
|
||||
///- restart app and repeat action
|
||||
///- restart phone and repeat action
|
||||
///to connect the lock.
|
||||
///
|
||||
///Return bike manually.
|
||||
///Steps 1: Close lock manually if lock is still open
|
||||
///- close app
|
||||
///- press on button at the top of the lock until it starts blinking
|
||||
///- wait until lock is closed completely
|
||||
///Step 2:
|
||||
///- contact support regarding manual locking please to terminate rent.
|
||||
/// </summary>
|
||||
public static string ErrorBookedSearchMessageEscalationLevel2 {
|
||||
get {
|
||||
return ResourceManager.GetString("ErrorBookedSearchMessageEscalationLevel2", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Lock is blocked. Please ensure that no spoke or any other obstacle prevents the lock from closing and try again..
|
||||
/// </summary>
|
||||
|
@ -1012,6 +1150,87 @@ namespace TINK.MultilingualResources {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Communication error during lock search..
|
||||
/// </summary>
|
||||
public static string ErrorConnectLockGeneralErrorMessage {
|
||||
get {
|
||||
return ResourceManager.GetString("ErrorConnectLockGeneralErrorMessage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Internet must be reachable to connect to lock of rented bike..
|
||||
/// </summary>
|
||||
public static string ErrorConnectLockRentedBikeNoWebMessage {
|
||||
get {
|
||||
return ResourceManager.GetString("ErrorConnectLockRentedBikeNoWebMessage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Internet must be reachable to connect to lock of reserved bike..
|
||||
/// </summary>
|
||||
public static string ErrorConnectLockReservedBikeNoWebMessage {
|
||||
get {
|
||||
return ResourceManager.GetString("ErrorConnectLockReservedBikeNoWebMessage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Please turn Bluetooth on, otherwise lock cannot be connected..
|
||||
/// </summary>
|
||||
public static string ErrorFindLockBluetoothNotOn {
|
||||
get {
|
||||
return ResourceManager.GetString("ErrorFindLockBluetoothNotOn", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Please turn Location on, otherwise lock cannot be connected..
|
||||
/// </summary>
|
||||
public static string ErrorFindLockLocationOff {
|
||||
get {
|
||||
return ResourceManager.GetString("ErrorFindLockLocationOff", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Please grant location permissions, otherwise lock cannot be connected..
|
||||
/// </summary>
|
||||
public static string ErrorFindLockLocationPermissionMissing {
|
||||
get {
|
||||
return ResourceManager.GetString("ErrorFindLockLocationPermissionMissing", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Lock can only be found when rented bike is nearby..
|
||||
/// </summary>
|
||||
public static string ErrorFindLockRentedBikeOutOfReachMessage {
|
||||
get {
|
||||
return ResourceManager.GetString("ErrorFindLockRentedBikeOutOfReachMessage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Lock status of the reserved bike could not be determined..
|
||||
/// </summary>
|
||||
public static string ErrorFindLockReservedBikeNoStausMessage {
|
||||
get {
|
||||
return ResourceManager.GetString("ErrorFindLockReservedBikeNoStausMessage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Lock can only be found when reserved bike is nearby..
|
||||
/// </summary>
|
||||
public static string ErrorFindLockReservedBikeOutOfReachMessage {
|
||||
get {
|
||||
return ResourceManager.GetString("ErrorFindLockReservedBikeOutOfReachMessage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Lock is blocked. Please ensure that no obstacle prevents lock from opening and try again..
|
||||
/// </summary>
|
||||
|
@ -1033,9 +1252,9 @@ namespace TINK.MultilingualResources {
|
|||
/// <summary>
|
||||
/// Looks up a localized string similar to Lock cannot be opened until bike is near..
|
||||
/// </summary>
|
||||
public static string ErrorOpenLockOutOfReadMessage {
|
||||
public static string ErrorOpenLockOutOfReachMessage {
|
||||
get {
|
||||
return ResourceManager.GetString("ErrorOpenLockOutOfReadMessage", resourceCulture);
|
||||
return ResourceManager.GetString("ErrorOpenLockOutOfReachMessage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1075,6 +1294,19 @@ namespace TINK.MultilingualResources {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Lock of reserved bike cannot be be connected right now.
|
||||
///If the bike is nearby:
|
||||
///- restart app and repeat action
|
||||
///- restart phone and repeat action
|
||||
///to connect the lock.
|
||||
/// </summary>
|
||||
public static string ErrorReservedSearchMessageEscalationLevel1 {
|
||||
get {
|
||||
return ResourceManager.GetString("ErrorReservedSearchMessageEscalationLevel1", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Returning bike at an unknown location is not possible.
|
||||
///Bike can be returned if
|
||||
|
@ -1106,12 +1338,30 @@ namespace TINK.MultilingualResources {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Internet must be available when returning the bike..
|
||||
/// </summary>
|
||||
public static string ErrorReturnBikeNoWebMessage {
|
||||
get {
|
||||
return ResourceManager.GetString("ErrorReturnBikeNoWebMessage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Connection error when returning the bike!.
|
||||
/// </summary>
|
||||
public static string ErrorReturnBikeNoWebTitle {
|
||||
get {
|
||||
return ResourceManager.GetString("ErrorReturnBikeNoWebTitle", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Error returning bike!.
|
||||
/// </summary>
|
||||
public static string ErrorReturnBikeNotAtStationTitle {
|
||||
public static string ErrorReturnBikeTitle {
|
||||
get {
|
||||
return ResourceManager.GetString("ErrorReturnBikeNotAtStationTitle", resourceCulture);
|
||||
return ResourceManager.GetString("ErrorReturnBikeTitle", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1214,6 +1464,24 @@ namespace TINK.MultilingualResources {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The session has expired. Please register again..
|
||||
/// </summary>
|
||||
public static string ExceptionTextSessionExpired {
|
||||
get {
|
||||
return ResourceManager.GetString("ExceptionTextSessionExpired", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Is WIFI available/ mobile networt available and mobile data activated / ... ?.
|
||||
/// </summary>
|
||||
public static string ExceptionTextWebConnectFailureException {
|
||||
get {
|
||||
return ResourceManager.GetString("ExceptionTextWebConnectFailureException", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Legal Information.
|
||||
/// </summary>
|
||||
|
@ -1514,6 +1782,33 @@ namespace TINK.MultilingualResources {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Log in.
|
||||
/// </summary>
|
||||
public static string MessageAccountPageManageLogin {
|
||||
get {
|
||||
return ResourceManager.GetString("MessageAccountPageManageLogin", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Manage personal data.
|
||||
/// </summary>
|
||||
public static string MessageAccountPageManagePersonalData {
|
||||
get {
|
||||
return ResourceManager.GetString("MessageAccountPageManagePersonalData", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Cancel.
|
||||
/// </summary>
|
||||
public static string MessageAnswerCancel {
|
||||
get {
|
||||
return ResourceManager.GetString("MessageAnswerCancel", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to No.
|
||||
/// </summary>
|
||||
|
@ -1532,6 +1827,15 @@ namespace TINK.MultilingualResources {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Retry.
|
||||
/// </summary>
|
||||
public static string MessageAnswerRetry {
|
||||
get {
|
||||
return ResourceManager.GetString("MessageAnswerRetry", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Yes.
|
||||
/// </summary>
|
||||
|
@ -1651,7 +1955,7 @@ namespace TINK.MultilingualResources {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Tariff {0}.
|
||||
/// Looks up a localized string similar to Tariff.
|
||||
/// </summary>
|
||||
public static string MessageBikesManagementTariffDescriptionTariffHeader {
|
||||
get {
|
||||
|
@ -1678,6 +1982,15 @@ namespace TINK.MultilingualResources {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Error when connecting with lock!.
|
||||
/// </summary>
|
||||
public static string MessageConnectLockErrorTitle {
|
||||
get {
|
||||
return ResourceManager.GetString("MessageConnectLockErrorTitle", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Questions? Remarks? Criticism?.
|
||||
/// </summary>
|
||||
|
@ -1697,6 +2010,15 @@ namespace TINK.MultilingualResources {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Error when connecting to lock!.
|
||||
/// </summary>
|
||||
public static string MessageErrorConnectTitle {
|
||||
get {
|
||||
return ResourceManager.GetString("MessageErrorConnectTitle", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Attention: Lock is closed!
|
||||
///{0}
|
||||
|
@ -1846,9 +2168,7 @@ namespace TINK.MultilingualResources {
|
|||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Session has expired.
|
||||
///Either there are more than 8 devices in use or the user's account is no longer valid.
|
||||
///Use of app is restricted to maximu 8 devices per account.
|
||||
///Please login to app once again. In case this fails please check on website if the account is still valid..
|
||||
///Please login to app once again..
|
||||
/// </summary>
|
||||
public static string MessageMapPageErrorAuthcookieUndefined {
|
||||
get {
|
||||
|
|
|
@ -106,7 +106,7 @@
|
|||
<value>Schloss kann erst geschlossen werden, wenn Rad nicht mehr bewegt wird. Bitte Rad abstellen und Vorgang wiederholen.</value>
|
||||
</data>
|
||||
<data name="ErrorBookedSearchMessage" xml:space="preserve">
|
||||
<value>Schloss des gemieteten Rads kann nicht gefunden werden.</value>
|
||||
<value>Das Schloss des gemieteten Fahrrads kann im Moment nicht verbunden werden.</value>
|
||||
</data>
|
||||
<data name="ErrorReservedSearchMessage" xml:space="preserve">
|
||||
<value>Schloss des reservierten Rads kann nicht gefunden werden.</value>
|
||||
|
@ -129,7 +129,7 @@
|
|||
<data name="ErrorReturnBikeNotAtStationMessage" xml:space="preserve">
|
||||
<value>Rückgabe ausserhalb von Station nicht möglich. Entfernung zur Station {0} ist {1} m.</value>
|
||||
</data>
|
||||
<data name="ErrorReturnBikeNotAtStationTitle" xml:space="preserve">
|
||||
<data name="ErrorReturnBikeTitle" xml:space="preserve">
|
||||
<value>Fehler bei Radrückgabe!</value>
|
||||
</data>
|
||||
<data name="ErrorReturnBikeLockClosedNoGPSMessage" xml:space="preserve">
|
||||
|
@ -177,9 +177,7 @@ Eine Radrückgabe ist nur möglich, wenn das Rad in Reichweite ist und Standorti
|
|||
</data>
|
||||
<data name="MessageMapPageErrorAuthcookieUndefined" xml:space="preserve">
|
||||
<value>Sitzung ist abgelaufen.
|
||||
Entweder es sind mehr als 8 Geräte in Benutzung oder das Konto ist nicht mehr gültig.
|
||||
Die Nutzung der App ist auf maximal 8 Geräten pro Konto möglich.
|
||||
Bitte erneut in App anmelden. Sollte dies fehlschlagen bitte auf Website prüfen, ob das Konto noch gültig ist.</value>
|
||||
Bitte erneut in App anmelden.</value>
|
||||
</data>
|
||||
<data name="StatusTextReservationExpiredCodeMaxReservationTime" xml:space="preserve">
|
||||
<value>Code ist {0}, max. Reservierungszeit von {1} Min. abgelaufen.
|
||||
|
@ -281,7 +279,7 @@ Bitte erneut in App anmelden. Sollte dies fehlschlagen bitte auf Website prüfen
|
|||
<data name="ErrorOpenLockStillClosedMessage" xml:space="preserve">
|
||||
<value>Nach Versuch Schloss zu öffnen wird Status geschlossen zurückgemeldet.</value>
|
||||
</data>
|
||||
<data name="ErrorOpenLockOutOfReadMessage" xml:space="preserve">
|
||||
<data name="ErrorOpenLockOutOfReachMessage" xml:space="preserve">
|
||||
<value>Schloss kann erst geöffnet werden, wenn Rad in der Nähe ist.</value>
|
||||
</data>
|
||||
<data name="ErrorCloseLockOutOfReachMessage" xml:space="preserve">
|
||||
|
@ -484,7 +482,7 @@ Bitte App neu starten um Rad Infos zu bekommen.</value>
|
|||
<value>Std./Tag</value>
|
||||
</data>
|
||||
<data name="MessageBikesManagementTariffDescriptionTariffHeader" xml:space="preserve">
|
||||
<value>Tarif {0}</value>
|
||||
<value>Tarif</value>
|
||||
</data>
|
||||
<data name="ActivityTextQuerryServer" xml:space="preserve">
|
||||
<value>Anfrage Server...</value>
|
||||
|
@ -751,4 +749,124 @@ Fehlerbehebung: Supportmails können wieder verschickt werden.</value>
|
|||
<data name="ChangeLog3_0_277" xml:space="preserve">
|
||||
<value>Fehlerbehebung: App schließt sich nicht mehr auf Fahrrad Wählen-Seite.</value>
|
||||
</data>
|
||||
<data name="ErrorBookedSearchMessageEscalationLevel1" xml:space="preserve">
|
||||
<value>Das Schloss des gemieteten Fahrrads kann im Moment nicht verbunden werden.
|
||||
Wenn das Fahrrad in der Nähe ist:
|
||||
- App neu starten und Vorgang wiederholen
|
||||
- Telefon neu starten und Vorgang wiederholen
|
||||
um das Schloss zu verbinden.</value>
|
||||
</data>
|
||||
<data name="MessageAnswerCancel" xml:space="preserve">
|
||||
<value>Abbrechen</value>
|
||||
</data>
|
||||
<data name="MessageAnswerRetry" xml:space="preserve">
|
||||
<value>Wiederholen</value>
|
||||
</data>
|
||||
<data name="MessageConnectLockErrorTitle" xml:space="preserve">
|
||||
<value>Fehler beim Verbinden mit Schloss!</value>
|
||||
</data>
|
||||
<data name="ErrorBookedSearchMessageEscalationLevel2" xml:space="preserve">
|
||||
<value>Das Schloss des gemieteten Fahrrads kann im Moment nicht verbunden werden.
|
||||
Wenn das Fahrrad in der Nähe ist:
|
||||
- App neu starten und Vorgang wiederholen
|
||||
- Telefon neu starten und Vorgang wiederholen
|
||||
um das Schloss zu verbinden.
|
||||
|
||||
Manuelle Fahrradrückgabe.
|
||||
Schitt 1: Schloss manuell schließen wenn nötig. Dazu
|
||||
- App schließen
|
||||
- auf den Knopf oben am Schloss drücken, bis dieser zu blinken beginnt
|
||||
- warten, bis das Schloss vollständig geschlossen ist
|
||||
Schritt 2:
|
||||
- Support bitte bezüglich der manuellen Schließung kontaktieren um Miete abzuschließen</value>
|
||||
</data>
|
||||
<data name="ChangeLog3_0_278" xml:space="preserve">
|
||||
<value>Hinweise hinzugefügt, um das Schließen des Schlosses zu erleichtern, falls dies nicht beim ersten Versuch gelingt.</value>
|
||||
</data>
|
||||
<data name="ActivityTextLockIsOutOfReach" xml:space="preserve">
|
||||
<value>Schloss außerhalb Reichweite</value>
|
||||
</data>
|
||||
<data name="ActivityTextLockNotFound" xml:space="preserve">
|
||||
<value>Schloss nicht gefunden</value>
|
||||
</data>
|
||||
<data name="ErrorFindLockRentedBikeOutOfReachMessage" xml:space="preserve">
|
||||
<value>Schloss kann erst gefunden werden, wenn gemietetes Rad in der Nähe ist.</value>
|
||||
</data>
|
||||
<data name="ErrorFindLockReservedBikeOutOfReachMessage" xml:space="preserve">
|
||||
<value>Schloss kann erst gefunden werden, wenn reserviertes Rad in der Nähe ist.</value>
|
||||
</data>
|
||||
<data name="MessageErrorConnectTitle" xml:space="preserve">
|
||||
<value>Fehler bei Verbinden mit Schloss!</value>
|
||||
</data>
|
||||
<data name="ErrorConnectLockGeneralErrorMessage" xml:space="preserve">
|
||||
<value>Kommunikationsfehler bei Schlosssuche.</value>
|
||||
</data>
|
||||
<data name="ErrorConnectLockRentedBikeNoWebMessage" xml:space="preserve">
|
||||
<value>Internet muss erreichbar sein um Verbindung mit Schloss für gemietetes Rad herzustellen.</value>
|
||||
</data>
|
||||
<data name="ErrorConnectLockReservedBikeNoWebMessage" xml:space="preserve">
|
||||
<value>Internet muss erreichbar sein um Verbindung mit Schloss für reserviertes Rad herzustellen.</value>
|
||||
</data>
|
||||
<data name="ErrorFindLockReservedBikeNoStausMessage" xml:space="preserve">
|
||||
<value>Schlossstatus des reservierten Rads konnte nicht ermittelt werden.</value>
|
||||
</data>
|
||||
<data name="ErrorFindLockBluetoothNotOn" xml:space="preserve">
|
||||
<value>Bitte Bluetooth anschalten, anderenfalls ist eine Verbindung mit dem Schloss nicht möglich.</value>
|
||||
</data>
|
||||
<data name="ErrorFindLockLocationPermissionMissing" xml:space="preserve">
|
||||
<value>Bitte Standort-Zugriffsfreigabe erteilen, anderenfalls ist eine Verbindung mit dem Schloss nicht möglich.
|
||||
|
||||
</value>
|
||||
</data>
|
||||
<data name="ErrorFindLockLocationOff" xml:space="preserve">
|
||||
<value>Bitte Standortbestimmung aktivieren, anderenfalls ist eine Verbindung mit dem Schloss nicht möglich.</value>
|
||||
</data>
|
||||
<data name="ChangeLog3_0_280" xml:space="preserve">
|
||||
<value>Fehlermeldungen verbessert für die Fälle, dass
|
||||
- Bluetooth deaktiviert ist,
|
||||
- die Standortfreigabe nicht erteilt wurde oder
|
||||
- die Standorterkennung deaktiviert ist.</value>
|
||||
</data>
|
||||
<data name="ErrorReservedSearchMessageEscalationLevel1" xml:space="preserve">
|
||||
<value>Das Schloss des reservierten Fahrrads kann im Moment nicht verbunden werden.
|
||||
Wenn das Fahrrad in der Nähe ist:
|
||||
- App neu starten und Vorgang wiederholen
|
||||
- Telefon neu starten und Vorgang wiederholen
|
||||
um das Schloss zu verbinden.</value>
|
||||
</data>
|
||||
<data name="ChangeLog3_0_282" xml:space="preserve">
|
||||
<value>Freigabe-Erlaubnisanfragen unter iOS ausführlicher formuliert.
|
||||
Hinweise, um das Verbinden Schlosses zu erleichtern, falls dies nicht beim ersten Versuch gelingt, erweitert.</value>
|
||||
</data>
|
||||
<data name="ExceptionTextSessionExpired" xml:space="preserve">
|
||||
<value>Die Sitzung ist abgelaufen. Bitte neu anmelden.</value>
|
||||
</data>
|
||||
<data name="ActivityTextAuthcookieNotDefinedException" xml:space="preserve">
|
||||
<value>Auth. abgelaufen</value>
|
||||
</data>
|
||||
<data name="ChangeLog3_0_284" xml:space="preserve">
|
||||
<value>Anzeige einer benutzerfreundlichen Meldung, wenn die Authentifizierung abgelaufen ist.</value>
|
||||
</data>
|
||||
<data name="MessageAccountPageManageLogin" xml:space="preserve">
|
||||
<value>Anmelden</value>
|
||||
</data>
|
||||
<data name="MessageAccountPageManagePersonalData" xml:space="preserve">
|
||||
<value>Persönliche Daten Verwalten</value>
|
||||
</data>
|
||||
<data name="ChangeLog3_0_285" xml:space="preserve">
|
||||
<value>Framework aktualisiert.
|
||||
Activity Indicator zu Konto-Verwaltungsseiten hinzugefügt und Logging erweitert.</value>
|
||||
</data>
|
||||
<data name="ActivityTextStartReturningBike" xml:space="preserve">
|
||||
<value>Starte Rückgabe...</value>
|
||||
</data>
|
||||
<data name="ExceptionTextWebConnectFailureException" xml:space="preserve">
|
||||
<value>Ist WLAN verfügbar/ Mobilfunknetz vefügbar und mobile Daten aktiviert / ... ?</value>
|
||||
</data>
|
||||
<data name="ChangeLog3_0_289" xml:space="preserve">
|
||||
<value>Flyout-Menü Überschift verschönert.</value>
|
||||
</data>
|
||||
<data name="ChangeLog3_0_290" xml:space="preserve">
|
||||
<value>Der aktuelle Standort wird mit höherer Genauigkeit abgefragt.</value>
|
||||
</data>
|
||||
</root>
|
|
@ -148,7 +148,7 @@
|
|||
<value>Loading Stations and Bikes...</value>
|
||||
</data>
|
||||
<data name="ErrorBookedSearchMessage" xml:space="preserve">
|
||||
<value>Lock of rented bike can not be found.</value>
|
||||
<value>Lock of rented bike cannot be be connected right now.</value>
|
||||
</data>
|
||||
<data name="ErrorCloseLockBoldBlockedMessage" xml:space="preserve">
|
||||
<value>Lock is blocked. Please ensure that no spoke or any other obstacle prevents the lock from closing and try again.</value>
|
||||
|
@ -172,7 +172,7 @@ Bike can only be returned if bike is in reach and location information is avail
|
|||
<data name="ErrorReturnBikeNotAtStationMessage" xml:space="preserve">
|
||||
<value>Returning bike outside of station is not possible. Distance to station {0} is {1} m.</value>
|
||||
</data>
|
||||
<data name="ErrorReturnBikeNotAtStationTitle" xml:space="preserve">
|
||||
<data name="ErrorReturnBikeTitle" xml:space="preserve">
|
||||
<value>Error returning bike!</value>
|
||||
</data>
|
||||
<data name="ErrorSupportmailCreateAttachment" xml:space="preserve">
|
||||
|
@ -243,9 +243,7 @@ Bike can only be returned if bike is in reach and location information is avail
|
|||
</data>
|
||||
<data name="MessageMapPageErrorAuthcookieUndefined" xml:space="preserve">
|
||||
<value>Session has expired.
|
||||
Either there are more than 8 devices in use or the user's account is no longer valid.
|
||||
Use of app is restricted to maximu 8 devices per account.
|
||||
Please login to app once again. In case this fails please check on website if the account is still valid.</value>
|
||||
Please login to app once again.</value>
|
||||
</data>
|
||||
<data name="MessagePhoneMail" xml:space="preserve">
|
||||
<value>Urgent questions?</value>
|
||||
|
@ -383,7 +381,7 @@ Please login to app once again. In case this fails please check on website if th
|
|||
<data name="ErrorOpenLockStillClosedMessage" xml:space="preserve">
|
||||
<value>After try to open lock state closed is reported.</value>
|
||||
</data>
|
||||
<data name="ErrorOpenLockOutOfReadMessage" xml:space="preserve">
|
||||
<data name="ErrorOpenLockOutOfReachMessage" xml:space="preserve">
|
||||
<value>Lock cannot be opened until bike is near.</value>
|
||||
</data>
|
||||
<data name="ErrorOpenLockTitle" xml:space="preserve">
|
||||
|
@ -593,7 +591,7 @@ Please restart app in order to get bike info.</value>
|
|||
<value>Max. fee</value>
|
||||
</data>
|
||||
<data name="MessageBikesManagementTariffDescriptionTariffHeader" xml:space="preserve">
|
||||
<value>Tariff {0}</value>
|
||||
<value>Tariff</value>
|
||||
</data>
|
||||
<data name="ActivityTextQuerryServer" xml:space="preserve">
|
||||
<value>Request server...</value>
|
||||
|
@ -846,4 +844,122 @@ Bugfix: Sending support mails works again. </value>
|
|||
<data name="ChangeLog3_0_277" xml:space="preserve">
|
||||
<value>Bugfix: No more closing of app on Select Bike page.</value>
|
||||
</data>
|
||||
<data name="ErrorBookedSearchMessageEscalationLevel1" xml:space="preserve">
|
||||
<value>Lock of rented bike cannot be be connected right now.
|
||||
If the bike is nearby:
|
||||
- restart app and repeat action
|
||||
- restart phone and repeat action
|
||||
to connect the lock.</value>
|
||||
</data>
|
||||
<data name="MessageAnswerCancel" xml:space="preserve">
|
||||
<value>Cancel</value>
|
||||
</data>
|
||||
<data name="MessageAnswerRetry" xml:space="preserve">
|
||||
<value>Retry</value>
|
||||
</data>
|
||||
<data name="MessageConnectLockErrorTitle" xml:space="preserve">
|
||||
<value>Error when connecting with lock!</value>
|
||||
</data>
|
||||
<data name="ErrorBookedSearchMessageEscalationLevel2" xml:space="preserve">
|
||||
<value>Lock of rented bike cannot be be connected right now.
|
||||
If the bike is nearby:
|
||||
- restart app and repeat action
|
||||
- restart phone and repeat action
|
||||
to connect the lock.
|
||||
|
||||
Return bike manually.
|
||||
Steps 1: Close lock manually if lock is still open
|
||||
- close app
|
||||
- press on button at the top of the lock until it starts blinking
|
||||
- wait until lock is closed completely
|
||||
Step 2:
|
||||
- contact support regarding manual locking please to terminate rent</value>
|
||||
</data>
|
||||
<data name="ChangeLog3_0_278" xml:space="preserve">
|
||||
<value>Hints added to ease closing of lock in case closing does not succeed on first try.</value>
|
||||
</data>
|
||||
<data name="ActivityTextLockIsOutOfReach" xml:space="preserve">
|
||||
<value>Lock out of reach</value>
|
||||
</data>
|
||||
<data name="ActivityTextLockNotFound" xml:space="preserve">
|
||||
<value>Lock not found</value>
|
||||
</data>
|
||||
<data name="ErrorFindLockRentedBikeOutOfReachMessage" xml:space="preserve">
|
||||
<value>Lock can only be found when rented bike is nearby.</value>
|
||||
</data>
|
||||
<data name="ErrorFindLockReservedBikeOutOfReachMessage" xml:space="preserve">
|
||||
<value>Lock can only be found when reserved bike is nearby.</value>
|
||||
</data>
|
||||
<data name="MessageErrorConnectTitle" xml:space="preserve">
|
||||
<value>Error when connecting to lock!</value>
|
||||
</data>
|
||||
<data name="ErrorConnectLockGeneralErrorMessage" xml:space="preserve">
|
||||
<value>Communication error during lock search.</value>
|
||||
</data>
|
||||
<data name="ErrorConnectLockRentedBikeNoWebMessage" xml:space="preserve">
|
||||
<value>Internet must be reachable to connect to lock of rented bike.</value>
|
||||
</data>
|
||||
<data name="ErrorConnectLockReservedBikeNoWebMessage" xml:space="preserve">
|
||||
<value>Internet must be reachable to connect to lock of reserved bike.</value>
|
||||
</data>
|
||||
<data name="ErrorFindLockReservedBikeNoStausMessage" xml:space="preserve">
|
||||
<value>Lock status of the reserved bike could not be determined.</value>
|
||||
</data>
|
||||
<data name="ErrorFindLockBluetoothNotOn" xml:space="preserve">
|
||||
<value>Please turn Bluetooth on, otherwise lock cannot be connected.</value>
|
||||
</data>
|
||||
<data name="ErrorFindLockLocationPermissionMissing" xml:space="preserve">
|
||||
<value>Please grant location permissions, otherwise lock cannot be connected.</value>
|
||||
</data>
|
||||
<data name="ErrorFindLockLocationOff" xml:space="preserve">
|
||||
<value>Please turn Location on, otherwise lock cannot be connected.</value>
|
||||
</data>
|
||||
<data name="ChangeLog3_0_280" xml:space="preserve">
|
||||
<value>Errormessages improved for szenarios when
|
||||
- bluetooth is off,
|
||||
- location permission is not granted or
|
||||
- location is off.</value>
|
||||
</data>
|
||||
<data name="ErrorReservedSearchMessageEscalationLevel1" xml:space="preserve">
|
||||
<value>Lock of reserved bike cannot be be connected right now.
|
||||
If the bike is nearby:
|
||||
- restart app and repeat action
|
||||
- restart phone and repeat action
|
||||
to connect the lock</value>
|
||||
</data>
|
||||
<data name="ChangeLog3_0_282" xml:space="preserve">
|
||||
<value>Permission requests messages on iOS formulated in more detail.
|
||||
Hints to ease connecting to lock in case connecting does not succeed on first try improved.</value>
|
||||
</data>
|
||||
<data name="ExceptionTextSessionExpired" xml:space="preserve">
|
||||
<value>The session has expired. Please register again.</value>
|
||||
</data>
|
||||
<data name="ActivityTextAuthcookieNotDefinedException" xml:space="preserve">
|
||||
<value>Auth. expired</value>
|
||||
</data>
|
||||
<data name="ChangeLog3_0_284" xml:space="preserve">
|
||||
<value>User friendly message is shown if authentication expired.</value>
|
||||
</data>
|
||||
<data name="MessageAccountPageManageLogin" xml:space="preserve">
|
||||
<value>Log in</value>
|
||||
</data>
|
||||
<data name="MessageAccountPageManagePersonalData" xml:space="preserve">
|
||||
<value>Manage personal data</value>
|
||||
</data>
|
||||
<data name="ChangeLog3_0_285" xml:space="preserve">
|
||||
<value>Framework updated.
|
||||
Activity indicator added account management pages and logging extended.</value>
|
||||
</data>
|
||||
<data name="ActivityTextStartReturningBike" xml:space="preserve">
|
||||
<value>Starting bike return...</value>
|
||||
</data>
|
||||
<data name="ExceptionTextWebConnectFailureException" xml:space="preserve">
|
||||
<value>Is WIFI available/ mobile networt available and mobile data activated / ... ?</value>
|
||||
</data>
|
||||
<data name="ChangeLog3_0_289" xml:space="preserve">
|
||||
<value>Flyout menu header improved.</value>
|
||||
</data>
|
||||
<data name="ChangeLog3_0_290" xml:space="preserve">
|
||||
<value>Geolocation is queried with higher accuracy.</value>
|
||||
</data>
|
||||
</root>
|
|
@ -131,8 +131,8 @@
|
|||
<target state="final">Schloss kann erst geschlossen werden, wenn Rad nicht mehr bewegt wird. Bitte Rad abstellen und Vorgang wiederholen.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ErrorBookedSearchMessage" translate="yes" xml:space="preserve">
|
||||
<source>Lock of rented bike can not be found.</source>
|
||||
<target state="final">Schloss des gemieteten Rads kann nicht gefunden werden.</target>
|
||||
<source>Lock of rented bike cannot be be connected right now.</source>
|
||||
<target state="translated">Das Schloss des gemieteten Fahrrads kann im Moment nicht verbunden werden.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ErrorReservedSearchMessage" translate="yes" xml:space="preserve">
|
||||
<source>Lock of reserved bike can not be found.</source>
|
||||
|
@ -162,7 +162,7 @@
|
|||
<source>Returning bike outside of station is not possible. Distance to station {0} is {1} m.</source>
|
||||
<target state="translated">Rückgabe ausserhalb von Station nicht möglich. Entfernung zur Station {0} ist {1} m.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ErrorReturnBikeNotAtStationTitle" translate="yes" xml:space="preserve">
|
||||
<trans-unit id="ErrorReturnBikeTitle" translate="yes" xml:space="preserve">
|
||||
<source>Error returning bike!</source>
|
||||
<target state="translated">Fehler bei Radrückgabe!</target>
|
||||
</trans-unit>
|
||||
|
@ -228,13 +228,9 @@ Eine Radrückgabe ist nur möglich, wenn das Rad in Reichweite ist und Standorti
|
|||
</trans-unit>
|
||||
<trans-unit id="MessageMapPageErrorAuthcookieUndefined" translate="yes" xml:space="preserve">
|
||||
<source>Session has expired.
|
||||
Either there are more than 8 devices in use or the user's account is no longer valid.
|
||||
Use of app is restricted to maximu 8 devices per account.
|
||||
Please login to app once again. In case this fails please check on website if the account is still valid.</source>
|
||||
Please login to app once again.</source>
|
||||
<target state="translated">Sitzung ist abgelaufen.
|
||||
Entweder es sind mehr als 8 Geräte in Benutzung oder das Konto ist nicht mehr gültig.
|
||||
Die Nutzung der App ist auf maximal 8 Geräten pro Konto möglich.
|
||||
Bitte erneut in App anmelden. Sollte dies fehlschlagen bitte auf Website prüfen, ob das Konto noch gültig ist.</target>
|
||||
Bitte erneut in App anmelden.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="StatusTextReservationExpiredCodeMaxReservationTime" translate="yes" xml:space="preserve">
|
||||
<source>Code {0}, max. reservation time of {1} minutes expired.</source>
|
||||
|
@ -368,7 +364,7 @@ Bitte erneut in App anmelden. Sollte dies fehlschlagen bitte auf Website prüfen
|
|||
<source>After try to open lock state closed is reported.</source>
|
||||
<target state="translated">Nach Versuch Schloss zu öffnen wird Status geschlossen zurückgemeldet.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ErrorOpenLockOutOfReadMessage" translate="yes" xml:space="preserve">
|
||||
<trans-unit id="ErrorOpenLockOutOfReachMessage" translate="yes" xml:space="preserve">
|
||||
<source>Lock cannot be opened until bike is near.</source>
|
||||
<target state="translated">Schloss kann erst geöffnet werden, wenn Rad in der Nähe ist.</target>
|
||||
</trans-unit>
|
||||
|
@ -645,8 +641,8 @@ Bitte App neu starten um Rad Infos zu bekommen.</target>
|
|||
<target state="translated">Std./Tag</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="MessageBikesManagementTariffDescriptionTariffHeader" translate="yes" xml:space="preserve">
|
||||
<source>Tariff {0}</source>
|
||||
<target state="translated">Tarif {0}</target>
|
||||
<source>Tariff</source>
|
||||
<target state="translated">Tarif</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ActivityTextQuerryServer" translate="yes" xml:space="preserve">
|
||||
<source>Request server...</source>
|
||||
|
@ -1010,6 +1006,182 @@ Fehlerbehebung: Supportmails können wieder verschickt werden.</target>
|
|||
<source>Bugfix: No more closing of app on Select Bike page.</source>
|
||||
<target state="translated">Fehlerbehebung: App schließt sich nicht mehr auf Fahrrad Wählen-Seite.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ErrorBookedSearchMessageEscalationLevel1" translate="yes" xml:space="preserve">
|
||||
<source>Lock of rented bike cannot be be connected right now.
|
||||
If the bike is nearby:
|
||||
- restart app and repeat action
|
||||
- restart phone and repeat action
|
||||
to connect the lock.</source>
|
||||
<target state="translated">Das Schloss des gemieteten Fahrrads kann im Moment nicht verbunden werden.
|
||||
Wenn das Fahrrad in der Nähe ist:
|
||||
- App neu starten und Vorgang wiederholen
|
||||
- Telefon neu starten und Vorgang wiederholen
|
||||
um das Schloss zu verbinden.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="MessageAnswerCancel" translate="yes" xml:space="preserve">
|
||||
<source>Cancel</source>
|
||||
<target state="translated">Abbrechen</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="MessageAnswerRetry" translate="yes" xml:space="preserve">
|
||||
<source>Retry</source>
|
||||
<target state="translated">Wiederholen</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="MessageConnectLockErrorTitle" translate="yes" xml:space="preserve">
|
||||
<source>Error when connecting with lock!</source>
|
||||
<target state="translated">Fehler beim Verbinden mit Schloss!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ErrorBookedSearchMessageEscalationLevel2" translate="yes" xml:space="preserve">
|
||||
<source>Lock of rented bike cannot be be connected right now.
|
||||
If the bike is nearby:
|
||||
- restart app and repeat action
|
||||
- restart phone and repeat action
|
||||
to connect the lock.
|
||||
|
||||
Return bike manually.
|
||||
Steps 1: Close lock manually if lock is still open
|
||||
- close app
|
||||
- press on button at the top of the lock until it starts blinking
|
||||
- wait until lock is closed completely
|
||||
Step 2:
|
||||
- contact support regarding manual locking please to terminate rent</source>
|
||||
<target state="translated">Das Schloss des gemieteten Fahrrads kann im Moment nicht verbunden werden.
|
||||
Wenn das Fahrrad in der Nähe ist:
|
||||
- App neu starten und Vorgang wiederholen
|
||||
- Telefon neu starten und Vorgang wiederholen
|
||||
um das Schloss zu verbinden.
|
||||
|
||||
Manuelle Fahrradrückgabe.
|
||||
Schitt 1: Schloss manuell schließen wenn nötig. Dazu
|
||||
- App schließen
|
||||
- auf den Knopf oben am Schloss drücken, bis dieser zu blinken beginnt
|
||||
- warten, bis das Schloss vollständig geschlossen ist
|
||||
Schritt 2:
|
||||
- Support bitte bezüglich der manuellen Schließung kontaktieren um Miete abzuschließen</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ChangeLog3_0_278" translate="yes" xml:space="preserve">
|
||||
<source>Hints added to ease closing of lock in case closing does not succeed on first try.</source>
|
||||
<target state="translated">Hinweise hinzugefügt, um das Schließen des Schlosses zu erleichtern, falls dies nicht beim ersten Versuch gelingt.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ActivityTextLockIsOutOfReach" translate="yes" xml:space="preserve">
|
||||
<source>Lock out of reach</source>
|
||||
<target state="translated">Schloss außerhalb Reichweite</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ActivityTextLockNotFound" translate="yes" xml:space="preserve">
|
||||
<source>Lock not found</source>
|
||||
<target state="translated">Schloss nicht gefunden</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ErrorFindLockRentedBikeOutOfReachMessage" translate="yes" xml:space="preserve">
|
||||
<source>Lock can only be found when rented bike is nearby.</source>
|
||||
<target state="translated">Schloss kann erst gefunden werden, wenn gemietetes Rad in der Nähe ist.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ErrorFindLockReservedBikeOutOfReachMessage" translate="yes" xml:space="preserve">
|
||||
<source>Lock can only be found when reserved bike is nearby.</source>
|
||||
<target state="translated">Schloss kann erst gefunden werden, wenn reserviertes Rad in der Nähe ist.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="MessageErrorConnectTitle" translate="yes" xml:space="preserve">
|
||||
<source>Error when connecting to lock!</source>
|
||||
<target state="translated">Fehler bei Verbinden mit Schloss!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ErrorConnectLockGeneralErrorMessage" translate="yes" xml:space="preserve">
|
||||
<source>Communication error during lock search.</source>
|
||||
<target state="translated">Kommunikationsfehler bei Schlosssuche.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ErrorConnectLockRentedBikeNoWebMessage" translate="yes" xml:space="preserve">
|
||||
<source>Internet must be reachable to connect to lock of rented bike.</source>
|
||||
<target state="translated">Internet muss erreichbar sein um Verbindung mit Schloss für gemietetes Rad herzustellen.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ErrorConnectLockReservedBikeNoWebMessage" translate="yes" xml:space="preserve">
|
||||
<source>Internet must be reachable to connect to lock of reserved bike.</source>
|
||||
<target state="translated">Internet muss erreichbar sein um Verbindung mit Schloss für reserviertes Rad herzustellen.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ErrorFindLockReservedBikeNoStausMessage" translate="yes" xml:space="preserve">
|
||||
<source>Lock status of the reserved bike could not be determined.</source>
|
||||
<target state="translated">Schlossstatus des reservierten Rads konnte nicht ermittelt werden.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ErrorFindLockBluetoothNotOn" translate="yes" xml:space="preserve">
|
||||
<source>Please turn Bluetooth on, otherwise lock cannot be connected.</source>
|
||||
<target state="translated">Bitte Bluetooth anschalten, anderenfalls ist eine Verbindung mit dem Schloss nicht möglich.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ErrorFindLockLocationPermissionMissing" translate="yes" xml:space="preserve">
|
||||
<source>Please grant location permissions, otherwise lock cannot be connected.</source>
|
||||
<target state="translated">Bitte Standort-Zugriffsfreigabe erteilen, anderenfalls ist eine Verbindung mit dem Schloss nicht möglich.
|
||||
|
||||
</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ErrorFindLockLocationOff" translate="yes" xml:space="preserve">
|
||||
<source>Please turn Location on, otherwise lock cannot be connected.</source>
|
||||
<target state="translated">Bitte Standortbestimmung aktivieren, anderenfalls ist eine Verbindung mit dem Schloss nicht möglich.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ChangeLog3_0_280" translate="yes" xml:space="preserve">
|
||||
<source>Errormessages improved for szenarios when
|
||||
- bluetooth is off,
|
||||
- location permission is not granted or
|
||||
- location is off.</source>
|
||||
<target state="translated">Fehlermeldungen verbessert für die Fälle, dass
|
||||
- Bluetooth deaktiviert ist,
|
||||
- die Standortfreigabe nicht erteilt wurde oder
|
||||
- die Standorterkennung deaktiviert ist.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ErrorReservedSearchMessageEscalationLevel1" translate="yes" xml:space="preserve">
|
||||
<source>Lock of reserved bike cannot be be connected right now.
|
||||
If the bike is nearby:
|
||||
- restart app and repeat action
|
||||
- restart phone and repeat action
|
||||
to connect the lock</source>
|
||||
<target state="translated">Das Schloss des reservierten Fahrrads kann im Moment nicht verbunden werden.
|
||||
Wenn das Fahrrad in der Nähe ist:
|
||||
- App neu starten und Vorgang wiederholen
|
||||
- Telefon neu starten und Vorgang wiederholen
|
||||
um das Schloss zu verbinden.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ChangeLog3_0_282" translate="yes" xml:space="preserve">
|
||||
<source>Permission requests messages on iOS formulated in more detail.
|
||||
Hints to ease connecting to lock in case connecting does not succeed on first try improved.</source>
|
||||
<target state="translated">Freigabe-Erlaubnisanfragen unter iOS ausführlicher formuliert.
|
||||
Hinweise, um das Verbinden Schlosses zu erleichtern, falls dies nicht beim ersten Versuch gelingt, erweitert.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ExceptionTextSessionExpired" translate="yes" xml:space="preserve">
|
||||
<source>The session has expired. Please register again.</source>
|
||||
<target state="translated">Die Sitzung ist abgelaufen. Bitte neu anmelden.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ActivityTextAuthcookieNotDefinedException" translate="yes" xml:space="preserve">
|
||||
<source>Auth. expired</source>
|
||||
<target state="translated">Auth. abgelaufen</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ChangeLog3_0_284" translate="yes" xml:space="preserve">
|
||||
<source>User friendly message is shown if authentication expired.</source>
|
||||
<target state="translated">Anzeige einer benutzerfreundlichen Meldung, wenn die Authentifizierung abgelaufen ist.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="MessageAccountPageManageLogin" translate="yes" xml:space="preserve">
|
||||
<source>Log in</source>
|
||||
<target state="translated">Anmelden</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="MessageAccountPageManagePersonalData" translate="yes" xml:space="preserve">
|
||||
<source>Manage personal data</source>
|
||||
<target state="translated">Persönliche Daten Verwalten</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ChangeLog3_0_285" translate="yes" xml:space="preserve">
|
||||
<source>Framework updated.
|
||||
Activity indicator added account management pages and logging extended.</source>
|
||||
<target state="translated">Framework aktualisiert.
|
||||
Activity Indicator zu Konto-Verwaltungsseiten hinzugefügt und Logging erweitert.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ActivityTextStartReturningBike" translate="yes" xml:space="preserve">
|
||||
<source>Starting bike return...</source>
|
||||
<target state="translated">Starte Rückgabe...</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ExceptionTextWebConnectFailureException" translate="yes" xml:space="preserve">
|
||||
<source>Is WIFI available/ mobile networt available and mobile data activated / ... ?</source>
|
||||
<target state="translated">Ist WLAN verfügbar/ Mobilfunknetz vefügbar und mobile Daten aktiviert / ... ?</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ChangeLog3_0_289" translate="yes" xml:space="preserve">
|
||||
<source>Flyout menu header improved.</source>
|
||||
<target state="translated">Flyout-Menü Überschift verschönert.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ChangeLog3_0_290" translate="yes" xml:space="preserve">
|
||||
<source>Geolocation is queried with higher accuracy.</source>
|
||||
<target state="translated">Der aktuelle Standort wird mit höherer Genauigkeit abgefragt.</target>
|
||||
</trans-unit>
|
||||
</group>
|
||||
</body>
|
||||
</file>
|
||||
|
|
|
@ -158,6 +158,19 @@ namespace TINK.Repository
|
|||
requestBuilder.CalculateAuthParameters(bikeId),
|
||||
UserAgent);
|
||||
|
||||
/// <summary> Notifies COPRI about start of returning sequence. </summary>
|
||||
/// <remarks> Operator specific call.</remarks>
|
||||
/// <param name="bikeId">Id of the bike to return.</param>+
|
||||
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||
/// <returns>Response on notification about start of returning sequence.</returns>
|
||||
public async Task<ResponseBase> StartReturningBike(
|
||||
string bikeId,
|
||||
Uri operatorUri)
|
||||
=> await DoStartReturningBike(
|
||||
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
|
||||
requestBuilder.StartReturningBike(bikeId),
|
||||
UserAgent);
|
||||
|
||||
/// <summary> Updates lock state for a booked bike. </summary>
|
||||
/// <param name="bikeId">Id of the bike to update locking state for.</param>
|
||||
/// <param name="location">Geolocation of lock.</param>
|
||||
|
@ -170,13 +183,11 @@ namespace TINK.Repository
|
|||
LocationDto location,
|
||||
lock_state state,
|
||||
double batteryLevel,
|
||||
Uri operatorUri)
|
||||
{
|
||||
return await DoUpdateLockingStateAsync(
|
||||
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
|
||||
requestBuilder.UpateLockingState(bikeId, location, state, batteryLevel),
|
||||
UserAgent);
|
||||
}
|
||||
Uri operatorUri)=>
|
||||
await DoUpdateLockingStateAsync(
|
||||
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
|
||||
requestBuilder.UpateLockingState(bikeId, location, state, batteryLevel),
|
||||
UserAgent);
|
||||
|
||||
/// <summary> Gets booking request request. </summary>
|
||||
/// <param name="bikeId">Id of the bike to book.</param>
|
||||
|
@ -547,34 +558,67 @@ namespace TINK.Repository
|
|||
#endif
|
||||
}
|
||||
|
||||
public static async Task<ReservationBookingResponse> DoUpdateLockingStateAsync(
|
||||
public static async Task<ResponseBase> DoStartReturningBike(
|
||||
string copriHost,
|
||||
string command,
|
||||
string agent = null)
|
||||
{
|
||||
#if !WINDOWS_UWP
|
||||
string l_oBikesAvaialbeResponse;
|
||||
string response;
|
||||
try
|
||||
{
|
||||
l_oBikesAvaialbeResponse = await PostAsync(copriHost, command, agent);
|
||||
response = await PostAsync(copriHost, command, agent);
|
||||
}
|
||||
catch (System.Exception l_oException)
|
||||
catch (System.Exception exception)
|
||||
{
|
||||
if (l_oException.GetIsConnectFailureException())
|
||||
if (exception.GetIsConnectFailureException())
|
||||
{
|
||||
throw new WebConnectFailureException("Aktualisierung des Schlossstatuses wegen Netzwerkfehler fehlgeschlagen.", l_oException);
|
||||
throw new WebConnectFailureException("Benachrichtigung von Start der Rückgabe wegen Netzwerkfehler fehlgeschlagen.", exception);
|
||||
}
|
||||
|
||||
if (l_oException.GetIsForbiddenException())
|
||||
if (exception.GetIsForbiddenException())
|
||||
{
|
||||
throw new WebForbiddenException("Aktualisierung des Schlossstatuses wegen Netzwerkfehler fehlgeschlagen.", l_oException);
|
||||
throw new WebForbiddenException("Benachrichtigung von Start der Rückgabe wegen Netzwerkfehler fehlgeschlagen.", exception);
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
// Extract bikes from response.
|
||||
return JsonConvertRethrow.DeserializeObject<ResponseContainer<ReservationBookingResponse>>(l_oBikesAvaialbeResponse)?.shareejson;
|
||||
return JsonConvertRethrow.DeserializeObject<ResponseContainer<ResponseBase>>(response)?.shareejson;
|
||||
#else
|
||||
return null;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static async Task<ReservationBookingResponse> DoUpdateLockingStateAsync(
|
||||
string copriHost,
|
||||
string command,
|
||||
string agent = null)
|
||||
{
|
||||
#if !WINDOWS_UWP
|
||||
string bikesAvaialbeResponse;
|
||||
try
|
||||
{
|
||||
bikesAvaialbeResponse = await PostAsync(copriHost, command, agent);
|
||||
}
|
||||
catch (System.Exception exception)
|
||||
{
|
||||
if (exception.GetIsConnectFailureException())
|
||||
{
|
||||
throw new WebConnectFailureException("Aktualisierung des Schlossstatuses wegen Netzwerkfehler fehlgeschlagen.", exception);
|
||||
}
|
||||
|
||||
if (exception.GetIsForbiddenException())
|
||||
{
|
||||
throw new WebForbiddenException("Aktualisierung des Schlossstatuses wegen Netzwerkfehler fehlgeschlagen.", exception);
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
// Extract bikes from response.
|
||||
return JsonConvertRethrow.DeserializeObject<ResponseContainer<ReservationBookingResponse>>(bikesAvaialbeResponse)?.shareejson;
|
||||
#else
|
||||
return null;
|
||||
#endif
|
||||
|
@ -591,16 +635,16 @@ namespace TINK.Repository
|
|||
{
|
||||
l_oBikesAvaialbeResponse = await PostAsync(copriHost, command, agent);
|
||||
}
|
||||
catch (System.Exception l_oException)
|
||||
catch (System.Exception exception)
|
||||
{
|
||||
if (l_oException.GetIsConnectFailureException())
|
||||
if (exception.GetIsConnectFailureException())
|
||||
{
|
||||
throw new WebConnectFailureException("Buchung des Fahrrads wegen Netzwerkfehler fehlgeschlagen.", l_oException);
|
||||
throw new WebConnectFailureException("Buchung des Fahrrads wegen Netzwerkfehler fehlgeschlagen.", exception);
|
||||
}
|
||||
|
||||
if (l_oException.GetIsForbiddenException())
|
||||
if (exception.GetIsForbiddenException())
|
||||
{
|
||||
throw new WebForbiddenException("Buchung des Fahrrads wegen Netzwerkfehler fehlgeschlagen.", l_oException);
|
||||
throw new WebForbiddenException("Buchung des Fahrrads wegen Netzwerkfehler fehlgeschlagen.", exception);
|
||||
}
|
||||
|
||||
throw;
|
||||
|
|
|
@ -1613,6 +1613,10 @@ namespace TINK.Repository
|
|||
|
||||
public Task<ReservationBookingResponse> CalculateAuthKeysAsync(string bikeId, Uri operatorUri) => null;
|
||||
|
||||
public Task<ResponseBase> StartReturningBike(
|
||||
string bikeId,
|
||||
Uri operatorUri) => null;
|
||||
|
||||
public Task<ReservationBookingResponse> UpdateLockingStateAsync(
|
||||
string bikeId,
|
||||
LocationDto geolocation,
|
||||
|
|
|
@ -159,6 +159,11 @@ namespace TINK.Repository
|
|||
public Task<ReservationBookingResponse> CalculateAuthKeysAsync(string bikeId, Uri operatorUri)
|
||||
=> throw new System.Exception("Schlosssuche im Offlinemodus nicht möglich!");
|
||||
|
||||
public Task<ResponseBase> StartReturningBike(
|
||||
string bikeId,
|
||||
Uri operatorUri)
|
||||
=> throw new System.Exception("Benachrichtigung von start der Rückgabe im Offlinemodus nicht möglich!");
|
||||
|
||||
public Task<ReservationBookingResponse> UpdateLockingStateAsync(
|
||||
string bikeId,
|
||||
LocationDto geolocation,
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
namespace TINK.Repository.Exception
|
||||
using TINK.MultilingualResources;
|
||||
|
||||
namespace TINK.Repository.Exception
|
||||
{
|
||||
public class WebConnectFailureException : CommunicationException
|
||||
{
|
||||
|
@ -6,13 +8,9 @@
|
|||
/// Returns a hint to fix communication problem.
|
||||
/// </summary>
|
||||
public static string GetHintToPossibleExceptionsReasons
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Ist WLAN verfügbar/ Mobilfunknetz vefügbar und mobile Daten aktiviert / ... ?";
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
=> AppResources.ExceptionTextWebConnectFailureException;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a communication exeption object.
|
||||
/// </summary>
|
||||
/// <param name="p_strMessage"></param>
|
||||
|
|
|
@ -48,6 +48,15 @@ namespace TINK.Repository
|
|||
string bikeId,
|
||||
Uri operatorUri);
|
||||
|
||||
/// <summary> Notifies COPRI about start of returning sequence. </summary>
|
||||
/// <remarks> Operator specific call.</remarks>
|
||||
/// <param name="bikeId">Id of the bike to return.</param>+
|
||||
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||
/// <returns>Response on notification about start of returning sequence.</returns>
|
||||
Task<ResponseBase> StartReturningBike(
|
||||
string bikeId,
|
||||
Uri operatorUri);
|
||||
|
||||
/// <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="location">Geolocation of lock.</param>
|
||||
|
|
|
@ -55,6 +55,12 @@ namespace TINK.Repository.Request
|
|||
/// <returns>Request to get keys.</returns>
|
||||
string CalculateAuthParameters(string bikeId);
|
||||
|
||||
/// <summary> Gets the request for notifying about start of returning sequence. </summary>
|
||||
/// <remarks> Operator specific call.</remarks>
|
||||
/// <param name="bikeId">Id of the bike to return.</param>
|
||||
/// <returns>Request to notify about start of returning sequence.</returns>
|
||||
string StartReturningBike(string bikeId);
|
||||
|
||||
/// <summary> Gets the request for updating lock state for a booked bike. </summary>
|
||||
/// <param name="bikeId">Id of the bike to update locking state for.</param>
|
||||
/// <param name="location">Geolocation of lock when state change occurred.</param>
|
||||
|
|
|
@ -96,6 +96,13 @@ namespace TINK.Repository.Request
|
|||
/// <returns>Response on request.</returns>
|
||||
public string CalculateAuthParameters(string bikeId) => throw new NotSupportedException();
|
||||
|
||||
/// <summary> Gets the request for notifying about start of returning sequence. </summary>
|
||||
/// <remarks> Operator specific call.</remarks>
|
||||
/// <param name="bikeId">Id of the bike to return.</param>
|
||||
/// <returns>Request to notify about start of returning sequence.</returns>
|
||||
public string StartReturningBike(string bikeId)
|
||||
=> throw new NotSupportedException();
|
||||
|
||||
public string UpateLockingState(string bikeId, LocationDto geolocation, lock_state state, double batteryPercentage)
|
||||
=> throw new NotSupportedException();
|
||||
|
||||
|
|
|
@ -95,15 +95,20 @@ namespace TINK.Repository.Request
|
|||
public string CalculateAuthParameters(string bikeId)
|
||||
=> $"request=booking_update&bike={bikeId}&authcookie={SessionCookie}{MerchantId}&genkey=1";
|
||||
|
||||
/// <summary> Gets the request for notifying about start of returning sequence. </summary>
|
||||
/// <remarks> Operator specific call.</remarks>
|
||||
/// <param name="bikeId">Id of the bike to return.</param>
|
||||
/// <returns>Request to notify about start of returning sequence.</returns>
|
||||
public string StartReturningBike(string bikeId)
|
||||
=> $"request=booking_update&bike={bikeId}&lock_state=locking&authcookie={SessionCookie}{MerchantId}";
|
||||
|
||||
/// <summary> Gets the request for updating lock state for a booked bike. </summary>
|
||||
/// <remarks> Operator specific call.</remarks>
|
||||
/// <param name="bikeId">Id of the bike to update locking state for.</param>
|
||||
/// <param name="state">New locking state.</param>
|
||||
/// <returns>Request to update locking state.</returns>
|
||||
public string UpateLockingState(string bikeId, LocationDto geolocation, lock_state state, double batteryPercentage)
|
||||
{
|
||||
return $"request=booking_update&bike={bikeId}{GetLocationParameters(geolocation)}&lock_state={state}{GetBatteryPercentageParameters(batteryPercentage)}&authcookie={SessionCookie}{MerchantId}";
|
||||
}
|
||||
=> $"request=booking_update&bike={bikeId}{GetLocationParameters(geolocation)}&lock_state={state}{GetBatteryPercentageParameters(batteryPercentage)}&authcookie={SessionCookie}{MerchantId}";
|
||||
|
||||
/// <summary> Gets booking request request (synonym: booking == renting == mieten). </summary>
|
||||
/// <remarks> Operator specific call.</remarks>
|
||||
|
|
|
@ -8,6 +8,9 @@ namespace TINK.Repository.Response
|
|||
{
|
||||
public const string RESPONSE_OK = "OK";
|
||||
|
||||
/// <summary> Holds the description of the action return bike. </summary>
|
||||
public const string RESPONSE_AUTHCOOKIE_EXPRIED = "Failure 1001:";
|
||||
|
||||
/// <summary> Holds the description of the action logout. </summary>
|
||||
public const string BIKES_LOGOUT_ACTIONTEXT = "Abmeldung fehlgeschlagen.";
|
||||
|
||||
|
@ -127,6 +130,34 @@ namespace TINK.Repository.Response
|
|||
return bikeInfoRequestedOccupied;
|
||||
}
|
||||
|
||||
/// <summary> Gets if request is ok.</summary>
|
||||
/// <param name="response">Response to verify.</param>
|
||||
/// <param name="textOfAction">Text describing request which is shown if validation fails.</param>
|
||||
/// <returns>Verified response.</returns>
|
||||
public static BikesReservedOccupiedResponse GetIsResponseOk(this BikesReservedOccupiedResponse response, string textOfAction)
|
||||
{
|
||||
if (response == null || response.response_state == null)
|
||||
{
|
||||
throw new InvalidResponseException<BikesReservedOccupiedResponse>(textOfAction, null);
|
||||
}
|
||||
|
||||
if (AuthcookieNotDefinedException.IsAuthcookieNotDefined(response, textOfAction, out AuthcookieNotDefinedException exception))
|
||||
{
|
||||
throw exception;
|
||||
}
|
||||
|
||||
if (response.response_state.Trim().ToUpper().StartsWith(RESPONSE_AUTHCOOKIE_EXPRIED.ToUpper()))
|
||||
{
|
||||
throw new AuthcookieNotDefinedException(
|
||||
$"{textOfAction}\r\n{AppResources.ExceptionTextSessionExpired}",
|
||||
response);
|
||||
}
|
||||
|
||||
GetIsResponseOk((ResponseBase)response, textOfAction);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary> Gets if request is ok.</summary>
|
||||
/// <param name="response">Response to verify.</param>
|
||||
/// <param name="textOfAction">Text describing request which is shown if validation fails.</param>
|
||||
|
|
|
@ -48,8 +48,8 @@ namespace TINK.Services.BluetoothLock
|
|||
switch (lockInfo.State )
|
||||
{
|
||||
case LockingState.Open:
|
||||
case LockingState.Disconnected:
|
||||
case LockingState.Unknown:
|
||||
case LockingState.UnknownDisconnected:
|
||||
case LockingState.UnknownFromHardwareError:
|
||||
// Open bikes are never disposable because as soon as a they are open they get booked.
|
||||
if (LocksInfo.FirstOrDefault(x => x.Id == lockInfo.Id) != null)
|
||||
{
|
||||
|
@ -64,8 +64,8 @@ namespace TINK.Services.BluetoothLock
|
|||
switch (lockInfo.State)
|
||||
{
|
||||
case LockingState.Open:
|
||||
case LockingState.Disconnected:
|
||||
case LockingState.Unknown:
|
||||
case LockingState.UnknownDisconnected:
|
||||
case LockingState.UnknownFromHardwareError:
|
||||
// Closed bikes are never reserved because as soon as they are open they get booked.
|
||||
if (LocksInfo.FirstOrDefault(x => x.Id == lockInfo.Id) != null)
|
||||
{
|
||||
|
@ -79,8 +79,8 @@ namespace TINK.Services.BluetoothLock
|
|||
case InUseStateEnum.Booked:
|
||||
switch (lockInfo.State)
|
||||
{
|
||||
case LockingState.Disconnected:
|
||||
case LockingState.Unknown:
|
||||
case LockingState.UnknownDisconnected:
|
||||
case LockingState.UnknownFromHardwareError:
|
||||
if (LocksInfo.FirstOrDefault(x => x.Id == lockInfo.Id) != null)
|
||||
{
|
||||
continue; // Lock was already added.
|
||||
|
@ -152,6 +152,6 @@ namespace TINK.Services.BluetoothLock
|
|||
/// <summary> Disconnects lock.</summary>
|
||||
/// <param name="bikeId"> Id of lock to disconnect.</param>
|
||||
/// <param name="bikeGuid"> Guid of lock to disconnect.</param>
|
||||
public async Task<LockingState> DisconnectAsync(int bikeId, Guid bikeGuid) => await Task.FromResult(LockingState.Disconnected);
|
||||
public async Task<LockingState> DisconnectAsync(int bikeId, Guid bikeGuid) => await Task.FromResult(LockingState.UnknownDisconnected);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,6 +60,6 @@ namespace TINK.Services.BluetoothLock
|
|||
/// <summary> Disconnects lock.</summary>
|
||||
/// <param name="bikeId"> Id of lock to disconnect.</param>
|
||||
/// <param name="bikeGuid"> Guid of lock to disconnect.</param>
|
||||
public async Task<LockingState> DisconnectAsync(int bikeId, Guid bikeGuid) => await Task.FromResult(LockingState.Disconnected);
|
||||
public async Task<LockingState> DisconnectAsync(int bikeId, Guid bikeGuid) => await Task.FromResult(LockingState.UnknownDisconnected);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
using Plugin.BLE.Abstractions.Contracts;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TINK.Services.BluetoothLock
|
||||
{
|
||||
public static class StateChecker
|
||||
{
|
||||
/// <summary>
|
||||
/// Get current bluetooth state
|
||||
/// </summary>
|
||||
/// <remarks>See https://github.com/xabre/xamarin-bluetooth-le/issues/112#issuecomment-380994887.</remarks>
|
||||
/// <param name="ble">Crossplatform bluetooth implementation object</param>
|
||||
/// <returns>BluetoothState</returns>
|
||||
public static Task<BluetoothState> GetBluetoothState(this IBluetoothLE ble)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<BluetoothState>();
|
||||
|
||||
if (ble.State != BluetoothState.Unknown)
|
||||
{
|
||||
// If we can detect state out of box just returning in
|
||||
tcs.SetResult(ble.State);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise let's setup dynamic event handler and wait for first state update
|
||||
EventHandler<Plugin.BLE.Abstractions.EventArgs.BluetoothStateChangedArgs> handler = null;
|
||||
handler = (o, e) =>
|
||||
{
|
||||
ble.StateChanged -= handler;
|
||||
// and return it as our state
|
||||
// we can have an 'Unknown' check here, but in normal situation it should never occur
|
||||
tcs.SetResult(e.NewState);
|
||||
};
|
||||
ble.StateChanged += handler;
|
||||
}
|
||||
|
||||
return tcs.Task;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -227,6 +227,11 @@ namespace TINK.Model.Services.CopriApi
|
|||
return await HttpsServer.CalculateAuthKeysAsync(bikeId, operatorUri);
|
||||
}
|
||||
|
||||
public async Task<ResponseBase> StartReturningBike(
|
||||
string bikeId,
|
||||
Uri operatorUri)
|
||||
=> await HttpsServer.StartReturningBike(bikeId, operatorUri);
|
||||
|
||||
public async Task<ReservationBookingResponse> UpdateLockingStateAsync(
|
||||
string bikeId,
|
||||
LocationDto location,
|
||||
|
|
|
@ -40,6 +40,12 @@ namespace TINK.Model.Services.CopriApi
|
|||
public Task<ReservationBookingResponse> CalculateAuthKeysAsync(string bikeId, Uri operatorUri)
|
||||
=> throw new NotSupportedException($"{nameof(CalculateAuthKeysAsync)} is not cachable.");
|
||||
|
||||
public async Task<ResponseBase> StartReturningBike(
|
||||
string bikeId,
|
||||
Uri operatorUri)
|
||||
=> await monkeyStore.StartReturningBike(bikeId, operatorUri);
|
||||
|
||||
|
||||
public async Task<ReservationBookingResponse> UpdateLockingStateAsync(
|
||||
string bikeId,
|
||||
LocationDto geolocation,
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
using TINK.Model.Device;
|
||||
using Xamarin.Essentials;
|
||||
|
||||
namespace TINK.Services.Geolocation
|
||||
{
|
||||
public class GeolocationAccuracyBestService : GeolocationService
|
||||
{
|
||||
public GeolocationAccuracyBestService(IGeolodationDependent dependent) : base(
|
||||
dependent, GeolocationAccuracy.Best)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using TINK.Model.Device;
|
||||
using Xamarin.Essentials;
|
||||
|
||||
namespace TINK.Services.Geolocation
|
||||
{
|
||||
public class GeolocationAccuracyHighService : GeolocationService
|
||||
{
|
||||
public GeolocationAccuracyHighService(IGeolodationDependent dependent) : base(
|
||||
dependent, GeolocationAccuracy.High)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using TINK.Model.Device;
|
||||
using Xamarin.Essentials;
|
||||
|
||||
namespace TINK.Services.Geolocation
|
||||
{
|
||||
public class GeolocationAccuracyMediumService : GeolocationService
|
||||
{
|
||||
public GeolocationAccuracyMediumService(IGeolodationDependent dependent) : base(
|
||||
dependent, GeolocationAccuracy.Medium)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,18 +5,23 @@ using System.Threading.Tasks;
|
|||
using TINK.Model.Device;
|
||||
using Xamarin.Essentials;
|
||||
|
||||
namespace TINK.Model.Services.Geolocation
|
||||
namespace TINK.Services.Geolocation
|
||||
{
|
||||
public class GeolocationService : IGeolocation
|
||||
public abstract class GeolocationService : IGeolocation
|
||||
{
|
||||
/// <summary> Timeout for geolocation request operations.</summary>
|
||||
private const int GEOLOCATIONREQUEST_TIMEOUT_MS = 5000;
|
||||
|
||||
private IGeolodationDependent Dependent { get; }
|
||||
|
||||
public GeolocationService(IGeolodationDependent dependent)
|
||||
private GeolocationAccuracy Accuracy { get; }
|
||||
|
||||
public GeolocationService(
|
||||
IGeolodationDependent dependent,
|
||||
GeolocationAccuracy accuracy = GeolocationAccuracy.Default)
|
||||
{
|
||||
Dependent = dependent;
|
||||
Accuracy = accuracy;
|
||||
}
|
||||
|
||||
public bool IsSimulation => false;
|
||||
|
@ -30,7 +35,7 @@ namespace TINK.Model.Services.Geolocation
|
|||
{
|
||||
try
|
||||
{
|
||||
var request = new GeolocationRequest(GeolocationAccuracy.Medium, TimeSpan.FromMilliseconds(GEOLOCATIONREQUEST_TIMEOUT_MS));
|
||||
var request = new GeolocationRequest(Accuracy, TimeSpan.FromMilliseconds(GEOLOCATIONREQUEST_TIMEOUT_MS));
|
||||
return cancellationToken.HasValue
|
||||
? await Xamarin.Essentials.Geolocation.GetLocationAsync(request, cancellationToken.Value)
|
||||
: await Xamarin.Essentials.Geolocation.GetLocationAsync(request);
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Threading.Tasks;
|
|||
using TINK.Model.Device;
|
||||
using Xamarin.Essentials;
|
||||
|
||||
namespace TINK.Model.Services.Geolocation
|
||||
namespace TINK.Services.Geolocation
|
||||
{
|
||||
/// <summary> Query geolocation. </summary>
|
||||
public interface IGeolocation : IGeolodationDependent
|
||||
|
|
|
@ -5,7 +5,7 @@ using System.Threading.Tasks;
|
|||
using TINK.Model.Device;
|
||||
using Xamarin.Essentials;
|
||||
|
||||
namespace TINK.Model.Services.Geolocation
|
||||
namespace TINK.Services.Geolocation
|
||||
{
|
||||
public class LastKnownGeolocationService : IGeolocation
|
||||
{
|
||||
|
@ -58,7 +58,7 @@ namespace TINK.Model.Services.Geolocation
|
|||
return location;
|
||||
}
|
||||
|
||||
return await new GeolocationService(Dependent).GetAsync(cancelationToken, timeStamp);
|
||||
return await new GeolocationAccuracyMediumService(Dependent).GetAsync(cancelationToken, timeStamp);
|
||||
}
|
||||
|
||||
/// <summary> If true location data returned is simulated.</summary>
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Threading.Tasks;
|
|||
using TINK.Model.Device;
|
||||
using Xamarin.Essentials;
|
||||
|
||||
namespace TINK.Model.Services.Geolocation
|
||||
namespace TINK.Services.Geolocation
|
||||
{
|
||||
public class SimulatedGeolocationService : IGeolocation
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<MultilingualFallbackLanguage>en-GB</MultilingualFallbackLanguage>
|
||||
<TranslationReport Condition="'$(Configuration)' == 'Release'">true</TranslationReport>
|
||||
<SuppressPseudoWarning Condition="'$(Configuration)' == 'Debug'">true</SuppressPseudoWarning>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
|
@ -13,10 +14,10 @@
|
|||
<NeutralLanguage>en-GB</NeutralLanguage>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DefineConstants>TRACE;USEFLYOUT</DefineConstants>
|
||||
<DefineConstants>TRACE;</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DefineConstants>TRACE;USEFLYOUT</DefineConstants>
|
||||
<DefineConstants>TRACE;</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">
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="TINK.Themes.LastenradBayern">
|
||||
<!-- Pallete -->
|
||||
<!-- Pallete v0: #009BDB v1: 7fd8ff kind of light blue-->
|
||||
<Color x:Key="primary-back-title-color">#009BDB</Color>
|
||||
<!-- Pallete-end -->
|
||||
<Style ApplyToDerivedTypes="true" TargetType="NavigationPage">
|
||||
|
|
|
@ -323,24 +323,13 @@ namespace TINK.ViewModel.Bikes.Bike
|
|||
|
||||
/// <summary> Command object to bind login page redirect link to view model.</summary>
|
||||
public System.Windows.Input.ICommand ShowAgbTappedCommand
|
||||
#if USEFLYOUT
|
||||
=> new Xamarin.Forms.Command(() => ShowAgbPageAsync());
|
||||
#else
|
||||
=> new Xamarin.Forms.Command(async () => await ShowAgbPageAsync());
|
||||
#endif
|
||||
|
||||
/// <summary> Opens login page. </summary>
|
||||
#if USEFLYOUT
|
||||
public void ShowAgbPageAsync()
|
||||
#else
|
||||
public async Task ShowAgbPageAsync()
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
// Switch to map page
|
||||
|
||||
#if USEFLYOUT
|
||||
var url = GetUrlFirstOrDefault(TariffDescription.OperatorAgb);
|
||||
if (string.IsNullOrEmpty(url))
|
||||
{
|
||||
|
@ -349,7 +338,7 @@ namespace TINK.ViewModel.Bikes.Bike
|
|||
}
|
||||
|
||||
OpenUrlInBrowser(url);
|
||||
#endif
|
||||
|
||||
}
|
||||
catch (Exception p_oException)
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using TINK.Model.Connector;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Model.User;
|
||||
using TINK.View;
|
||||
using TINK.Model.Device;
|
||||
|
|
|
@ -3,7 +3,7 @@ using System.ComponentModel;
|
|||
using System.Runtime.CompilerServices;
|
||||
using TINK.Model.Connector;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Model.User;
|
||||
using TINK.View;
|
||||
using BikeInfoMutable = TINK.Model.Bike.BluetoothLock.BikeInfoMutable;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using TINK.Model.Connector;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Model.State;
|
||||
using TINK.View;
|
||||
using TINK.Model.User;
|
||||
|
|
|
@ -4,7 +4,7 @@ using TINK.Model.Connector;
|
|||
using TINK.Model.Bike.BluetoothLock;
|
||||
using TINK.Model.State;
|
||||
using TINK.View;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using Serilog;
|
||||
using TINK.Repository.Exception;
|
||||
|
@ -155,7 +155,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
else
|
||||
{
|
||||
// Bluetooth out of reach. Lock state is no more known.
|
||||
SelectedBike.LockInfo.State = LockingState.Disconnected;
|
||||
SelectedBike.LockInfo.State = LockingState.UnknownDisconnected;
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = "Returning bike...";
|
||||
|
@ -193,7 +193,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<BookedClosed>().Information("User selected booked bike {bike} but returning failed. COPRI returned an not at station error.", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnBikeNotAtStationTitle,
|
||||
AppResources.ErrorReturnBikeTitle,
|
||||
string.Format(AppResources.ErrorReturnBikeNotAtStationMessage, notAtStationException.StationNr, notAtStationException.Distance),
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
@ -203,7 +203,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<BookedClosed>().Information("User selected booked bike {bike} but returing failed. COPRI returned an no GPS- data error.", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnBikeNotAtStationTitle,
|
||||
AppResources.ErrorReturnBikeTitle,
|
||||
string.Format(AppResources.ErrorReturnBikeLockClosedNoGPSMessage),
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
@ -220,12 +220,12 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedClosed>().Error("User selected availalbe bike {bike} but reserving failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
Log.ForContext<BookedClosed>().Error("User selected booked bike {bike} but returning failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
"Fehler beim Zurückgeben des Rads!",
|
||||
AppResources.ErrorReturnBikeTitle,
|
||||
exception.Message,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
|
@ -316,7 +316,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
BikesViewModel.ActionText = AppResources.ActivityTextOpeningLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].OpenAsync())?.GetLockingState() ?? LockingState.Disconnected;
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].OpenAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
@ -328,8 +328,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockOutOfReadMessage,
|
||||
"OK");
|
||||
AppResources.ErrorOpenLockOutOfReachMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldIsBlockedException)
|
||||
{
|
||||
|
@ -338,7 +338,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockBoldBlockedMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldWasBlockedException)
|
||||
{
|
||||
|
@ -373,7 +373,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
// In all other cases state is supposed to be unknown. Example: Lock is out of reach and no more bluetooth connected.
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.Disconnected;
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
|
|
|
@ -8,12 +8,13 @@ using TINK.Repository.Exception;
|
|||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Services.BluetoothLock.Exception;
|
||||
using TINK.Services.BluetoothLock.Tdo;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Model.State;
|
||||
using TINK.MultilingualResources;
|
||||
using TINK.View;
|
||||
using TINK.Model.User;
|
||||
using TINK.Model.Device;
|
||||
using TINK.Model.User.Account;
|
||||
|
||||
namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
|
@ -86,28 +87,28 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
// Repeat booking to get a new seed/ k_user value.
|
||||
await ConnectorFactory(IsConnected).Command.CalculateAuthKeys(SelectedBike);
|
||||
}
|
||||
catch (Exception l_oException)
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
if (l_oException is WebConnectFailureException)
|
||||
if (exception is WebConnectFailureException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedDisconnected>().Information("User selected booked bike {l_oId} to connect to lock. (Copri server not reachable).", SelectedBike.Id);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
"Fehler bei Verbinden mit Schloss!",
|
||||
$"Internet muss erreichbar sein um Verbindung mit Schloss für gemietetes Rad herzustellen.\r\n{l_oException.Message}\r\n{WebConnectFailureException.GetHintToPossibleExceptionsReasons}",
|
||||
"OK");
|
||||
AppResources.MessageConnectLockErrorTitle,
|
||||
$"{AppResources.ErrorConnectLockRentedBikeNoWebMessage}\r\n{exception.Message}\r\n{WebConnectFailureException.GetHintToPossibleExceptionsReasons}",
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedDisconnected>().Error("User selected booked bike {l_oId} to connect to lock. {@l_oException}", SelectedBike.Id, l_oException);
|
||||
Log.ForContext<BookedDisconnected>().Error("User selected booked bike {l_oId} to connect to lock. {@l_oException}", SelectedBike.Id, exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
"Fehler bei Verbinden mit Schloss!",
|
||||
$"Kommunikationsfehler bei Schlosssuche.\r\n{l_oException.Message}",
|
||||
"OK");
|
||||
AppResources.MessageConnectLockErrorTitle,
|
||||
$"{AppResources.ErrorConnectLockGeneralErrorMessage}\r\n{exception.Message}",
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
// Restart polling again.
|
||||
|
@ -135,26 +136,68 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
{
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
if (exception is OutOfReachException)
|
||||
if (exception is ConnectBluetoothNotOnException)
|
||||
{
|
||||
continueConnect = false;
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageConnectLockErrorTitle,
|
||||
AppResources.ErrorFindLockBluetoothNotOn,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is ConnectLocationPermissionMissingException)
|
||||
{
|
||||
continueConnect = false;
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageConnectLockErrorTitle,
|
||||
AppResources.ErrorFindLockLocationPermissionMissing,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is ConnectLocationOffException)
|
||||
{
|
||||
continueConnect = false;
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageConnectLockErrorTitle,
|
||||
AppResources.ErrorFindLockLocationOff,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is OutOfReachException)
|
||||
{
|
||||
Log.ForContext<BookedDisconnected>().Debug("Lock can not be found. {Exception}", exception);
|
||||
|
||||
continueConnect = await ViewService.DisplayAlert(
|
||||
"Fehler bei Verbinden mit Schloss!",
|
||||
"Schloss kann erst gefunden werden, wenn gemietetes Rad in der Nähe ist.",
|
||||
"Wiederholen",
|
||||
"Abbrechen");
|
||||
AppResources.MessageConnectLockErrorTitle,
|
||||
AppResources.ErrorFindLockRentedBikeOutOfReachMessage,
|
||||
AppResources.MessageAnswerRetry,
|
||||
AppResources.MessageAnswerCancel);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedDisconnected>().Error("Lock can not be found. {Exception}", exception);
|
||||
|
||||
string message;
|
||||
if (retryCount < 2)
|
||||
{
|
||||
message = AppResources.ErrorBookedSearchMessage;
|
||||
}
|
||||
else if (retryCount < 3)
|
||||
{
|
||||
message = AppResources.ErrorBookedSearchMessageEscalationLevel1;
|
||||
}
|
||||
else
|
||||
{
|
||||
message = AppResources.ErrorBookedSearchMessageEscalationLevel2;
|
||||
}
|
||||
|
||||
|
||||
continueConnect = await ViewService.DisplayAdvancedAlert(
|
||||
"Fehler bei Verbinden mit Schloss!",
|
||||
AppResources.ErrorBookedSearchMessage,
|
||||
exception.Message,
|
||||
"Wiederholen",
|
||||
"Abbrechen");
|
||||
AppResources.MessageConnectLockErrorTitle,
|
||||
message,
|
||||
"", // bool IsReportLevelVerbose ? exception.Message : string.Empty, // or use ActiveUser.DebugLevel.HasFlag(Permissions.ReportLevel) instead?
|
||||
AppResources.MessageAnswerRetry,
|
||||
AppResources.MessageAnswerCancel);
|
||||
}
|
||||
|
||||
if (continueConnect)
|
||||
|
@ -178,9 +221,9 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
BikesViewModel.ActionText = "";
|
||||
await ViewService.DisplayAlert(
|
||||
"Fehler bei Verbinden mit Schloss!",
|
||||
AppResources.MessageConnectLockErrorTitle,
|
||||
$"Schlossstatus des gemieteten Rads konnte nicht ermittelt werden.",
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
// Restart polling again.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
|
|
|
@ -4,7 +4,7 @@ using TINK.Model.Connector;
|
|||
using TINK.Model.Bike.BluetoothLock;
|
||||
using TINK.Model.State;
|
||||
using TINK.View;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using Serilog;
|
||||
using TINK.Repository.Exception;
|
||||
|
@ -131,18 +131,74 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
|
||||
// Notify COPRI about start reaturning bike
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartReturningBike;
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
||||
try
|
||||
{
|
||||
await ConnectorFactory(IsConnected).Command.StartReturningBike(
|
||||
SelectedBike);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
if (exception is WebConnectFailureException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedOpen>().Information("User selected booked bike {bike} but returing failed (Copri server not reachable).", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorReturnBikeNoWebTitle,
|
||||
string.Format("{0}\r\n{1}", AppResources.ErrorReturnBikeNoWebMessage, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Error("User selected booked bike {bike} but returning failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnBikeTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
// Close lock
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextClosingLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.Disconnected;
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
// Signal cts to cancel getting geolocation.
|
||||
ctsLocation.Cancel();
|
||||
Task updateLockingStateTask = Task.CompletedTask;
|
||||
try
|
||||
{
|
||||
updateLockingStateTask = ConnectorFactory(IsConnected).Command.UpdateLockingStateAsync(
|
||||
SelectedBike);
|
||||
}
|
||||
catch (Exception innerExceptionStartUpdateLockingState)
|
||||
{
|
||||
// No location information available/ updating state failed.
|
||||
Log.ForContext<BookedOpen>().Information("Start update locking state failed on lock operating error. {Exception}", SelectedBike, innerExceptionStartUpdateLockingState);
|
||||
}
|
||||
|
||||
if (exception is OutOfReachException)
|
||||
{
|
||||
|
@ -181,20 +237,16 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.Disconnected;
|
||||
|
||||
// Wait until cancel getting geolocation has completed.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
|
||||
await Task.WhenAll(new List<Task> { currentLocationTask ?? Task.CompletedTask, updateLockingStateTask });
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception innerExWhenAll)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedOpen>().Information("Canceling query location failed on closing lock error. {Exception}", SelectedBike, ex);
|
||||
// No location information available/ updating state failed.
|
||||
Log.ForContext<BookedOpen>().Information("Canceling query location/ updating lock state failed on closing lock error. {Exception}", SelectedBike, innerExWhenAll);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
|
@ -208,11 +260,24 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
if (SelectedBike.LockInfo.State != LockingState.Closed)
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Error($"Lock can not be closed. Invalid locking state state {SelectedBike.LockInfo.State} detected.");
|
||||
|
||||
// Signal cts to cancel getting geolocation.
|
||||
ctsLocation.Cancel();
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
|
||||
// Signal cts to cancel getting geolocation.
|
||||
ctsLocation.Cancel();
|
||||
Task updateLockingStateTask = Task.CompletedTask;
|
||||
try
|
||||
{
|
||||
updateLockingStateTask = ConnectorFactory(IsConnected).Command.UpdateLockingStateAsync(
|
||||
SelectedBike);
|
||||
}
|
||||
catch (Exception innerExceptionStartUpdateLockingState)
|
||||
{
|
||||
// No location information available/ updating state failed.
|
||||
Log.ForContext<BookedOpen>().Information("Start update locking state failed on unexpected state. {Exception}", SelectedBike, innerExceptionStartUpdateLockingState);
|
||||
}
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
SelectedBike.LockInfo.State == LockingState.Open
|
||||
|
@ -224,12 +289,12 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
|
||||
await Task.WhenAll(new List<Task> { currentLocationTask ?? Task.CompletedTask, updateLockingStateTask});
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception innerExWhenAll)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedOpen>().Information("Canceling query location failed on unexpected lock state failed. {Exception}", SelectedBike, ex);
|
||||
Log.ForContext<BookedOpen>().Information("Canceling query location/ updating lock state failed failed on unexpected lock state failed. {Exception}", SelectedBike, innerExWhenAll);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
|
@ -311,7 +376,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<BookedOpen>().Information("User selected booked bike {bike} but returing failed. COPRI returned an error.", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnBikeNotAtStationTitle,
|
||||
AppResources.ErrorReturnBikeTitle,
|
||||
string.Format(AppResources.ErrorReturnBikeNotAtStationMessage, notAtStationException.StationNr, notAtStationException.Distance),
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
@ -321,7 +386,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<BookedOpen>().Information("User selected booked bike {bike} but returing failed. COPRI returned an no GPS- data error.", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnBikeNotAtStationTitle,
|
||||
AppResources.ErrorReturnBikeTitle,
|
||||
string.Format(AppResources.ErrorReturnBikeLockOpenNoGPSMessage),
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
@ -338,9 +403,12 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Error("User selected availalbe bike {bike} but reserving failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
Log.ForContext<BookedOpen>().Error("User selected booked bike {bike} but returning failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
|
||||
await ViewService.DisplayAlert("Fehler beim Zurückgeben des Rads!", exception.Message, "OK");
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnBikeTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
|
@ -448,7 +516,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
BikesViewModel.ActionText = AppResources.ActivityTextClosingLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.Disconnected;
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
@ -494,7 +562,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.Disconnected;
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
// Wait until cancel getting geolocation has completed.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
|
|
|
@ -0,0 +1,684 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using TINK.Model.Connector;
|
||||
using TINK.Model.Bike.BluetoothLock;
|
||||
using TINK.Model.State;
|
||||
using TINK.View;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using Serilog;
|
||||
using TINK.Repository.Exception;
|
||||
using TINK.Services.BluetoothLock.Exception;
|
||||
using Xamarin.Essentials;
|
||||
using TINK.MultilingualResources;
|
||||
using TINK.Model.Bikes.Bike.BluetoothLock;
|
||||
using TINK.Model.User;
|
||||
using TINK.Repository.Request;
|
||||
using TINK.Model.Device;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using TINK.Model;
|
||||
|
||||
namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
public class BookedOpen : Base, IRequestHandler
|
||||
{
|
||||
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||
public BookedOpen(
|
||||
IBikeInfoMutable selectedBike,
|
||||
Func<bool> isConnectedDelegate,
|
||||
Func<bool, IConnector> connectorFactory,
|
||||
IGeolocation geolocation,
|
||||
ILocksService lockService,
|
||||
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||
ISmartDevice smartDevice,
|
||||
IViewService viewService,
|
||||
IBikesViewModel bikesViewModel,
|
||||
IUser activeUser) : base(
|
||||
selectedBike,
|
||||
AppResources.ActionCloseAndReturn, // Copri button text: "Schloss schließen & Miete beenden"
|
||||
true, // Show button to allow user to return bike.
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser)
|
||||
{
|
||||
LockitButtonText = AppResources.ActionClose; // BT button text "Schließen".
|
||||
IsLockitButtonVisible = true; // Show button to allow user to lock bike.
|
||||
}
|
||||
|
||||
/// <summary> Gets the bike state. </summary>
|
||||
public override InUseStateEnum State => InUseStateEnum.Disposable;
|
||||
|
||||
/// <summary> Close lock and return bike.</summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption1() => await CloseLockAndReturnBike();
|
||||
|
||||
/// <summary> Close lock in order to pause ride and update COPRI lock state.</summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption2() => await CloseLock();
|
||||
|
||||
/// <summary> Close lock and return bike.</summary>
|
||||
public async Task<IRequestHandler> CloseLockAndReturnBike()
|
||||
{
|
||||
// Prevent concurrent interaction
|
||||
BikesViewModel.IsIdle = false;
|
||||
|
||||
// Start getting geolocation.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationStart;
|
||||
var ctsLocation = new CancellationTokenSource();
|
||||
Task<Location> currentLocationTask = null;
|
||||
var timeStamp = DateTime.Now;
|
||||
try
|
||||
{
|
||||
currentLocationTask = Geolocation.GetAsync(ctsLocation.Token, timeStamp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedOpen>().Information("Returning bike {Bike} is not possible. Start query location failed. {Exception}", SelectedBike, ex);
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageErrorQueryLocationStartTitle,
|
||||
$"{AppResources.MessageErrorQueryLocationMessage}\r\n{ex.Message}",
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
// Ask whether to really return bike?
|
||||
var l_oResult = await ViewService.DisplayAlert(
|
||||
string.Empty,
|
||||
string.Format(AppResources.QuestionCloseLockAndReturnBike, SelectedBike.GetFullDisplayName()),
|
||||
AppResources.MessageAnswerYes,
|
||||
AppResources.MessageAnswerNo);
|
||||
|
||||
if (l_oResult == false)
|
||||
{
|
||||
// User aborted closing and returning bike process
|
||||
Log.ForContext<BookedOpen>().Information("User selected booked bike {l_oId} in order to close and return but action was canceled.", SelectedBike.Id);
|
||||
|
||||
// Cancel getting geolocation.
|
||||
ctsLocation.Cancel();
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedOpen>().Information("Canceling query location failed on abort returning opened bike failed. {Exception}", SelectedBike, ex);
|
||||
}
|
||||
|
||||
BikesViewModel.IsIdle = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
// Unlock bike.
|
||||
Log.ForContext<BookedOpen>().Information("Request to return bike {bike} detected.", SelectedBike);
|
||||
|
||||
// Stop polling before returning bike.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
|
||||
// Notify COPRI about start reaturning bike
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartReturningBike;
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
||||
try
|
||||
{
|
||||
await ConnectorFactory(IsConnected).Command.StartReturningBike(
|
||||
SelectedBike);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
if (exception is WebConnectFailureException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedOpen>().Information("User selected booked bike {bike} but returing failed (Copri server not reachable).", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorReturnBikeNoWebTitle,
|
||||
string.Format("{0}\r\n{1}", AppResources.ErrorReturnBikeNoWebMessage, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Error("User selected booked bike {bike} but returning failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnBikeTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
// Close lock
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextClosingLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
// Signal cts to cancel getting geolocation.
|
||||
ctsLocation.Cancel();
|
||||
Task updateLockingStateTask = Task.CompletedTask;
|
||||
try
|
||||
{
|
||||
updateLockingStateTask = ConnectorFactory(IsConnected).Command.UpdateLockingStateAsync(
|
||||
SelectedBike);
|
||||
}
|
||||
catch (Exception innerExceptionStartUpdateLockingState)
|
||||
{
|
||||
// No location information available/ updating state failed.
|
||||
Log.ForContext<BookedOpen>().Information("Start update locking state failed on lock operating error. {Exception}", SelectedBike, innerExceptionStartUpdateLockingState);
|
||||
}
|
||||
|
||||
// Signal cts to cancel getting geolocation.
|
||||
ctsLocation.Cancel();
|
||||
|
||||
if (exception is OutOfReachException)
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockOutOfReachMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CounldntCloseMovingException)
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockMovingMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntCloseBoldBlockedException)
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockBoldBlockedMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Error("Lock can not be closed. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
// Wait until cancel getting geolocation has completed.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
try
|
||||
{
|
||||
await Task.WhenAll(new List<Task> { currentLocationTask ?? Task.CompletedTask, updateLockingStateTask });
|
||||
}
|
||||
catch (Exception innerExWhenAll)
|
||||
{
|
||||
// No location information available/ updating state failed.
|
||||
Log.ForContext<BookedOpen>().Information("Canceling query location/ updating lock state failed on closing lock error. {Exception}", SelectedBike, innerExWhenAll);
|
||||
}
|
||||
|
||||
// Wait until cancel getting geolocation has completed.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedOpen>().Information("Canceling query location failed on closing lock error. {Exception}", SelectedBike, ex);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
if (SelectedBike.LockInfo.State != LockingState.Closed)
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Error($"Lock can not be closed. Invalid locking state state {SelectedBike.LockInfo.State} detected.");
|
||||
|
||||
// Signal cts to cancel getting geolocation.
|
||||
ctsLocation.Cancel();
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
|
||||
// Signal cts to cancel getting geolocation.
|
||||
ctsLocation.Cancel();
|
||||
Task updateLockingStateTask = Task.CompletedTask;
|
||||
try
|
||||
{
|
||||
updateLockingStateTask = ConnectorFactory(IsConnected).Command.UpdateLockingStateAsync(
|
||||
SelectedBike);
|
||||
}
|
||||
catch (Exception innerExceptionStartUpdateLockingState)
|
||||
{
|
||||
// No location information available/ updating state failed.
|
||||
Log.ForContext<BookedOpen>().Information("Start update locking state failed on unexpected state. {Exception}", SelectedBike, innerExceptionStartUpdateLockingState);
|
||||
}
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
SelectedBike.LockInfo.State == LockingState.Open
|
||||
? AppResources.ErrorCloseLockStillOpenMessage
|
||||
: string.Format(AppResources.ErrorCloseLockUnexpectedStateMessage, SelectedBike.LockInfo.State),
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
// Wait until cancel getting geolocation has completed.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
try
|
||||
{
|
||||
await Task.WhenAll(new List<Task> { currentLocationTask ?? Task.CompletedTask, updateLockingStateTask});
|
||||
}
|
||||
catch (Exception innerExWhenAll)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedOpen>().Information("Canceling query location/ updating lock state failed failed on unexpected lock state failed. {Exception}", SelectedBike, innerExWhenAll);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocation;
|
||||
Location currentLocation = null;
|
||||
try
|
||||
{
|
||||
var task = await Task.WhenAny(new List<Task> { currentLocationTask });
|
||||
currentLocation = currentLocationTask.Result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedOpen>().Information("Returning bike {Bike} is not possible. Query location failed. {Exception}", SelectedBike, ex);
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.MessageErrorQueryLocationTitle,
|
||||
AppResources.MessageErrorQueryLocationMessage,
|
||||
ex.GetErrorMessage(),
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
// Lock list to avoid multiple taps while copri action is pending.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextReturningBike;
|
||||
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
||||
var feedBackUri = SelectedBike?.OperatorUri;
|
||||
BookingFinishedModel bookingFinished;
|
||||
try
|
||||
{
|
||||
bookingFinished = await ConnectorFactory(IsConnected).Command.DoReturn(
|
||||
SelectedBike,
|
||||
currentLocation != null
|
||||
? new LocationDto.Builder
|
||||
{
|
||||
Latitude = currentLocation.Latitude,
|
||||
Longitude = currentLocation.Longitude,
|
||||
Accuracy = currentLocation.Accuracy ?? double.NaN,
|
||||
Age = timeStamp.Subtract(currentLocation.Timestamp.DateTime),
|
||||
}.Build()
|
||||
: null,
|
||||
SmartDevice);
|
||||
// If canceling bike succedes remove bike because it is not ready to be booked again
|
||||
IsRemoveBikeRequired = true;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
if (exception is WebConnectFailureException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedOpen>().Information("User selected booked bike {bike} but returing failed (Copri server not reachable).", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
AppResources.ErrorReturnBikeNoWebTitle,
|
||||
string.Format("{0}\r\n{1}", AppResources.ErrorReturnBikeNoWebMessage, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is NotAtStationException notAtStationException)
|
||||
{
|
||||
// COPRI returned an error.
|
||||
Log.ForContext<BookedOpen>().Information("User selected booked bike {bike} but returing failed. COPRI returned an error.", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnBikeTitle,
|
||||
string.Format(AppResources.ErrorReturnBikeNotAtStationMessage, notAtStationException.StationNr, notAtStationException.Distance),
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is NoGPSDataException)
|
||||
{
|
||||
// COPRI returned an error.
|
||||
Log.ForContext<BookedOpen>().Information("User selected booked bike {bike} but returing failed. COPRI returned an no GPS- data error.", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnBikeTitle,
|
||||
string.Format(AppResources.ErrorReturnBikeLockOpenNoGPSMessage),
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is ResponseException copriException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedOpen>().Information("User selected booked bike {bike} but returing failed. COPRI returned an error.", SelectedBike);
|
||||
|
||||
await ViewService.DisplayAdvancedAlert(
|
||||
"Statusfehler beim Zurückgeben des Rads!",
|
||||
copriException.Message,
|
||||
copriException.Response,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Error("User selected booked bike {bike} but returning failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnBikeTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
Log.ForContext<BookedOpen>().Information("User returned bike {bike} successfully.", SelectedBike);
|
||||
|
||||
// Disconnect lock.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextDisconnectingLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = await LockService.DisconnectAsync(SelectedBike.LockInfo.Id, SelectedBike.LockInfo.Guid);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Error("Lock can not be disconnected. {Exception}", exception);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorDisconnect;
|
||||
}
|
||||
|
||||
#if !USERFEEDBACKDLG_OFF
|
||||
// Do get Feedback
|
||||
var feedback = await ViewService.DisplayUserFeedbackPopup(bookingFinished?.Co2Saving);
|
||||
|
||||
try
|
||||
{
|
||||
await ConnectorFactory(IsConnected).Command.DoSubmitFeedback(
|
||||
new UserFeedbackDto { BikeId = SelectedBike.Id, IsBikeBroken = feedback.IsBikeBroken, Message = feedback.Message },
|
||||
feedBackUri);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
if (exception is ResponseException copriException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedOpen>().Information("Submitting feedback for bike {bike} failed. COPRI returned an error.", SelectedBike);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Error("Submitting feedback for bike {bike} failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
}
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorReturnSubmitFeedbackTitle,
|
||||
AppResources.ErrorReturnSubmitFeedbackMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bookingFinished != null && bookingFinished.MiniSurvey.Questions.Count > 0)
|
||||
{
|
||||
await ViewService.PushModalAsync(ViewTypes.MiniSurvey);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
/// <summary> Close lock in order to pause ride and update COPRI lock state.</summary>
|
||||
public async Task<IRequestHandler> CloseLock()
|
||||
{
|
||||
// Unlock bike.
|
||||
BikesViewModel.IsIdle = false;
|
||||
Log.ForContext<BookedOpen>().Information("User request to lock bike {bike} in order to pause ride.", SelectedBike);
|
||||
|
||||
// Start getting geolocation.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationStart;
|
||||
var ctsLocation = new CancellationTokenSource();
|
||||
Task<Location> currentLocationTask = null;
|
||||
var timeStamp = DateTime.Now;
|
||||
try
|
||||
{
|
||||
currentLocationTask = Geolocation.GetAsync(ctsLocation.Token, timeStamp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedOpen>().Information("Closing lock of bike {Bike} is not possible. Starting query location failed. {Exception}", SelectedBike, ex);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorQueryLocationQuery;
|
||||
}
|
||||
|
||||
// Stop polling before returning bike.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
|
||||
// Close lock
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextClosingLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
// Signal cts to cancel getting geolocation.
|
||||
ctsLocation.Cancel();
|
||||
|
||||
if (exception is OutOfReachException)
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. {Exception}", exception);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockOutOfReachMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CounldntCloseMovingException)
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockMovingMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntCloseBoldBlockedException)
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockBoldBlockedMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Error("Lock can not be closed. {Exception}", exception);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
// Wait until cancel getting geolocation has completed.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedOpen>().Information("Canceling query location failed on closing lock error. {Exception}", SelectedBike, ex);
|
||||
}
|
||||
|
||||
// Wait until cancel getting geolocation has completed.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedOpen>().Information("Canceling query location failed on closing lock error. {Exception}", SelectedBike, ex);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
// Get geoposition.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocation;
|
||||
Location currentLocation = null;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask });
|
||||
currentLocation = currentLocationTask.Result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedOpen>().Information("Getting geolocation when closing lock of bike {Bike} failed. {Exception}", SelectedBike, ex);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorQueryLocationWhenAny;
|
||||
}
|
||||
|
||||
// Lock list to avoid multiple taps while copri action is pending.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdatingLockingState;
|
||||
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
||||
try
|
||||
{
|
||||
await ConnectorFactory(IsConnected).Command.UpdateLockingStateAsync(
|
||||
SelectedBike,
|
||||
currentLocation != null
|
||||
? new LocationDto.Builder
|
||||
{
|
||||
Latitude = currentLocation.Latitude,
|
||||
Longitude = currentLocation.Longitude,
|
||||
Accuracy = currentLocation.Accuracy ?? double.NaN,
|
||||
Age = timeStamp.Subtract(currentLocation.Timestamp.DateTime),
|
||||
}.Build()
|
||||
: null);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (exception is WebConnectFailureException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedOpen>().Information("User locked bike {bike} in order to pause ride but updating failed (Copri server not reachable).", SelectedBike);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorNoWebUpdateingLockstate;
|
||||
}
|
||||
else if (exception is ResponseException copriException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedOpen>().Information("User locked bike {bike} in order to pause ride but updating failed. Message: {Message} Details: {Details}", SelectedBike, copriException.Message, copriException.Response);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorStatusUpdateingLockstate;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedOpen>().Error("User locked bike {bike} in order to pause ride but updating failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorConnectionUpdateingLockstate;
|
||||
}
|
||||
}
|
||||
|
||||
Log.ForContext<BookedOpen>().Information("User paused ride using {bike} successfully.", SelectedBike);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ using TINK.Model.Connector;
|
|||
using TINK.Model.State;
|
||||
using TINK.View;
|
||||
using TINK.Repository.Exception;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Services.BluetoothLock.Exception;
|
||||
using TINK.MultilingualResources;
|
||||
|
@ -76,7 +76,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
BikesViewModel.ActionText = AppResources.ActivityTextOpeningLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].OpenAsync())?.GetLockingState() ?? LockingState.Disconnected;
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].OpenAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
@ -88,8 +88,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockOutOfReadMessage,
|
||||
"OK");
|
||||
AppResources.ErrorOpenLockOutOfReachMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldIsBlockedException)
|
||||
{
|
||||
|
@ -98,7 +98,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockBoldBlockedMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldWasBlockedException)
|
||||
{
|
||||
|
@ -107,7 +107,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockStillOpenTitle,
|
||||
AppResources.ErrorOpenLockBoldWasBlockedMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenInconsistentStateExecption inconsistentState
|
||||
&& inconsistentState.State == LockingState.Closed)
|
||||
|
@ -117,7 +117,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockStillClosedMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -126,14 +126,14 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
exception.Message,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
// When bold is blocked lock is still closed even if exception occurres.
|
||||
// In all other cases state is supposed to be unknown. Example: Lock is out of reach and no more bluetooth connected.
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.Disconnected;
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
|
@ -236,7 +236,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
BikesViewModel.ActionText = AppResources.ActivityTextClosingLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.Disconnected;
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
@ -251,7 +251,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockOutOfReachMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CounldntCloseMovingException)
|
||||
{
|
||||
|
@ -260,7 +260,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockMovingMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntCloseBoldBlockedException)
|
||||
{
|
||||
|
@ -269,7 +269,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockBoldBlockedMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -277,12 +277,12 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
exception.Message,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.Disconnected;
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
// Wait until cancel getting geolocation has completed.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
|
|
|
@ -0,0 +1,386 @@
|
|||
using Serilog;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using TINK.Model.Bike.BluetoothLock;
|
||||
using TINK.Model.Connector;
|
||||
using TINK.Model.State;
|
||||
using TINK.View;
|
||||
using TINK.Repository.Exception;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Services.BluetoothLock.Exception;
|
||||
using TINK.MultilingualResources;
|
||||
using TINK.Model.Bikes.Bike.BluetoothLock;
|
||||
using TINK.Model.User;
|
||||
using Xamarin.Essentials;
|
||||
using TINK.Repository.Request;
|
||||
using TINK.Model.Device;
|
||||
using System.Threading;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
public class BookedUnknown : Base, IRequestHandler
|
||||
{
|
||||
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...).</param>
|
||||
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||
public BookedUnknown(
|
||||
IBikeInfoMutable selectedBike,
|
||||
Func<bool> isConnectedDelegate,
|
||||
Func<bool, IConnector> connectorFactory,
|
||||
IGeolocation geolocation,
|
||||
ILocksService lockService,
|
||||
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||
ISmartDevice smartDevice,
|
||||
IViewService viewService,
|
||||
IBikesViewModel bikesViewModel,
|
||||
IUser activeUser) : base(
|
||||
selectedBike,
|
||||
AppResources.ActionOpenAndPause, // Schloss öffnen und Miete fortsetzen.
|
||||
true, // Show button to enabled returning of bike.
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser)
|
||||
{
|
||||
LockitButtonText = AppResources.ActionClose; // BT button text "Schließen".;
|
||||
IsLockitButtonVisible = true; // Show button to enable opening lock in case user took a pause and does not want to return the bike.
|
||||
}
|
||||
|
||||
/// <summary> Gets the bike state. </summary>
|
||||
public override InUseStateEnum State => InUseStateEnum.Booked;
|
||||
|
||||
/// <summary> Open bike and update COPRI lock state. </summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption1() => await OpenLock();
|
||||
|
||||
/// <summary> Close lock in order to pause ride and update COPRI lock state.</summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption2() => await CloseLock();
|
||||
|
||||
|
||||
/// <summary> Open bike and update COPRI lock state. </summary>
|
||||
public async Task<IRequestHandler> OpenLock()
|
||||
{
|
||||
// Unlock bike.
|
||||
Log.ForContext<BookedUnknown>().Information("User request to unlock bike {bike}.", SelectedBike);
|
||||
|
||||
// Stop polling before returning bike.
|
||||
BikesViewModel.IsIdle = false;
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOpeningLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].OpenAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
if (exception is OutOfReachException)
|
||||
{
|
||||
Log.ForContext<BookedUnknown>().Debug("Lock can not be opened. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockOutOfReachMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldIsBlockedException)
|
||||
{
|
||||
Log.ForContext<BookedUnknown>().Debug("Lock can not be opened. Bold is blocked. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockBoldBlockedMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldWasBlockedException)
|
||||
{
|
||||
Log.ForContext<BookedUnknown>().Debug("Lock can not be opened. Bold was or is blocked. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockStillOpenTitle,
|
||||
AppResources.ErrorOpenLockBoldWasBlockedMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenInconsistentStateExecption inconsistentState
|
||||
&& inconsistentState.State == LockingState.Closed)
|
||||
{
|
||||
Log.ForContext<BookedUnknown>().Debug("Lock can not be opened. lock reports state closed. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockStillClosedMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedUnknown>().Error("Lock can not be opened. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
// When bold is blocked lock is still closed even if exception occurres.
|
||||
// In all other cases state is supposed to be unknown. Example: Lock is out of reach and no more bluetooth connected.
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextReadingChargingLevel;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.BatteryPercentage = await LockService[SelectedBike.LockInfo.Id].GetBatteryPercentageAsync();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (exception is OutOfReachException)
|
||||
{
|
||||
Log.ForContext<BookedUnknown>().Debug("Akkustate can not be read, bike out of range. {Exception}", exception);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorReadingChargingLevelOutOfReach;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedUnknown>().Error("Akkustate can not be read. {Exception}", exception);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorReadingChargingLevelGeneral;
|
||||
}
|
||||
}
|
||||
|
||||
// Lock list to avoid multiple taps while copri action is pending.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdatingLockingState;
|
||||
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
||||
try
|
||||
{
|
||||
await ConnectorFactory(IsConnected).Command.UpdateLockingStateAsync(SelectedBike);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (exception is WebConnectFailureException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedUnknown>().Information("User locked bike {bike} in order to pause ride but updating failed (Copri server not reachable).", SelectedBike);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorNoWebUpdateingLockstate;
|
||||
}
|
||||
else if (exception is ResponseException copriException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedUnknown>().Information("User locked bike {bike} in order to pause ride but updating failed. {response}.", SelectedBike, copriException.Response);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorStatusUpdateingLockstate;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedUnknown>().Error("User locked bike {bike} in order to pause ride but updating failed . {@l_oException}", SelectedBike.Id, exception);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorConnectionUpdateingLockstate;
|
||||
}
|
||||
}
|
||||
|
||||
Log.ForContext<BookedUnknown>().Information("User paused ride using {bike} successfully.", SelectedBike);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
/// <summary> Close lock in order to pause ride and update COPRI lock state.</summary>
|
||||
public async Task<IRequestHandler> CloseLock()
|
||||
{
|
||||
// Unlock bike.
|
||||
BikesViewModel.IsIdle = false;
|
||||
|
||||
Log.ForContext<BookedUnknown>().Information("User request to lock bike {bike} in order to pause ride.", SelectedBike);
|
||||
|
||||
// Start getting geolocation.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationStart;
|
||||
var ctsLocation = new CancellationTokenSource();
|
||||
Task<Location> currentLocationTask = null;
|
||||
var timeStamp = DateTime.Now;
|
||||
try
|
||||
{
|
||||
currentLocationTask = Geolocation.GetAsync(ctsLocation.Token, timeStamp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedUnknown>().Information("Returning bike {Bike} is not possible. Start query location failed. {Exception}", SelectedBike, ex);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorQueryLocationQuery;
|
||||
}
|
||||
|
||||
// Stop polling before returning bike.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
|
||||
// Close lock
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextClosingLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
// Signal cts to cancel getting geolocation.
|
||||
ctsLocation.Cancel();
|
||||
|
||||
if (exception is OutOfReachException)
|
||||
{
|
||||
Log.ForContext<BookedUnknown>().Debug("Lock can not be closed. {Exception}", exception);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockOutOfReachMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CounldntCloseMovingException)
|
||||
{
|
||||
Log.ForContext<BookedUnknown>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockMovingMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntCloseBoldBlockedException)
|
||||
{
|
||||
Log.ForContext<BookedUnknown>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockBoldBlockedMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedUnknown>().Error("Lock can not be closed. {Exception}", exception);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
// Wait until cancel getting geolocation has completed.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedUnknown>().Information("Canceling query location failed on unexpected lock state failed. {Exception}", SelectedBike, ex);
|
||||
}
|
||||
|
||||
// Wait until cancel getting geolocation has completed.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedUnknown>().Information("Canceling query location failed on unexpected lock state failed. {Exception}", SelectedBike, ex);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
// Get geoposition.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocation;
|
||||
Location currentLocation = null;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
|
||||
currentLocation = currentLocationTask?.Result ?? null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<BookedUnknown>().Information("Get geolocation failed when closing lock of bike {Bike} with unknown state. {Exception}", SelectedBike, ex);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorQueryLocationWhenAny;
|
||||
}
|
||||
|
||||
// Lock list to avoid multiple taps while copri action is pending.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdatingLockingState;
|
||||
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
||||
try
|
||||
{
|
||||
await ConnectorFactory(IsConnected).Command.UpdateLockingStateAsync(
|
||||
SelectedBike,
|
||||
currentLocation != null
|
||||
? new LocationDto.Builder
|
||||
{
|
||||
Latitude = currentLocation.Latitude,
|
||||
Longitude = currentLocation.Longitude,
|
||||
Accuracy = currentLocation.Accuracy ?? double.NaN,
|
||||
Age = timeStamp.Subtract(currentLocation.Timestamp.DateTime),
|
||||
}.Build()
|
||||
: null);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (exception is WebConnectFailureException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedUnknown>().Information("User locked bike {bike} in order to pause ride but updating failed (Copri server not reachable).", SelectedBike);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorNoWebUpdateingLockstate;
|
||||
}
|
||||
else if (exception is ResponseException copriException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<BookedUnknown>().Information("User locked bike {bike} in order to pause ride but updating failed. Message: {Message} Details: {Details}", SelectedBike, copriException.Message, copriException.Response);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorStatusUpdateingLockstate;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedUnknown>().Error("User locked bike {bike} in order to pause ride but updating failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorConnectionUpdateingLockstate;
|
||||
}
|
||||
}
|
||||
|
||||
Log.ForContext<BookedUnknown>().Information("User paused ride using {bike} successfully.", SelectedBike);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ using TINK.Model.Connector;
|
|||
using TINK.Model.State;
|
||||
using TINK.View;
|
||||
using TINK.Repository.Exception;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Services.BluetoothLock.Tdo;
|
||||
using TINK.MultilingualResources;
|
||||
|
@ -149,12 +149,12 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
{
|
||||
Log.ForContext<DisposableDisconnected>().Debug("Lock state can not be retrieved, lock is out of reach. {Exception}", exception);
|
||||
|
||||
BikesViewModel.ActionText = "Schloss außerhalb Reichweite";
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextLockIsOutOfReach;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<DisposableDisconnected>().Error("Lock state can not be retrieved. {Exception}", exception);
|
||||
BikesViewModel.ActionText = "Schloss nicht gefunden";
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextLockNotFound;
|
||||
}
|
||||
|
||||
// Restart polling again.
|
||||
|
@ -165,8 +165,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
SelectedBike.LockInfo.State = result?.State?.GetLockingState() ?? LockingState.Disconnected;
|
||||
if (SelectedBike.LockInfo.State == LockingState.Disconnected)
|
||||
SelectedBike.LockInfo.State = result?.State?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
if (SelectedBike.LockInfo.State == LockingState.UnknownDisconnected)
|
||||
{
|
||||
// Do not display any messages here, because search is implicit.
|
||||
Log.ForContext<DisposableDisconnected>().Information("Lock for bike {bike} not found.", SelectedBike);
|
||||
|
@ -262,7 +262,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
BikesViewModel.ActionText = AppResources.ActivityTextOpeningLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].OpenAsync())?.GetLockingState() ?? LockingState.Disconnected;
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].OpenAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
@ -273,8 +273,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockOutOfReadMessage,
|
||||
"OK");
|
||||
AppResources.ErrorOpenLockOutOfReachMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldIsBlockedException)
|
||||
{
|
||||
|
@ -283,7 +283,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockBoldBlockedMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldWasBlockedException)
|
||||
{
|
||||
|
@ -292,7 +292,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockStillOpenTitle,
|
||||
AppResources.ErrorOpenLockBoldWasBlockedMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenInconsistentStateExecption inconsistentState
|
||||
&& inconsistentState.State == LockingState.Closed)
|
||||
|
@ -302,7 +302,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockStillClosedMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -310,12 +310,12 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
exception.Message,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.Disconnected;
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
|
|
|
@ -6,7 +6,7 @@ using TINK.Model.Connector;
|
|||
using TINK.Model.State;
|
||||
using TINK.View;
|
||||
using TINK.Repository.Exception;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Services.BluetoothLock.Exception;
|
||||
using TINK.MultilingualResources;
|
||||
|
@ -97,7 +97,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
BikesViewModel.ActionText = AppResources.ActivityTextClosingLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.Disconnected;
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
@ -109,7 +109,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockOutOfReachMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CounldntCloseMovingException)
|
||||
{
|
||||
|
@ -118,7 +118,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockMovingMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntCloseBoldBlockedException)
|
||||
{
|
||||
|
@ -127,7 +127,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockBoldBlockedMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -136,12 +136,12 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
exception.Message,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.Disconnected;
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
|
@ -228,7 +228,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
BikesViewModel.ActionText = "Verschließe Schloss...";
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.Disconnected;
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
@ -236,7 +236,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.Disconnected;
|
||||
: LockingState.UnknownDisconnected;
|
||||
}
|
||||
|
||||
// Disconnect lock.
|
||||
|
|
|
@ -8,7 +8,7 @@ using TINK.Model.State;
|
|||
using TINK.View;
|
||||
|
||||
using IBikeInfoMutable = TINK.Model.Bikes.Bike.BluetoothLock.IBikeInfoMutable;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Services.BluetoothLock.Exception;
|
||||
using TINK.MultilingualResources;
|
||||
|
@ -228,7 +228,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
BikesViewModel.ActionText = AppResources.ActivityTextOpeningLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].OpenAsync())?.GetLockingState() ?? LockingState.Disconnected;
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].OpenAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
@ -239,8 +239,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockOutOfReadMessage,
|
||||
"OK");
|
||||
AppResources.ErrorOpenLockOutOfReachMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldIsBlockedException)
|
||||
{
|
||||
|
@ -249,7 +249,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockBoldBlockedMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldWasBlockedException)
|
||||
{
|
||||
|
@ -258,7 +258,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockStillOpenTitle,
|
||||
AppResources.ErrorOpenLockBoldWasBlockedMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenInconsistentStateExecption inconsistentState
|
||||
&& inconsistentState.State == LockingState.Closed)
|
||||
|
@ -268,7 +268,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockStillClosedMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -276,12 +276,12 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
exception.Message,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.Disconnected;
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
|
|
|
@ -6,7 +6,7 @@ using TINK.Repository.Exception;
|
|||
using TINK.Model.Bike.BluetoothLock;
|
||||
using TINK.Model.State;
|
||||
using TINK.View;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Services.BluetoothLock.Exception;
|
||||
using TINK.Services.BluetoothLock.Tdo;
|
||||
|
@ -161,18 +161,18 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
Log.ForContext<ReservedDisconnected>().Information("User selected requested bike {l_oId} to connect to lock. (Copri server not reachable).", SelectedBike.Id);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
"Fehler bei Verbinden mit Schloss!",
|
||||
$"Internet muss erreichbar sein um Verbindung mit Schloss für reserviertes Rad herzustellen.\r\n{exception.Message}\r\n{WebConnectFailureException.GetHintToPossibleExceptionsReasons}",
|
||||
"OK");
|
||||
AppResources.MessageErrorConnectTitle,
|
||||
$"{AppResources.ErrorConnectLockReservedBikeNoWebMessage}\r\n{exception.Message}\r\n{WebConnectFailureException.GetHintToPossibleExceptionsReasons}",
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<ReservedDisconnected>().Error("User selected requested bike {l_oId} to scan for lock. {@l_oException}", SelectedBike.Id, exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
"Fehler bei Verbinden mit Schloss!",
|
||||
$"Kommunikationsfehler bei Schlosssuche.\r\n{exception.Message}",
|
||||
"OK");
|
||||
AppResources.MessageErrorConnectTitle,
|
||||
$"{AppResources.ErrorConnectLockGeneralErrorMessage}\r\n{exception.Message}",
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
// Restart polling again.
|
||||
|
@ -206,25 +206,64 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
if (exception is OutOfReachException)
|
||||
if (exception is ConnectBluetoothNotOnException)
|
||||
{
|
||||
continueConnect = false;
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageErrorConnectTitle,
|
||||
AppResources.ErrorFindLockBluetoothNotOn,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is ConnectLocationPermissionMissingException)
|
||||
{
|
||||
continueConnect = false;
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageConnectLockErrorTitle,
|
||||
AppResources.ErrorFindLockLocationPermissionMissing,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is ConnectLocationOffException)
|
||||
{
|
||||
continueConnect = false;
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageConnectLockErrorTitle,
|
||||
AppResources.ErrorFindLockLocationOff,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is OutOfReachException)
|
||||
{
|
||||
Log.ForContext<ReservedDisconnected>().Debug("Lock state can not be retrieved. {Exception}", exception);
|
||||
|
||||
continueConnect = await ViewService.DisplayAlert(
|
||||
"Fehler bei Verbinden mit Schloss!",
|
||||
"Schloss kann erst gefunden werden, wenn reserviertes Rad in der Nähe ist.",
|
||||
"Wiederholen",
|
||||
"Abbrechen");
|
||||
AppResources.MessageErrorConnectTitle,
|
||||
AppResources.ErrorFindLockReservedBikeOutOfReachMessage,
|
||||
AppResources.MessageAnswerRetry,
|
||||
AppResources.MessageAnswerCancel);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<BookedDisconnected>().Error("Lock can not be found. {Exception}", exception);
|
||||
|
||||
string message;
|
||||
if (retryCount < 2)
|
||||
{
|
||||
message = AppResources.ErrorReservedSearchMessage;
|
||||
}
|
||||
else
|
||||
{
|
||||
message = AppResources.ErrorReservedSearchMessageEscalationLevel1;
|
||||
}
|
||||
|
||||
Log.ForContext<ReservedDisconnected>().Error("Lock state can not be retrieved. {Exception}", exception);
|
||||
continueConnect = await ViewService.DisplayAdvancedAlert(
|
||||
"Fehler bei Verbinden mit Schloss!",
|
||||
AppResources.ErrorReservedSearchMessage,
|
||||
exception.Message,
|
||||
"Wiederholen",
|
||||
"Abbrechen");
|
||||
AppResources.MessageErrorConnectTitle,
|
||||
message,
|
||||
"", // bool IsReportLevelVerbose ? exception.Message : string.Empty, // or use ActiveUser.DebugLevel.HasFlag(Permissions.ReportLevel) instead?
|
||||
AppResources.MessageAnswerRetry,
|
||||
AppResources.MessageAnswerCancel );
|
||||
}
|
||||
|
||||
if (continueConnect)
|
||||
|
@ -247,9 +286,9 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
BikesViewModel.ActionText = "";
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
"Fehler bei Verbinden mit Schloss!",
|
||||
$"Schlossstatus des reservierten Rads konnte nicht ermittelt werden.",
|
||||
"OK");
|
||||
AppResources.MessageErrorConnectTitle,
|
||||
AppResources.ErrorFindLockReservedBikeNoStausMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
// Restart polling again.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
|
@ -345,7 +384,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
BikesViewModel.ActionText = AppResources.ActivityTextOpeningLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].OpenAsync())?.GetLockingState() ?? LockingState.Disconnected;
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].OpenAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
@ -356,8 +395,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockOutOfReadMessage,
|
||||
"OK");
|
||||
AppResources.ErrorOpenLockOutOfReachMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldIsBlockedException)
|
||||
{
|
||||
|
@ -366,7 +405,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockBoldBlockedMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldWasBlockedException)
|
||||
{
|
||||
|
@ -375,7 +414,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockStillOpenTitle,
|
||||
AppResources.ErrorOpenLockBoldWasBlockedMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenInconsistentStateExecption inconsistentState
|
||||
&& inconsistentState.State == LockingState.Closed)
|
||||
|
@ -385,7 +424,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockStillClosedMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -393,12 +432,12 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
exception.Message,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.Disconnected;
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
|
|
|
@ -6,7 +6,7 @@ using TINK.Repository.Exception;
|
|||
using TINK.Model.Bike.BluetoothLock;
|
||||
using TINK.Model.State;
|
||||
using TINK.View;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Services.BluetoothLock.Exception;
|
||||
using TINK.Model.Bikes.Bike.BluetoothLock;
|
||||
|
@ -140,7 +140,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
BikesViewModel.ActionText = "Wiederverschließe Schloss...";
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.Disconnected;
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
@ -148,7 +148,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.Disconnected;
|
||||
: LockingState.UnknownDisconnected;
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
|
@ -174,7 +174,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
BikesViewModel.ActionText = AppResources.ActivityTextClosingLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.Disconnected;
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
@ -218,7 +218,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.Disconnected;
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||
|
|
|
@ -6,7 +6,7 @@ using TINK.Model.Connector;
|
|||
using TINK.Model.State;
|
||||
using TINK.View;
|
||||
using TINK.Repository.Exception;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Services.BluetoothLock.Exception;
|
||||
using TINK.MultilingualResources;
|
||||
|
@ -72,7 +72,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
BikesViewModel.ActionText = AppResources.ActivityTextOpeningLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].OpenAsync())?.GetLockingState() ?? LockingState.Disconnected;
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].OpenAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
@ -84,8 +84,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockOutOfReadMessage,
|
||||
"OK");
|
||||
AppResources.ErrorOpenLockOutOfReachMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldIsBlockedException)
|
||||
{
|
||||
|
@ -94,7 +94,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockBoldBlockedMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldWasBlockedException)
|
||||
{
|
||||
|
@ -103,7 +103,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockStillOpenTitle,
|
||||
AppResources.ErrorOpenLockBoldWasBlockedMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenInconsistentStateExecption inconsistentState
|
||||
&& inconsistentState.State == LockingState.Closed)
|
||||
|
@ -113,7 +113,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockStillClosedMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -122,14 +122,14 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
exception.Message,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
// When bold is blocked lock is still closed even if exception occurres.
|
||||
// In all other cases state is supposed to be unknown. Example: Lock is out of reach and no more bluetooth connected.
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.Disconnected;
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
|
@ -236,7 +236,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
BikesViewModel.ActionText = AppResources.ActivityTextClosingLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.Disconnected;
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
@ -251,7 +251,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockOutOfReachMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CounldntCloseMovingException)
|
||||
{
|
||||
|
@ -260,7 +260,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockMovingMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntCloseBoldBlockedException)
|
||||
{
|
||||
|
@ -269,7 +269,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockBoldBlockedMessage,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -277,12 +277,12 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
exception.Message,
|
||||
"OK");
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.Disconnected;
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
// Wait until cancel getting geolocation has completed.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
|
|
|
@ -0,0 +1,386 @@
|
|||
using Serilog;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using TINK.Model.Bike.BluetoothLock;
|
||||
using TINK.Model.Connector;
|
||||
using TINK.Model.State;
|
||||
using TINK.View;
|
||||
using TINK.Repository.Exception;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Services.BluetoothLock.Exception;
|
||||
using TINK.MultilingualResources;
|
||||
using TINK.Model.Bikes.Bike.BluetoothLock;
|
||||
using TINK.Model.User;
|
||||
using Xamarin.Essentials;
|
||||
using TINK.Repository.Request;
|
||||
using TINK.Model.Device;
|
||||
using System.Threading;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
public class ReservedUnknown : Base, IRequestHandler
|
||||
{
|
||||
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...)</param>
|
||||
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||
public ReservedUnknown(
|
||||
IBikeInfoMutable selectedBike,
|
||||
Func<bool> isConnectedDelegate,
|
||||
Func<bool, IConnector> connectorFactory,
|
||||
IGeolocation geolocation,
|
||||
ILocksService lockService,
|
||||
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||
ISmartDevice smartDevice,
|
||||
IViewService viewService,
|
||||
IBikesViewModel bikesViewModel,
|
||||
IUser activeUser) : base(
|
||||
selectedBike,
|
||||
AppResources.ActionOpenAndBook, // BT button text "Schloss öffnen und Rad mieten."
|
||||
false, // Show button to enabled returning of bike.
|
||||
isConnectedDelegate,
|
||||
connectorFactory,
|
||||
geolocation,
|
||||
lockService,
|
||||
viewUpdateManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser)
|
||||
{
|
||||
LockitButtonText = AppResources.ActionClose; // BT button text "Schließen"
|
||||
IsLockitButtonVisible = true; // Show button to enable opening lock in case user took a pause and does not want to return the bike.
|
||||
}
|
||||
|
||||
/// <summary> Gets the bike state. </summary>
|
||||
public override InUseStateEnum State => InUseStateEnum.Reserved;
|
||||
|
||||
/// <summary> Open bike and update COPRI lock state. </summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption1() => await OpenLock();
|
||||
|
||||
/// <summary> Open bike and update COPRI lock state. </summary>
|
||||
public async Task<IRequestHandler> OpenLock()
|
||||
{
|
||||
// Unlock bike.
|
||||
Log.ForContext<ReservedUnknown>().Information("User request to unlock bike {bike}.", SelectedBike);
|
||||
|
||||
// Stop polling before returning bike.
|
||||
BikesViewModel.IsIdle = false;
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOpeningLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].OpenAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
if (exception is OutOfReachException)
|
||||
{
|
||||
Log.ForContext<ReservedUnknown>().Debug("Lock can not be opened. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockOutOfReachMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldIsBlockedException)
|
||||
{
|
||||
Log.ForContext<ReservedUnknown>().Debug("Lock can not be opened. Bold is blocked. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockBoldBlockedMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenBoldWasBlockedException)
|
||||
{
|
||||
Log.ForContext<ReservedUnknown>().Debug("Lock can not be opened. Bold was or is blocked. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockStillOpenTitle,
|
||||
AppResources.ErrorOpenLockBoldWasBlockedMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntOpenInconsistentStateExecption inconsistentState
|
||||
&& inconsistentState.State == LockingState.Closed)
|
||||
{
|
||||
Log.ForContext<ReservedUnknown>().Debug("Lock can not be opened. lock reports state closed. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
AppResources.ErrorOpenLockStillClosedMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<ReservedUnknown>().Error("Lock can not be opened. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorOpenLockTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
// When bold is blocked lock is still closed even if exception occurres.
|
||||
// In all other cases state is supposed to be unknown. Example: Lock is out of reach and no more bluetooth connected.
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextReadingChargingLevel;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.BatteryPercentage = await LockService[SelectedBike.LockInfo.Id].GetBatteryPercentageAsync();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (exception is OutOfReachException)
|
||||
{
|
||||
Log.ForContext<ReservedUnknown>().Debug("Akkustate can not be read, bike out of range. {Exception}", exception);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorReadingChargingLevelOutOfReach;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<ReservedUnknown>().Error("Akkustate can not be read. {Exception}", exception);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorReadingChargingLevelGeneral;
|
||||
}
|
||||
}
|
||||
|
||||
// Lock list to avoid multiple taps while copri action is pending.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdatingLockingState;
|
||||
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
||||
try
|
||||
{
|
||||
await ConnectorFactory(IsConnected).Command.UpdateLockingStateAsync(SelectedBike);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (exception is WebConnectFailureException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<ReservedUnknown>().Information("User locked bike {bike} in order to pause ride but updating failed (Copri server not reachable).", SelectedBike);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorNoWebUpdateingLockstate;
|
||||
}
|
||||
else if (exception is ResponseException copriException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<ReservedUnknown>().Information("User locked bike {bike} in order to pause ride but updating failed. {response}.", SelectedBike, copriException.Response);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorStatusUpdateingLockstate;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<ReservedUnknown>().Error("User locked bike {bike} in order to pause ride but updating failed . {@l_oException}", SelectedBike.Id, exception);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorConnectionUpdateingLockstate;
|
||||
}
|
||||
}
|
||||
|
||||
Log.ForContext<ReservedUnknown>().Information("User paused ride using {bike} successfully.", SelectedBike);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
/// <summary> Close lock in order to pause ride and update COPRI lock state.</summary>
|
||||
public async Task<IRequestHandler> HandleRequestOption2() => await CloseLock();
|
||||
|
||||
|
||||
/// <summary> Close lock in order to pause ride and update COPRI lock state.</summary>
|
||||
public async Task<IRequestHandler> CloseLock()
|
||||
{
|
||||
// Unlock bike.
|
||||
BikesViewModel.IsIdle = false;
|
||||
|
||||
Log.ForContext<ReservedUnknown>().Information("User request to lock bike {bike} in order to pause ride.", SelectedBike);
|
||||
|
||||
// Start getting geolocation.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationStart;
|
||||
var ctsLocation = new CancellationTokenSource();
|
||||
Task<Location> currentLocationTask = null;
|
||||
var timeStamp = DateTime.Now;
|
||||
try
|
||||
{
|
||||
currentLocationTask = Geolocation.GetAsync(ctsLocation.Token, timeStamp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<ReservedUnknown>().Information("Returning bike {Bike} is not possible. Start query location failed. {Exception}", SelectedBike, ex);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorQueryLocationQuery;
|
||||
}
|
||||
|
||||
// Stop polling before returning bike.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||
await ViewUpdateManager().StopUpdatePeridically();
|
||||
|
||||
// Close lock
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextClosingLock;
|
||||
try
|
||||
{
|
||||
SelectedBike.LockInfo.State = (await LockService[SelectedBike.LockInfo.Id].CloseAsync())?.GetLockingState() ?? LockingState.UnknownDisconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
|
||||
// Signal cts to cancel getting geolocation.
|
||||
ctsLocation.Cancel();
|
||||
|
||||
if (exception is OutOfReachException)
|
||||
{
|
||||
Log.ForContext<ReservedUnknown>().Debug("Lock can not be closed. {Exception}", exception);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockOutOfReachMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CounldntCloseMovingException)
|
||||
{
|
||||
Log.ForContext<ReservedUnknown>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockMovingMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else if (exception is CouldntCloseBoldBlockedException)
|
||||
{
|
||||
Log.ForContext<ReservedUnknown>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
AppResources.ErrorCloseLockBoldBlockedMessage,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<ReservedUnknown>().Error("Lock can not be closed. {Exception}", exception);
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.ErrorCloseLockTitle,
|
||||
exception.Message,
|
||||
AppResources.MessageAnswerOk);
|
||||
}
|
||||
|
||||
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||
? stateAwareException.State
|
||||
: LockingState.UnknownDisconnected;
|
||||
|
||||
// Wait until cancel getting geolocation has completed.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<ReservedUnknown>().Information("Canceling query location failed on closing lock error. {Exception}", SelectedBike, ex);
|
||||
}
|
||||
|
||||
// Wait until cancel getting geolocation has completed.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationCancelWait;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<ReservedUnknown>().Information("Canceling query location failed on closing lock error. {Exception}", SelectedBike, ex);
|
||||
}
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
|
||||
// Get geoposition.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocation;
|
||||
Location currentLocation = null;
|
||||
try
|
||||
{
|
||||
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
|
||||
currentLocation = currentLocationTask?.Result ?? null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<ReservedUnknown>().Information("Returning bike {Bike} is not possible. {Exception}", SelectedBike, ex);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorQueryLocationWhenAny;
|
||||
}
|
||||
|
||||
// Lock list to avoid multiple taps while copri action is pending.
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdatingLockingState;
|
||||
|
||||
IsConnected = IsConnectedDelegate();
|
||||
|
||||
try
|
||||
{
|
||||
await ConnectorFactory(IsConnected).Command.UpdateLockingStateAsync(
|
||||
SelectedBike,
|
||||
currentLocation != null
|
||||
? new LocationDto.Builder
|
||||
{
|
||||
Latitude = currentLocation.Latitude,
|
||||
Longitude = currentLocation.Longitude,
|
||||
Accuracy = currentLocation.Accuracy ?? double.NaN,
|
||||
Age = timeStamp.Subtract(currentLocation.Timestamp.DateTime),
|
||||
}.Build()
|
||||
: null);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (exception is WebConnectFailureException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<ReservedUnknown>().Information("User locked bike {bike} in order to pause ride but updating failed (Copri server not reachable).", SelectedBike);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorNoWebUpdateingLockstate;
|
||||
}
|
||||
else if (exception is ResponseException copriException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<ReservedUnknown>().Information("User locked bike {bike} in order to pause ride but updating failed. Message: {Message} Details: {Details}", SelectedBike, copriException.Message, copriException.Response);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorStatusUpdateingLockstate;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<ReservedUnknown>().Error("User locked bike {bike} in order to pause ride but updating failed. {@l_oException}", SelectedBike.Id, exception);
|
||||
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextErrorConnectionUpdateingLockstate;
|
||||
}
|
||||
}
|
||||
|
||||
Log.ForContext<ReservedUnknown>().Information("User paused ride using {bike} successfully.", SelectedBike);
|
||||
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||
BikesViewModel.ActionText = string.Empty;
|
||||
BikesViewModel.IsIdle = true;
|
||||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
using TINK.Model.Bike.BluetoothLock;
|
||||
using TINK.Model.Connector;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.View;
|
||||
using TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
|
||||
using TINK.Model.User;
|
||||
|
@ -59,7 +59,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
|
|||
string.Format(AppResources.MarkingBikeInfoErrorStateDisposableClosedDetected, selectedBluetoothLockBike.Description));
|
||||
|
||||
case LockingState.Open:
|
||||
case LockingState.Unknown:
|
||||
case LockingState.UnknownFromHardwareError:
|
||||
// Unexepected state detected.
|
||||
/// This state is unexpected because
|
||||
/// - app does not allow to return bike/ cancel reservation when lock is closed
|
||||
|
@ -117,7 +117,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
|
|||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
case LockingState.Disconnected:
|
||||
case LockingState.UnknownDisconnected:
|
||||
return new ReservedDisconnected(
|
||||
selectedBluetoothLockBike,
|
||||
isConnectedDelegate,
|
||||
|
@ -146,7 +146,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
|
|||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
case LockingState.Unknown:
|
||||
case LockingState.UnknownFromHardwareError:
|
||||
// User wants to return bike/ pause ride.
|
||||
return new ReservedUnknown(
|
||||
selectedBluetoothLockBike,
|
||||
|
@ -198,7 +198,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
|
|||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
case LockingState.Unknown:
|
||||
case LockingState.UnknownFromHardwareError:
|
||||
// User wants to return bike/ pause ride.
|
||||
return new BookedUnknown(
|
||||
selectedBluetoothLockBike,
|
||||
|
|
|
@ -28,13 +28,9 @@ namespace TINK.ViewModel.Bikes.Bike
|
|||
return string.Empty;
|
||||
|
||||
// Up to version MessageBikesManagementTariffDescriptionTariffHeaderNameId
|
||||
#if USCSHARP9
|
||||
return string.Format(AppResources.MessageBikesManagementTariffDescriptionTariffHeader, Tariff?.Name ?? "-");
|
||||
#else
|
||||
return string.Format(AppResources.MessageBikesManagementTariffDescriptionTariffHeader, Tariff?.Name ?? "-");
|
||||
#endif
|
||||
}
|
||||
return Tariff?.Name ?? "-";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Costs per hour in euro.
|
||||
|
|
|
@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
|||
using TINK.Model.Bike;
|
||||
using TINK.Model.Connector;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Model.User;
|
||||
using TINK.View;
|
||||
using TINK.ViewModel.Bikes.Bike;
|
||||
|
@ -381,9 +381,7 @@ namespace TINK.ViewModel.Bikes
|
|||
if (Exception != null)
|
||||
{
|
||||
// An error occurred getting data from copri.
|
||||
return IsReportLevelVerbose
|
||||
? Exception.GetShortErrorInfoText()
|
||||
: AppResources.ActivityTextException;
|
||||
return Exception.GetShortErrorInfoText(IsReportLevelVerbose);
|
||||
}
|
||||
|
||||
if (!IsConnected)
|
||||
|
|
|
@ -15,7 +15,7 @@ using System.Linq;
|
|||
using TINK.Model.Bike.BluetoothLock;
|
||||
using System.Collections.Generic;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.ViewModel.Bikes;
|
||||
using TINK.Services.BluetoothLock.Tdo;
|
||||
using Plugin.BLE.Abstractions.Contracts;
|
||||
|
@ -145,7 +145,7 @@ namespace TINK.ViewModel.BikesAtStation
|
|||
#if USEFLYOUT
|
||||
=> new Xamarin.Forms.Command(() => OpenSupportPageAsync());
|
||||
#else
|
||||
=> new Xamarin.Forms.Command(async () => await OpenLoginPageAsync());
|
||||
=> new Xamarin.Forms.Command(async () => await OpenSupportPageAsync());
|
||||
#endif
|
||||
|
||||
/// <summary> Command object to bind login page redirect link to view model.</summary>
|
||||
|
@ -194,7 +194,7 @@ namespace TINK.ViewModel.BikesAtStation
|
|||
#if USEFLYOUT
|
||||
ViewService.ShowPage(ViewTypes.ContactPage, AppResources.MarkingFeedbackAndContact);
|
||||
#else
|
||||
await ViewService.ShowPage("//LoginPage");
|
||||
await ViewService.ShowPage("//ContactPage");
|
||||
#endif
|
||||
}
|
||||
catch (Exception p_oException)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using TINK.Model.Services.CopriApi.ServerUris;
|
||||
|
@ -14,27 +15,33 @@ using Xamarin.Forms;
|
|||
namespace TINK.ViewModel.Info
|
||||
{
|
||||
/// <summary> View model for contact page.</summary>
|
||||
public class ContactPageViewModel
|
||||
public class ContactPageViewModel : INotifyPropertyChanged
|
||||
{
|
||||
/// <summary> Reference on view service to show modal notifications and to perform navigation. </summary>
|
||||
private IViewService ViewService { get; }
|
||||
|
||||
/// <summary> Station selected by user. </summary>
|
||||
private IStation SelectedStation;
|
||||
private IStation SelectedStation { get; set; } = new NullStation();
|
||||
|
||||
Uri ActiveUri { get; }
|
||||
|
||||
/// <summary> Holds the name of the app (sharee.bike, Mein konrad, ...)</summary>
|
||||
string AppName { get; }
|
||||
|
||||
/// <summary> Holds a reference to the external trigger service. </summary>
|
||||
private Action OpenUrlInExternalBrowser { get; }
|
||||
|
||||
Func<string> CreateAttachment { get; }
|
||||
|
||||
/// <summary> Notifies view about changes. </summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
/// <summary> Constructs a contact page view model. </summary>
|
||||
/// <param name="openUrlInExternalBrowser">Action to open an external browser.</param>
|
||||
/// <param name="viewService">View service to notify user.</param>
|
||||
public ContactPageViewModel(
|
||||
IStation selectedStation,
|
||||
Uri activeUri,
|
||||
string appName,
|
||||
Func<string> createAttachment,
|
||||
Action openUrlInExternalBrowser,
|
||||
IViewService viewService)
|
||||
|
@ -42,6 +49,10 @@ namespace TINK.ViewModel.Info
|
|||
ActiveUri = activeUri
|
||||
?? throw new ArgumentException("Can not instantiate contact page view model- object. No active uri available.");
|
||||
|
||||
AppName = !string.IsNullOrEmpty(appName)
|
||||
? appName
|
||||
: throw new ArgumentException("Can not instantiate contact page view model- object. No app name availalbe.");
|
||||
|
||||
CreateAttachment = createAttachment
|
||||
?? throw new ArgumentException("Can not instantiate contact page view model- object. No create attachment provider available.");
|
||||
|
||||
|
@ -50,9 +61,27 @@ namespace TINK.ViewModel.Info
|
|||
|
||||
OpenUrlInExternalBrowser = openUrlInExternalBrowser
|
||||
?? throw new ArgumentException("Can not instantiate contact page view model- object. No user external browse service available.");
|
||||
}
|
||||
|
||||
/// <summary> Is invoked when page is shown. </summary>
|
||||
public async Task OnAppearing(
|
||||
IStation selectedStation)
|
||||
{
|
||||
if (SelectedStation?.Id == selectedStation?.Id)
|
||||
{
|
||||
// Nothing to do because either both are null or of same id.
|
||||
return;
|
||||
}
|
||||
|
||||
// Station might be null-station, if no station info is avialable.
|
||||
SelectedStation = selectedStation;
|
||||
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MailAddressText)));
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(OfficeHoursText)));
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(PhoneNumberText)));
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ProviderNameText)));
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsOperatorInfoAvaliable)));
|
||||
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary> Command object to bind login button to view model. </summary>
|
||||
|
@ -186,7 +215,7 @@ namespace TINK.ViewModel.Info
|
|||
#if USEFLYOUT
|
||||
ViewService.PushAsync(ViewTypes.SelectStationPage);
|
||||
#else
|
||||
await ViewService.ShowPage("//SelectStationPage");
|
||||
await ViewService.PushAsync(ViewTypes.SelectStationPage);
|
||||
#endif
|
||||
}
|
||||
catch (Exception p_oException)
|
||||
|
@ -249,7 +278,7 @@ namespace TINK.ViewModel.Info
|
|||
get
|
||||
{
|
||||
var l_oHint = new FormattedString();
|
||||
l_oHint.Spans.Add(new Span { Text = string.Format(AppResources.MessageRateMail, GetAppName(ActiveUri)) });
|
||||
l_oHint.Spans.Add(new Span { Text = string.Format(AppResources.MessageRateMail, AppName) });
|
||||
return l_oHint;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ using System.Threading;
|
|||
using TINK.MultilingualResources;
|
||||
using TINK.ViewModel.Info;
|
||||
using TINK.Repository;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Services.Geolocation;
|
||||
|
||||
namespace TINK.ViewModel.Contact
|
||||
{
|
||||
|
@ -85,7 +85,7 @@ namespace TINK.ViewModel.Contact
|
|||
/// <summary> False if user tabed on station marker to show bikes at a given station.</summary>
|
||||
private bool isMapPageEnabled = false;
|
||||
|
||||
Model.Services.Geolocation.IGeolocation GeolocationService { get; }
|
||||
IGeolocation GeolocationService { get; }
|
||||
|
||||
/// <summary> False if user tabed on station marker to show bikes at a given station.</summary>
|
||||
public bool IsMapPageEnabled
|
||||
|
@ -628,9 +628,8 @@ namespace TINK.ViewModel.Contact
|
|||
if (Exception != null)
|
||||
{
|
||||
// An error occurred getting data from copri.
|
||||
return TinkApp.IsReportLevelVerbose
|
||||
? Exception.GetShortErrorInfoText()
|
||||
: AppResources.ActivityTextException;
|
||||
return Exception.GetShortErrorInfoText(TinkApp.IsReportLevelVerbose);
|
||||
|
||||
}
|
||||
|
||||
if (!IsConnected)
|
||||
|
|
|
@ -13,7 +13,7 @@ using TINK.Settings;
|
|||
using TINK.Model.Bike.BluetoothLock;
|
||||
using System.Collections.Generic;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Services.Geolocation;
|
||||
using System.Linq;
|
||||
using TINK.Model;
|
||||
using Xamarin.Forms;
|
||||
|
|
|
@ -25,7 +25,7 @@ using TINK.MultilingualResources;
|
|||
using TINK.Services.BluetoothLock;
|
||||
using TINK.ViewModel.Info;
|
||||
using TINK.Repository;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Services.Geolocation;
|
||||
|
||||
#if !TRYNOTBACKSTYLE
|
||||
#endif
|
||||
|
@ -60,7 +60,6 @@ namespace TINK.ViewModel.Map
|
|||
/// </summary>
|
||||
private Plugin.BLE.Abstractions.Contracts.IBluetoothLE BluetoothService { get; set; }
|
||||
|
||||
|
||||
/// <summary> Notifies view about changes. </summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
|
@ -299,9 +298,6 @@ namespace TINK.ViewModel.Map
|
|||
/// Invoked when page is shown.
|
||||
/// Starts update process.
|
||||
/// </summary>
|
||||
/// <param name="p_oFilterDictionaryMapPage">Holds map page filter settings.</param>
|
||||
/// <param name="p_oPolling">Holds polling management object.</param>
|
||||
/// <param name="p_bIsShowWhatsNewRequired">If true whats new page will be shown.</param>
|
||||
public async Task OnAppearing()
|
||||
{
|
||||
try
|
||||
|
@ -821,9 +817,7 @@ namespace TINK.ViewModel.Map
|
|||
if (Exception != null)
|
||||
{
|
||||
// An error occurred getting data from copri.
|
||||
return TinkApp.IsReportLevelVerbose
|
||||
? Exception.GetShortErrorInfoText()
|
||||
: AppResources.ActivityTextException;
|
||||
return Exception.GetShortErrorInfoText(TinkApp.IsReportLevelVerbose);
|
||||
}
|
||||
|
||||
if (!IsConnected)
|
||||
|
|
|
@ -12,7 +12,7 @@ using TINK.Settings;
|
|||
using TINK.Model.Bike.BluetoothLock;
|
||||
using System.Collections.Generic;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Services.Geolocation;
|
||||
using System.Linq;
|
||||
using TINK.Model;
|
||||
using Xamarin.Forms;
|
||||
|
|
|
@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
|||
using TINK.Model;
|
||||
using TINK.Model.Connector;
|
||||
using TINK.Repository.Exception;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.Settings;
|
||||
using TINK.View;
|
||||
using TINK.ViewModel.Map;
|
||||
|
@ -65,18 +65,12 @@ namespace TINK.ViewModel
|
|||
|
||||
/// <summary> Constructs a settings page view model object.</summary>
|
||||
/// <param name="tinkApp"> Reference to tink app model.</param>
|
||||
/// <param name="p_oUser"></param>
|
||||
/// <param name="p_oDevice"></param>
|
||||
/// <param name="p_oFilterGroup">Filter to apply on stations and bikes.</param>
|
||||
/// <param name="p_oUris">Available copri server host uris including uri to use for next start.</param>
|
||||
/// <param name="p_oPolling"> Holds whether to poll or not and the periode leght is polling is on. </param>
|
||||
/// <param name="p_oDefaultPollingPeriode">Default polling periode lenght.</param>
|
||||
/// <param name="p_oMinimumLogEventLevel">Controls logging level.</param>
|
||||
/// <param name="p_oViewService">Interface to view</param>
|
||||
/// <param name="geoloctionServicesContainer"></param>
|
||||
/// <param name="viewService">Interface to view</param>
|
||||
public SettingsPageViewModel(
|
||||
ITinkApp tinkApp,
|
||||
IServicesContainer<IGeolocation> geoloctionServicesContainer,
|
||||
IViewService p_oViewService)
|
||||
IViewService viewService)
|
||||
{
|
||||
TinkApp = tinkApp
|
||||
?? throw new ArgumentException("Can not instantiate settings page view model- object. No tink app object available.");
|
||||
|
@ -84,7 +78,7 @@ namespace TINK.ViewModel
|
|||
GeoloctionServicesContainer = geoloctionServicesContainer
|
||||
?? throw new ArgumentException($"Can not instantiate {nameof(SettingsPageViewModel)}- object. Geolocation services container object must not be null.");
|
||||
|
||||
m_oViewService = p_oViewService
|
||||
m_oViewService = viewService
|
||||
?? throw new ArgumentException("Can not instantiate settings page view model- object. No user view service available.");
|
||||
|
||||
m_oMinimumLogEventLevel = TinkApp.MinimumLogEventLevel;
|
||||
|
@ -155,8 +149,10 @@ namespace TINK.ViewModel
|
|||
GeolocationServices = new ServicesViewModel(
|
||||
GeoloctionServicesContainer.Select(x => x.GetType().FullName),
|
||||
new Dictionary<string, string> {
|
||||
{ typeof(LastKnownGeolocationService).FullName, "Smartdevice-LastKnowGeolocation" },
|
||||
{ typeof(GeolocationService).FullName, "Smartdevice-MediumAccuracy" },
|
||||
{ typeof(LastKnownGeolocationService).FullName, "LastKnowGeolocation" },
|
||||
{ typeof(GeolocationAccuracyMediumService).FullName, "Medium Accuracy" },
|
||||
{ typeof(GeolocationAccuracyHighService).FullName, "High Accuracy" },
|
||||
{ typeof(GeolocationAccuracyBestService).FullName, "Best Accuracy" },
|
||||
{ typeof(SimulatedGeolocationService).FullName, "Simulation-AlwaysSamePosition" } },
|
||||
GeoloctionServicesContainer.Active.GetType().FullName);
|
||||
}
|
||||
|
@ -323,6 +319,9 @@ namespace TINK.ViewModel
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary> Empty if no user is logged in session cookie otherwise. </summary>
|
||||
public string SessionCookie => TinkApp.ActiveUser.IsLoggedIn ? TinkApp.ActiveUser.SessionCookie : "";
|
||||
|
||||
/// <summary>Polling periode.</summary>
|
||||
public PollingViewModel Polling { get; }
|
||||
|
||||
|
|
|
@ -112,13 +112,22 @@ namespace TINK.ViewModel
|
|||
}
|
||||
|
||||
/// <summary> Gets message that logged in user has not booked any bikes. </summary>
|
||||
public static string GetShortErrorInfoText(this Exception exception)
|
||||
/// <param name="isReportLevelVerbose">Holds whether report level is verbose or not.</param>
|
||||
public static string GetShortErrorInfoText(this Exception exception, bool isReportLevelVerbose)
|
||||
{
|
||||
if (exception == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (exception is AuthcookieNotDefinedException)
|
||||
return AppResources.ActivityTextAuthcookieNotDefinedException;
|
||||
|
||||
if (!isReportLevelVerbose)
|
||||
{
|
||||
return AppResources.ActivityTextException;
|
||||
}
|
||||
|
||||
// An error occurred getting bikes information.
|
||||
#if USCSHARP9
|
||||
switch (exception)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue