mirror of
https://dev.azure.com/TeilRad/sharee.bike%20App/_git/Code
synced 2025-06-21 21:46:27 +02:00
Manually merged.
This commit is contained in:
parent
d5832e010e
commit
c7c9f252af
112 changed files with 1127 additions and 352 deletions
21
TINKLib/Model/BookingFinishedModel.cs
Normal file
21
TINKLib/Model/BookingFinishedModel.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using TINK.Model.MiniSurvey;
|
||||
|
||||
namespace TINK.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds tasks to be accoumplished/ information shown to user after booking has finished.
|
||||
/// </summary>
|
||||
public class BookingFinishedModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Minisurvey to query user.
|
||||
/// </summary>
|
||||
public MiniSurveyModel MiniSurvey { get; set; } = new MiniSurveyModel();
|
||||
|
||||
/// <summary>
|
||||
/// Holds info about co2 saving accomplished by using cargo bike.
|
||||
/// </summary>
|
||||
public string Co2Saving { get; set; }
|
||||
|
||||
}
|
||||
}
|
|
@ -122,13 +122,13 @@ namespace TINK.Model.Connector
|
|||
Log.ForContext<Command>().Error("Unexpected booking request detected. No user logged in.");
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
public async Task<MiniSurveyModel> DoReturn(
|
||||
public async Task<BookingFinishedModel> DoReturn(
|
||||
Bikes.Bike.BluetoothLock.IBikeInfoMutable bike,
|
||||
LocationDto location,
|
||||
ISmartDevice smartDevice)
|
||||
{
|
||||
Log.ForContext<Command>().Error("Unexpected returning request detected. No user logged in.");
|
||||
return await Task.FromResult(new MiniSurveyModel());
|
||||
return await Task.FromResult(new BookingFinishedModel());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -248,7 +248,7 @@ namespace TINK.Model.Connector
|
|||
/// <param name="bike">Bike to return.</param>
|
||||
/// <param name="locaton">Position of the bike.</param>
|
||||
/// <param name="smartDevice">Provides info about hard and software.</param>
|
||||
public async Task<MiniSurveyModel> DoReturn(
|
||||
public async Task<BookingFinishedModel> DoReturn(
|
||||
Bikes.Bike.BluetoothLock.IBikeInfoMutable bike,
|
||||
LocationDto location,
|
||||
ISmartDevice smartDevice)
|
||||
|
@ -258,7 +258,7 @@ namespace TINK.Model.Connector
|
|||
throw new ArgumentNullException("Can not return bike. No bike object available.");
|
||||
}
|
||||
|
||||
ReservationCancelReturnResponse response;
|
||||
DoReturnResponse response;
|
||||
try
|
||||
{
|
||||
response = (await CopriServer.DoReturn(bike.Id, location, smartDevice, bike.OperatorUri)).GetIsReturnBikeResponseOk(bike.Id);
|
||||
|
@ -270,7 +270,7 @@ namespace TINK.Model.Connector
|
|||
}
|
||||
|
||||
bike.Load(Bikes.Bike.BC.NotifyPropertyChangedLevel.None);
|
||||
return response?.Create() ?? new MiniSurveyModel();
|
||||
return response?.Create() ?? new BookingFinishedModel();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace TINK.Model.Connector
|
|||
/// <param name="bike">Bike to return.</param>
|
||||
/// <param name="location">Geolocation of lock when returning bike.</param>
|
||||
/// <param name="smartDevice">Provides info about hard and software.</param>
|
||||
Task<MiniSurveyModel> DoReturn(Bikes.Bike.BluetoothLock.IBikeInfoMutable bike, LocationDto geolocation = null, ISmartDevice smartDevice = null);
|
||||
Task<BookingFinishedModel> DoReturn(Bikes.Bike.BluetoothLock.IBikeInfoMutable bike, LocationDto geolocation = null, ISmartDevice smartDevice = null);
|
||||
|
||||
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
|
||||
bool IsConnected { get; }
|
||||
|
|
|
@ -512,6 +512,46 @@ namespace TINK.Model.Connector
|
|||
};
|
||||
}
|
||||
|
||||
/// <summary> Creates a booking finished object from response.</summary>
|
||||
/// <param name="response">Response to create survey object from.</param>
|
||||
public static BookingFinishedModel Create(this DoReturnResponse response)
|
||||
{
|
||||
var bookingFinished = new BookingFinishedModel
|
||||
{
|
||||
Co2Saving = response?.co2saving
|
||||
};
|
||||
|
||||
if (response?.user_miniquery == null)
|
||||
|
||||
{
|
||||
return bookingFinished;
|
||||
}
|
||||
|
||||
var miniquery = response.user_miniquery;
|
||||
bookingFinished.MiniSurvey = new MiniSurveyModel
|
||||
{
|
||||
Title = miniquery.title,
|
||||
Subtitle = miniquery.subtitle,
|
||||
Footer = miniquery.footer
|
||||
};
|
||||
|
||||
foreach (var question in miniquery?.questions?.OrderBy(x => x.Key) ?? new Dictionary<string, MiniSurveyResponse.Question>().OrderBy(x => x.Key))
|
||||
{
|
||||
if (string.IsNullOrEmpty(question.Key.Trim())
|
||||
|| question.Value.query == null)
|
||||
{
|
||||
// Skip invalid entries.
|
||||
continue;
|
||||
}
|
||||
|
||||
bookingFinished.MiniSurvey.Questions.Add(
|
||||
question.Key,
|
||||
new MiniSurveyModel.QuestionModel());
|
||||
}
|
||||
|
||||
return bookingFinished;
|
||||
}
|
||||
|
||||
/// <summary> Creates a survey object from response.</summary>
|
||||
/// <param name="response">Response to create survey object from.</param>
|
||||
public static MiniSurveyModel Create(this ReservationCancelReturnResponse response)
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
namespace TINK.Model.MiniSurvey
|
||||
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds mini survey.
|
||||
/// </summary>
|
||||
public class MiniSurveyModel
|
||||
{
|
||||
public enum Type
|
||||
|
@ -12,21 +15,17 @@ namespace TINK.Model.MiniSurvey
|
|||
}
|
||||
public class QuestionModel
|
||||
{
|
||||
public QuestionModel()
|
||||
{
|
||||
PossibleAnswers = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the query description.
|
||||
/// </summary>
|
||||
public string Text { get; set; }
|
||||
|
||||
public Type Type { get; set; }
|
||||
|
||||
public Dictionary<string, string> PossibleAnswers { get; private set; }
|
||||
}
|
||||
|
||||
public MiniSurveyModel()
|
||||
{
|
||||
Questions = new Dictionary<string, QuestionModel>();
|
||||
/// <summary>
|
||||
/// Holds the collection of possible answers.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> PossibleAnswers { get; private set; } = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
public string Title { get; set; }
|
||||
|
@ -35,6 +34,6 @@ namespace TINK.Model.MiniSurvey
|
|||
|
||||
public string Footer { get; set; }
|
||||
|
||||
public Dictionary<string, QuestionModel> Questions { get; }
|
||||
public Dictionary<string, QuestionModel> Questions { get; } = new Dictionary<string, QuestionModel>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -455,8 +455,13 @@ namespace TINK.Model
|
|||
AppResources.ChangeLog3_0_250 // Third-party components updated.
|
||||
},
|
||||
{
|
||||
new Version(3, 0, 262),
|
||||
AppResources.ChangeLog3_0_262
|
||||
new Version(3, 0, 260),
|
||||
// Same info as for version 3.0.251 and 3.0.252
|
||||
AppResources.ChangeLog3_0_231 // Minor improvements.
|
||||
},
|
||||
{
|
||||
new Version(3, 0, 263),
|
||||
AppResources.ChangeLog3_0_263
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -872,11 +872,11 @@ namespace TINK.MultilingualResources {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Geolocation permission request refactored..
|
||||
/// Looks up a localized string similar to CO2 saving is displayed for bikes with GPS-lock after returning bike..
|
||||
/// </summary>
|
||||
public static string ChangeLog3_0_262 {
|
||||
public static string ChangeLog3_0_263 {
|
||||
get {
|
||||
return ResourceManager.GetString("ChangeLog3_0_262", resourceCulture);
|
||||
return ResourceManager.GetString("ChangeLog3_0_263", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -710,7 +710,7 @@ Kleinere Verbesserungen.</value>
|
|||
Kartenzentrierfehler behoben.
|
||||
Kleine Verbesserungen.</value>
|
||||
</data>
|
||||
<data name="ChangeLog3_0_262" xml:space="preserve">
|
||||
<value>Anfrage nach Geolocation-Zugriffserlaubnis überarbeitet.</value>
|
||||
<data name="ChangeLog3_0_263" xml:space="preserve">
|
||||
<value>Bei Fahrrädern mit GPS-Schloss wird die CO2-Einsparung nach der Rückgabe des Fahrrads angezeigt.</value>
|
||||
</data>
|
||||
</root>
|
|
@ -805,7 +805,7 @@ Minor fixes.</value>
|
|||
Center map to current position issue fixed.
|
||||
Minor improvements.</value>
|
||||
</data>
|
||||
<data name="ChangeLog3_0_262" xml:space="preserve">
|
||||
<value>Geolocation permission request refactored.</value>
|
||||
<data name="ChangeLog3_0_263" xml:space="preserve">
|
||||
<value>CO2 saving is displayed for bikes with GPS-lock after returning bike.</value>
|
||||
</data>
|
||||
</root>
|
|
@ -952,9 +952,9 @@ Minor improvements.</source>
|
|||
Kartenzentrierfehler behoben.
|
||||
Kleine Verbesserungen.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ChangeLog3_0_262" translate="yes" xml:space="preserve">
|
||||
<source>Geolocation permission request refactored.</source>
|
||||
<target state="translated">Anfrage nach Geolocation-Zugriffserlaubnis überarbeitet.</target>
|
||||
<trans-unit id="ChangeLog3_0_263" translate="yes" xml:space="preserve">
|
||||
<source>CO2 saving is displayed for bikes with GPS-lock after returning bike.</source>
|
||||
<target state="translated">Bei Fahrrädern mit GPS-Schloss wird die CO2-Einsparung nach der Rückgabe des Fahrrads angezeigt.</target>
|
||||
</trans-unit>
|
||||
</group>
|
||||
</body>
|
||||
|
|
|
@ -204,7 +204,7 @@ namespace TINK.Repository
|
|||
/// <param name="smartDevice">Provides info about hard and software.</param>
|
||||
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||
/// <returns>Response on returning request.</returns>
|
||||
public async Task<ReservationCancelReturnResponse> DoReturn(
|
||||
public async Task<DoReturnResponse> DoReturn(
|
||||
string bikeId,
|
||||
LocationDto location,
|
||||
ISmartDevice smartDevice,
|
||||
|
@ -615,16 +615,16 @@ namespace TINK.Repository
|
|||
#endif
|
||||
}
|
||||
|
||||
public static async Task<ReservationCancelReturnResponse> DoReturn(
|
||||
public static async Task<DoReturnResponse> DoReturn(
|
||||
string copriHost,
|
||||
string command,
|
||||
string userAgent = null)
|
||||
{
|
||||
#if !WINDOWS_UWP
|
||||
string cancelOrReturnResponse;
|
||||
string doReturnResponse;
|
||||
try
|
||||
{
|
||||
cancelOrReturnResponse = await PostAsync(copriHost, command, userAgent);
|
||||
doReturnResponse = await PostAsync(copriHost, command, userAgent);
|
||||
}
|
||||
catch (System.Exception l_oException)
|
||||
{
|
||||
|
@ -642,7 +642,7 @@ namespace TINK.Repository
|
|||
}
|
||||
|
||||
// Extract bikes from response.
|
||||
return JsonConvertRethrow.DeserializeObject<ResponseContainer<ReservationCancelReturnResponse>>(cancelOrReturnResponse)?.shareejson;
|
||||
return JsonConvertRethrow.DeserializeObject<ResponseContainer<DoReturnResponse>>(doReturnResponse)?.shareejson;
|
||||
#else
|
||||
return null;
|
||||
#endif
|
||||
|
|
|
@ -1625,14 +1625,12 @@ namespace TINK.Repository
|
|||
return null;
|
||||
}
|
||||
|
||||
public Task<ReservationCancelReturnResponse> DoReturn(
|
||||
public Task<DoReturnResponse> DoReturn(
|
||||
string bikeId,
|
||||
LocationDto geolocation,
|
||||
ISmartDevice smartDevice,
|
||||
Uri operatorUri)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
=> null;
|
||||
|
||||
public Task<SubmitFeedbackResponse> DoSubmitFeedback(string bikeId, string message, bool isBikeBroken, Uri operatorUri)
|
||||
=> null;
|
||||
|
|
|
@ -172,14 +172,12 @@ namespace TINK.Repository
|
|||
throw new System.Exception("Buchung im Offlinemodus nicht möglich!");
|
||||
}
|
||||
|
||||
public Task<ReservationCancelReturnResponse> DoReturn(
|
||||
public Task<DoReturnResponse> DoReturn(
|
||||
string bikeId,
|
||||
LocationDto geolocation,
|
||||
ISmartDevice smartDevice,
|
||||
Uri operatorUri)
|
||||
{
|
||||
throw new System.Exception("Rückgabe im Offlinemodus nicht möglich!");
|
||||
}
|
||||
=> throw new System.Exception("Rückgabe im Offlinemodus nicht möglich!");
|
||||
|
||||
public Task<SubmitFeedbackResponse> DoSubmitFeedback(string bikeId, string message, bool isBikeBroken, Uri operatorUri) =>
|
||||
throw new System.Exception("Übermittlung von Feedback im Offlinemodus nicht möglich!");
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace TINK.Repository.Exception
|
|||
{
|
||||
public class ReturnBikeException : ResponseException
|
||||
{
|
||||
public ReturnBikeException(ReservationCancelReturnResponse response, string message) : base(response, message)
|
||||
public ReturnBikeException(BikesReservedOccupiedResponse response, string message) : base(response, message)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ namespace TINK.Repository
|
|||
/// <param name="smartDevice">Provides info about hard and software.</param>
|
||||
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||
/// <returns>Response on returning request.</returns>
|
||||
Task<ReservationCancelReturnResponse> DoReturn(
|
||||
Task<DoReturnResponse> DoReturn(
|
||||
string bikeId,
|
||||
LocationDto location,
|
||||
ISmartDevice smartDevice,
|
||||
|
|
15
TINKLib/Repository/Response/DoReturnResponse.cs
Normal file
15
TINKLib/Repository/Response/DoReturnResponse.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using System.Runtime.Serialization;
|
||||
|
||||
namespace TINK.Repository.Response
|
||||
{
|
||||
public class DoReturnResponse : BikesReservedOccupiedResponse
|
||||
{
|
||||
/// <summary> Mini survey.</summary>
|
||||
[DataMember]
|
||||
public MiniSurveyResponse user_miniquery { get; private set; }
|
||||
|
||||
[DataMember]
|
||||
public string co2saving { get; private set; }
|
||||
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace TINK.Repository.Response
|
||||
{
|
||||
|
|
|
@ -181,8 +181,8 @@ namespace TINK.Repository.Response
|
|||
/// <param name="textOfAction">Text describing request which is shown if validation fails.</param>
|
||||
/// <param name="bikeId">Id of bike.</param>
|
||||
/// <returns>Verified response.</returns>
|
||||
public static ReservationCancelReturnResponse GetIsReturnBikeResponseOk(
|
||||
this ReservationCancelReturnResponse returnBikeResponse,
|
||||
public static DoReturnResponse GetIsReturnBikeResponseOk(
|
||||
this DoReturnResponse returnBikeResponse,
|
||||
string bikeId)
|
||||
{
|
||||
// Check if bike is at station.
|
||||
|
|
|
@ -234,14 +234,12 @@ namespace TINK.Model.Services.CopriApi
|
|||
return await HttpsServer.DoBookAsync(bikeId, guid, batteryPercentage, operatorUri);
|
||||
}
|
||||
|
||||
public async Task<ReservationCancelReturnResponse> DoReturn(
|
||||
public async Task<DoReturnResponse> DoReturn(
|
||||
string bikeId,
|
||||
LocationDto location,
|
||||
ISmartDevice smartDevice,
|
||||
Uri operatorUri)
|
||||
{
|
||||
return await HttpsServer.DoReturn(bikeId, location, smartDevice, operatorUri);
|
||||
}
|
||||
=> await HttpsServer.DoReturn(bikeId, location, smartDevice, operatorUri);
|
||||
|
||||
/// <summary>
|
||||
/// Submits feedback to copri server.
|
||||
|
|
|
@ -53,14 +53,12 @@ namespace TINK.Model.Services.CopriApi
|
|||
return await monkeyStore.DoBookAsync(bikeId, guid, batteryPercentage, operatorUri);
|
||||
}
|
||||
|
||||
public async Task<ReservationCancelReturnResponse> DoReturn(
|
||||
public async Task<DoReturnResponse> DoReturn(
|
||||
string bikeId,
|
||||
LocationDto geolocation,
|
||||
ISmartDevice smartDevice,
|
||||
Uri operatorUri)
|
||||
{
|
||||
return await monkeyStore.DoReturn(bikeId, geolocation, smartDevice, operatorUri);
|
||||
}
|
||||
=> await monkeyStore.DoReturn(bikeId, geolocation, smartDevice, operatorUri);
|
||||
|
||||
public Task<SubmitFeedbackResponse> DoSubmitFeedback(string bikeId, string messge, bool bIsBikeBroke, Uri operatorUri)
|
||||
=> throw new NotImplementedException();
|
||||
|
|
59
TINKLib/Services/Permissions/Plugin/Permissions.cs
Normal file
59
TINKLib/Services/Permissions/Plugin/Permissions.cs
Normal file
|
@ -0,0 +1,59 @@
|
|||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
namespace TINK.Services.Permissions.Plugin
|
||||
{
|
||||
using global::Plugin.Permissions;
|
||||
|
||||
public class Permissions : ILocationPermission
|
||||
{
|
||||
/// <summary> Checks the permission status.</summary>
|
||||
public async Task<Status> CheckStatusAsync()
|
||||
{
|
||||
switch (await CrossPermissions.Current.CheckPermissionStatusAsync<LocationPermission>())
|
||||
{
|
||||
case global::Plugin.Permissions.Abstractions.PermissionStatus.Denied:
|
||||
return Status.Denied;
|
||||
|
||||
case global::Plugin.Permissions.Abstractions.PermissionStatus.Granted:
|
||||
return Status.Granted;
|
||||
|
||||
case global::Plugin.Permissions.Abstractions.PermissionStatus.Unknown:
|
||||
return Status.Unknown;
|
||||
|
||||
default:
|
||||
// Comprises
|
||||
// - PermissionStatus.Disabled and
|
||||
// - PermissionStatus.Restricted.
|
||||
return Status.DeniedRequiresSettingsUI;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Requests location permission.</summary>
|
||||
/// <returns>Permission status after request.</returns>
|
||||
public async Task<Status> RequestAsync()
|
||||
{
|
||||
switch (await CrossPermissions.Current.RequestPermissionAsync<LocationPermission>())
|
||||
{
|
||||
case global::Plugin.Permissions.Abstractions.PermissionStatus.Denied:
|
||||
return Status.Denied;
|
||||
|
||||
case global::Plugin.Permissions.Abstractions.PermissionStatus.Granted:
|
||||
return Status.Granted;
|
||||
|
||||
case global::Plugin.Permissions.Abstractions.PermissionStatus.Unknown:
|
||||
return Status.Unknown;
|
||||
|
||||
default:
|
||||
// Comprises
|
||||
// - PermissionStatus.Disabled and
|
||||
// - PermissionStatus.Restricted.
|
||||
return Status.DeniedRequiresSettingsUI;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Opens app settings dialog.</summary>
|
||||
public bool OpenAppSettings()
|
||||
=> CrossPermissions.Current.OpenAppSettings();
|
||||
}
|
||||
}
|
|
@ -50,6 +50,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Services\Permissions\Essentials\" />
|
||||
<Folder Include="Services\Permissions\Plugin\" />
|
||||
<Folder Include="ViewModel\Info\BikeInfo\" />
|
||||
<Folder Include="ViewModel\FeesAndBikes\" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -77,7 +77,10 @@ namespace TINK.View
|
|||
/// <summary> Pushes a page onto the modal stack. </summary>
|
||||
Task PopModalAsync();
|
||||
|
||||
Task<IUserFeedback> DisplayUserFeedbackPopup();
|
||||
/// <summary> Displays user feedback popup.</summary>
|
||||
/// <param name="co2Saving"> Co2 saving information.</param>
|
||||
/// <returns>User feedback.</returns>
|
||||
Task<IUserFeedback> DisplayUserFeedbackPopup(string co2Saving = null);
|
||||
|
||||
#if USCSHARP9
|
||||
/// <summary>
|
||||
|
|
|
@ -15,9 +15,9 @@ using TINK.Model.User;
|
|||
using Xamarin.Essentials;
|
||||
using TINK.Repository.Request;
|
||||
using TINK.Model.Device;
|
||||
using TINK.Model.MiniSurvey;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using TINK.Model;
|
||||
|
||||
namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
|
@ -162,10 +162,10 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
IsConnected = IsConnectedDelegate();
|
||||
|
||||
var feedBackUri = SelectedBike?.OperatorUri;
|
||||
MiniSurveyModel miniSurvey;
|
||||
BookingFinishedModel bookingFinished;
|
||||
try
|
||||
{
|
||||
miniSurvey = await ConnectorFactory(IsConnected).Command.DoReturn(
|
||||
bookingFinished = await ConnectorFactory(IsConnected).Command.DoReturn(
|
||||
SelectedBike,
|
||||
currentLocationDto);
|
||||
|
||||
|
@ -250,9 +250,10 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
BikesViewModel.ActionText = AppResources.ActivityTextErrorDisconnect;
|
||||
}
|
||||
|
||||
|
||||
#if !USERFEEDBACKDLG_OFF
|
||||
// Do get Feedback
|
||||
var feedback = await ViewService.DisplayUserFeedbackPopup();
|
||||
var feedback = await ViewService.DisplayUserFeedbackPopup(bookingFinished?.Co2Saving);
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -288,7 +289,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||
}
|
||||
#endif
|
||||
if (miniSurvey != null && miniSurvey.Questions.Count > 0)
|
||||
if (bookingFinished != null && bookingFinished.MiniSurvey.Questions.Count > 0)
|
||||
{
|
||||
await ViewService.PushModalAsync(ViewTypes.MiniSurvey);
|
||||
}
|
||||
|
|
|
@ -15,9 +15,9 @@ using TINK.Model.Bikes.Bike.BluetoothLock;
|
|||
using TINK.Model.User;
|
||||
using TINK.Repository.Request;
|
||||
using TINK.Model.Device;
|
||||
using TINK.Model.MiniSurvey;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using TINK.Model;
|
||||
|
||||
namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
|
@ -273,10 +273,10 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
IsConnected = IsConnectedDelegate();
|
||||
|
||||
var feedBackUri = SelectedBike?.OperatorUri;
|
||||
MiniSurveyModel miniSurvey;
|
||||
BookingFinishedModel bookingFinished;
|
||||
try
|
||||
{
|
||||
miniSurvey = await ConnectorFactory(IsConnected).Command.DoReturn(
|
||||
bookingFinished = await ConnectorFactory(IsConnected).Command.DoReturn(
|
||||
SelectedBike,
|
||||
currentLocation != null
|
||||
? new LocationDto.Builder
|
||||
|
@ -368,7 +368,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
#if !USERFEEDBACKDLG_OFF
|
||||
// Do get Feedback
|
||||
var feedback = await ViewService.DisplayUserFeedbackPopup();
|
||||
var feedback = await ViewService.DisplayUserFeedbackPopup(bookingFinished?.Co2Saving);
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -404,7 +404,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
}
|
||||
#endif
|
||||
|
||||
if (miniSurvey != null && miniSurvey.Questions.Count > 0)
|
||||
if (bookingFinished != null && bookingFinished.MiniSurvey.Questions.Count > 0)
|
||||
{
|
||||
await ViewService.PushModalAsync(ViewTypes.MiniSurvey);
|
||||
}
|
||||
|
|
|
@ -314,17 +314,84 @@ namespace TINK.ViewModel.Map
|
|||
ActiveFilterMap = TinkApp.GroupFilterMapPage;
|
||||
|
||||
ActionText = AppResources.ActivityTextRequestingLocationPermissions;
|
||||
Status status = await RequestLocationPermission();
|
||||
|
||||
// Check location permission
|
||||
var status = await PermissionsService.CheckStatusAsync();
|
||||
if (TinkApp.CenterMapToCurrentLocation
|
||||
&& !GeolocationService.IsSimulation
|
||||
&& status != Status.Granted)
|
||||
{
|
||||
var permissionResult = await PermissionsService.RequestAsync();
|
||||
|
||||
if (permissionResult != Status.Granted)
|
||||
{
|
||||
var dialogResult = await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
AppResources.MessageCenterMapLocationPermissionOpenDialog,
|
||||
AppResources.MessageAnswerYes,
|
||||
AppResources.MessageAnswerNo);
|
||||
|
||||
if (dialogResult)
|
||||
{
|
||||
// User decided to give access to locations permissions.
|
||||
PermissionsService.OpenAppSettings();
|
||||
ActionText = "";
|
||||
IsRunning = false;
|
||||
IsMapPageEnabled = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ActionText = AppResources.ActivityTextMapLoadingStationsAndBikes;
|
||||
IsConnected = TinkApp.GetIsConnected();
|
||||
var resultStationsAndBikes = await TinkApp.GetConnector(IsConnected).Query.GetBikesAndStationsAsync();
|
||||
|
||||
TinkApp.Stations = resultStationsAndBikes.Response.StationsAll;
|
||||
|
||||
if (Pins.Count > 0 && Pins.Count != resultStationsAndBikes.Response.StationsAll.Count)
|
||||
{
|
||||
// Either
|
||||
// - user logged in/ logged out which might lead to more/ less stations beeing available
|
||||
// - new stations were added/ existing ones remove
|
||||
Pins.Clear();
|
||||
}
|
||||
|
||||
// Check if there are alreay any pins to the map
|
||||
// i.e detecte first call of member OnAppearing after construction
|
||||
if (Pins.Count <= 0)
|
||||
{
|
||||
Log.ForContext<MapPageViewModel>().Debug($"{(ActiveFilterMap.GetGroup().Any() ? $"Active map filter is {string.Join(",", ActiveFilterMap.GetGroup())}." : "Map filter is off.")}");
|
||||
|
||||
// Map was not yet initialized.
|
||||
// Get stations from Copri
|
||||
Log.ForContext<MapPageViewModel>().Verbose("No pins detected on page.");
|
||||
if (resultStationsAndBikes.Response.StationsAll.CopriVersion < CopriCallsStatic.UnsupportedVersionLower)
|
||||
{
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageWaring,
|
||||
string.Format(AppResources.MessageCopriVersionIsOutdated, ContactPageViewModel.GetAppName(TinkApp.Uris.ActiveUri)),
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
Log.ForContext<MapPageViewModel>().Error($"Outdated version of app detected. Version expected is {resultStationsAndBikes.Response.StationsAll.CopriVersion}.");
|
||||
}
|
||||
|
||||
if (resultStationsAndBikes.Response.StationsAll.CopriVersion >= CopriCallsStatic.UnsupportedVersionUpper)
|
||||
{
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageWaring,
|
||||
string.Format(AppResources.MessageAppVersionIsOutdated, ContactPageViewModel.GetAppName(TinkApp.Uris.ActiveUri)),
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
Result<StationsAndBikesContainer> resultStationsAndBikes = await TinkApp.GetConnector(IsConnected).Query.GetBikesAndStationsAsync();
|
||||
|
||||
TinkApp.Stations = resultStationsAndBikes.Response.StationsAll;
|
||||
|
||||
await SetStationsOnMap(resultStationsAndBikes.Response.StationsAll);
|
||||
await HandleAuthCookieNotDefinedException(resultStationsAndBikes.Exception);
|
||||
// COPRI reports an auth cookie error.
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageWaring,
|
||||
AppResources.MessageMapPageErrorAuthcookieUndefined,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
|
||||
// Update pin colors.
|
||||
|
@ -337,6 +404,31 @@ namespace TINK.ViewModel.Map
|
|||
// Update pins color form count of bikes located at station.
|
||||
UpdatePinsColor(colors);
|
||||
|
||||
// Move and scale before getting stations and bikes which takes some time.
|
||||
ActionText = AppResources.ActivityTextCenterMap;
|
||||
if (TinkApp.CenterMapToCurrentLocation)
|
||||
{
|
||||
Location currentLocation = null;
|
||||
try
|
||||
{
|
||||
currentLocation = await GeolocationService.GetAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.ForContext<MapPageViewModel>().Error("Getting location failed. {Exception}", ex);
|
||||
}
|
||||
|
||||
TinkApp.MapSpan = MapSpan.FromCenterAndRadius(
|
||||
new Xamarin.Forms.GoogleMaps.Position(currentLocation.Latitude, currentLocation.Longitude),
|
||||
TinkApp.MapSpan.Radius);
|
||||
|
||||
TinkApp.Save();
|
||||
}
|
||||
|
||||
MoveAndScale(m_oMoveToRegionDelegate, TinkApp.MapSpan);
|
||||
|
||||
m_oViewUpdateManager = CreateUpdateTask();
|
||||
|
||||
Log.ForContext<MapPageViewModel>().Verbose("Update pins color done.");
|
||||
|
||||
// Move and scale before getting stations and bikes which takes some time.
|
||||
|
@ -375,144 +467,6 @@ namespace TINK.ViewModel.Map
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the auth cookie is not defined.
|
||||
/// </summary>
|
||||
private async Task HandleAuthCookieNotDefinedException(Exception exception)
|
||||
{
|
||||
if (exception?.GetType() == typeof(AuthcookieNotDefinedException))
|
||||
{
|
||||
Log.ForContext<MapPageViewModel>().Error("Map page is shown (probable for the first time after startup of app) and COPRI auth cookie is not defined. {@l_oException}", exception);
|
||||
|
||||
// COPRI reports an auth cookie error.
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageWaring,
|
||||
AppResources.MessageMapPageErrorAuthcookieUndefined,
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
await TinkApp.GetConnector(IsConnected).Command.DoLogout();
|
||||
TinkApp.ActiveUser.Logout();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the available stations on the map.
|
||||
/// </summary>
|
||||
private async Task SetStationsOnMap(StationDictionary stations)
|
||||
{
|
||||
if (Pins.Count > 0 && Pins.Count != stations.Count)
|
||||
{
|
||||
// Either
|
||||
// - user logged in/ logged out which might lead to more/ less stations beeing available
|
||||
// - new stations were added/ existing ones remove
|
||||
Pins.Clear();
|
||||
}
|
||||
|
||||
// Check if there are alreay any pins to the map
|
||||
// i.e detecte first call of member OnAppearing after construction
|
||||
if (Pins.Count <= 0)
|
||||
{
|
||||
Log.ForContext<MapPageViewModel>().Debug($"{(ActiveFilterMap.GetGroup().Any() ? $"Active map filter is {string.Join(",", ActiveFilterMap.GetGroup())}." : "Map filter is off.")}");
|
||||
|
||||
// Map was not yet initialized.
|
||||
// Get stations from Copri
|
||||
Log.ForContext<MapPageViewModel>().Verbose("No pins detected on page.");
|
||||
if (stations.CopriVersion < CopriCallsStatic.UnsupportedVersionLower)
|
||||
{
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageWaring,
|
||||
string.Format(AppResources.MessageCopriVersionIsOutdated, ContactPageViewModel.GetAppName(TinkApp.Uris.ActiveUri)),
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
Log.ForContext<MapPageViewModel>().Error($"Outdated version of app detected. Version expected is {stations.CopriVersion}.");
|
||||
}
|
||||
|
||||
if (stations.CopriVersion >= CopriCallsStatic.UnsupportedVersionUpper)
|
||||
{
|
||||
await ViewService.DisplayAlert(
|
||||
AppResources.MessageWaring,
|
||||
string.Format(AppResources.MessageAppVersionIsOutdated, ContactPageViewModel.GetAppName(TinkApp.Uris.ActiveUri)),
|
||||
AppResources.MessageAnswerOk);
|
||||
|
||||
Log.ForContext<MapPageViewModel>().Error($"Outdated version of app detected. Version expected is {stations.CopriVersion}.");
|
||||
}
|
||||
|
||||
// Set pins to their positions on map.
|
||||
InitializePins(stations);
|
||||
|
||||
Log.ForContext<MapPageViewModel>().Verbose("Update of pins done.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the map to the current position of the user.
|
||||
/// If location permission hasn't been granted, the position is not adjusted.
|
||||
/// </summary>
|
||||
private async Task MoveMapToCurrentPositionOfUser(Status status)
|
||||
{
|
||||
if (status == Status.Granted)
|
||||
{
|
||||
ActionText = AppResources.ActivityTextCenterMap;
|
||||
if (TinkApp.CenterMapToCurrentLocation)
|
||||
{
|
||||
Location currentLocation = null;
|
||||
try
|
||||
{
|
||||
currentLocation = await GeolocationService.GetAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.ForContext<MapPageViewModel>().Error("Getting location failed. {Exception}", ex);
|
||||
}
|
||||
|
||||
TinkApp.MapSpan = MapSpan.FromCenterAndRadius(
|
||||
new Xamarin.Forms.GoogleMaps.Position(currentLocation.Latitude, currentLocation.Longitude),
|
||||
TinkApp.MapSpan.Radius);
|
||||
|
||||
TinkApp.Save();
|
||||
}
|
||||
MoveAndScale(m_oMoveToRegionDelegate, TinkApp.MapSpan);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Requests the location permission from the user.
|
||||
/// If the user declines, a dialog prompot is shown, telling the user to toggle the permission in the device settings.
|
||||
/// </summary>
|
||||
/// <returns>The permission status.</returns>
|
||||
private async Task<Status> RequestLocationPermission()
|
||||
{
|
||||
// Check location permission
|
||||
var status = await PermissionsService.CheckStatusAsync();
|
||||
if (TinkApp.CenterMapToCurrentLocation
|
||||
&& !GeolocationService.IsSimulation
|
||||
&& status != Status.Granted)
|
||||
{
|
||||
status = await PermissionsService.RequestAsync();
|
||||
|
||||
if (status != Status.Granted)
|
||||
{
|
||||
var dialogResult = await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
AppResources.MessageCenterMapLocationPermissionOpenDialog,
|
||||
AppResources.MessageAnswerYes,
|
||||
AppResources.MessageAnswerNo);
|
||||
|
||||
if (dialogResult)
|
||||
{
|
||||
// User decided to give access to locations permissions.
|
||||
PermissionsService.OpenAppSettings();
|
||||
ActionText = "";
|
||||
IsRunning = false;
|
||||
IsMapPageEnabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/// <summary> Moves map and scales visible region depending on active filter. </summary>
|
||||
public static void MoveAndScale(
|
||||
Action<MapSpan> moveToRegionDelegate,
|
||||
|
@ -878,7 +832,7 @@ namespace TINK.ViewModel.Map
|
|||
if (permissionResult != Status.Granted)
|
||||
{
|
||||
var dialogResult = await ViewService.DisplayAlert(
|
||||
AppResources.MessageTitleHint,
|
||||
AppResources.MessageTitleHint,
|
||||
AppResources.MessageBikesManagementLocationPermission,
|
||||
"Ja",
|
||||
"Nein");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue