Version 3.0.347

This commit is contained in:
ohauff 2022-10-26 20:53:18 +02:00
parent a018f21fea
commit 7f49fb0ac5
41 changed files with 292 additions and 187 deletions

View file

@ -616,13 +616,13 @@ namespace TINK.Model
new List<AppFlavor> { AppFlavor.LastenradBayern }
},
{
new Version(3, 0, 346),
AppResources.ChangeLog_3_0_346_LB_MK,
new Version(3, 0, 347),
AppResources.ChangeLog_3_0_347_LB_MK,
new List<AppFlavor> { AppFlavor.LastenradBayern, AppFlavor.MeinKonrad }
},
{
new Version(3, 0, 346),
AppResources.ChangeLog_3_0_346_SB,
new Version(3, 0, 347),
AppResources.ChangeLog_3_0_347_SB,
new List<AppFlavor> { AppFlavor.ShareeBike }
},
};

View file

@ -669,11 +669,12 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to &lt;i&gt;Select Bike&lt;/i&gt; page revised..
/// Looks up a localized string similar to &lt;i&gt;Select Bike&lt;/i&gt; page revised.&lt;br/&gt;
///Minor improvements.&lt;br/&gt;.
/// </summary>
public static string ChangeLog_3_0_346_LB_MK {
public static string ChangeLog_3_0_347_LB_MK {
get {
return ResourceManager.GetString("ChangeLog_3_0_346_LB_MK", resourceCulture);
return ResourceManager.GetString("ChangeLog_3_0_347_LB_MK", resourceCulture);
}
}
@ -684,11 +685,12 @@ namespace TINK.MultilingualResources {
///&lt;li/&gt;&lt;i&gt;Bike Locations&lt;/i&gt; or
///&lt;li/&gt;&lt;i&gt;Select Bike&lt;/i&gt;
///&lt;/ul&gt;
///page..
///page.&lt;br/&gt;
///Minor improvements.&lt;br/&gt;.
/// </summary>
public static string ChangeLog_3_0_346_SB {
public static string ChangeLog_3_0_347_SB {
get {
return ResourceManager.GetString("ChangeLog_3_0_346_SB", resourceCulture);
return ResourceManager.GetString("ChangeLog_3_0_347_SB", resourceCulture);
}
}
@ -1500,6 +1502,15 @@ namespace TINK.MultilingualResources {
}
}
/// <summary>
/// Looks up a localized string similar to Not connected to network..
/// </summary>
public static string ErrorNotConnectedToNetwork {
get {
return ResourceManager.GetString("ErrorNotConnectedToNetwork", 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>
@ -1721,7 +1732,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Is WIFI available/ mobile networt available and mobile data activated / ... ?.
/// Looks up a localized string similar to Is WIFI available/ mobile network available and mobile data activated / ... ?.
/// </summary>
public static string ExceptionTextWebConnectFailureException {
get {

View file

@ -1066,16 +1066,23 @@ Sie können nun auf einen Blick sehen, welche App-Version Sie installiert haben:
<data name="MarkingStartupPage" xml:space="preserve">
<value>Startseite</value>
</data>
<data name="ChangeLog_3_0_346_LB_MK" xml:space="preserve">
<value>&lt;i&gt;Rad auswählen&lt;/i&gt; Seite überarbeitet.</value>
<data name="ChangeLog_3_0_347_LB_MK" xml:space="preserve">
<value>&lt;i&gt;Rad auswählen&lt;/i&gt; Seite überarbeitet.&lt;br/&gt;
Kleinere Verbesserungen.&lt;br/&gt;
</value>
</data>
<data name="ChangeLog_3_0_346_SB" xml:space="preserve">
<data name="ErrorNotConnectedToNetwork" xml:space="preserve">
<value>Keine Verbindung zum Netzwerk.</value>
</data>
<data name="ChangeLog_3_0_347_SB" xml:space="preserve">
<value>&lt;i&gt;Rad auswählen&lt;/i&gt;- Seite überarbeitet.&lt;br/&gt;
Einstellung hinzugefügt mit der festgelegt werden kann, ob die App mit der Seite
&lt;ul&gt;
&lt;li/&gt;&lt;i&gt;Radstandorte&lt;/i&gt; oder
&lt;li/&gt;&lt;i&gt;Rad auswählen&lt;/i&gt;
&lt;/ul&gt;
gestartet wird.</value>
gestartet wird.&lt;br/&gt;
Kleinere Verbesserungen.&lt;br/&gt;</value>
</data>
</root>

View file

@ -941,7 +941,7 @@ Activity indicator added account management pages and logging extended.</value>
<value>Starting bike return...</value>
</data>
<data name="ExceptionTextWebConnectFailureException" xml:space="preserve">
<value>Is WIFI available/ mobile networt available and mobile data activated / ... ?</value>
<value>Is WIFI available/ mobile network available and mobile data activated / ... ?</value>
</data>
<data name="ChangeLog3_0_289" xml:space="preserve">
<value>Flyout menu header improved.</value>
@ -1158,16 +1158,21 @@ You can now see at a glance which app version you have installed: in the menu at
<data name="MarkingStartupPage" xml:space="preserve">
<value>Startup page</value>
</data>
<data name="ChangeLog_3_0_346_LB_MK" xml:space="preserve">
<value>&lt;i&gt;Select Bike&lt;/i&gt; page revised.</value>
<data name="ChangeLog_3_0_347_LB_MK" xml:space="preserve">
<value>&lt;i&gt;Select Bike&lt;/i&gt; page revised.&lt;br/&gt;
Minor improvements.&lt;br/&gt;</value>
</data>
<data name="ChangeLog_3_0_346_SB" xml:space="preserve">
<data name="ChangeLog_3_0_347_SB" xml:space="preserve">
<value>&lt;i&gt;Select Bike&lt;/i&gt;- page revised.&lt;br/&gt;
Setting added to select whether the app starts up showing either
&lt;ul&gt;
&lt;li/&gt;&lt;i&gt;Bike Locations&lt;/i&gt; or
&lt;li/&gt;&lt;i&gt;Select Bike&lt;/i&gt;
&lt;/ul&gt;
page.</value>
page.&lt;br/&gt;
Minor improvements.&lt;br/&gt;</value>
</data>
<data name="ErrorNotConnectedToNetwork" xml:space="preserve">
<value>Not connected to network.</value>
</data>
</root>

View file

@ -1145,7 +1145,7 @@ Activity Indicator zu Konto-Verwaltungsseiten hinzugefügt und Logging erweitert
<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>
<source>Is WIFI available/ mobile network 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">
@ -1450,25 +1450,35 @@ Sie können nun auf einen Blick sehen, welche App-Version Sie installiert haben:
<source>Startup page</source>
<target state="translated">Startseite</target>
</trans-unit>
<trans-unit id="ChangeLog_3_0_346_LB_MK" translate="yes" xml:space="preserve">
<source><bpt id="1">&lt;i&gt;</bpt>Select Bike<ept id="1">&lt;/i&gt;</ept> page revised.</source>
<target state="translated"><bpt id="1">&lt;i&gt;</bpt>Rad auswählen<ept id="1">&lt;/i&gt;</ept> Seite überarbeitet.</target>
<trans-unit id="ChangeLog_3_0_347_LB_MK" translate="yes" xml:space="preserve">
<source><bpt id="1">&lt;i&gt;</bpt>Select Bike<ept id="1">&lt;/i&gt;</ept> page revised.&lt;br/&gt;
Minor improvements.&lt;br/&gt;</source>
<target state="translated"><bpt id="1">&lt;i&gt;</bpt>Rad auswählen<ept id="1">&lt;/i&gt;</ept> Seite überarbeitet.&lt;br/&gt;
Kleinere Verbesserungen.&lt;br/&gt;
</target>
</trans-unit>
<trans-unit id="ChangeLog_3_0_346_SB" translate="yes" xml:space="preserve">
<trans-unit id="ErrorNotConnectedToNetwork" translate="yes" xml:space="preserve">
<source>Not connected to network.</source>
<target state="translated">Keine Verbindung zum Netzwerk.</target>
</trans-unit>
<trans-unit id="ChangeLog_3_0_347_SB" translate="yes" xml:space="preserve">
<source><bpt id="1">&lt;i&gt;</bpt>Select Bike<ept id="1">&lt;/i&gt;</ept>- page revised.&lt;br/&gt;
Setting added to select whether the app starts up showing either
<bpt id="2">&lt;ul&gt;</bpt>
&lt;li/&gt;<bpt id="3">&lt;i&gt;</bpt>Bike Locations<ept id="3">&lt;/i&gt;</ept> or
&lt;li/&gt;<bpt id="4">&lt;i&gt;</bpt>Select Bike<ept id="4">&lt;/i&gt;</ept>
<ept id="2">&lt;/ul&gt;</ept>
page.</source>
<target state="translated"><bpt id="1">&lt;i&gt;</bpt>Rad auswählen<ept id="1">&lt;/i&gt;</ept>- Seite überarbeitet.&lt;br/&gt;
page.&lt;br/&gt;
Minor improvements.&lt;br/&gt;</source>
<target state="translated">&lt;i&gt;Rad auswählen&lt;/i&gt;- Seite überarbeitet.&lt;br/&gt;
Einstellung hinzugefügt mit der festgelegt werden kann, ob die App mit der Seite
<bpt id="2">&lt;ul&gt;</bpt>
&lt;li/&gt;<bpt id="3">&lt;i&gt;</bpt>Radstandorte<ept id="3">&lt;/i&gt;</ept> oder
&lt;li/&gt;<bpt id="4">&lt;i&gt;</bpt>Rad auswählen<ept id="4">&lt;/i&gt;</ept>
<ept id="2">&lt;/ul&gt;</ept>
gestartet wird.</target>
&lt;ul&gt;
&lt;li/&gt;&lt;i&gt;Radstandorte&lt;/i&gt; oder
&lt;li/&gt;&lt;i&gt;Rad auswählen&lt;/i&gt;
&lt;/ul&gt;
gestartet wird.&lt;br/&gt;
Kleinere Verbesserungen.&lt;br/&gt;</target>
</trans-unit>
</group>
</body>

View file

@ -212,14 +212,10 @@ namespace TINK.Model.Services.CopriApi
}
public async Task<ReservationBookingResponse> DoReserveAsync(string bikeId, Uri operatorUri)
{
return await HttpsServer.DoReserveAsync(bikeId, operatorUri);
}
=> await HttpsServer.DoReserveAsync(bikeId, operatorUri);
public async Task<ReservationCancelReturnResponse> DoCancelReservationAsync(string bikeId, Uri operatorUri)
{
return await HttpsServer.DoCancelReservationAsync(bikeId, operatorUri);
}
=> await HttpsServer.DoCancelReservationAsync(bikeId, operatorUri);
public async Task<ReservationBookingResponse> CalculateAuthKeysAsync(string bikeId, Uri operatorUri)
{

View file

@ -6,6 +6,7 @@ using TINK.Model.Device;
using TINK.Repository;
using TINK.Repository.Request;
using TINK.Repository.Response;
using TINK.Services.CopriApi.Exception;
namespace TINK.Model.Services.CopriApi
{
@ -35,13 +36,13 @@ namespace TINK.Model.Services.CopriApi
public string MerchantId => monkeyStore.MerchantId;
public Task<ReservationBookingResponse> DoReserveAsync(string bikeId, Uri operatorUri)
=> throw new NotSupportedException($"{nameof(DoReserveAsync)} is not cachable.");
=> throw new RequestNotCachableException(nameof(DoReserveAsync));
public Task<ReservationCancelReturnResponse> DoCancelReservationAsync(string bikeId, Uri operatorUri)
=> throw new NotSupportedException($"{nameof(DoCancelReservationAsync)} is not cachable.");
=> throw new RequestNotCachableException(nameof(DoCancelReservationAsync));
public Task<ReservationBookingResponse> CalculateAuthKeysAsync(string bikeId, Uri operatorUri)
=> throw new NotSupportedException($"{nameof(CalculateAuthKeysAsync)} is not cachable.");
=> throw new RequestNotCachableException(nameof(CalculateAuthKeysAsync));
public async Task<ResponseBase> StartReturningBike(
string bikeId,
@ -65,9 +66,7 @@ namespace TINK.Model.Services.CopriApi
versionInfo);
public async Task<ReservationBookingResponse> DoBookAsync(string bikeId, Guid guid, double batteryPercentage, Uri operatorUri)
{
return await monkeyStore.DoBookAsync(bikeId, guid, batteryPercentage, operatorUri);
}
=> await monkeyStore.DoBookAsync(bikeId, guid, batteryPercentage, operatorUri);
public async Task<ReservationBookingResponse> BookAvailableAndStartOpeningAsync(
string bikeId,
@ -93,37 +92,26 @@ namespace TINK.Model.Services.CopriApi
=> await monkeyStore.ReturnAndStartClosingAsync(bikeId, smartDevice, operatorUri);
public Task<SubmitFeedbackResponse> DoSubmitFeedback(string bikeId, int? currentChargeBars, string messge, bool bIsBikeBroke, Uri operatorUri)
=> throw new NotImplementedException();
=> throw new RequestNotCachableException(nameof(DoSubmitFeedback));
/// <summary> Submits mini survey to copri server. </summary>
/// <param name="answers">Collection of answers.</param>
public Task<ResponseBase> DoSubmitMiniSurvey(IDictionary<string, string> answers)
=> throw new NotSupportedException();
=> throw new RequestNotCachableException(nameof(DoSubmitMiniSurvey));
public async Task<AuthorizationResponse> DoAuthorizationAsync(string p_strMailAddress, string p_strPassword, string p_strDeviceId)
{
return await monkeyStore.DoAuthorizationAsync(p_strMailAddress, p_strPassword, p_strDeviceId);
}
=> await monkeyStore.DoAuthorizationAsync(p_strMailAddress, p_strPassword, p_strDeviceId);
public async Task<AuthorizationoutResponse> DoAuthoutAsync()
{
return await monkeyStore.DoAuthoutAsync();
}
=> await monkeyStore.DoAuthoutAsync();
public async Task<BikesAvailableResponse> GetBikesAvailableAsync()
{
return await monkeyStore.GetBikesAvailableAsync();
}
=> await monkeyStore.GetBikesAvailableAsync();
public async Task<BikesReservedOccupiedResponse> GetBikesOccupiedAsync()
{
return await monkeyStore.GetBikesOccupiedAsync();
}
=> await monkeyStore.GetBikesOccupiedAsync();
public async Task<StationsAvailableResponse> GetStationsAsync()
{
return await monkeyStore.GetStationsAsync();
}
=> await monkeyStore.GetStationsAsync();
}
}

View file

@ -0,0 +1,12 @@
using TINK.MultilingualResources;
namespace TINK.Services.CopriApi.Exception
{
public class RequestNotCachableException : System.Exception
{
public RequestNotCachableException(string nameOfAction) : base(AppResources.ErrorNotConnectedToNetwork, new System.Exception($"{nameOfAction} is not cacheable."))
{
}
}
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Threading.Tasks;
using Serilog;
using TINK.Model.Connector;
@ -7,6 +7,7 @@ using TINK.Model.State;
using TINK.Model.User;
using TINK.MultilingualResources;
using TINK.Repository.Exception;
using TINK.Services.CopriApi.Exception;
using TINK.View;
using BikeInfoMutable = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfoMutable;
@ -59,20 +60,21 @@ namespace TINK.ViewModel.Bikes.Bike.BC.RequestHandler
{
await ConnectorFactory(IsConnected).Command.DoReserve(SelectedBike);
}
catch (Exception l_oException)
catch (Exception exception)
{
if (l_oException is BookingDeclinedException)
if (exception is BookingDeclinedException)
{
// Too many bikes booked.
Log.ForContext<Disposable>().Information("Request declined because maximum count of bikes {l_oException.MaxBikesCount} already requested/ booked.", (l_oException as BookingDeclinedException).MaxBikesCount);
Log.ForContext<Disposable>().Information("Request declined because maximum count of bikes {l_oException.MaxBikesCount} already requested/ booked.", (exception as BookingDeclinedException).MaxBikesCount);
BikesViewModel.ActionText = string.Empty;
await ViewService.DisplayAlert(
AppResources.MessageTitleHint,
string.Format(AppResources.MessageReservationBikeErrorTooManyReservationsRentals, SelectedBike.Id, (l_oException as BookingDeclinedException).MaxBikesCount),
string.Format(AppResources.MessageReservationBikeErrorTooManyReservationsRentals, SelectedBike.Id, (exception as BookingDeclinedException).MaxBikesCount),
AppResources.MessageAnswerOk);
}
else if (l_oException is WebConnectFailureException)
else if (exception is WebConnectFailureException
|| exception is RequestNotCachableException)
{
// Copri server is not reachable.
Log.ForContext<Disposable>().Information("User selected availalbe bike {l_oId} but reserving failed (Copri server not reachable).", SelectedBike.Id);
@ -80,15 +82,15 @@ namespace TINK.ViewModel.Bikes.Bike.BC.RequestHandler
BikesViewModel.ActionText = string.Empty;
await ViewService.DisplayAlert(
AppResources.MessageReservingBikeErrorConnectionTitle,
string.Format("{0}\r\n{1}", l_oException.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
string.Format("{0}\r\n{1}", exception.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
AppResources.MessageAnswerOk);
}
else
{
Log.ForContext<Disposable>().Error("User selected availalbe bike {l_oId} but reserving failed. {@l_oException}", SelectedBike.Id, l_oException);
Log.ForContext<Disposable>().Error("User selected availalbe bike {l_oId} but reserving failed. {@l_oException}", SelectedBike.Id, exception);
BikesViewModel.ActionText = string.Empty;
await ViewService.DisplayAlert(AppResources.MessageReservingBikeErrorGeneralTitle, l_oException.Message, AppResources.MessageAnswerOk);
await ViewService.DisplayAlert(AppResources.MessageReservingBikeErrorGeneralTitle, exception.Message, AppResources.MessageAnswerOk);
}
BikesViewModel.ActionText = string.Empty; // Todo: Remove this statement because in catch block ActionText is already set to empty above.

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Threading.Tasks;
using Serilog;
using TINK.Model.Connector;
@ -6,6 +6,7 @@ using TINK.Model.Device;
using TINK.Model.User;
using TINK.MultilingualResources;
using TINK.Repository.Exception;
using TINK.Services.CopriApi.Exception;
using TINK.View;
using BikeInfoMutable = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfoMutable;
@ -63,34 +64,35 @@ namespace TINK.ViewModel.Bikes.Bike.BC.RequestHandler
// If canceling bike succedes remove bike because it is not ready to be booked again
IsRemoveBikeRequired = true;
}
catch (Exception l_oException)
catch (Exception exception)
{
if (l_oException is InvalidAuthorizationResponseException)
if (exception is InvalidAuthorizationResponseException)
{
// Copri response is invalid.
Log.ForContext<Reserved>().Error("User selected reserved bike {l_oId} but canceling reservation failed (Invalid auth. response).", SelectedBike.Id);
BikesViewModel.ActionText = String.Empty;
await ViewService.DisplayAlert("Fehler beim Stornieren der Buchung!", l_oException.Message, "OK");
await ViewService.DisplayAlert("Fehler beim Stornieren der Buchung!", exception.Message, "OK");
BikesViewModel.IsIdle = true;
return this;
}
else if (l_oException is WebConnectFailureException)
else if (exception is WebConnectFailureException
|| exception is RequestNotCachableException)
{
// Copri server is not reachable.
Log.ForContext<Reserved>().Information("User selected reserved bike {l_oId} but cancel reservation failed (Copri server not reachable).", SelectedBike.Id);
BikesViewModel.ActionText = String.Empty;
await ViewService.DisplayAlert(
"Verbingungsfehler beim Stornieren der Buchung!",
string.Format("{0}\r\n{1}", l_oException.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
string.Format("{0}\r\n{1}", exception.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
"OK");
BikesViewModel.IsIdle = true;
return this;
}
else
{
Log.ForContext<Reserved>().Error("User selected reserved bike {l_oId} but cancel reservation failed. {@l_oException}.", SelectedBike.Id, l_oException);
Log.ForContext<Reserved>().Error("User selected reserved bike {l_oId} but cancel reservation failed. {@l_oException}.", SelectedBike.Id, exception);
BikesViewModel.ActionText = String.Empty;
await ViewService.DisplayAlert("Fehler beim Stornieren der Buchung!", l_oException.Message, "OK");
await ViewService.DisplayAlert("Fehler beim Stornieren der Buchung!", exception.Message, "OK");
BikesViewModel.IsIdle = true;
return this;
}

View file

@ -57,7 +57,6 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
/// <summary> Open bike and update COPRI lock state. </summary>
public async Task<IRequestHandler> HandleRequestOption2() => await OpenLock();
/// <summary> Return bike. </summary>
public async Task<IRequestHandler> ReturnBike()
{

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Threading.Tasks;
using Serilog;
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock;
@ -10,6 +10,7 @@ using TINK.Repository.Exception;
using TINK.Services.BluetoothLock;
using TINK.Services.BluetoothLock.Exception;
using TINK.Services.BluetoothLock.Tdo;
using TINK.Services.CopriApi.Exception;
using TINK.Services.Geolocation;
using TINK.View;
@ -85,7 +86,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
BikesViewModel.ActionText = string.Empty;
if (exception is WebConnectFailureException)
if (exception is WebConnectFailureException
|| exception is RequestNotCachableException)
{
// 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);

View file

@ -11,6 +11,7 @@ using TINK.Repository.Exception;
using TINK.Services.BluetoothLock;
using TINK.Services.BluetoothLock.Exception;
using TINK.Services.BluetoothLock.Tdo;
using TINK.Services.CopriApi.Exception;
using TINK.Services.Geolocation;
using TINK.View;
@ -101,7 +102,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
string.Format(AppResources.MessageReservationBikeErrorTooManyReservationsRentals, SelectedBike.Id, (exception as BookingDeclinedException).MaxBikesCount),
AppResources.MessageAnswerOk);
}
else if (exception is WebConnectFailureException)
else if (exception is WebConnectFailureException
|| exception is RequestNotCachableException)
{
// Copri server is not reachable.
Log.ForContext<DisposableDisconnected>().Information("User selected availalbe bike {bike} but reserving failed (Copri server not reachable).", SelectedBike);

View file

@ -9,6 +9,7 @@ using TINK.MultilingualResources;
using TINK.Repository.Exception;
using TINK.Services.BluetoothLock;
using TINK.Services.BluetoothLock.Exception;
using TINK.Services.CopriApi.Exception;
using TINK.Services.Geolocation;
using TINK.View;
using IBikeInfoMutable = TINK.Model.Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable;
@ -93,35 +94,36 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
// If canceling bike succedes remove bike because it is not ready to be booked again
IsRemoveBikeRequired = true;
}
catch (Exception l_oException)
catch (Exception exception)
{
BikesViewModel.ActionText = string.Empty;
if (l_oException is InvalidAuthorizationResponseException)
if (exception is InvalidAuthorizationResponseException)
{
// Copri response is invalid.
Log.ForContext<BikesViewModel>().Error("User selected reserved bike {l_oId} but canceling reservation failed (Invalid auth. response).", SelectedBike.Id);
await ViewService.DisplayAlert(
AppResources.MessageCancelReservationBikeErrorGeneralTitle,
l_oException.Message,
exception.Message,
AppResources.MessageAnswerOk);
}
else if (l_oException is WebConnectFailureException)
else if (exception is WebConnectFailureException
|| exception is RequestNotCachableException)
{
// Copri server is not reachable.
Log.ForContext<BikesViewModel>().Information("User selected reserved bike {l_oId} but cancel reservation failed (Copri server not reachable).", SelectedBike.Id);
await ViewService.DisplayAlert(
AppResources.MessageCancelReservationBikeErrorConnectionTitle,
string.Format("{0}\r\n{1}", l_oException.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
string.Format("{0}\r\n{1}", exception.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
AppResources.MessageAnswerOk);
}
else
{
Log.ForContext<BikesViewModel>().Error("User selected reserved bike {l_oId} but cancel reservation failed. {@l_oException}.", SelectedBike.Id, l_oException);
Log.ForContext<BikesViewModel>().Error("User selected reserved bike {l_oId} but cancel reservation failed. {@l_oException}.", SelectedBike.Id, exception);
await ViewService.DisplayAlert(
AppResources.MessageCancelReservationBikeErrorGeneralTitle,
l_oException.Message,
exception.Message,
AppResources.MessageAnswerOk);
}

View file

@ -10,6 +10,7 @@ using TINK.Repository.Exception;
using TINK.Services.BluetoothLock;
using TINK.Services.BluetoothLock.Exception;
using TINK.Services.BluetoothLock.Tdo;
using TINK.Services.CopriApi.Exception;
using TINK.Services.Geolocation;
using TINK.View;
@ -88,33 +89,34 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
// If canceling bike succedes remove bike because it is not ready to be booked again
IsRemoveBikeRequired = true;
}
catch (Exception l_oException)
catch (Exception exception)
{
BikesViewModel.ActionText = string.Empty;
if (l_oException is InvalidAuthorizationResponseException)
if (exception is InvalidAuthorizationResponseException)
{
// Copri response is invalid.
Log.ForContext<ReservedDisconnected>().Error("User selected reserved bike {l_oId} but canceling reservation failed (Invalid auth. response).", SelectedBike.Id);
await ViewService.DisplayAlert(
AppResources.MessageCancelReservationBikeErrorGeneralTitle,
l_oException.Message,
exception.Message,
AppResources.MessageAnswerOk);
}
else if (l_oException is WebConnectFailureException)
else if (exception is WebConnectFailureException
|| exception is RequestNotCachableException)
{
// Copri server is not reachable.
Log.ForContext<ReservedDisconnected>().Information("User selected reserved bike {l_oId} but cancel reservation failed (Copri server not reachable).", SelectedBike.Id);
await ViewService.DisplayAlert(
AppResources.MessageCancelReservationBikeErrorConnectionTitle,
string.Format("{0}\r\n{1}", l_oException.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
string.Format("{0}\r\n{1}", exception.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
AppResources.MessageAnswerOk);
}
else
{
Log.ForContext<ReservedDisconnected>().Error("User selected reserved bike {l_oId} but cancel reservation failed. {@l_oException}.", SelectedBike.Id, l_oException);
Log.ForContext<ReservedDisconnected>().Error("User selected reserved bike {l_oId} but cancel reservation failed. {@l_oException}.", SelectedBike.Id, exception);
await ViewService.DisplayAlert(
AppResources.MessageCancelReservationBikeErrorGeneralTitle,
l_oException.Message,
exception.Message,
"OK");
}
@ -156,7 +158,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
BikesViewModel.ActionText = string.Empty;
if (exception is WebConnectFailureException)
if (exception is WebConnectFailureException
|| exception is RequestNotCachableException)
{
// Copri server is not reachable.
Log.ForContext<ReservedDisconnected>().Information("User selected requested bike {l_oId} to connect to lock. (Copri server not reachable).", SelectedBike.Id);

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Threading.Tasks;
using Serilog;
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock;
@ -9,6 +9,7 @@ using TINK.MultilingualResources;
using TINK.Repository.Exception;
using TINK.Services.BluetoothLock;
using TINK.Services.BluetoothLock.Exception;
using TINK.Services.CopriApi.Exception;
using TINK.Services.Geolocation;
using TINK.View;
@ -231,34 +232,35 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
// If canceling bike succedes remove bike because it is not ready to be booked again
IsRemoveBikeRequired = true;
}
catch (Exception l_oException)
catch (Exception exception)
{
BikesViewModel.ActionText = String.Empty;
if (l_oException is InvalidAuthorizationResponseException)
if (exception is InvalidAuthorizationResponseException)
{
// Copri response is invalid.
Log.ForContext<ReservedOpen>().Error("User selected reserved bike {l_oId} but canceling reservation failed (Invalid auth. response).", SelectedBike.Id);
await ViewService.DisplayAlert(
AppResources.MessageCancelReservationBikeErrorGeneralTitle,
l_oException.Message,
exception.Message,
AppResources.MessageAnswerOk);
}
else if (l_oException is WebConnectFailureException)
else if (exception is WebConnectFailureException
|| exception is RequestNotCachableException)
{
// Copri server is not reachable.
Log.ForContext<ReservedOpen>().Information("User selected reserved bike {l_oId} but cancel reservation failed (Copri server not reachable).", SelectedBike.Id);
await ViewService.DisplayAlert(
AppResources.MessageCancelReservationBikeErrorConnectionTitle,
string.Format("{0}\r\n{1}", l_oException.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
string.Format("{0}\r\n{1}", exception.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
AppResources.MessageAnswerOk);
}
else
{
Log.ForContext<ReservedOpen>().Error("User selected reserved bike {l_oId} but cancel reservation failed. {@l_oException}.", SelectedBike.Id, l_oException);
Log.ForContext<ReservedOpen>().Error("User selected reserved bike {l_oId} but cancel reservation failed. {@l_oException}.", SelectedBike.Id, exception);
await ViewService.DisplayAlert(
AppResources.MessageCancelReservationBikeErrorGeneralTitle,
l_oException.Message,
exception.Message,
"OK");
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Threading.Tasks;
using Serilog;
using TINK.Model.Bikes.BikeInfoNS.CopriLock;
@ -8,6 +8,7 @@ using TINK.Model.State;
using TINK.Model.User;
using TINK.MultilingualResources;
using TINK.Repository.Exception;
using TINK.Services.CopriApi.Exception;
using TINK.View;
namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
@ -170,7 +171,8 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
string.Format(AppResources.MessageReservationBikeErrorTooManyReservationsRentals, SelectedBike.GetFullDisplayName(), (exception as BookingDeclinedException).MaxBikesCount),
AppResources.MessageAnswerOk);
}
else if (exception is WebConnectFailureException)
else if (exception is WebConnectFailureException
|| exception is RequestNotCachableException)
{
// Copri server is not reachable.
Log.ForContext<DisposableClosed>().Information("User selected availalbe bike {bike} but reserving failed (Copri server not reachable).", SelectedBike);

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Threading.Tasks;
using Serilog;
using TINK.Model.Bikes.BikeInfoNS.CopriLock;
@ -7,6 +7,7 @@ using TINK.Model.Device;
using TINK.Model.User;
using TINK.MultilingualResources;
using TINK.Repository.Exception;
using TINK.Services.CopriApi.Exception;
using TINK.View;
namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
@ -101,7 +102,8 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
exception.Message,
AppResources.MessageAnswerOk);
}
else if (exception is WebConnectFailureException)
else if (exception is WebConnectFailureException
|| exception is RequestNotCachableException)
{
// Copri server is not reachable.
Log.ForContext<BikesViewModel>().Information("User selected reserved bike {Id} but cancel reservation failed (Copri server not reachable).", SelectedBike.Id);

View file

@ -1,10 +1,13 @@
using TINK.Model;
using System.ComponentModel;
using TINK.Model;
namespace TINK.ViewModel.Settings
{
/// <summary>Holds filter item incluting full state (avaialble, activated, name, ...). </summary>
public class FilterItemMutable
public class FilterItemMutable : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
/// <summary> Switch value</summary>
private bool m_bIsActivatedSwitch;
@ -42,6 +45,12 @@ namespace TINK.ViewModel.Settings
set
{
if (m_bIsActivatedSwitch == value)
{
// Nothing to do.
return;
}
m_bIsActivatedSwitch = value;
if (!IsEnabled)
{
@ -50,6 +59,7 @@ namespace TINK.ViewModel.Settings
}
State = m_bIsActivatedSwitch ? FilterState.On : FilterState.Off;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsActivated)));
}
}
@ -58,5 +68,6 @@ namespace TINK.ViewModel.Settings
/// <summary> State of the filter.</summary>
public FilterState State { get; private set; }
}
}

View file

@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using TINK.Model;
using TINK.Model.Connector;
@ -9,8 +10,10 @@ namespace TINK.ViewModel.Settings
{
/// <summary> Holds the filters to display..</summary>
/// <remarks> Former name: FilterCollectionMutable.</remarks>
public class SettingsBikeFilterViewModel : ObservableCollection<FilterItemMutable>
public class SettingsBikeFilterViewModel : ObservableCollection<FilterItemMutable>, INotifyPropertyChanged
{
public new event PropertyChangedEventHandler PropertyChanged;
/// <summary> Constructs a filter collection object.</summary>
/// <param name="filterSettings">All available filters.</param>
/// <param name="filterGroupUser">Filters which apply to logged in user.</param>
@ -22,28 +25,35 @@ namespace TINK.ViewModel.Settings
{
if (filter.Key == FilterHelper.CARGOBIKE)
{
Add(new FilterItemMutable(
var cargo = new FilterItemMutable(
filter.Key,
filter.Value,
(filterGroupUser != null && filterGroupUser.Count() > 0) ? filterGroupUser.Contains(filter.Key) : true,
AppResources.MarkingCargoBike));
AppResources.MarkingCargoBike);
Add(cargo);
cargo.PropertyChanged += (sender, ev) => PropertyChanged?.Invoke(sender, ev);
continue;
}
if (filter.Key == FilterHelper.CITYBIKE)
{
Add(new FilterItemMutable(
var city = new FilterItemMutable(
filter.Key,
filter.Value,
(filterGroupUser != null && filterGroupUser.Count() > 0) ? filterGroupUser.Contains(filter.Key) : true,
AppResources.MarkingCityBike));
AppResources.MarkingCityBike);
Add(city);
city.PropertyChanged += (sender, ev) => PropertyChanged?.Invoke(sender, ev);
continue;
}
Add(new FilterItemMutable(
var item = new FilterItemMutable(
filter.Key,
filter.Value,
filterGroupUser != null ? filterGroupUser.Contains(filter.Key) : true,
filter.Key));
filter.Key);
Add(item);
item.PropertyChanged += (sender, ev) => PropertyChanged?.Invoke(sender, ev);
}
}

View file

@ -114,6 +114,30 @@ namespace TINK.ViewModel
TinkApp.FilterGroupSetting,
TinkApp.ActiveUser.IsLoggedIn ? TinkApp.ActiveUser.Group : null);
GroupFilter.PropertyChanged += (s, e) =>
{
// Serialize on value changed. On iOS OnDisappearing might not be invoked (when app is directly closed before leaving settings page).
try
{
var filterGroup = GroupFilter.ToDictionary(x => x.Key, x => x.State);
TinkApp.FilterGroupSetting = new GroupFilterSettings(filterGroup.Count > 0 ? filterGroup : null);
// Update map page filter.
// Reasons for which map page filter has to be updated:
// - user activated/ deactivated a group (cargo/ city bikes)
TinkApp.GroupFilterMapPage =
GroupFilterMapPageHelper.CreateUpdated(
TinkApp.GroupFilterMapPage,
TinkApp.ActiveUser.DoFilter(TinkApp.FilterGroupSetting.DoFilter()));
TinkApp.Save();
}
catch (Exception ex)
{
Log.ForContext<SettingsPageViewModel>().Error(ex, "Serializing startup page failed.");
}
};
m_oViewUpdateManager = new IdlePollingUpdateTaskManager();
Polling = new PollingViewModel(TinkApp.Polling);
@ -166,6 +190,22 @@ namespace TINK.ViewModel
{ ViewTypes.FindBikePage.ToString(), AppResources.MarkingFindBike },
},
tinkApp.StartupSettings.StartupPage.ToString());
StartupSettings.PropertyChanged += (s, e) =>
{
// Serialize on value changed. On iOS OnDisappearing might not be invoked (when app is directly closed before leaving settings page).
try
{
TinkApp.StartupSettings.StartupPage = Enum.TryParse(StartupSettings.Active, out ViewTypes startupPage)
? startupPage
: Model.Settings.StartupSettings.DefaultStartupPage;
TinkApp.Save();
} catch (Exception ex)
{
Log.ForContext<SettingsPageViewModel>().Error(ex, "Serializing startup page failed.");
}
};
}
/// <summary>
@ -234,10 +274,7 @@ namespace TINK.ViewModel
/// <summary>
/// Gets the value of device identifier (for debugging purposes).
/// </summary>
public string DeviceIdentifier
{
get { return TinkApp.SmartDevice.Identifier; }
}
public string DeviceIdentifier => TinkApp.SmartDevice.Identifier;
/// <summary>
/// Invoked when page is shutdown.
@ -258,22 +295,6 @@ namespace TINK.ViewModel
TinkApp.ExpiresAfter = TimeSpan.FromSeconds(ExpiresAfterTotalSeconds);
var filterGroup = GroupFilter.ToDictionary(x => x.Key, x => x.State);
TinkApp.FilterGroupSetting = new GroupFilterSettings(filterGroup.Count > 0 ? filterGroup : null);
// Update map page filter.
// Reasons for which map page filter has to be updated:
// - user activated/ deactivated a group (TINKCorpi/ TINKSms/ Konrad)
// - user logged off
TinkApp.GroupFilterMapPage =
GroupFilterMapPageHelper.CreateUpdated(
TinkApp.GroupFilterMapPage,
TinkApp.ActiveUser.DoFilter(TinkApp.FilterGroupSetting.DoFilter()));
TinkApp.StartupSettings.StartupPage = Enum.TryParse(StartupSettings.Active, out ViewTypes startupPage) ? startupPage : Model.Settings.StartupSettings.DefaultStartupPage;
TinkApp.CenterMapToCurrentLocation = CenterMapToCurrentLocation;
if (IsLogToExternalFolderVisible)
{
// If no external folder is available do not update model value.
@ -356,7 +377,25 @@ namespace TINK.ViewModel
}
}
public bool CenterMapToCurrentLocation { get; set; }
bool _CenterMapToCurrentLocation = true;
public bool CenterMapToCurrentLocation
{
get => _CenterMapToCurrentLocation;
set
{
if (value == _CenterMapToCurrentLocation)
{
// Nothing to do.
return;
}
_CenterMapToCurrentLocation = value;
// Serialize on value changed. On iOS OnDisappearing might not be invoked (when app is directly closed before leaving settings page).
TinkApp.CenterMapToCurrentLocation = CenterMapToCurrentLocation;
TinkApp.Save();
}
}
/// <summary> Holds either
/// - a value indicating whether to use external folder (e.g. SD card)/ or internal folder for storing log-files or
@ -408,8 +447,6 @@ namespace TINK.ViewModel
public string ExpiresAfterTotalSecondsText
{
get => expiresAfterTotalSeconds.ToString("0");
}
}
}
}