Version 3.0.371

This commit is contained in:
Anja 2023-08-31 12:31:38 +02:00
parent bdb2dec1c1
commit 6d22dbf40b
145 changed files with 2289 additions and 764 deletions

View file

@ -22,7 +22,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BC
/// <summary>
/// Holds the drive object.
/// </summary>
public Drive Drive { get; }
public DriveMutable Drive { get; }
/// <summary> Gets the information where the data origins from. </summary>
public DataSource DataSource { get; }
@ -32,7 +32,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BC
protected BikeInfo(
IStateInfo stateInfo,
Bike bike,
Drive drive,
DriveMutable drive,
DataSource dataSource,
bool? isDemo = DEFAULTVALUEISDEMO,
IEnumerable<string> group = null,

View file

@ -15,7 +15,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BC
private readonly Bike _Bike;
/// <summary> Holds the drive of the bike. </summary>
private readonly Drive _Drive;
private readonly DriveMutable _Drive;
/// <summary> Holds the state info of the bike. </summary>
private readonly StateInfoMutable _StateInfo;
@ -31,7 +31,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BC
/// <param name="stateInfo">Bike state info.</param>
protected BikeInfoMutable(
Bike bike,
Drive drive,
DriveMutable drive,
DataSource dataSource,
bool isDemo = BikeInfo.DEFAULTVALUEISDEMO,
IEnumerable<string> group = null,
@ -105,7 +105,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BC
public string Description => _Bike.Description;
public Drive Drive => _Drive;
public DriveMutable Drive => _Drive;
/// <summary>
/// Fired whenever property of bike changes.

View file

@ -18,7 +18,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BC
/// <summary>
/// Holds the drive.
/// </summary>
Drive Drive { get; }
DriveMutable Drive { get; }
/// <summary> Gets or sets the information where the data origins from. </summary>
DataSource DataSource { get; }

View file

@ -59,7 +59,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BC
/// <summary>
/// Hold the drive object.
/// </summary>
Drive Drive { get; }
DriveMutable Drive { get; }
/// <summary> Gets or sets the information where the data origins from. </summary>
DataSource DataSource { get; set; }

View file

@ -20,7 +20,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
/// <param name="tariffDescription">Hold tariff description of bike.</param>
public BikeInfo(
Bike bike,
Drive drive,
DriveMutable drive,
DataSource dataSource,
int lockId,
Guid lockGuid,
@ -65,7 +65,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
/// <param name="dateTimeProvider">Date time provider to calculate remaining time.</param>
public BikeInfo(
Bike bike,
Drive drive,
DriveMutable drive,
DataSource dataSource,
int lockId,
Guid lockGuid,
@ -121,7 +121,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
/// <param name="wheelType"></param>
public BikeInfo(
Bike bike,
Drive drive,
DriveMutable drive,
DataSource dataSource,
int lockId,
Guid lockGuid,

View file

@ -32,7 +32,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command
}
/// <summary>
/// Possible steps of closing a lock.
/// Possible states of closing a lock.
/// </summary>
public enum State
{
@ -182,7 +182,8 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command
}
}
// Start query geolocation data.
//// Start Action
//// Step: Start query geolocation data.
Log.ForContext<T>().Debug($"Starting step {Step.StartingQueryingLocation}...");
InvokeCurrentStep(Step.StartingQueryingLocation);
var ctsLocation = new CancellationTokenSource();
@ -199,7 +200,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command
await InvokeCurrentStateAsync(State.StartGeolocationException, ex.Message);
}
// Close lock.
//// Step: Close lock.
IGeolocation currentLocation;
Log.ForContext<T>().Debug($"Starting step {Step.ClosingLock}...");
InvokeCurrentStep(Step.ClosingLock);
@ -236,7 +237,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command
// Signal cts to cancel getting geolocation.
ctsLocation.Cancel();
//// Step: Wait until getting geolocation and stop polling has completed.
// Wait until getting geolocation and stop polling has completed.
currentLocation = await WaitForPendingTasks(currentLocationTask);
// Update current state from exception
@ -256,14 +257,14 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command
throw;
}
// Step: Update backend.
// Update backend.
// Do this even if current lock state is open (lock state must not necessarily be open before try to open, i.e. something undefined between open and closed).
await UpdateLockingState(currentLocation, timeStampNow);
throw;
}
//// Step: Wait until getting geolocation and stop polling has completed.
//// Step: Wait until getting geolocation and stop polling has completed.
currentLocation = await WaitForPendingTasks(currentLocationTask);
bike.LockInfo.State = lockingState?.GetLockingState() ?? LockingState.UnknownDisconnected;
@ -276,7 +277,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command
return;
}
//// Step: Update backend.
//// Step: Update backend.
await UpdateLockingState(currentLocation, timeStampNow);
}
}

View file

@ -97,6 +97,8 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command
}
}
//// Start Action
//// Step: Start query geolocation data.
InvokeCurrentStep(Step.StartingQueryLocation);
// Get geolocation which was requested when closing lock.
@ -123,7 +125,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command
await InvokeCurrentStateAsync(State.DisconnetedNoLocationError, "");
// Disconnect lock.
//// Step: Disconnect lock.
InvokeCurrentStep(Step.DisconnectingLockOnDisconnectedNoLocationError);
try
{

View file

@ -22,7 +22,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.CopriLock
/// <param name="tariffDescription">Hold tariff description of bike.</param>
public BikeInfo(
Bike bike,
Drive drive,
DriveMutable drive,
DataSource dataSource,
string currentStationId,
LockInfo lockInfo,
@ -70,7 +70,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.CopriLock
/// <param name="dateTimeProvider">Provider for current date time to calculate remaining time on demand for state of type reserved.</param>
public BikeInfo(
Bike bike,
Drive drive,
DriveMutable drive,
DataSource dataSource,
DateTime requestedAt,
string mailAddress,
@ -122,7 +122,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.CopriLock
/// <param name="tariffDescription">Hold tariff description of bike.</param>
public BikeInfo(
Bike bike,
Drive drive,
DriveMutable drive,
DataSource dataSource,
DateTime bookedAt,
string mailAddress,

View file

@ -2,32 +2,35 @@ using Serilog;
namespace TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS
{
/// <summary>
/// Holds the state of a chargeable battery.
/// </summary>
public class Battery : IBattery
{
private Battery() { }
/// <summary>
/// Holds the current charging level of the battery in percent, double.NaN if unknown.
/// Gets the current charging level of the battery in percent, double.NaN if unknown.
/// </summary>
public double CurrentChargePercent { get; private set; } = double.NaN;
/// <summary>
/// Holds the current charging level of the battery in bars, null if unknown.
/// Gets the current charging level of the battery in bars, null if unknown.
/// </summary>
public int? CurrentChargeBars { get; private set; } = null;
/// <summary>
/// Holds the maximum charging level of the battery in bars, null if unknown.
/// Gets the maximum charging level of the battery in bars, null if unknown.
/// </summary>
public int? MaxChargeBars { get; private set; } = null;
/// <summary>
/// Holds whether backend is aware of battery charging level.
/// Gets whether backend is aware of battery charging level.
/// </summary>
public bool? IsBackendAccessible { get; private set; } = null;
/// <summary>
/// Holds whether to display battery level or not.
/// Gets whether to display battery level or not.
/// </summary>
public bool? IsHidden { get; private set; } = null;

View file

@ -0,0 +1,84 @@
using System.ComponentModel;
namespace TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS
{
/// <summary>
/// Manages the state of a chargeable battery.
/// </summary>
public class BatteryMutable : IBatteryMutable, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
IBattery _battery;
public BatteryMutable(IBattery battery)
{
_battery = battery;
}
/// <summary>
/// Gets the current charging level of the battery in percent, double.NaN if unknown.
/// </summary>
public double CurrentChargePercent => _battery.CurrentChargePercent;
/// <summary>
/// Gets or sets the current charging level of the battery in bars, null if unknown.
/// </summary>
public int? CurrentChargeBars
{
get => _battery.CurrentChargeBars;
set
{
double GetCurrentChargePercent()
{
if (value == null)
{
// Filling level is unknown.
return double.NaN;
}
if (_battery.MaxChargeBars == null || _battery.MaxChargeBars == 0)
{
// Percentage filling level can not be calculated.
return _battery.CurrentChargePercent;
}
return (int)(100 * value / _battery.MaxChargeBars);
}
if (_battery.CurrentChargeBars == value)
{
// Nothing to do.
return;
}
_battery = new Battery.Builder
{
MaxChargeBars = _battery.MaxChargeBars,
IsBackendAccessible = _battery.IsBackendAccessible,
IsHidden = _battery.IsHidden,
CurrentChargeBars = value,
CurrentChargePercent = GetCurrentChargePercent(),
}.Build();
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentChargeBars)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentChargePercent)));
}
}
/// <summary>
/// Gets the maximum charging level of the battery in bars, null if unknown.
/// </summary>
public int? MaxChargeBars => _battery.MaxChargeBars;
/// <summary>
/// Gets whether backend is aware of battery charging level.
/// </summary>
public bool? IsBackendAccessible => _battery.IsBackendAccessible;
/// <summary>
/// Gets whether to display battery level or not.
/// </summary>
public bool? IsHidden => _battery.IsHidden;
}
}

View file

@ -1,7 +1,7 @@
namespace TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS
{
public interface IBattery
public interface IBattery
{
/// <summary>
/// Holds the current charging level of the battery in percent, double.NaN if unknown.

View file

@ -0,0 +1,35 @@
using System.ComponentModel;
namespace TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS
{
/// <summary>
/// Manages the state of a chargeable battery.
/// </summary>
public interface IBatteryMutable : INotifyPropertyChanged
{
/// <summary>
/// Gets the current charging level of the battery in percent, double.NaN if unknown.
/// </summary>
double CurrentChargePercent { get; }
/// <summary>
/// Gets or sets the current charging level of the battery in bars. Must not be larger than MaxChargeBars, null if unknown.
/// </summary>
int? CurrentChargeBars { get; set; }
/// <summary>
/// Gets the maximum charging level of the battery in bars, null if unknown.
/// </summary>
int? MaxChargeBars { get; }
/// <summary>
/// Gets whether backend is aware of battery charging level.
/// </summary>
bool? IsBackendAccessible { get; }
/// <summary>
/// Gets whether to display battery level or not.
/// </summary>
bool? IsHidden { get; }
}
}

View file

@ -1,4 +1,4 @@
using TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
using TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
using TINK.Model.Bikes.BikeInfoNS.DriveNS.EngineNS;
namespace TINK.Model.Bikes.BikeInfoNS.DriveNS
@ -6,32 +6,32 @@ namespace TINK.Model.Bikes.BikeInfoNS.DriveNS
public enum DriveType
{
/// <summary>
/// Bike without pedalling aid.
/// Bike without pedaling aid.
/// </summary>
SoleHumanPowered,
/// <summary>
/// pedal electric cycle: Pedalling is assisted by an electric engine.
/// pedal electric cycle: Pedaling is assisted by an electric engine.
/// </summary>
Pedelec
}
public class Drive
public class DriveMutable
{
public Drive(
public DriveMutable(
IEngine engine = null,
IBattery battery = null)
{
if (engine == null)
{
Engine = new Engine();
Battery = new Battery.Builder().Build();
Battery = new BatteryMutable(new Battery.Builder().Build());
Type = DriveType.SoleHumanPowered;
return;
}
Engine = engine;
Battery = battery ?? new Battery.Builder().Build();
Battery = new BatteryMutable(battery ?? new Battery.Builder().Build());
Type = DriveType.Pedelec;
}
@ -48,15 +48,6 @@ namespace TINK.Model.Bikes.BikeInfoNS.DriveNS
/// <summary>
/// Battery powering the engine.
/// </summary>
public IBattery _Battery = new Battery.Builder().Build();
/// <summary>
/// Battery powering the engine.
/// </summary>
public IBattery Battery
{
get => _Battery;
set => _Battery = value ?? new Battery.Builder().Build();
}
public IBatteryMutable Battery { get; private set; }
}
}

View file

@ -7,16 +7,16 @@ namespace TINK.Model.Connector.Updater
{
public static class DriveFactory
{
public static Drive Create(this BikeType bikeType)
public static DriveMutable Create(this BikeType bikeType)
{
if (string.IsNullOrEmpty(bikeType?.engine?.manufacturer))
{
// Bike is has no engine
return new Drive();
return new DriveMutable();
}
// Bike is a pedelec.
return new Drive(
return new DriveMutable(
new Engine(bikeType?.engine?.manufacturer),
new Battery.Builder
{

View file

@ -712,6 +712,16 @@ namespace TINK.Model
new Version(3, 0, 370),
AppResources.ChangeLog_3_0_370
},
{
new Version(3, 0, 371),
AppResources.ChangeLog_3_0_371_SB,
new List<AppFlavor> { AppFlavor.ShareeBike }
},
{
new Version(3, 0, 371),
AppResources.ChangeLog_3_0_371_MK,
new List<AppFlavor> { AppFlavor.MeinKonrad}
},
};
/// <summary> Manges the whats new information.</summary>

View file

@ -1452,9 +1452,6 @@ namespace TINK.MultilingualResources {
}
}
/// <summary>
/// Looks up a localized string similar to Changes in the return process: FIRST you must always complete the &quot;Close lock&quot; process. Only THEN you can finish the rental! If your rental was successfully ended, you will see a confirmation dialog..
/// </summary>
public static string ChangeLog_3_0_367_MK_SB {
get {
return ResourceManager.GetString("ChangeLog_3_0_367_MK_SB", resourceCulture);
@ -1475,6 +1472,25 @@ namespace TINK.MultilingualResources {
}
}
/// <summary>
/// Looks up a localized string similar to 1. Easy access to FAQ: In the menu under Help, you can now easily search for a solution yourself for questions and problems.&lt;br/&gt;
///2. City area vs. suburb bikes: Rental bikes that belong to the city area and cannot be returned to the suburbs are now marked by appropriate icons. Conversely, rental bikes from the suburbs cannot be returned in the city area (also marked with icons)!.
/// </summary>
public static string ChangeLog_3_0_371_MK {
get {
return ResourceManager.GetString("ChangeLog_3_0_371_MK", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Easy access to FAQ: In the menu under Help, you can now easily search for a solution yourself for questions and problems..
/// </summary>
public static string ChangeLog_3_0_371_SB {
get {
return ResourceManager.GetString("ChangeLog_3_0_371_SB", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Your session has expired. Please login new and try again..
/// </summary>
@ -2109,6 +2125,15 @@ namespace TINK.MultilingualResources {
}
}
/// <summary>
/// Looks up a localized string similar to City area.
/// </summary>
public static string MarkingBikeIsBoundToCity {
get {
return ResourceManager.GetString("MarkingBikeIsBoundToCity", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to There are currently no bicycles available at this station..
/// </summary>
@ -2263,7 +2288,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Instructions.
/// Looks up a localized string similar to Help.
/// </summary>
public static string MarkingFeesAndBikes {
get {
@ -2687,7 +2712,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Instructions.
/// Looks up a localized string similar to Manual.
/// </summary>
public static string MarkingTabBikes {
get {
@ -2696,7 +2721,16 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Pricing.
/// Looks up a localized string similar to FAQ.
/// </summary>
public static string MarkingTabFaq {
get {
return ResourceManager.GetString("MarkingTabFaq", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Tariffs.
/// </summary>
public static string MarkingTabFees {
get {
@ -2839,6 +2873,26 @@ namespace TINK.MultilingualResources {
}
}
/// <summary>
/// Looks up a localized string similar to The rental of this {0} can only be terminated at {0} stations within the city area.
///
///A rental end in the suburbs Litzelstetten, Dingelsdorf, Wallhausen and Dettingen is not allowed..
/// </summary>
public static string MessageBikeIsBoundToCityInfoText {
get {
return ResourceManager.GetString("MessageBikeIsBoundToCityInfoText", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Bike belongs in the city area!.
/// </summary>
public static string MessageBikeIsBoundToCityInfoTitle {
get {
return ResourceManager.GetString("MessageBikeIsBoundToCityInfoTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Please enable Bluetooth to manage bike lock/locks..
/// </summary>
@ -3131,15 +3185,6 @@ namespace TINK.MultilingualResources {
}
}
/// <summary>
/// Looks up a localized string similar to Information.
/// </summary>
public static string MessageTitleInformation {
get {
return ResourceManager.GetString("MessageTitleInformation", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Warning.
/// </summary>
@ -3475,6 +3520,24 @@ namespace TINK.MultilingualResources {
}
}
/// <summary>
/// Looks up a localized string similar to Please state your name and/or the e-mail address of your rental bike account:.
/// </summary>
public static string SupportmailBodyNotLoggedIn {
get {
return ResourceManager.GetString("SupportmailBodyNotLoggedIn", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Describe your problem:.
/// </summary>
public static string SupportmailBodyText {
get {
return ResourceManager.GetString("SupportmailBodyText", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to {0}-app request.
/// </summary>

View file

@ -79,13 +79,13 @@
<value>Meine Räder</value>
</data>
<data name="MarkingFeesAndBikes" xml:space="preserve">
<value>Bedienung</value>
<value>Hilfe</value>
</data>
<data name="MarkingSettings" xml:space="preserve">
<value>Einstellungen</value>
</data>
<data name="MarkingTabBikes" xml:space="preserve">
<value>Bedienung</value>
<value>Anleitung</value>
</data>
<data name="MarkingTabFees" xml:space="preserve">
<value>Tarife</value>
@ -1143,6 +1143,17 @@ Vielen Dank für Ihre Fahrt!</value>
<data name="SupportmailSubjectAppmailWithStation" xml:space="preserve">
<value>{0}-App Anfrage: Station {1}</value>
</data>
<data name="MarkingBikeIsBoundToCity" xml:space="preserve">
<value>Stadtgebiet</value>
</data>
<data name="MessageBikeIsBoundToCityInfoText" xml:space="preserve">
<value>Die Miete dieses {0}s kann nur an {0}-Stationen innerhalb des Stadtgebiets beendet werden.
Ein Mietende in den Vororten Litzelstetten, Dingelsdorf, Wallhausen und Dettingen ist nicht erlaubt.</value>
</data>
<data name="MessageBikeIsBoundToCityInfoTitle" xml:space="preserve">
<value>Rad gehört ins Stadtgebiet!</value>
</data>
<data name="ErrorConnectLock" xml:space="preserve">
<value>Bitte treten Sie so nah wie möglich an das Fahrradschloss heran und versuchen Sie es erneut.</value>
</data>
@ -1238,4 +1249,20 @@ Wichtig: Senden Sie eine E-Mail an den Kundensupport (sonst wird Ihre bezahlte M
- Miete beenden (vorausgesetzt Sie befinden sich an einer passenden Station).&lt;br/&gt;
3. Nach Wahl von &lt;b&gt;Miete beenden&lt;/b&gt;: Prozess verfolgen, Rückmeldung ausfüllen und &lt;b&gt;unbedingt die Mietende-Bestätigung abwarten!&lt;/b&gt;</value>
</data>
<data name="MarkingTabFaq" xml:space="preserve">
<value>FAQ</value>
</data>
<data name="SupportmailBodyText" xml:space="preserve">
<value>Beschreiben Sie Ihr Problem:</value>
</data>
<data name="SupportmailBodyNotLoggedIn" xml:space="preserve">
<value>Bitte nennen Sie Ihren Namen und/oder die E-Mail Adresse Ihres Mietrad-Accounts:</value>
</data>
<data name="ChangeLog_3_0_371_MK" xml:space="preserve">
<value>1. Einfacher Zugriff auf die FAQ: Im Menü unter Hilfe können Sie bei Fragen und Problemen nun ganz einfach selber nach einer Lösung suchen.&lt;br/&gt;
2. Stadtgebiet- vs. Vorort-Räder: Mieträder, die ins Stadtgebiet gehören und nicht in den Vororten zurückgegeben werden können, sind nun durch entsprechende Icons markiert. Andersherum gilt, dass Mieträder aus den Vororten nicht im Stadtgebiet zurückgegeben werden können (ebenfalls mit Icons gekennzeichnet)!</value>
</data>
<data name="ChangeLog_3_0_371_SB" xml:space="preserve">
<value>Einfacher Zugriff auf die FAQ: Im Menü unter Hilfe können Sie bei Fragen und Problemen nun ganz einfach selber nach einer Lösung suchen.</value>
</data>
</root>

View file

@ -187,7 +187,7 @@ Rental can be ended if
<value>Contact</value>
</data>
<data name="MarkingFeesAndBikes" xml:space="preserve">
<value>Instructions</value>
<value>Help</value>
</data>
<data name="MarkingLoggedInStateInfoLoggedIn" xml:space="preserve">
<value>Logged in as {0}.</value>
@ -211,10 +211,10 @@ Rental can be ended if
<value>Settings</value>
</data>
<data name="MarkingTabBikes" xml:space="preserve">
<value>Instructions</value>
<value>Manual</value>
</data>
<data name="MarkingTabFees" xml:space="preserve">
<value>Pricing</value>
<value>Tariffs</value>
</data>
<data name="MessageAnswerOk" xml:space="preserve">
<value>OK</value>
@ -1269,6 +1269,17 @@ Thank you for your ride!</value>
<data name="SupportmailSubjectAppmail" xml:space="preserve">
<value>{0}-app request</value>
</data>
<data name="MarkingBikeIsBoundToCity" xml:space="preserve">
<value>City area</value>
</data>
<data name="MessageBikeIsBoundToCityInfoText" xml:space="preserve">
<value>The rental of this {0} can only be terminated at {0} stations within the city area.
A rental end in the suburbs Litzelstetten, Dingelsdorf, Wallhausen and Dettingen is not allowed.</value>
</data>
<data name="MessageBikeIsBoundToCityInfoTitle" xml:space="preserve">
<value>Bike belongs in the city area!</value>
</data>
<data name="ErrorLockStatusUnknown" xml:space="preserve">
<value>Position of lock bolt is unknown. Lock could be closed or open. Please try again or report bike to operator!</value>
</data>
@ -1330,4 +1341,20 @@ Important: Send an email to customer support (otherwise your paid rental will co
- End rental (provided you are at a suitable station).&lt;br/&gt;
3. After choosing &lt;b&gt;End rental&lt;/b&gt;: Follow the process, fill in the feedback and &lt;b&gt;wait for the end of rental confirmation!&lt;/b&gt;</value>
</data>
<data name="MarkingTabFaq" xml:space="preserve">
<value>FAQ</value>
</data>
<data name="SupportmailBodyText" xml:space="preserve">
<value>Describe your problem:</value>
</data>
<data name="SupportmailBodyNotLoggedIn" xml:space="preserve">
<value>Please state your name and/or the e-mail address of your rental bike account:</value>
</data>
<data name="ChangeLog_3_0_371_MK" xml:space="preserve">
<value>1. Easy access to FAQ: In the menu under Help, you can now easily search for a solution yourself for questions and problems.&lt;br/&gt;
2. City area vs. suburb bikes: Rental bikes that belong to the city area and cannot be returned to the suburbs are now marked by appropriate icons. Conversely, rental bikes from the suburbs cannot be returned in the city area (also marked with icons)!</value>
</data>
<data name="ChangeLog_3_0_371_SB" xml:space="preserve">
<value>Easy access to FAQ: In the menu under Help, you can now easily search for a solution yourself for questions and problems.</value>
</data>
</root>

View file

@ -95,19 +95,19 @@
<target state="final">Meine Räder</target>
</trans-unit>
<trans-unit id="MarkingFeesAndBikes" translate="yes" xml:space="preserve">
<source>Instructions</source>
<target state="translated">Bedienung</target>
<source>Help</source>
<target state="translated">Hilfe</target>
</trans-unit>
<trans-unit id="MarkingSettings" translate="yes" xml:space="preserve">
<source>Settings</source>
<target state="final">Einstellungen</target>
</trans-unit>
<trans-unit id="MarkingTabBikes" translate="yes" xml:space="preserve">
<source>Instructions</source>
<target state="final">Bedienung</target>
<source>Manual</source>
<target state="translated">Anleitung</target>
</trans-unit>
<trans-unit id="MarkingTabFees" translate="yes" xml:space="preserve">
<source>Pricing</source>
<source>Tariffs</source>
<target state="translated">Tarife</target>
</trans-unit>
<trans-unit id="ErrorLockMoving" translate="yes" xml:space="preserve">
@ -1574,6 +1574,22 @@ Vielen Dank für Ihre Fahrt!</target>
<source>{0}-app request: station {1}</source>
<target state="translated">{0}-App Anfrage: Station {1}</target>
</trans-unit>
<trans-unit id="MarkingBikeIsBoundToCity" translate="yes" xml:space="preserve">
<source>City area</source>
<target state="translated">Stadtgebiet</target>
</trans-unit>
<trans-unit id="MessageBikeIsBoundToCityInfoText" translate="yes" xml:space="preserve">
<source>The rental of this {0} can only be terminated at {0} stations within the city area.
A rental end in the suburbs Litzelstetten, Dingelsdorf, Wallhausen and Dettingen is not allowed.</source>
<target state="translated">Die Miete dieses {0}s kann nur an {0}-Stationen innerhalb des Stadtgebiets beendet werden.
Ein Mietende in den Vororten Litzelstetten, Dingelsdorf, Wallhausen und Dettingen ist nicht erlaubt.</target>
</trans-unit>
<trans-unit id="MessageBikeIsBoundToCityInfoTitle" translate="yes" xml:space="preserve">
<source>Bike belongs in the city area!</source>
<target state="translated">Rad gehört ins Stadtgebiet!</target>
</trans-unit>
<trans-unit id="ErrorConnectLock" translate="yes" xml:space="preserve">
<source>Please step as close as possible to the bike lock and try again.</source>
<target state="translated">Bitte treten Sie so nah wie möglich an das Fahrradschloss heran und versuchen Sie es erneut.</target>
@ -1710,6 +1726,28 @@ Wichtig: Senden Sie eine E-Mail an den Kundensupport (sonst wird Ihre bezahlte M
- Miete beenden (vorausgesetzt Sie befinden sich an einer passenden Station).<it id="1" pos="open">&lt;br/&gt;</it>
3. Nach Wahl von <bpt id="1">&lt;b&gt;</bpt>Miete beenden<ept id="1">&lt;/b&gt;</ept>: Prozess verfolgen, Rückmeldung ausfüllen und <bpt id="1">&lt;b&gt;</bpt>unbedingt die Mietende-Bestätigung abwarten!<ept id="1">&lt;/b&gt;</ept></target>
</trans-unit>
<trans-unit id="MarkingTabFaq" translate="yes" xml:space="preserve">
<source>FAQ</source>
<target state="translated">FAQ</target>
</trans-unit>
<trans-unit id="SupportmailBodyText" translate="yes" xml:space="preserve">
<source>Describe your problem:</source>
<target state="translated">Beschreiben Sie Ihr Problem:</target>
</trans-unit>
<trans-unit id="SupportmailBodyNotLoggedIn" translate="yes" xml:space="preserve">
<source>Please state your name and/or the e-mail address of your rental bike account:</source>
<target state="translated">Bitte nennen Sie Ihren Namen und/oder die E-Mail Adresse Ihres Mietrad-Accounts:</target>
</trans-unit>
<trans-unit id="ChangeLog_3_0_371_MK" translate="yes" xml:space="preserve">
<source>1. Easy access to FAQ: In the menu under Help, you can now easily search for a solution yourself for questions and problems.&lt;br/&gt;
2. City area vs. suburb bikes: Rental bikes that belong to the city area and cannot be returned to the suburbs are now marked by appropriate icons. Conversely, rental bikes from the suburbs cannot be returned in the city area (also marked with icons)!</source>
<target state="translated">1. Einfacher Zugriff auf die FAQ: Im Menü unter Hilfe können Sie bei Fragen und Problemen nun ganz einfach selber nach einer Lösung suchen.&lt;br/&gt;
2. Stadtgebiet- vs. Vorort-Räder: Mieträder, die ins Stadtgebiet gehören und nicht in den Vororten zurückgegeben werden können, sind nun durch entsprechende Icons markiert. Andersherum gilt, dass Mieträder aus den Vororten nicht im Stadtgebiet zurückgegeben werden können (ebenfalls mit Icons gekennzeichnet)!</target>
</trans-unit>
<trans-unit id="ChangeLog_3_0_371_SB" translate="yes" xml:space="preserve">
<source>Easy access to FAQ: In the menu under Help, you can now easily search for a solution yourself for questions and problems.</source>
<target state="translated">Einfacher Zugriff auf die FAQ: Im Menü unter Hilfe können Sie bei Fragen und Problemen nun ganz einfach selber nach einer Lösung suchen.</target>
</trans-unit>
</group>
</body>
</file>

View file

@ -82,7 +82,7 @@ namespace TINK.View
/// <param name="co2Saving"> Co2 saving information.</param>
/// <returns>User feedback.</returns>
Task<IUserFeedback> DisplayUserFeedbackPopup(
IBattery battery = null,
IBatteryMutable battery = null,
string co2Saving = null);
#if USCSHARP9

View file

@ -1,7 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TINK.Themes.Konrad">
<ResourceDictionary
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
x:Class="TINK.Themes.Konrad">
<!--Main color-->
<Color x:Key="primary-back-title-color">#D21113</Color>
@ -134,14 +136,22 @@
<Setter Property="FontSize" Value="20"/>
<Setter Property="TextTransform" Value="Uppercase"/>
<Setter Property="TextColor" Value="White"/>
<Setter Property="VerticalOptions" Value="Center"/>
<Setter Property="VerticalOptions" Value="Start"/>
<Setter Property="HorizontalOptions" Value="Start"/>
<Setter Property="Grid.Column" Value="1"/>
<Setter Property="Padding" Value="0,12,0,12"/>
</Style>
<Style x:Key="Image-Navbar" TargetType="Image">
<Setter Property="Source" Value="swk_theme.png"/>
<Setter Property="Aspect" Value="AspectFill"/>
<Setter Property="Grid.ColumnSpan" Value="2"/>
</Style>
<!--TabbedPage-->
<Style x:Key="TabbedPageStyle" TargetType="TabbedPage">
<Setter Property="BarBackgroundColor" Value="White"/>
<Setter Property="UnselectedTabColor" Value="DimGray"/>
<Setter Property="SelectedTabColor" Value="{x:DynamicResource primary-back-title-color}"/>
<Setter Property="android:TabbedPage.ToolbarPlacement" Value="Default"/>
</Style>
</ResourceDictionary>

View file

@ -1,7 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TINK.Themes.ShareeBike">
<ResourceDictionary
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
x:Class="TINK.Themes.ShareeBike">
<!--Main color-->
<Color x:Key="primary-back-title-color">#009899</Color>
@ -149,18 +151,25 @@
<!--Navbar-->
<Style x:Key="Label-Navbar" TargetType="Label">
<Setter Property="FontSize" Value="20"/>
<!--<Setter Property="TextTransform" Value="Uppercase"/>-->
<Setter Property="TextColor" Value="White"/>
<Setter Property="FontSize" Value="20"/>
<Setter Property="TextColor" Value="White"/>
<Setter Property="FontFamily" Value="RobotoRegular"/>
<Setter Property="VerticalOptions" Value="Center"/>
<Setter Property="HorizontalOptions" Value="Start"/>
<Setter Property="Grid.Column" Value="1"/>
</Style>
<Setter Property="VerticalOptions" Value="Start"/>
<Setter Property="HorizontalOptions" Value="Start"/>
<Setter Property="Padding" Value="0,12,0,12"/>
</Style>
<Style x:Key="Image-Navbar" TargetType="Image">
<Setter Property="Source" Value="swk_theme.png"/>
<Setter Property="Aspect" Value="AspectFill"/>
<Setter Property="Grid.ColumnSpan" Value="2"/>
</Style>
<!--TabbedPage-->
<Style x:Key="TabbedPageStyle" TargetType="TabbedPage">
<Setter Property="BarBackgroundColor" Value="White"/>
<Setter Property="UnselectedTabColor" Value="DimGray"/>
<Setter Property="SelectedTabColor" Value="{x:DynamicResource primary-back-title-color}"/>
<Setter Property="android:TabbedPage.ToolbarPlacement" Value="Default"/>
</Style>
</ResourceDictionary>

View file

@ -3,6 +3,7 @@ using System;
using System.ComponentModel;
using System.Text.RegularExpressions;
using TINK.Model.Bikes.BikeInfoNS.BikeNS;
using TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
#if !USEFLYOUT
#endif
using TINK.Model.Connector;
@ -136,20 +137,32 @@ namespace TINK.ViewModel.Bikes.Bike
selectedBike.PropertyChanged +=
(sender, eventargs) => OnSelectedBikePropertyChanged(eventargs.PropertyName);
var battery = selectedBike.Drive?.Battery;
if (battery != null)
{
battery.PropertyChanged += (_, args) =>
{
if (args.PropertyName == nameof(BatteryMutable.CurrentChargeBars))
{
RaisePropertyChanged(this, new PropertyChangedEventArgs(nameof(CurrentChargeBars)));
}
};
}
BikesViewModel = bikesViewModel
?? throw new ArgumentException($"Can not construct {GetType().Name}-object. {nameof(bikesViewModel)} must not be null.");
OpenUrlInBrowser = openUrlInBrowser ?? (url => { Log.ForContext<BikeViewModelBase>().Error($"No browse service avialble to upen {url}."); });
OpenUrlInBrowser = openUrlInBrowser ?? (url => { Log.ForContext<BikeViewModelBase>().Error($"No browse service available to open {url}."); });
}
/// <summary>
/// Handles BikeInfoMutable events.
/// Helper member to raise events. Maps model event change notification to view model events.
/// </summary>
/// <param name="p_strNameOfProp"></param>
private void OnSelectedBikePropertyChanged(string p_strNameOfProp)
/// <param name="nameOfProp"></param>
private void OnSelectedBikePropertyChanged(string nameOfProp)
{
if (p_strNameOfProp == nameof(State))
if (nameOfProp == nameof(State))
{
OnSelectedBikeStateChanged(); // Notify derived class about change of state.
}
@ -211,7 +224,7 @@ namespace TINK.ViewModel.Bikes.Bike
Bike.Drive.Type == Model.Bikes.BikeInfoNS.DriveNS.DriveType.Pedelec
&& (!Bike.Drive.Battery.IsHidden.HasValue /* no value means show battery level */ || Bike.Drive.Battery.IsHidden.Value == false);
/// Gets the image path for bike type Citybike, CargoLong, Trike or Pedelec.
/// Gets the image path for bike type City bike, CargoLong, Trike or Pedelec.
public string DisplayedBikeImageSourceString => $"bike_{Bike.TypeOfBike}_{Bike.Drive.Type}_{Bike.WheelType}.png";
/// <summary>
@ -302,7 +315,7 @@ namespace TINK.ViewModel.Bikes.Bike
/// <summary>
/// Gets reserved into display text.
/// </summary>
/// <todo>Log unexpeced states.</todo>
/// <todo>Log unexpected states.</todo>
/// <param name="p_oInUseState"></param>
/// <returns>Display text</returns>
private string GetReservedInfo(
@ -316,7 +329,7 @@ namespace TINK.ViewModel.Bikes.Bike
/// <summary>
/// Gets booked into display text.
/// </summary>
/// <todo>Log unexpeced states.</todo>
/// <todo>Log unexpected states.</todo>
/// <param name="p_oInUseState"></param>
/// <returns>Display text</returns>
private string GetBookedInfo(
@ -366,7 +379,7 @@ namespace TINK.ViewModel.Bikes.Bike
}
}
/// <summary> Holds description about the tarif. </summary>
/// <summary> Holds description about the tariff. </summary>
public TariffDescriptionViewModel TariffDescription => new TariffDescriptionViewModel(Bike.TariffDescription);
/// <summary> Gets the value of property <see cref="StateColor"/> when PropertyChanged was fired. </summary>

View file

@ -23,6 +23,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
{
public Xamarin.Forms.Command ShowTrackingInfoCommand { get; private set; }
public Xamarin.Forms.Command ShowRideTypeInfoCommand { get; private set; }
public Xamarin.Forms.Command ShowBikeIsBoundToCityInfoCommand { get; private set; }
/// <summary> Notifies GUI about changes. </summary>
public override event PropertyChangedEventHandler PropertyChanged;
@ -123,6 +124,16 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
});
ShowBikeIsBoundToCityInfoCommand = new Xamarin.Forms.Command(async () => {
// later, if value comes from backend: message = TariffDescription.CityAreaType
await ViewService.DisplayAlert(
AppResources.MessageBikeIsBoundToCityInfoTitle,
String.Format(AppResources.MessageBikeIsBoundToCityInfoText,selectedBike.TypeOfBike),
AppResources.MessageAnswerOk);
});
RequestHandler = user.IsLoggedIn
? RequestHandlerFactory.Create(
selectedBike,
@ -178,6 +189,9 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
RaisePropertyChangedEvent(lastHandler);
}
public bool IsBikeBoundToCity
=> Bike.AaRideType == TINK.Model.Bikes.BikeInfoNS.BikeNS.AaRideType.NoAaRide ? true : false;
/// <summary> Gets visibility of the copri command button. </summary>
public bool IsButtonVisible
=> RequestHandler.IsButtonVisible;

View file

@ -1,15 +1,10 @@
using System;
using System.Threading.Tasks;
using Serilog;
using TINK.Model.Connector;
using TINK.Model;
using TINK.MultilingualResources;
using TINK.Repository.Exception;
using TINK.Repository.Request;
using TINK.Services.Logging;
using TINK.View;
using static TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command.CloseCommand;
using TINK.Services.BluetoothLock;
using System.ComponentModel;
namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
@ -33,20 +28,6 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
/// </summary>
private IViewService ViewService { get; }
/// <summary>
/// Service to control locks.
/// </summary>
private ILocksService LockService { get; }
/// <summary> Provides a connector object.</summary>
protected Func<bool, IConnector> ConnectorFactory { get; }
/// <summary> Delegate to retrieve connected state. </summary>
private Func<bool> IsConnectedDelegate { get; }
/// <summary>Gets the is connected state. </summary>
bool IsConnected;
/// <summary>Object to start or stop update of view model objects from Copri.</summary>
private Func<IPollingUpdateTaskManager> ViewUpdateManager { get; }
@ -83,7 +64,6 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
switch (step)
{
case Step.StartStopingPolling:
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
break;
case Step.StartingQueryingLocation:
@ -188,12 +168,12 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
// 1. Step
// Parameter for RentalProcess View
BikesViewModel.RentalProcess = new RentalProcess(SelectedBike.Id)
BikesViewModel.StartRentalProcess(new RentalProcessViewModel(SelectedBike.Id)
{
State = CurrentRentalProcess.CloseLock,
StepIndex = 1,
Result = CurrentStepStatus.None
};
});
// Close Lock
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessCloseLockStepCloseLock;
@ -215,9 +195,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
await ViewUpdateManager().StartAsync();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
BikesViewModel.IsIdle = true;
return;
}
@ -231,90 +210,31 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
BikesViewModel.RentalProcess.Result = CurrentStepStatus.None;
BikesViewModel.RentalProcess.ImportantStepInfoText = String.Empty;
//// Ask if lock is closed
//var isLockClosed = await ViewService.DisplayAlert(
// AppResources.QuestionRentalProcessCloseLockCheckLockTitle,
// AppResources.QuestionRentalProcessCloseLockCheckLockText,
// AppResources.QuestionRentalProcessCloseLockCheckLockAnswerYes,
// AppResources.QuestionRentalProcessCloseLockCheckLockAnswerNo);
// Question if park bike or end rental
IsEndRentalRequested = await ViewService.DisplayAlert(
AppResources.QuestionRentalProcessCloseLockEndOrContinueTitle,
AppResources.QuestionRentalProcessCloseLockEndOrContinueText,
AppResources.QuestionRentalProcessCloseLockEndRentalAnswer,
AppResources.QuestionRentalProcessCloseLockContinueRentalAnswer);
//// If lock is not closed
//if(isLockClosed == false)
//{
// var retryOrContactresult = await ViewService.DisplayAlert(
// AppResources.MessageRentalProcessCloseLockNotClosedTitle,
// AppResources.MessageRentalProcessCloseLockNotClosedText,
// AppResources.MessageAnswerRetry,
// AppResources.MessageAnswerContactSupport);
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
// BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
// if (retryOrContactresult == true)
// {
// //restart CloseLock()
// }
// else if(retryOrContactresult == false)
// {
// await OpenContactPageAsync();
// }
//}
// If lock is closed
//else if(isLockClosed == true)
//{
IsEndRentalRequested = await ViewService.DisplayAlert(
AppResources.QuestionRentalProcessCloseLockEndOrContinueTitle,
AppResources.QuestionRentalProcessCloseLockEndOrContinueText,
AppResources.QuestionRentalProcessCloseLockEndRentalAnswer,
AppResources.QuestionRentalProcessCloseLockContinueRentalAnswer);
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
// Continue with End rental in RequestHandler
if (IsEndRentalRequested == true)
{
return;
}
// Park bike
else if(IsEndRentalRequested == false)
{
await ViewService.DisplayAlert(
AppResources.MessageRentalProcessCloseLockFinishedTitle,
AppResources.MessageRentalProcessCloseLockFinishedText,
AppResources.MessageAnswerOk);
}
//}
// Message for parking bike
if(IsEndRentalRequested == false)
{
await ViewService.DisplayAlert(
AppResources.MessageRentalProcessCloseLockFinishedTitle,
AppResources.MessageRentalProcessCloseLockFinishedText,
AppResources.MessageAnswerOk);
}
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
BikesViewModel.IsIdle = true;
return;
}
/// <summary> Opens support. </summary>
//#if USEFLYOUT
// public void OpenContactPageAsync()
//#else
// public async Task OpenContactPageAsync()
//#endif
// {
// try
// {
// // Open Contact Page with Contact information for operator of SelectedBike
//#if USEFLYOUT
// ViewService.ShowPage(ViewTypes.ContactPage, AppResources.MarkingFeedbackAndContact);
//#else
// await ViewService.ShowPage("//ContactPage");
//#endif
// }
// catch (Exception p_oException)
// {
// Log.Error("Ein unerwarteter Fehler ist auf der Seite Kontakt aufgetreten. Kontext: Klick auf Konakt aufnehmen bei Schloss schließen (Schloss nicht zu!). {@Exception}", p_oException);
// return;
// }
// }
/// <summary>
/// True if user requested End rental.
/// Default value of user request to end rental = false.
/// </summary>
private bool isEndRentalRequested = false;

View file

@ -76,12 +76,12 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
?? throw new ArgumentException($"Can not construct {typeof(EndRentalActionViewModel<T>)}-object. {nameof(bikesViewModel)} must not be null.");
// Set parameter for RentalProcess View to initial value.
BikesViewModel.RentalProcess = new RentalProcess(SelectedBike.Id)
BikesViewModel.StartRentalProcess(new RentalProcessViewModel(SelectedBike.Id)
{
State = CurrentRentalProcess.None,
StepIndex = 0,
Result = CurrentStepStatus.None
};
});
}
/// <summary>
@ -155,12 +155,12 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
// 1. Step
// Parameter for RentalProcess View
BikesViewModel.RentalProcess = new RentalProcess(SelectedBike.Id)
BikesViewModel.StartRentalProcess(new RentalProcessViewModel(SelectedBike.Id)
{
State = CurrentRentalProcess.EndRental,
StepIndex = 1,
Result = CurrentStepStatus.None
};
});
// Get Location
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessEndRentalStepGPS;
@ -271,7 +271,16 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
BikesViewModel.RentalProcess.ImportantStepInfoText = String.Empty;
var feedBackUri = SelectedBike?.OperatorUri;
var feedback = await ViewService.DisplayUserFeedbackPopup(SelectedBike.Drive?.Battery);
var battery = SelectedBike.Drive?.Battery;
var feedback = await ViewService.DisplayUserFeedbackPopup(
battery,
bookingFinished?.Co2Saving);
if (battery != null
&& feedback.CurrentChargeBars != null)
{
SelectedBike.Drive.Battery.CurrentChargeBars = feedback.CurrentChargeBars;
}
#endif
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;

View file

@ -62,7 +62,16 @@ namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
await ViewUpdateManager().StopAsync();
// Do get Feedback
var feedback = await ViewService.DisplayUserFeedbackPopup(SelectedBike.Drive?.Battery, SelectedBike?.BookingFinishedModel?.Co2Saving);
var battery = SelectedBike.Drive?.Battery;
var feedback = await ViewService.DisplayUserFeedbackPopup(
battery,
SelectedBike?.BookingFinishedModel?.Co2Saving);
if (battery != null
&& feedback.CurrentChargeBars != null)
{
SelectedBike.Drive.Battery.CurrentChargeBars = feedback.CurrentChargeBars;
}
BikesViewModel.ActionText = AppResources.ActivityTextSubmittingFeedback;
IsConnected = IsConnectedDelegate();

View file

@ -10,7 +10,6 @@ using TINK.Model.Bikes;
using TINK.Model.Connector;
using TINK.Model.Device;
using TINK.Model.User;
using TINK.MultilingualResources;
using TINK.Services.BluetoothLock;
using TINK.Services.Geolocation;
using TINK.Services.Permissions;
@ -344,24 +343,25 @@ namespace TINK.ViewModel.Bikes
}
/// <summary> Used to display active rental process.</summary>
private IRentalProcess _rentalProcess = new RentalProcess();
private IRentalProcessViewModel _rentalProcess = new RentalProcessViewModel();
/// <summary> Holds the active rental process.</summary>
public IRentalProcess RentalProcess
public IRentalProcessViewModel RentalProcess => _rentalProcess;
/// <summary>
/// Starts the rental process.
/// </summary>
/// <param name="processViewModel">Rental process values to start with.</param>
public void StartRentalProcess(IRentalProcessViewModel processViewModel)
{
get => _rentalProcess;
set
{
if (value == _rentalProcess)
return;
if (processViewModel == _rentalProcess)
return;
_rentalProcess = value;
_rentalProcess.LoadFrom(processViewModel);
BikeInRentalProcess = this.FirstOrDefault(bike => bike.Id == _rentalProcess.BikeId) as Bike.BluetoothLock.BikeViewModel;
BikeInRentalProcess = this.FirstOrDefault(bike => bike.Id == _rentalProcess.BikeId) as Bike.BluetoothLock.BikeViewModel;
base.OnPropertyChanged(new PropertyChangedEventArgs(nameof(RentalProcess)));
base.OnPropertyChanged(new PropertyChangedEventArgs(nameof(BikeInRentalProcess)));
}
base.OnPropertyChanged(new PropertyChangedEventArgs(nameof(RentalProcess)));
base.OnPropertyChanged(new PropertyChangedEventArgs(nameof(BikeInRentalProcess)));
}
public Bike.BluetoothLock.BikeViewModel BikeInRentalProcess { get; private set; }

View file

@ -4,7 +4,13 @@ namespace TINK.ViewModel.Bikes
public interface IBikesViewModel
{
/// <summary> Holds info about active rental process. </summary>
IRentalProcess RentalProcess { get; set; }
IRentalProcessViewModel RentalProcess { get; }
/// <summary>
/// Starts the rental process.
/// </summary>
/// <param name="processViewModel">Rental process values to start with.</param>
void StartRentalProcess(IRentalProcessViewModel process);
/// <summary> Holds info about current action. </summary>
string ActionText { get; set; }

View file

@ -2,8 +2,14 @@ using TINK.Model;
namespace TINK.ViewModel.Bikes
{
public interface IRentalProcess
public interface IRentalProcessViewModel
{
/// <summary>
/// Loads rental process view model from source.
/// </summary>
/// <param name="processViewModel">Source object to load from.</param>
void LoadFrom(IRentalProcessViewModel processViewModel);
/// <summary>
/// Gets the id of the bike which is rental ends.
/// </summary>

View file

@ -21,16 +21,31 @@ namespace TINK.ViewModel.Bikes
Failed = 2,
}
public class RentalProcess : IRentalProcess, INotifyPropertyChanged
public class RentalProcessViewModel : IRentalProcessViewModel, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public RentalProcess(string bikeId = null) => BikeId = bikeId ?? string.Empty;
public RentalProcessViewModel(string bikeId = null) => BikeId = bikeId ?? string.Empty;
/// <summary>
/// Loads rental process view model from source.
/// </summary>
/// <param name="processViewModel">Source object to load from </param>
public void LoadFrom(IRentalProcessViewModel processViewModel)
{
BikeId = processViewModel.BikeId;
_state = processViewModel.State;
_stepIndex = processViewModel.StepIndex;
_stepInfoText = processViewModel.StepInfoText;
_importantStepInfoText = processViewModel.ImportantStepInfoText;
_result = processViewModel.Result;
EndRentalInfo = processViewModel.EndRentalInfo;
}
/// <summary>
/// Gets the id of the bike which is rental ends.
/// </summary>
public string BikeId { get; }
public string BikeId { get; private set; }
/// <summary> Holds info about active rental process. </summary>
private CurrentRentalProcess _state = CurrentRentalProcess.None;
@ -53,9 +68,7 @@ namespace TINK.ViewModel.Bikes
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(State)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(StepIndex)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Result)));
}
}
/// <summary> Holds info about current step in rental process. </summary>

View file

@ -5,6 +5,7 @@ using System.Threading.Tasks;
using System.Windows.Input;
using Plugin.Messaging;
using Serilog;
using TINK.Model;
using TINK.Model.Stations;
using TINK.Model.Stations.StationNS;
using TINK.MultilingualResources;
@ -31,6 +32,9 @@ namespace TINK.ViewModel.Info
/// <summary> Holds the name of the app (sharee.bike, Mein konrad, ...)</summary>
string AppFlavorName { get; }
/// <summary> Reference on the tink app instance. </summary>
private ITinkApp TinkApp { get; }
/// <summary> Holds a reference to the external trigger service. </summary>
private Action OpenUrlInExternalBrowser { get; }
@ -45,6 +49,7 @@ namespace TINK.ViewModel.Info
/// <param name="viewService">View service to notify user.</param>
public ContactPageViewModel(
string appFlavorName,
ITinkApp tinkApp,
Func<string> createAttachment,
Action openUrlInExternalBrowser,
IViewService viewService)
@ -53,6 +58,9 @@ namespace TINK.ViewModel.Info
? appFlavorName
: throw new ArgumentException("Can not instantiate contact page view model- object. No app name centered.");
TinkApp = tinkApp
?? throw new ArgumentException("Can not instantiate settings page view model- object. No tink app object available.");
CreateAttachment = createAttachment
?? throw new ArgumentException("Can not instantiate contact page view model- object. No create attachment provider available.");
@ -141,7 +149,8 @@ namespace TINK.ViewModel.Info
Cc = APPSUPPORTMAILADDRESS.ToUpper() != MailAddressText.ToUpper() // do not sent copy if same mail address
&& MailAddressText != "konrad@sharee.bike" // do not sent copy if Mein konrad
? new List<string> { APPSUPPORTMAILADDRESS } : new List<string>(),
Subject = string.Format(AppResources.SupportmailSubjectOperatormail, AppFlavorName, SelectedStation?.Id)
Subject = string.Format(AppResources.SupportmailSubjectOperatormail, AppFlavorName, SelectedStation?.Id),
Body = TinkApp.ActiveUser.Mail != null ? $"{AppResources.SupportmailBodyText}\r\n\r\n\r\n\r\n{string.Format(AppResources.MarkingLoggedInStateInfoLoggedIn, TinkApp.ActiveUser.Mail)}" : $"{AppResources.SupportmailBodyText}\r\n\r\n\r\n\r\n{string.Format(AppResources.SupportmailBodyNotLoggedIn)}"
});
return;
@ -172,7 +181,8 @@ namespace TINK.ViewModel.Info
var message = new EmailMessage
{
To = new List<string> { APPSUPPORTMAILADDRESS },
Subject = SelectedStation?.Id != null ? string.Format(AppResources.SupportmailSubjectAppmailWithStation, AppFlavorName, SelectedStation?.Id) : string.Format(AppResources.SupportmailSubjectAppmail, AppFlavorName)
Subject = SelectedStation?.Id != null ? string.Format(AppResources.SupportmailSubjectAppmailWithStation, AppFlavorName, SelectedStation?.Id) : string.Format(AppResources.SupportmailSubjectAppmail, AppFlavorName),
Body = TinkApp.ActiveUser.Mail != null ? $"{AppResources.SupportmailBodyText}\r\n\r\n\r\n\r\n{string.Format(AppResources.MarkingLoggedInStateInfoLoggedIn, TinkApp.ActiveUser.Mail)}" : $"{AppResources.SupportmailBodyText}\r\n\r\n\r\n\r\n{string.Format(AppResources.SupportmailBodyNotLoggedIn)}"
};
// Send with attachment.

View file

@ -6,7 +6,6 @@ using TINK.Model;
using TINK.Model.Bikes;
using TINK.Model.Connector;
using TINK.Model.Services.CopriApi;
using TINK.ViewModel.Info;
using Xamarin.Forms;
namespace TINK.ViewModel.Contact
@ -15,6 +14,10 @@ namespace TINK.ViewModel.Contact
{
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Holds the current ui two letter ISO language name.
/// </summary>
private string UiIsoLanguageName { get; }
/// <summary> Holds value whether site caching is on or off.</summary>
bool IsSiteCachingOn { get; }
@ -71,6 +74,7 @@ namespace TINK.ViewModel.Contact
string feesResourcePath,
string bikesResourcePath,
bool isSiteCachingOn,
string uiIsoLangugageName,
Func<IQuery> queryProvider,
Action<IResourceUrls> updateUrlsAction)
{
@ -80,6 +84,7 @@ namespace TINK.ViewModel.Contact
IsSiteCachingOn = isSiteCachingOn;
QueryProvider = queryProvider;
UpdateUrlsAction = updateUrlsAction;
UiIsoLanguageName = uiIsoLangugageName;
}
/// <summary> Holds the name of the host.</summary>
@ -130,6 +135,13 @@ namespace TINK.ViewModel.Contact
: await Task.FromResult(ViewModelHelper.FromBody("No bikes instruction resource available. Resource path is null or empty."))
};
FAQ = new HtmlWebViewSource
{
Html = UiIsoLanguageName == "de"
? await ViewModelHelper.GetSource($"https://sharee.bike/faq/fahrrad-nutzung/", IsSiteCachingOn)
: await ViewModelHelper.GetSource($"https://sharee.bike/faq/bike-usage/", IsSiteCachingOn)
};
// Set state to idle.
IsIdle = true;
}
@ -138,6 +150,8 @@ namespace TINK.ViewModel.Contact
private HtmlWebViewSource typesOfBikesText;
private HtmlWebViewSource faq;
public HtmlWebViewSource RentBikeText
{
get => rentBikeText;
@ -157,5 +171,15 @@ namespace TINK.ViewModel.Contact
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TypesOfBikesText)));
}
}
public HtmlWebViewSource FAQ
{
get => faq;
set
{
faq = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(FAQ)));
}
}
}
}