Version 3.0.363

This commit is contained in:
Anja 2023-04-19 12:14:14 +02:00
parent 4ff3307997
commit 91d42552c7
212 changed files with 1799 additions and 1318 deletions

17
.vsspell Normal file
View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Visual Studio Spell Checker configuration file - [https://github.com/EWSoftware/VSSpellChecker]
Do not edit the XML. Use the configuration file editor in Visual Studio to modify the settings. -->
<SpellCheckerConfiguration Format="2018.8.16.0">
<InheritAdditionalDictionaryFolders>True</InheritAdditionalDictionaryFolders>
<AdditionalDictionaryFolders>
<Folder>.\\</Folder>
</AdditionalDictionaryFolders>
<SelectedLanguages />
<InheritIgnoredClassifications>True</InheritIgnoredClassifications>
<IgnoredClassifications />
<InheritIgnoredWords>True</InheritIgnoredWords>
<IgnoredWordsFile>IgnoredWords.dic</IgnoredWordsFile>
<InheritExclusionExpressions>True</InheritExclusionExpressions>
<InheritIgnoredFilePatterns>True</InheritIgnoredFilePatterns>
<InheritXmlSettings>True</InheritXmlSettings>
</SpellCheckerConfiguration>

11
IgnoredWords.dic Normal file
View file

@ -0,0 +1,11 @@
cts
Darmstadt
enum
Freiburg
haveltec
javaminister
konrad
Mein
sharee
tink
xdoc

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="internalOnly" package="com.TeilRad.LastenradBayern" android:versionName="3.0.362" android:versionCode="362">
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="internalOnly" package="com.TeilRad.LastenradBayern" android:versionName="3.0.363" android:versionCode="363">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="31" />
<!-- Google Maps related permissions -->
<!-- Permission to receive remote notifications from Google Play Services -->

View file

@ -56,8 +56,8 @@
<key>CFBundleDisplayName</key>
<string>LastenradBayern</string>
<key>CFBundleVersion</key>
<string>362</string>
<string>363</string>
<key>CFBundleShortVersionString</key>
<string>3.0.362</string>
<string>3.0.363</string>
</dict>
</plist>

View file

@ -66,7 +66,7 @@
<Frame>
<StackLayout>
<Label FormattedText="{Binding LikeTinkApp}"/>
<!--- Mail to app- releated support -->
<!--- Mail to app- related support -->
<Button
Text="{x:Static resources:AppResources.ActionContactMailAppReleated}"
IsEnabled="{Binding IsSendMailAvailable}"

View file

@ -1,4 +1,4 @@
using System;
using System;
using TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
using Xamarin.CommunityToolkit.UI.Views;
using Xamarin.Forms.Xaml;
@ -69,7 +69,7 @@ namespace TINK.View
#endif
{
/// <summary>
/// Holds the current chargeing level of the battery entered by user in bars, null if unkonwn.
/// Holds the current charging level of the battery entered by user in bars, null if unknown.
/// </summary>
public int? CurrentChargeBars { get; set; }
@ -87,4 +87,4 @@ namespace TINK.View
public string Message { get; set; }
}
}
}
}

View file

@ -24,7 +24,7 @@
x:Name="EMailEntry"
Text="{Binding MailAddress}"
IsEnabled="{Binding IsLoggedOut}"/>
<Label Text="{x:Static resources:AppResources.MarkingLoginPasswordLabel}"/>
<Label Text="{x:Static resources:AppResources.MarkingLoginPasswordPlaceholder}"/>
<Entry
Placeholder="{x:Static resources:AppResources.MarkingLoginPasswordPlaceholder}"
AutomationId="password_text"

View file

@ -100,7 +100,7 @@ namespace TINK.View.MyBikes
{
if (m_oViewModel == null)
{
// View model might be null (Example: Occured when page to querry for location permissions was opened)
// View model might be null (Example: Occured when page to query for location permissions was opened)
return;
}

View file

@ -1,5 +1,5 @@
using System;
using TINK.Model.Station;
using System;
using TINK.Model.Stations;
#if USEFLYOUT
using TINK.View.MasterDetail;
#endif
@ -9,12 +9,12 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.Root
{
/// <summary>
/// Mamages creation of detail pages if a flyout page menu entry is selected.
/// Manages creation of detail pages if a flyout page menu entry is selected.
/// Exposes flyout page style navigation which is used by detail pages.
/// </summary>
/// <remarks>
/// Examples of use cases when detail pages do navigation:
// - switch to map page after succesfully logging in/ logging out
// - switch to map page after successfully logging in/ logging out
// - switch to login page form bikes at station page if not yet logged in
/// </remarks>
[XamlCompilation(XamlCompilationOptions.Compile)]
@ -29,7 +29,7 @@ namespace TINK.View.Root
InitializeComponent();
FlyoutPage.ListView.ItemSelected += OnListViewItemSelected;
// Any type of split behaviour conflics with map shifting functionality (assuming FlyoutPage behaves same like MasterDetailPage).
// Any type of split behavior conflicts with map shifting functionality (assuming FlyoutPage behaves same like MasterDetailPage).
FlyoutLayoutBehavior = FlyoutLayoutBehavior.Popover;
var navigationPage = Detail as NavigationPage;
@ -62,7 +62,7 @@ namespace TINK.View.Root
}
// Set selected station to new
App.ModelRoot.SelectedStation = new NullStation();
App.ModelRoot.SelectedStation = new TINK.Model.Stations.StationNS.NullStation();
ShowPage(item.TargetType, item.Title);
@ -92,4 +92,4 @@ namespace TINK.View.Root
Detail = new NavigationPage(page);
}
}
}
}

View file

@ -441,7 +441,7 @@ namespace TINK.Services.BluetoothLock.BLE
if (authInfo.K_seed.Length != SEEDLENGTH
|| authInfo.K_u.Length <= 0)
{
throw new AuthKeyException($"Can not authenticate. Invalid seed-/ k-user-lenght {authInfo.K_seed.Length}/ {authInfo.K_u.Length} detected.");
throw new AuthKeyException($"Can not authenticate. Invalid seed-/ k-user-length {authInfo.K_seed.Length}/ {authInfo.K_u.Length} detected.");
}
if (Device.State == Plugin.BLE.Abstractions.DeviceState.Connected)
@ -551,7 +551,7 @@ namespace TINK.Services.BluetoothLock.BLE
if (authInfo.K_seed.Length != SEEDLENGTH
|| authInfo.K_u.Length <= 0)
{
throw new AuthKeyException($"Can not authenticate. Invalid seed-/ k-user-lenght {authInfo.K_seed.Length}/ {authInfo.K_u.Length} detected.");
throw new AuthKeyException($"Can not authenticate. Invalid seed-/ k-user-length {authInfo.K_seed.Length}/ {authInfo.K_u.Length} detected.");
}
Log.ForContext<LockItBase>().Debug($"Connection state is {deviceState} in context of auth.");
@ -636,11 +636,11 @@ namespace TINK.Services.BluetoothLock.BLE
cts.CancelAfter(READ_TIMEOUT_MS);
try
{
seedLockEncrypted = await authCharacteristic.ReadAsync(cts.Token); // encrypted seed value (random value) from lock to decypt using k_user
seedLockEncrypted = await authCharacteristic.ReadAsync(cts.Token); // encrypted seed value (random value) from lock to decrypt using k_user
}
catch (System.Exception exception)
{
Log.ForContext<LockItBase>().Error("Retrieveing encrypted random value from lock (seed)(ReadAsync-call) failed.{ReadCharacteristic}{Exception}", ToSerilogString(authCharacteristic), exception);
Log.ForContext<LockItBase>().Error("Retrieving encrypted random value from lock (seed)(ReadAsync-call) failed.{ReadCharacteristic}{Exception}", ToSerilogString(authCharacteristic), exception);
throw new System.Exception(string.Format("Can not authenticate. Reading encrypted seed failed. {0}", exception.Message), exception);
}
finally
@ -648,7 +648,7 @@ namespace TINK.Services.BluetoothLock.BLE
cts.Dispose();
}
Log.ForContext<LockItBase>().Debug("Retrieveing encrypted random value from lock (seed)(ReadAsync-call) succeeded.{ReadCharacteristic}{Reading}", ToSerilogString(authCharacteristic), "***");
Log.ForContext<LockItBase>().Debug("Retrieving encrypted random value from lock (seed)(ReadAsync-call) succeeded.{ReadCharacteristic}{Reading}", ToSerilogString(authCharacteristic), "***");
var crypto = new AuthCryptoHelper(
seedLockEncrypted,
@ -701,7 +701,7 @@ namespace TINK.Services.BluetoothLock.BLE
/// <exception cref="BluetoothDisconnectedException">App is not connected to lock.</exception>
/// <exception cref="CoundntGetCharacteristicException">Getting state characteristic to read from failed.</exception>
/// <exception cref="Exception">
/// Call not from main thread or unkonwn platform detected or
/// Call not from main thread or unknown platform detected or
/// query device state (connected, disconnected, ....) failed for an unknown reason or returned an unexpected value or
/// reading state characteristic failed or reading from characteristic was empty.
/// </exception>
@ -1044,8 +1044,8 @@ namespace TINK.Services.BluetoothLock.BLE
{
ActivateLockWriteCounter--;
Log.ForContext<LockItBase>().Error(open
? "Encypting command to open lock failed. {Exception}"
: "Encypting command to close lock failed. {Exception}",
? "Encrypting command to open lock failed. {Exception}"
: "Encrypting command to close lock failed. {Exception}",
exception);
throw new System.Exception(open
? $"Can not open lock. Encrypting command to lock/ unlock failed. {exception.Message}"
@ -1251,6 +1251,6 @@ namespace TINK.Services.BluetoothLock.BLE
=> charcteristic.Id.ToString();
private static string ToSerilogString(byte[] byteArray)
=> "***"; // For debuging purposes it might be reqired to return string.Join(",", byteArray); Do not log any confidental value in production context.
=> "***"; // For debugging purposes it might be required to return string.Join(",", byteArray); Do not log any confidental value in production context.
}
}

View file

@ -162,7 +162,7 @@ namespace TINK.Services.BluetoothLock.BLE
// - LockitLockingState.Closed
// - LockitLockingState.Unknown
// - LockitLockingState.CouldntOpenBoldBlocked
// Internal error which sould never occure. Lock refuses to open but connection is ok.
// Internal error which should never occur. Lock refuses to open but connection is ok.
Log.ForContext<LockItEventBased>().Debug($"Opening lock failed. Unexpected lock state {lockingState.Value.GetLockingState()} detected.");
throw new CouldntOpenInconsistentStateExecption(lockingState.Value.GetLockingState());
}
@ -280,7 +280,7 @@ namespace TINK.Services.BluetoothLock.BLE
// - LockitLockingState.Open
// - LockitLockingState.Unknown
// - LockitLockingState.CouldntOpenBoldBlocked
// Internal error which sould never occurre. Lock refuses to close but connection is ok.
// Internal error which should never occur. Lock refuses to close but connection is ok.
Log.ForContext<LockItEventBased>().Debug($"Opening lock failed. Unexpected lock state {lockingState.Value.GetLockingState()} detected.");
throw new CouldntCloseInconsistentStateExecption(lockingState.Value.GetLockingState());
}

View file

@ -128,7 +128,7 @@ namespace TINK.Services.BluetoothLock.BLE
// - LockitLockingState.Closed
// - LockitLockingState.CouldntCloseMoving (should never happen because command open was send)
// - LockitLockingState.CouldntCloseBoldBlocked (should never happen because command open was send)
// Internal error which sould never occure. Lock refuses to open but connection is ok.
// Internal error which should never occur. Lock refuses to open but connection is ok.
Log.ForContext<LockItPolling>().Debug($"Opening lock failed. Unexpected lock state {info.State.Value.GetLockingState()} detected.");
throw new CouldntOpenInconsistentStateExecption(info.State.Value.GetLockingState());
}
@ -235,7 +235,7 @@ namespace TINK.Services.BluetoothLock.BLE
// - LockitLockingState.Open
// - LockitLockingState.Unknown
// - LockitLockingState.CouldntOpenBoldBlocked
// Internal error which sould never occurre. Lock refuses to close but connection is ok.
// Internal error which should never occur. Lock refuses to close but connection is ok.
Log.ForContext<LockItPolling>().Debug($"Closing lock failed. Unexpected lock state {info.State.Value.GetLockingState()} detected.");
throw new CouldntCloseInconsistentStateExecption(info.State.Value.GetLockingState());
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@ -20,7 +20,7 @@ namespace TINK.Services.BluetoothLock.BLE
Cipher = cipher;
}
/// <summary> Holds timeout values for series of connecting attemps to a lock or multiple locks. </summary>
/// <summary> Holds timeout values for series of connecting attempts to a lock or multiple locks. </summary>
public ITimeOutProvider TimeOut { get; set; }
protected ICipher Cipher { get; }
@ -179,4 +179,4 @@ namespace TINK.Services.BluetoothLock.BLE
return LockingState.UnknownDisconnected;
}
}
}
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock;
@ -8,7 +8,7 @@ namespace TINK.Services.BluetoothLock
{
public interface ILocksService
{
/// <summary> Holds timeout values for series of connecting attemps to a lock or multiple locks. </summary>
/// <summary> Holds timeout values for series of connecting attempts to a lock or multiple locks. </summary>
ITimeOutProvider TimeOut { get; set; }
/// <summary> Gets lock info for all lock in reach./// </summary>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="internalOnly" package="com.TeilRad.Meinkonrad" android:versionName="3.0.362" android:versionCode="362">
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="internalOnly" package="com.TeilRad.Meinkonrad" android:versionName="3.0.363" android:versionCode="363">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="31" />
<!-- Google Maps related permissions -->
<!-- Permission to receive remote notifications from Google Play Services -->

View file

@ -56,8 +56,8 @@
<key>CFBundleDisplayName</key>
<string>Mein konrad</string>
<key>CFBundleVersion</key>
<string>362</string>
<string>363</string>
<key>CFBundleShortVersionString</key>
<string>3.0.362</string>
<string>3.0.363</string>
</dict>
</plist>

View file

@ -30,6 +30,13 @@
<!--Arrow down from line-->
<x:String x:Key="ArrowDown">&#xf063;</x:String>
<!--Info in Circle-->
<x:String x:Key="InfoCircle">&#xf05a;</x:String>
<!--AaAbRideType-->
<x:String x:Key="LocationPin">&#xf3c5;</x:String>
<x:String x:Key="ArrowReturnBack">&#xf0e2;</x:String>
<!-- Add more resources here -->
<ResourceDictionary.MergedDictionaries>
<!-- Add more resource dictionaries here -->

View file

@ -12,6 +12,7 @@
<ContentView.Resources>
<conv:StringNotNullOrEmptyToVisibleConverter x:Key="Label_Converter"/>
</ContentView.Resources>
<Frame
Padding="10"
Margin="0,5,0,5"
@ -23,75 +24,157 @@
Orientation="Vertical"
Padding="10">
<!-- Icons, Name, ID -->
<Grid Padding="0,0,5,10"
<!-- Icons, Name, ID, ... -->
<Grid
Padding="0"
RowSpacing="15"
ColumnSpacing="5"
ColumnDefinitions="Auto,Auto,*"
RowDefinitions="Auto,Auto">
RowDefinitions="Auto,Auto,Auto">
<!-- Icon of the bike -->
<!-- Bike image -->
<Image
Grid.Column="0"
Grid.Row="0"
Grid.RowSpan="2"
Source="{Binding DisplayedBikeImageSourceString}"
HeightRequest="60"
Aspect="AspectFit"
HorizontalOptions="Start"
VerticalOptions="End"/>
Grid.Column="0"
Grid.Row="0"
Grid.RowSpan="2"
VerticalOptions="End"
Source="{Binding DisplayedBikeImageSourceString}"
HeightRequest="60"
Aspect="AspectFit"/>
<!-- Battery level -->
<!-- Battery level image -->
<sharedGui:BarLevelView
Grid.Column="1"
Grid.Row="1"
Current="{Binding CurrentChargeBars}"
Maximum="{Binding MaxChargeBars}"
VerticalOptions="End"
IsVisible="{Binding IsBatteryChargeVisible}"/>
Grid.Column="1"
Grid.Row="0"
Grid.RowSpan="2"
VerticalOptions="End"
Current="{Binding CurrentChargeBars}"
Maximum="{Binding MaxChargeBars}"
IsVisible="{Binding IsBatteryChargeVisible}"/>
<!-- Name of the bike -->
<Label
<!-- Rental state and error -->
<StackLayout
Grid.Column="0"
Grid.ColumnSpan="2"
Grid.Row="2"
Spacing="0"
Orientation="Vertical"
HorizontalOptions="Start"
VerticalOptions="End">
<!-- Rental state -->
<Label
Text="{Binding StateText}"
FontSize="Small"
TextColor="{Binding StateColor}"/>
<!-- Rental state error info -->
<Label
Text="{Binding ErrorText}"
FontSize="Small"
IsVisible="{Binding ErrorText, Converter={StaticResource Label_Converter}}"
TextColor="Red"/>
</StackLayout>
<!-- Name and Id of the bike -->
<StackLayout
Grid.Column="1"
Grid.ColumnSpan="2"
Grid.Row="0"
FontAttributes="Bold"
FontSize="Large"
HorizontalTextAlignment="Right"
Text="{Binding Name}"/>
Orientation="Vertical"
VerticalOptions="Start"
HorizontalOptions="End"
Spacing="0">
<!-- Id of the bike -->
<Label
<!-- Name -->
<Label
FontAttributes="Bold"
FontSize="Large"
TextColor="Black"
HorizontalTextAlignment="Right"
Text="{Binding Name}"/>
<!-- Id -->
<Label
TextColor="DimGray"
FontAttributes="Bold"
HorizontalTextAlignment="Right"
IsVisible="{Binding DisplayId, Converter={StaticResource Label_Converter}}"
Text="{Binding DisplayId}"/>
</StackLayout>
<!-- AaAbRideType -->
<StackLayout
Grid.Column="2"
Grid.Row="1"
FontAttributes="Bold"
HorizontalTextAlignment="Right"
IsVisible="{Binding DisplayId, Converter={StaticResource Label_Converter}}"
Text="{Binding DisplayId}"/>
Grid.RowSpan="2"
Spacing="0"
HorizontalOptions="End"
VerticalOptions="End"
IsVisible="{Binding AaRideType}">
<StackLayout
Orientation="Horizontal"
HorizontalOptions="End">
<Image>
<Image.Source>
<FontImageSource
Glyph="{StaticResource LocationPin}"
Color="Black"
FontFamily="FA-S"
Size="20"/>
</Image.Source>
</Image>
<Image>
<Image.Source>
<FontImageSource
Glyph="{StaticResource ArrowReturnBack}"
Color="Black"
FontFamily="FA-S"
Size="20"/>
</Image.Source>
</Image>
<Button
Command="{Binding ShowRideTypeInfoCommand}"
WidthRequest="24"
HeightRequest="24"
BackgroundColor="Transparent"
BorderWidth="0"
Padding="0"
Margin="5,0,0,0">
<Button.ImageSource>
<FontImageSource
Glyph="{StaticResource InfoCircle}"
Color="DimGray"
FontFamily="FA-S"
Size="20"/>
</Button.ImageSource>
</Button>
</StackLayout>
<Label
Text= "{Binding StationId}"
FontSize="Small"
HorizontalOptions="End"/>
</StackLayout>
</Grid>
<!-- Rental state -->
<Label
Text="{Binding StateText}"
TextColor="{Binding StateColor}"/>
<Label
Text="{Binding ErrorText}"
IsVisible="{Binding ErrorText, Converter={StaticResource Label_Converter}}"
TextColor="Red"/>
<!-- Buttons -->
<Button
Text="{Binding ButtonText}"
IsVisible="{Binding IsButtonVisible}"
Command="{Binding OnButtonClicked}"/>
Text="{Binding ButtonText}"
IsVisible="{Binding IsButtonVisible}"
Command="{Binding OnButtonClicked}"/>
<Button
Style="{StaticResource SecondaryButton}"
Text="{Binding LockitButtonText}"
IsVisible="{Binding IsLockitButtonVisible}"
Command="{Binding OnLockitButtonClicked}"/>
Style="{StaticResource SecondaryButton}"
Text="{Binding LockitButtonText}"
IsVisible="{Binding IsLockitButtonVisible}"
Command="{Binding OnLockitButtonClicked}"/>
<!-- Rental description (tarif name, options and rental info -->
<Grid
RowSpacing="0"
IsVisible="{Binding TariffDescription.Header, Converter={StaticResource Label_Converter}}">
RowSpacing="0"
IsVisible="{Binding TariffDescription.Header, Converter={StaticResource Label_Converter}}">
<Grid.RowDefinitions>
<!-- start tarif- entries -->
<RowDefinition Height="Auto" />
@ -115,19 +198,52 @@
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- start tarif- entries (should be a CollectionView) -->
<Label
Text= "{x:Static resources:AppResources.MessageBikesManagementTariffDescriptionTariffHeader}"
IsVisible="{Binding TariffDescription.Header, Converter={StaticResource Label_Converter}}"
Grid.Row="0"
FontAttributes="Bold"/>
Text= "{x:Static resources:AppResources.MessageBikesManagementTariffDescriptionTariffHeader}"
IsVisible="{Binding TariffDescription.Header, Converter={StaticResource Label_Converter}}"
Grid.Row="0"
FontAttributes="Bold"/>
<Label
Text="{Binding TariffDescription.Header}"
IsVisible="{Binding TariffDescription.Header, Converter={StaticResource Label_Converter}}"
Grid.Row="0"
Grid.Column="1"
FontAttributes="Bold"/>
Text="{Binding TariffDescription.Header}"
IsVisible="{Binding TariffDescription.Header, Converter={StaticResource Label_Converter}}"
Grid.Row="0"
Grid.Column="1"
FontAttributes="Bold"/>
<!--Tracking-->
<Grid
Grid.Row="0"
Grid.Column="1"
Grid.ColumnSpan="2"
ColumnDefinitions="*,Auto"
IsVisible="{Binding TariffDescription.TrackingInfoText, Converter={StaticResource Label_Converter}}">
<Label
Text= "Tracking"
Grid.Column="0"
HorizontalOptions="End"/>
<Button
Command="{Binding ShowTrackingInfoCommand}"
WidthRequest="24"
HeightRequest="24"
BackgroundColor="Transparent"
BorderWidth="0"
Grid.Column="1"
Padding="0"
Margin="0">
<Button.ImageSource>
<FontImageSource
Glyph="{StaticResource InfoCircle}"
Color="DimGray"
FontFamily="FA-S"
Size="20"/>
</Button.ImageSource>
</Button>
</Grid>
<Label
Text= "{Binding TariffDescription.TarifEntry1.Description}"
IsVisible="{Binding TariffDescription.TarifEntry1.Description, Converter={StaticResource Label_Converter}}"
@ -136,7 +252,8 @@
Text="{Binding TariffDescription.TarifEntry1.Value}"
IsVisible="{Binding TariffDescription.TarifEntry1.Value, Converter={StaticResource Label_Converter}}"
Grid.Row="1"
Grid.Column="1"/>
Grid.Column="1"
Grid.ColumnSpan="2"/>
<Label
Text= "{Binding TariffDescription.TarifEntry2.Description}"
IsVisible="{Binding TariffDescription.TarifEntry2.Description, Converter={StaticResource Label_Converter}}"
@ -145,7 +262,8 @@
Text="{Binding TariffDescription.TarifEntry2.Value}"
IsVisible="{Binding TariffDescription.TarifEntry2.Value, Converter={StaticResource Label_Converter}}"
Grid.Row="2"
Grid.Column="1"/>
Grid.Column="1"
Grid.ColumnSpan="2"/>
<Label
Text= "{Binding TariffDescription.TarifEntry3.Description}"
IsVisible="{Binding TariffDescription.TarifEntry3.Description, Converter={StaticResource Label_Converter}}"
@ -154,7 +272,8 @@
Text="{Binding TariffDescription.TarifEntry3.Value}"
IsVisible="{Binding TariffDescription.TarifEntry3.Value, Converter={StaticResource Label_Converter}}"
Grid.Row="3"
Grid.Column="1"/>
Grid.Column="1"
Grid.ColumnSpan="2"/>
<Label
Text= "{Binding TariffDescription.TarifEntry4.Description}"
IsVisible="{Binding TariffDescription.TarifEntry4.Description, Converter={StaticResource Label_Converter}}"
@ -163,7 +282,8 @@
Text="{Binding TariffDescription.TarifEntry4.Value}"
IsVisible="{Binding TariffDescription.TarifEntry4.Value, Converter={StaticResource Label_Converter}}"
Grid.Row="4"
Grid.Column="1"/>
Grid.Column="1"
Grid.ColumnSpan="2"/>
<Label
Text= "{Binding TariffDescription.TarifEntry5.Description}"
IsVisible="{Binding TariffDescription.TarifEntry5.Description, Converter={StaticResource Label_Converter}}"
@ -172,7 +292,8 @@
Text="{Binding TariffDescription.TarifEntry5.Value}"
IsVisible="{Binding TariffDescription.TarifEntry5.Value, Converter={StaticResource Label_Converter}}"
Grid.Row="5"
Grid.Column="1"/>
Grid.Column="1"
Grid.ColumnSpan="2"/>
<Label
Text= "{Binding TariffDescription.TarifEntry6.Description}"
IsVisible="{Binding TariffDescription.TarifEntry6.Description, Converter={StaticResource Label_Converter}}"
@ -181,7 +302,8 @@
Text="{Binding TariffDescription.TarifEntry6.Value}"
IsVisible="{Binding TariffDescription.TarifEntry6.Value, Converter={StaticResource Label_Converter}}"
Grid.Row="6"
Grid.Column="1"/>
Grid.Column="1"
Grid.ColumnSpan="2"/>
<Label
Text= "{Binding TariffDescription.TarifEntry7.Description}"
IsVisible="{Binding TariffDescription.TarifEntry7.Description, Converter={StaticResource Label_Converter}}"
@ -190,7 +312,8 @@
Text="{Binding TariffDescription.TarifEntry7.Value}"
IsVisible="{Binding TariffDescription.TarifEntry7.Value, Converter={StaticResource Label_Converter}}"
Grid.Row="7"
Grid.Column="1"/>
Grid.Column="1"
Grid.ColumnSpan="2"/>
<Label
Text= "{Binding TariffDescription.TarifEntry8.Description}"
IsVisible="{Binding TariffDescription.TarifEntry8.Description, Converter={StaticResource Label_Converter}}"
@ -199,7 +322,8 @@
Text="{Binding TariffDescription.TarifEntry8.Value}"
IsVisible="{Binding TariffDescription.TarifEntry8.Value, Converter={StaticResource Label_Converter}}"
Grid.Row="8"
Grid.Column="1"/>
Grid.Column="1"
Grid.ColumnSpan="2"/>
<Label
Text= "{Binding TariffDescription.TarifEntry9.Description}"
IsVisible="{Binding TariffDescription.TarifEntry9.Description, Converter={StaticResource Label_Converter}}"
@ -208,33 +332,29 @@
Text="{Binding TariffDescription.TarifEntry9.Value}"
IsVisible="{Binding TariffDescription.TarifEntry9.Value, Converter={StaticResource Label_Converter}}"
Grid.Row="9"
Grid.Column="1"/>
Grid.Column="1"
Grid.ColumnSpan="2"/>
<!-- start tarif- entries (should be a CollectionView) -->
<Label
Text= "{Binding TariffDescription.InfoEntry1}"
IsVisible="{Binding TariffDescription.InfoEntry1, Converter={StaticResource Label_Converter}}"
Grid.Row="10"
Grid.ColumnSpan="2"/>
Grid.ColumnSpan="3"/>
<Label
Text= "{Binding TariffDescription.InfoEntry2}"
IsVisible="{Binding TariffDescription.InfoEntry2, Converter={StaticResource Label_Converter}}"
Grid.Row="11"
Grid.ColumnSpan="2"/>
Grid.ColumnSpan="3"/>
<Label
Text= "{Binding TariffDescription.InfoEntry3}"
IsVisible="{Binding TariffDescription.InfoEntry3, Converter={StaticResource Label_Converter}}"
Grid.Row="12"
Grid.ColumnSpan="2"/>
Grid.ColumnSpan="3"/>
<Label
Text= "{Binding TariffDescription.InfoEntry4}"
IsVisible="{Binding TariffDescription.InfoEntry4, Converter={StaticResource Label_Converter}}"
Grid.Row="13"
Grid.ColumnSpan="2"/>
<Label
Text= "{Binding TariffDescription.TrackingInfoText}"
IsVisible="{Binding TariffDescription.TrackingInfoText, Converter={StaticResource Label_Converter}}"
Grid.Row="14"
Grid.ColumnSpan="2"/>
Grid.ColumnSpan="3"/>
</Grid>
</StackLayout>
</Frame>

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:conv="clr-namespace:TINK.View"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
@ -68,7 +68,7 @@
<Frame>
<StackLayout>
<Label FormattedText="{Binding LikeTinkApp}"/>
<!--- Mail to app- releated support -->
<!--- Mail to app- related support -->
<Button
Text="{x:Static resources:AppResources.ActionContactMailAppReleated}"
IsEnabled="{Binding IsSendMailAvailable}"
@ -90,4 +90,4 @@
</Frame>
</ScrollView>
</ContentPage.Content>
</ContentPage>
</ContentPage>

View file

@ -1,4 +1,4 @@
using System;
using System;
using TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
using Xamarin.CommunityToolkit.UI.Views;
using Xamarin.Forms.Xaml;
@ -70,7 +70,7 @@ namespace TINK.View
#endif
{
/// <summary>
/// Holds the current chargeing level of the battery entered by user in bars, null if unkonwn.
/// Holds the current charging level of the battery entered by user in bars, null if unknown.
/// </summary>
public int? CurrentChargeBars { get; set; }
@ -88,4 +88,4 @@ namespace TINK.View
public string Message { get; set; }
}
}
}
}

View file

@ -100,7 +100,7 @@ namespace TINK.View.MyBikes
{
if (m_oViewModel == null)
{
// View model might be null (Example: Occured when page to querry for location permissions was opened)
// View model might be null (Example: Occured when page to query for location permissions was opened)
return;
}

View file

@ -1,5 +1,5 @@
using System;
using TINK.Model.Station;
using System;
using TINK.Model.Stations;
#if USEFLYOUT
using TINK.View.MasterDetail;
#endif
@ -9,12 +9,12 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.Root
{
/// <summary>
/// Mamages creation of detail pages if a flyout page menu entry is selected.
/// Manages creation of detail pages if a flyout page menu entry is selected.
/// Exposes flyout page style navigation which is used by detail pages.
/// </summary>
/// <remarks>
/// Examples of use cases when detail pages do navigation:
// - switch to map page after succesfully logging in/ logging out
// - switch to map page after successfully logging in/ logging out
// - switch to login page form bikes at station page if not yet logged in
/// </remarks>
[XamlCompilation(XamlCompilationOptions.Compile)]
@ -29,7 +29,7 @@ namespace TINK.View.Root
InitializeComponent();
FlyoutPage.ListView.ItemSelected += OnListViewItemSelected;
// Any type of split behaviour conflics with map shifting functionality (assuming FlyoutPage behaves same like MasterDetailPage).
// Any type of split behavior conflics with map shifting functionality (assuming FlyoutPage behaves same like MasterDetailPage).
FlyoutLayoutBehavior = FlyoutLayoutBehavior.Popover;
var navigationPage = Detail as NavigationPage;
@ -62,7 +62,7 @@ namespace TINK.View.Root
}
// Set selected station to new
App.ModelRoot.SelectedStation = new NullStation();
App.ModelRoot.SelectedStation = new TINK.Model.Stations.StationNS.NullStation();
ShowPage(item.TargetType, item.Title);
@ -92,4 +92,4 @@ namespace TINK.View.Root
Detail = new NavigationPage(page);
}
}
}
}

View file

@ -46,6 +46,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D5B69C6F-3413-4773-923E-21A65B21C3A3}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.vsspell = .vsspell
EndProjectSection
EndProject
Global

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="internalOnly" package="com.hauffware.sharee" android:versionName="3.0.362" android:versionCode="362">
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="internalOnly" package="com.hauffware.sharee" android:versionName="3.0.363" android:versionCode="363">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="31" />
<!-- Google Maps related permissions -->
<!-- Permission to receive remote notifications from Google Play Services -->

View file

@ -56,8 +56,8 @@
<key>CFBundleDisplayName</key>
<string>sharee.bike</string>
<key>CFBundleVersion</key>
<string>362</string>
<string>363</string>
<key>CFBundleShortVersionString</key>
<string>3.0.362</string>
<string>3.0.363</string>
</dict>
</plist>

View file

@ -32,7 +32,11 @@
<!--Info in Circle-->
<x:String x:Key="InfoCircle">&#xf05a;</x:String>
<!--AaAbRideType-->
<x:String x:Key="LocationPin">&#xf3c5;</x:String>
<x:String x:Key="ArrowReturnBack">&#xf0e2;</x:String>
<!-- Add more resources here -->
<ResourceDictionary.MergedDictionaries>
<!-- Add more resource dictionaries here -->

View file

@ -25,77 +25,158 @@
Orientation="Vertical"
Padding="10">
<!-- Icons, Name, ID -->
<Grid Padding="0,0,5,10"
<!-- Icons, Name, ID, ... -->
<Grid
Padding="0"
RowSpacing="15"
ColumnSpacing="5"
ColumnDefinitions="Auto,Auto,*"
RowDefinitions="Auto,Auto">
RowDefinitions="Auto,Auto,Auto">
<!-- Icon of the bike -->
<!-- Bike image -->
<Image
Grid.Column="0"
Grid.Row="0"
Grid.RowSpan="2"
Source="{Binding DisplayedBikeImageSourceString}"
HeightRequest="60"
Aspect="AspectFit"
HorizontalOptions="Start"
VerticalOptions="End"/>
Grid.Column="0"
Grid.Row="0"
Grid.RowSpan="2"
VerticalOptions="End"
Source="{Binding DisplayedBikeImageSourceString}"
HeightRequest="60"
Aspect="AspectFit"/>
<!-- Battery level -->
<!-- Battery level image -->
<sharedGui:BarLevelView
Grid.Column="1"
Grid.Row="1"
Current="{Binding CurrentChargeBars}"
Maximum="{Binding MaxChargeBars}"
VerticalOptions="End"
IsVisible="{Binding IsBatteryChargeVisible}"/>
Grid.Column="1"
Grid.Row="0"
Grid.RowSpan="2"
VerticalOptions="End"
Current="{Binding CurrentChargeBars}"
Maximum="{Binding MaxChargeBars}"
IsVisible="{Binding IsBatteryChargeVisible}"/>
<!-- Name of the bike -->
<Label
<!-- Rental state and error -->
<StackLayout
Grid.Column="0"
Grid.ColumnSpan="2"
Grid.Row="2"
Spacing="0"
Orientation="Vertical"
HorizontalOptions="Start"
VerticalOptions="End">
<!-- Rental state -->
<Label
Text="{Binding StateText}"
FontSize="Small"
TextColor="{Binding StateColor}"/>
<!-- Rental state error info -->
<Label
Text="{Binding ErrorText}"
FontSize="Small"
IsVisible="{Binding ErrorText, Converter={StaticResource Label_Converter}}"
TextColor="Red"/>
</StackLayout>
<!-- Name and Id of the bike -->
<StackLayout
Grid.Column="1"
Grid.ColumnSpan="2"
Grid.Row="0"
FontAttributes="Bold"
FontSize="Large"
HorizontalTextAlignment="Right"
Text="{Binding Name}"/>
Orientation="Vertical"
VerticalOptions="Start"
HorizontalOptions="End"
Spacing="0">
<!-- Name -->
<Label
FontAttributes="Bold"
FontSize="Large"
TextColor="Black"
HorizontalTextAlignment="Right"
Text="{Binding Name}"/>
<!-- Id of the bike -->
<Label
<!-- Id -->
<Label
TextColor="DimGray"
FontAttributes="Bold"
HorizontalTextAlignment="Right"
IsVisible="{Binding DisplayId, Converter={StaticResource Label_Converter}}"
Text="{Binding DisplayId}"/>
</StackLayout>
<!-- AaAbRideType -->
<StackLayout
Grid.Column="2"
Grid.Row="1"
FontAttributes="Bold"
HorizontalTextAlignment="Right"
IsVisible="{Binding DisplayId, Converter={StaticResource Label_Converter}}"
Text="{Binding DisplayId}"/>
Grid.RowSpan="2"
Spacing="0"
HorizontalOptions="End"
VerticalOptions="End"
IsVisible="{Binding AaRideType}">
<StackLayout
Orientation="Horizontal"
HorizontalOptions="End">
<Image>
<Image.Source>
<FontImageSource
Glyph="{StaticResource LocationPin}"
Color="Black"
FontFamily="FA-S"
Size="20"/>
</Image.Source>
</Image>
<Image>
<Image.Source>
<FontImageSource
Glyph="{StaticResource ArrowReturnBack}"
Color="Black"
FontFamily="FA-S"
Size="20"/>
</Image.Source>
</Image>
<Button
Command="{Binding ShowRideTypeInfoCommand}"
WidthRequest="24"
HeightRequest="24"
BackgroundColor="Transparent"
BorderWidth="0"
Padding="0"
Margin="5,0,0,0">
<Button.ImageSource>
<FontImageSource
Glyph="{StaticResource InfoCircle}"
Color="DimGray"
FontFamily="FA-S"
Size="20"/>
</Button.ImageSource>
</Button>
</StackLayout>
<Label
Text= "{Binding StationId}"
FontSize="Small"
HorizontalOptions="End"/>
</StackLayout>
</Grid>
<!-- Rental state -->
<Label
Text="{Binding StateText}"
TextColor="{Binding StateColor}"/>
<Label
Text="{Binding ErrorText}"
IsVisible="{Binding ErrorText, Converter={StaticResource Label_Converter}}"
TextColor="Red"/>
<!-- Buttons -->
<Button
Text="{Binding ButtonText}"
IsVisible="{Binding IsButtonVisible}"
Command="{Binding OnButtonClicked}"/>
<Button
Style="{StaticResource SecondaryButton}"
Text="{Binding LockitButtonText}"
IsVisible="{Binding IsLockitButtonVisible}"
Command="{Binding OnLockitButtonClicked}"/>
<!-- Buttons -->
<Button
Text="{Binding ButtonText}"
IsVisible="{Binding IsButtonVisible}"
Command="{Binding OnButtonClicked}"/>
<Button
Style="{StaticResource SecondaryButton}"
Text="{Binding LockitButtonText}"
IsVisible="{Binding IsLockitButtonVisible}"
Command="{Binding OnLockitButtonClicked}"/>
<!-- Rental description (tarif name, options and rental info -->
<Grid
RowSpacing="0"
IsVisible="{Binding TariffDescription.Header, Converter={StaticResource Label_Converter}}">
<Grid.RowDefinitions>
<!-- Rental description (tarif name, options and rental info -->
<Grid
RowSpacing="0"
IsVisible="{Binding TariffDescription.Header, Converter={StaticResource Label_Converter}}">
<Grid.RowDefinitions>
<!-- start tarif- entries -->
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
@ -113,59 +194,58 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
</Grid.ColumnDefinitions>
<!-- start tarif- entries (should be a CollectionView) -->
<Label
Text= "{x:Static resources:AppResources.MessageBikesManagementTariffDescriptionTariffHeader}"
IsVisible="{Binding TariffDescription.Header, Converter={StaticResource Label_Converter}}"
Grid.Row="0"
FontAttributes="Bold"/>
<Label
Text="{Binding TariffDescription.Header}"
IsVisible="{Binding TariffDescription.Header, Converter={StaticResource Label_Converter}}"
Grid.Row="0"
Grid.Column="1"
FontAttributes="Bold"/>
<!--Tracking-->
<Grid
Grid.Row="0"
Grid.Column="1"
Grid.ColumnSpan="2"
ColumnDefinitions="*,Auto"
IsVisible="{Binding TariffDescription.TrackingInfoText, Converter={StaticResource Label_Converter}}">
<Label
Text= "Tracking"
FontAttributes="Bold"
Grid.Column="0"
HorizontalOptions="End"/>
<Button
Command="{Binding ShowTrackingInfoCommand}"
WidthRequest="24"
HeightRequest="24"
BackgroundColor="Transparent"
BorderWidth="0"
<!-- start tarif- entries (should be a CollectionView) -->
<Label
Text= "{x:Static resources:AppResources.MessageBikesManagementTariffDescriptionTariffHeader}"
IsVisible="{Binding TariffDescription.Header, Converter={StaticResource Label_Converter}}"
Grid.Row="0"
FontAttributes="Bold"/>
<Label
Text="{Binding TariffDescription.Header}"
IsVisible="{Binding TariffDescription.Header, Converter={StaticResource Label_Converter}}"
Grid.Row="0"
Grid.Column="1"
Padding="0"
Margin="0">
<Button.ImageSource>
<FontImageSource
Glyph="{StaticResource InfoCircle}"
Color="DimGray"
FontFamily="FA-S"
Size="20"/>
</Button.ImageSource>
</Button>
</Grid>
FontAttributes="Bold"/>
<!--Tracking-->
<Grid
Grid.Row="0"
Grid.Column="1"
Grid.ColumnSpan="2"
ColumnDefinitions="*,Auto"
IsVisible="{Binding TariffDescription.TrackingInfoText, Converter={StaticResource Label_Converter}}">
<Label
Text= "Tracking"
Grid.Column="0"
HorizontalOptions="End"/>
<Button
Command="{Binding ShowTrackingInfoCommand}"
WidthRequest="24"
HeightRequest="24"
BackgroundColor="Transparent"
BorderWidth="0"
Grid.Column="1"
Padding="0"
Margin="0">
<Button.ImageSource>
<FontImageSource
Glyph="{StaticResource InfoCircle}"
Color="DimGray"
FontFamily="FA-S"
Size="20"/>
</Button.ImageSource>
</Button>
</Grid>
<Label
Text= "{Binding TariffDescription.TarifEntry1.Description}"
IsVisible="{Binding TariffDescription.TarifEntry1.Description, Converter={StaticResource Label_Converter}}"
Grid.Row="1"/>

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:conv="clr-namespace:TINK.View"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
@ -67,7 +67,7 @@
<Frame>
<StackLayout>
<Label FormattedText="{Binding LikeTinkApp}"/>
<!--- Mail to app- releated support -->
<!--- Mail to app- related support -->
<Button
Text="{x:Static resources:AppResources.ActionContactMailAppReleated}"
IsEnabled="{Binding IsSendMailAvailable}"
@ -89,4 +89,4 @@
</Frame>
</ScrollView>
</ContentPage.Content>
</ContentPage>
</ContentPage>

View file

@ -1,4 +1,4 @@
using System;
using System;
using TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
using Xamarin.CommunityToolkit.UI.Views;
using Xamarin.Forms.Xaml;
@ -69,7 +69,7 @@ namespace TINK.View
#endif
{
/// <summary>
/// Holds the current chargeing level of the battery entered by user in bars, null if unkonwn.
/// Holds the current charging level of the battery entered by user in bars, null if unknown.
/// </summary>
public int? CurrentChargeBars { get; set; }
@ -87,4 +87,4 @@ namespace TINK.View
public string Message { get; set; }
}
}
}
}

View file

@ -100,7 +100,7 @@ namespace TINK.View.MyBikes
{
if (m_oViewModel == null)
{
// View model might be null (Example: Occured when page to querry for location permissions was opened)
// View model might be null (Example: Occured when page to query for location permissions was opened)
return;
}

View file

@ -1,5 +1,5 @@
using System;
using TINK.Model.Station;
using System;
using TINK.Model.Stations;
#if USEFLYOUT
using TINK.View.MasterDetail;
#endif
@ -9,12 +9,12 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.Root
{
/// <summary>
/// Mamages creation of detail pages if a flyout page menu entry is selected.
/// Manages creation of detail pages if a flyout page menu entry is selected.
/// Exposes flyout page style navigation which is used by detail pages.
/// </summary>
/// <remarks>
/// Examples of use cases when detail pages do navigation:
// - switch to map page after succesfully logging in/ logging out
// - switch to map page after successfully logging in/ logging out
// - switch to login page form bikes at station page if not yet logged in
/// </remarks>
[XamlCompilation(XamlCompilationOptions.Compile)]
@ -29,7 +29,7 @@ namespace TINK.View.Root
InitializeComponent();
FlyoutPage.ListView.ItemSelected += OnListViewItemSelected;
// Any type of split behaviour conflics with map shifting functionality (assuming FlyoutPage behaves same like MasterDetailPage).
// Any type of split behavior conflics with map shifting functionality (assuming FlyoutPage behaves same like MasterDetailPage).
FlyoutLayoutBehavior = FlyoutLayoutBehavior.Popover;
var navigationPage = Detail as NavigationPage;
@ -62,7 +62,7 @@ namespace TINK.View.Root
}
// Set selected station to new
App.ModelRoot.SelectedStation = new NullStation();
App.ModelRoot.SelectedStation = new TINK.Model.Stations.StationNS.NullStation();
ShowPage(item.TargetType, item.Title);
@ -92,4 +92,4 @@ namespace TINK.View.Root
Detail = new NavigationPage(page);
}
}
}
}

View file

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Serilog;
using TINK.Model.Station;
using TINK.Model.Stations.StationNS;
using BikeInfo = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfo;
using BikeInfoMutable = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfoMutable;
@ -25,7 +25,7 @@ namespace TINK.Model.Bikes
/// </summary>
/// <param name="bikesAll"> Object holding bikes info from copri to update from. Holds station id but not station name.</param>
/// <param name="stations"> All stations to get station names from.</param>
/// <param name="p_oDateTimeProvider">Provices date time information.</param>
/// <param name="p_oDateTimeProvider">Provides date time information.</param>
public void Update(
IEnumerable<BikeInfo> bikesAll,
IEnumerable<IStation> stations)
@ -74,18 +74,18 @@ namespace TINK.Model.Bikes
}
/// <summary>
/// Adds a new bike to collecion of bike.
/// Adds a new bike to collection of bike.
/// </summary>
/// <param name="newBike">New bike to add.</param>
/// <exception cref="Exception">Thrown if bike is not unique.</exception>
public new void Add(BikeInfoMutable newBike)
{
// Ensure that bike id of new bike is is unique
// Ensure that bike id of new bike is unique
foreach (BikeInfoMutable bike in Items)
{
if (bike.Id == newBike.Id)
{
throw new Exception(string.Format("Can not add bike with {0} to collection ob bike. Id is not unnique.", newBike));
throw new Exception(string.Format("Can not add bike with {0} to collection ob bike. Id is not unique.", newBike));
}
}
@ -93,7 +93,7 @@ namespace TINK.Model.Bikes
}
/// <summary>
/// Bike selected by user for regerving or cancel reservation.
/// Bike selected by user for reserving or cancel reservation.
/// </summary>
public BikeInfoMutable SelectedBike
{
@ -115,7 +115,7 @@ namespace TINK.Model.Bikes
=> this.FirstOrDefault(bike => bike.Id == id);
/// <summary>
/// Deteermines whether a bike by given key exists.
/// Determines whether a bike by given key exists.
/// </summary>
/// <param name="p_strKey">Key to check.</param>
/// <returns>True if bike exists.</returns>

View file

@ -6,7 +6,7 @@ using TINK.Model.State;
namespace TINK.Model.Bikes.BikeInfoNS.BC
{
public class BikeInfo : IBikeInfo
public abstract class BikeInfo : IBikeInfo
{
/// <summary> Default value of demo property. </summary>
public const bool DEFAULTVALUEISDEMO = false;
@ -64,72 +64,6 @@ namespace TINK.Model.Bikes.BikeInfoNS.BC
bikeInfo.TariffDescription)
{ }
/// <summary>
/// Constructs a bike info object for a available bike.
/// </summary>
/// <param name="dataSource">Specified the source of the data.</param>
/// <param name="stationId">Id of station where bike is located.</param>
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <param name="tariffDescription">Hold tariff description of bike.</param>
public BikeInfo(
Bike bike,
Drive drive,
DataSource dataSource,
string stationId,
Uri operatorUri = null,
RentalDescription tariffDescription = null,
bool? isDemo = DEFAULTVALUEISDEMO,
IEnumerable<string> group = null) : this(
new StateInfo(),
bike,
drive,
dataSource,
isDemo,
group,
stationId,
operatorUri,
tariffDescription)
{
}
/// <summary>
/// Constructs a bike info object for a booked bike.
/// </summary>
/// <param name="dataSource">Specified the source of the data.</param>
/// <param name="dateTimeProvider">Provider for current date time to calculate remainig time on demand for state of type reserved.</param>
/// <param name="currentStationId">Name of station where bike is located, null if bike is on the road.</param>
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <param name="tariffDescription">Hold tariff description of bike.</param>
/// <param name="bookedAt">Date time when bike was booked</param>
/// <param name="mailAddress">Mail address of user which booked bike.</param>
/// <param name="code">Booking code.</param>
public BikeInfo(
Bike bike,
Drive drive,
DataSource dataSource,
bool? isDemo,
IEnumerable<string> group,
string currentStationId,
Uri operatorUri,
RentalDescription tariffDescription,
DateTime bookedAt,
string mailAddress,
string code) : this(
new StateInfo(
bookedAt,
mailAddress,
code),
bike,
drive,
dataSource,
isDemo,
group,
currentStationId,
operatorUri,
tariffDescription)
{
}
/// <summary> True if device is demo device, false otherwise. </summary>
public bool IsDemo { get; }
@ -141,7 +75,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BC
/// </summary>
public string StationId { get; }
/// <summary> Holds description about the tarif. </summary>
/// <summary> Holds description about the tariff. </summary>
public RentalDescription TariffDescription { get; }
/// Holds the rent state of the bike.

View file

@ -9,7 +9,7 @@ using TINK.Model.State;
namespace TINK.Model.Bikes.BikeInfoNS.BC
{
[DataContract]
public class BikeInfoMutable : IBikeInfoMutable, INotifyPropertyChanged
public abstract class BikeInfoMutable : IBikeInfoMutable, INotifyPropertyChanged
{
/// <summary> Holds the bike. </summary>
private readonly Bike _Bike;
@ -24,7 +24,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BC
/// Constructs a bike.
/// </summary>
/// <param name="isDemo">True if device is demo device, false otherwise.</param>
/// <param name="dateTimeProvider">Provider for current date time to calculate remainig time on demand for state of type reserved.</param>
/// <param name="dateTimeProvider">Provider for current date time to calculate remaining time on demand for state of type reserved.</param>
/// <param name="stationId">Name of station where bike is located, null if bike is on the road.</param>
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <param name="tariffDescription">Hold tariff description of bike.</param>
@ -55,24 +55,6 @@ namespace TINK.Model.Bikes.BikeInfoNS.BC
TariffDescription = tariffDescription;
}
/// <summary> Constructs a bike object from source. </summary>
public BikeInfoMutable(IBikeInfo bike, string stationName) : this(
bike != null
? bike.Bike
: throw new ArgumentNullException(nameof(bike)),
bike.Drive,
bike.DataSource,
bike.IsDemo,
bike.Group,
bike.StationId,
stationName,
bike.OperatorUri,
bike.TariffDescription,
null /* date time provider */,
bike.State)
{
}
/// <summary> Id of station a which bike is located, null otherwise.</summary>
[DataMember]
public string StationId { get; }
@ -81,7 +63,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BC
[DataMember]
public string StationName { get; }
/// <summary> Holds description about the tarif. </summary>
/// <summary> Holds description about the tariff. </summary>
[DataMember]
public RentalDescription TariffDescription { get; private set; }
@ -113,6 +95,12 @@ namespace TINK.Model.Bikes.BikeInfoNS.BC
public TypeOfBike? TypeOfBike => _Bike.TypeOfBike;
/// <summary>
/// Gets whether bike is a AA bike (bike must be always returned a the same station) or AB bike (start and end stations can be different stations).
/// </summary>
public AaRideType? AaRideType => _Bike.AaRideType;
public LockModel LockModel => _Bike.LockModel;
public string Description => _Bike.Description;

View file

@ -30,6 +30,11 @@ namespace TINK.Model.Bikes.BikeInfoNS.BC
/// </summary>
TypeOfBike? TypeOfBike { get; }
/// <summary>
/// Gets whether bike is a AA bike (bike must be always returned a the same station) or AB bike (start and end stations can be different stations).
/// </summary>
AaRideType? AaRideType { get; }
/// <summary> Gets the model of the lock. </summary>
LockModel LockModel { get; }

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
namespace TINK.Model.Bikes.BikeInfoNS.BikeNS
@ -21,12 +21,19 @@ namespace TINK.Model.Bikes.BikeInfoNS.BikeNS
City = 2,
}
/// <summary> Holds whether bike is a AA bike (bike must be always returned a the same station) or AB bike (start and end stations can be different stations).</summary>
public enum AaRideType
{
NoAaRide = 0,
AaRide = 1,
}
/// <summary> Holds the model of lock. </summary>
public enum LockModel
{
ILockIt, // haveltec GbmH Brandenburg, Germany bluetooth lock
BordComputer, // Teilrad BC
Sigo, // Sigo Gmbh Darmstadt, Germany bike lock
BordComputer, // TeilRad BC
Sigo, // Sigo GmbH Darmstadt, Germany bike lock
}
/// <summary> Holds the type of lock. </summary>
@ -47,10 +54,12 @@ namespace TINK.Model.Bikes.BikeInfoNS.BikeNS
LockModel lockModel,
WheelType? wheelType = null,
TypeOfBike? typeOfBike = null,
AaRideType? aaRideType = null,
string description = null)
{
WheelType = wheelType;
TypeOfBike = typeOfBike;
AaRideType = aaRideType;
LockModel = lockModel;
Id = id;
Description = description;
@ -71,6 +80,11 @@ namespace TINK.Model.Bikes.BikeInfoNS.BikeNS
/// </summary>
public TypeOfBike? TypeOfBike { get; }
/// <summary>
/// Gets whether bike is a AA bike (bike must be always returned a the same station) or AB bike (start and end stations can be different stations).
/// </summary>
public AaRideType? AaRideType { get; }
/// <summary> Gets the model of the lock. </summary>
public LockModel LockModel { get; private set; }

View file

@ -33,9 +33,10 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
bike != null
? new Bike(
bike.Id,
LockModel.ILockIt /* Ensure consistend lock model value */,
LockModel.ILockIt /* Ensure consistent lock model value */,
bike.WheelType,
bike.TypeOfBike,
bike.AaRideType,
bike.Description)
: throw new ArgumentNullException(nameof(bike)),
drive,
@ -53,7 +54,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
/// Constructs a bike info object for a requested bike.
/// </summary>
/// <param name="dataSource">Specified the source of the data.</param>
/// <param name="dateTimeProvider">Provider for current date time to calculate remainig time on demand for state of type reserved.</param>
/// <param name="dateTimeProvider">Provider for current date time to calculate remaining time on demand for state of type reserved.</param>
/// <param name="lockId">Id of the lock.</param>
/// <param name="lockGuid">GUID specifying the lock.</param>
/// <param name="requestedAt">Date time when bike was requested</param>
@ -61,7 +62,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
/// <param name="currentStationId">Name of station where bike is located, null if bike is on the road.</param>
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <param name="tariffDescription">Hold tariff description of bike.</param>
/// <param name="dateTimeProvider">Date time provider to calculate reaining time.</param>
/// <param name="dateTimeProvider">Date time provider to calculate remaining time.</param>
public BikeInfo(
Bike bike,
Drive drive,
@ -87,9 +88,10 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
bike != null
? new Bike(
bike.Id,
LockModel.ILockIt /* Ensure consistend lock model value */,
LockModel.ILockIt /* Ensure consistent lock model value */,
bike.WheelType,
bike.TypeOfBike,
bike.AaRideType,
bike.Description)
: throw new ArgumentNullException(nameof(bike)),
drive,
@ -139,9 +141,10 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
bike != null
? new Bike(
bike.Id,
LockModel.ILockIt /* Ensure consistend lock model value */,
LockModel.ILockIt /* Ensure consistent lock model value */,
bike.WheelType,
bike.TypeOfBike,
bike.AaRideType,
bike.Description)
: throw new ArgumentNullException(),
drive,
@ -155,7 +158,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
LockInfo = new LockInfo.Builder { Id = lockId, Guid = lockGuid, UserKey = userKey, AdminKey = adminKey, Seed = seed }.Build();
}
public BikeInfo(Model.Bikes.BikeInfoNS.BC.BikeInfo bikeInfo, LockInfo lockInfo) : base(
public BikeInfo(BC.BikeInfo bikeInfo, LockInfo lockInfo) : base(
bikeInfo ?? throw new ArgumentException($"Can not copy-construct {typeof(BikeInfo).Name}-object. Source bike info must not be null."))
{
LockInfo = lockInfo

View file

@ -38,8 +38,9 @@ namespace TINK.Model.Bikes.BikeInfoNS.CopriLock
? new Bike(
bike.Id,
LockModel.Sigo,
bike.WheelType /* Ensure consistend lock model value */,
bike.WheelType /* Ensure consistent lock model value */,
bike.TypeOfBike,
bike.AaRideType,
bike.Description)
: throw new ArgumentNullException(nameof(bike)),
drive,
@ -66,7 +67,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.CopriLock
/// <param name="lockInfo">Lock info.</param>
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <param name="tariffDescription">Hold tariff description of bike.</param>
/// <param name="dateTimeProvider">Provider for current date time to calculate remainig time on demand for state of type reserved.</param>
/// <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,
@ -88,9 +89,10 @@ namespace TINK.Model.Bikes.BikeInfoNS.CopriLock
bike != null
? new Bike(
bike.Id,
LockModel.Sigo /* Ensure consistend lock model value */,
LockModel.Sigo /* Ensure consistent lock model value */,
bike.WheelType,
bike.TypeOfBike,
bike.AaRideType,
bike.Description)
: throw new ArgumentNullException(nameof(bike)),
drive,
@ -136,9 +138,10 @@ namespace TINK.Model.Bikes.BikeInfoNS.CopriLock
bike != null
? new Bike(
bike.Id,
LockModel.Sigo /* Ensure consistend lock model value */,
LockModel.Sigo /* Ensure consistent lock model value */,
bike.WheelType,
bike.TypeOfBike,
bike.AaRideType,
bike.Description)
: throw new ArgumentNullException(nameof(bike)),
drive,

View file

@ -35,7 +35,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.CopriLock
return;
}
// Add a dummy querry. Querries are not yet read from COPRI but compiled into the app.
// Add a dummy query. Querries are not yet read from COPRI but compiled into the app.
BookingFinishedModel.MiniSurvey.Questions.Add("q1", new MiniSurvey.QuestionModel());
}

View file

@ -1,4 +1,4 @@
using Serilog;
using Serilog;
namespace TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS
{
@ -12,12 +12,12 @@ namespace TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS
public double CurrentChargePercent { get; private set; } = double.NaN;
/// <summary>
/// Holds the current chargeing level of the battery in bars, null if unkonwn.
/// Holds the current charging level of the battery in bars, null if unknown.
/// </summary>
public int? CurrentChargeBars { get; private set; } = null;
/// <summary>
/// Holds the maximum chargeing level of the battery in bars, null if unkonwn.
/// Holds the maximum charging level of the battery in bars, null if unknown.
/// </summary>
public int? MaxChargeBars { get; private set; } = null;
@ -34,12 +34,12 @@ namespace TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS
public class Builder
{
/// <summary>
/// Holds the current chargeing level of the battery in bars.
/// Holds the current charging level of the battery in bars.
/// </summary>
public int? CurrentChargeBars { get; set; } = null;
/// <summary>
/// Holds the maximum chargeing level of the battery in bars.
/// Holds the maximum charging level of the battery in bars.
/// </summary>
public int? MaxChargeBars { get; set; } = null;
@ -83,7 +83,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS
&& MaxChargeBars == null)
{
// If current charge bars is set, max charge must be set as well.
Log.ForContext<Battery>().Error($"Current bars value can not be set to {CurrentChargeBars} if max bars is not se.");
Log.ForContext<Battery>().Error($"Current bars value can not be set to {CurrentChargeBars} if max bars is not set.");
CurrentChargeBars = null;
}
@ -92,7 +92,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS
&& CurrentChargeBars > MaxChargeBars)
{
// If current charge bars must never be larger than max charge bars.
Log.ForContext<Battery>().Error($"Invalid current bars value {CurrentChargeBars} detected. Value must never be largen than max value bars {MaxChargeBars}.");
Log.ForContext<Battery>().Error($"Invalid current bars value {CurrentChargeBars} detected. Value must never be larger than max value bars {MaxChargeBars}.");
CurrentChargeBars = null;
}

View file

@ -1,4 +1,4 @@

namespace TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS
{
public interface IBattery
@ -9,12 +9,12 @@ namespace TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS
double CurrentChargePercent { get; }
/// <summary>
/// Holds the current chargeing level of the battery in bars. Must not be arger than MaxChargeBars, null if unkonwn.
/// Holds the current charging level of the battery in bars. Must not be larger than MaxChargeBars, null if unknown.
/// </summary>
int? CurrentChargeBars { get; }
/// <summary>
/// Holds the maximum chargeing level of the battery in bars, null if unkonwn.
/// Holds the maximum charging level of the battery in bars, null if unknown.
/// </summary>
int? MaxChargeBars { get; }

View file

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
namespace TINK.Model.Bikes
{
@ -12,7 +12,7 @@ namespace TINK.Model.Bikes
T GetById(string id);
/// <summary>
/// Deteermines whether a bike by given key exists.
/// Determines whether a bike by given key exists.
/// </summary>
/// <param name="p_strKey">Key to check.</param>
/// <returns>True if bike exists.</returns>
@ -27,7 +27,7 @@ namespace TINK.Model.Bikes
void RemoveById(string id);
/// <summary>
/// Adds a new element to dictinary.
/// Adds a new element to dictionary.
/// </summary>
/// <param name="newElement">New element to add.</param>
void Add(T newElement);

View file

@ -129,7 +129,7 @@ namespace TINK.Model.Connector
string BikeId { get; }
/// <summary>
/// Holds the current chargeing level of the battery in bars, null if unkonwn.
/// Holds the current charging level of the battery in bars, null if unknown.
/// </summary>
int? CurrentChargeBars { get; set; }

View file

@ -1,4 +1,4 @@

namespace TINK.Model.Connector
{
#if USCSHARP9
@ -18,7 +18,7 @@ namespace TINK.Model.Connector
public string BikeId { get; set; }
/// <summary>
/// Holds the current chargeing level of the battery in bars, null if unkonwn.
/// Holds the current charging level of the battery in bars, null if unknown.
/// </summary>
public int? CurrentChargeBars { get; set; }

View file

@ -1,17 +1,17 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TINK.Model.Bikes;
using TINK.Model.Connector.Filter;
using TINK.Model.Services.CopriApi;
using TINK.Model.Station;
using TINK.Model.Stations;
using TINK.Model.Stations.StationNS;
using BikeInfo = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfo;
namespace TINK.Model.Connector
{
/// <summary> Filters connector respones.</summary>
/// <summary> Filters connector responses.</summary>
/// <remarks>Former name: Filter</remarks>
public class FilteredConnector : IFilteredConnector
{
@ -50,7 +50,7 @@ namespace TINK.Model.Connector
/// <summary> Holds the filter. </summary>
private IGroupFilter Filter { get; }
/// <summary> Holds the reference to object which performs copry queries.</summary>
/// <summary> Holds the reference to object which performs copri queries.</summary>
private IQuery m_oInnerQuery;
/// <summary> Constructs a query object.</summary>
@ -111,7 +111,7 @@ namespace TINK.Model.Connector
return bikes.Where(x => filter.DoFilter(x.Group).Count() > 0).ToDictionary(x => x.Id);
}
/// <summary> Filter stations by broup. </summary>
/// <summary> Filter stations by group. </summary>
/// <returns></returns>
private static Dictionary<string, IStation> DoFilter(StationDictionary stations, IGroupFilter filter)
{

View file

@ -1,16 +1,16 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TINK.Model.Bikes;
using TINK.Model.Services.CopriApi;
using TINK.Model.Station;
using TINK.Model.Stations;
using TINK.Model.Stations.StationNS;
using BikeInfo = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfo;
namespace TINK.Model.Connector
{
/// <summary> Filters connector respones.</summary>
/// <summary> Filters connector responses.</summary>
public class NullFilterConnector : IFilteredConnector
{
/// <summary> Constructs a filter object. </summary>
@ -44,7 +44,7 @@ namespace TINK.Model.Connector
/// <summary> Object to perform filtered queries.</summary>
private class QueryProvider : IQuery
{
/// <summary> Holds the reference to object which performs copry queries.</summary>
/// <summary> Holds the reference to object which performs copri queries.</summary>
private IQuery m_oInnerQuery;
/// <summary> Constructs a query object.</summary>
@ -100,7 +100,7 @@ namespace TINK.Model.Connector
return bikes.Where(x => x.Group.Intersect(filter).Count() > 0).ToDictionary(x => x.Id);
}
/// <summary> Filter stations by broup. </summary>
/// <summary> Filter stations by group. </summary>
/// <returns></returns>
public static Dictionary<string, IStation> DoFilter(StationDictionary stations, IEnumerable<string> p_oFilter)
{

View file

@ -29,7 +29,7 @@ namespace TINK.Model.Connector
}
}
/// <summary> Gets all stations including postions and bikes.</summary>
/// <summary> Gets all stations including positions and bikes.</summary>
public async Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync()
{
var resultStations = await server.GetStations();
@ -73,7 +73,7 @@ namespace TINK.Model.Connector
/// <returns>Collection of bikes.</returns>
public async Task<Result<BikeCollection>> GetBikesOccupiedAsync()
{
Log.ForContext<CachedQuery>().Error("Unexpected call to get be bikes occpied detected. No user is logged in.");
Log.ForContext<CachedQuery>().Error("Unexpected call to get be bikes occupied detected. No user is logged in.");
return new Result<BikeCollection>(
typeof(CopriCallsMonkeyStore),

View file

@ -29,7 +29,7 @@ namespace TINK.Model.Connector
}
}
/// <summary> Gets all stations including postions.</summary>
/// <summary> Gets all stations including positions.</summary>
public async Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync()
{
var stationsResponse = await Server.GetStations();

View file

@ -1,4 +1,4 @@
using System.Threading.Tasks;
using System.Threading.Tasks;
using TINK.Model.Bikes;
using TINK.Model.Services.CopriApi;
@ -6,7 +6,7 @@ namespace TINK.Model.Connector
{
public interface IQuery
{
/// <summary> Gets all stations including postions.</summary>
/// <summary> Gets all stations including positions.</summary>
Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync();
/// <summary> Gets bikes occupied is a user is logged in. </summary>

View file

@ -28,7 +28,7 @@ namespace TINK.Model.Connector
}
}
/// <summary> Gets all stations including postions.</summary>
/// <summary> Gets all stations including positions.</summary>
public async Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync()
{
var stationsAllResponse = await server.GetStationsAsync();
@ -44,7 +44,7 @@ namespace TINK.Model.Connector
/// <returns>Collection of bikes.</returns>
public async Task<Result<BikeCollection>> GetBikesOccupiedAsync()
{
Log.ForContext<Query>().Error("Unexpected call to get be bikes occpied detected. No user is logged in.");
Log.ForContext<Query>().Error("Unexpected call to get be bikes occupied detected. No user is logged in.");
return new Result<BikeCollection>(
typeof(CopriCallsMonkeyStore),
await Task.FromResult(new BikeCollection(new Dictionary<string, BikeInfo>())),

View file

@ -30,7 +30,7 @@ namespace TINK.Model.Connector
server = copriServer as ICopriServer;
}
/// <summary> Gets all stations including postions.</summary>
/// <summary> Gets all stations including positions.</summary>
public async Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync()
{
var stationResponse = await server.GetStationsAsync();

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
@ -9,6 +9,7 @@ using TINK.Model.Services.CopriApi.ServerUris;
using TINK.Model.State;
using TINK.Repository.Exception;
using TINK.Repository.Response;
using TINK.Repository.Response.Stations.Station;
namespace TINK.Model.Connector
{
@ -26,7 +27,7 @@ namespace TINK.Model.Connector
/// </summary>
/// <param name="stationInfo">Object to get information from.</param>
/// <returns>Position information.</returns>
public static IPosition GetPosition(this StationsAvailableResponse.StationInfo stationInfo)
public static IPosition GetPosition(this StationInfo stationInfo)
=> GetPosition(stationInfo.gps);
/// <summary> Gets the position from StationInfo object. </summary>
@ -52,14 +53,14 @@ namespace TINK.Model.Connector
if (group == null || group.Length == 0)
{
// If not logged in stations groups are empty form COPRI version v4.1.
Log.Debug("Can not get goup form string. Group text can not be null.");
Log.Debug("Can not get group form string. Group text can not be null.");
return new List<string>();
}
return new HashSet<string>(group).ToList();
}
/// <summary> Gets if user acknowldged ags or not. </summary>
/// <summary> Gets if user acknowledged AGBs or not. </summary>
/// <param name="authorizationResponse">Object to get information from.</param>
/// <returns>Position information.</returns>
public static bool GetIsAgbAcknowledged(this AuthorizationResponse authorizationResponse)
@ -77,7 +78,7 @@ namespace TINK.Model.Connector
/// <summary> Gets the position from StationInfo object. </summary>
/// <param name="stationInfo">Object to get information from.</param>
/// <returns>Position information.</returns>
public static IEnumerable<string> GetGroup(this StationsAvailableResponse.StationInfo stationInfo)
public static IEnumerable<string> GetGroup(this StationInfo stationInfo)
{
try
{
@ -297,8 +298,19 @@ namespace TINK.Model.Connector
? typeOfBike
: (TypeOfBike?)null;
/// <summary>
/// Gets whether bike is a AA bike (bike must be always returned a the same station) or AB bike (start and end stations can be different stations).
/// </summary>
/// <param name="bikeInfo">Object to get AA info from.</param>
/// <returns>AA info.</returns>
public static AaRideType? GetAaRideType(this BikeInfoBase bikeInfo)
=> Enum.TryParse(bikeInfo?.aa_ride, true, out AaRideType aaRide)
? aaRide
: (AaRideType?)null;
/// <summary> Get position from a ,- separated string. </summary>
/// <param name="gps">Text to extract positon from.</param>
/// <param name="gps">Text to extract position from.</param>
/// <returns>Position object.</returns>
public static IPosition GetPosition(Repository.Response.Position gps)
=> PositionFactory.Create(
@ -306,7 +318,7 @@ namespace TINK.Model.Connector
double.TryParse(gps?.longitude, NumberStyles.Float, CultureInfo.InvariantCulture, out double longitude) ? longitude : double.NaN);
/// <summary> Get position from a ,- separated string. </summary>
/// <param name="gps">Text to extract positon from.</param>
/// <param name="gps">Text to extract position from.</param>
/// <returns>Position object.</returns>
public static Map.IMapSpan GetMapSpan(this MapSpan mapSpan)
=> Map.MapSpanFactory.Create(
@ -343,7 +355,7 @@ namespace TINK.Model.Connector
/// Gets the operator Uri from response.
/// </summary>
/// <param name="bikeInfo"> Response to get uri from.</param>
/// <returns>Operatore Uri</returns>
/// <returns>Operator Uri</returns>
public static Uri GetOperatorUri(this BikeInfoBase bikeInfo)
{
return bikeInfo?.uri_operator != null && !string.IsNullOrEmpty(bikeInfo?.uri_operator)
@ -351,7 +363,7 @@ namespace TINK.Model.Connector
: null;
}
/// <summary> Tries to get the copriversion from response.</summary>
/// <summary> Tries to get the copri version from response.</summary>
/// <param name="response">Response to get version info from.</param>
/// <returns>COPRI version</returns>
public static bool TryGetCopriVersion(this CopriVersion response, out Version copriVersion)
@ -362,7 +374,7 @@ namespace TINK.Model.Connector
&& Version.TryParse(response.copri_version, out copriVersion);
}
/// <summary> Gets the copriversion from.</summary>
/// <summary> Gets the copri version from.</summary>
/// <param name="response">Response to get version info from.</param>
/// <returns>COPRI version</returns>
public static Version GetCopriVersion(this CopriVersion response)

View file

@ -7,7 +7,6 @@ using TINK.Model.MiniSurvey;
using TINK.Model.State;
using TINK.Repository.Response;
using BikeExtension = TINK.Model.Bikes.BikeInfoNS.BikeNS.BikeExtension;
using BikeInfo = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfo;
namespace TINK.Model.Connector.Updater
{
@ -63,7 +62,7 @@ namespace TINK.Model.Connector.Updater
var lockType = lockModel.HasValue
? BikeExtension.GetLockType(lockModel.Value)
: BikeExtension.GetLockType(DEFAULTLOCKMODEL); // Map bikes without "system"- entry in response to backend- locks.
: BikeExtension.GetLockType(DEFAULTLOCKMODEL); // Map bikes without "system"- entry in response to back end- locks.
try
{
@ -76,6 +75,7 @@ namespace TINK.Model.Connector.Updater
LockModel.Sigo,
bikeInfo.GetWheelType(),
bikeInfo.GetTypeOfBike(),
bikeInfo.GetAaRideType(),
bikeInfo.description),
DriveFactory.Create(bikeInfo?.bike_type),
dataSource,
@ -94,7 +94,7 @@ namespace TINK.Model.Connector.Updater
bikeInfo.GetGroup(),
miniSurvey: bikeInfo.user_miniquery != null
? new MiniSurveyModel(new Dictionary<string, IQuestionModel> {
{ "q1", new QuestionModel()} // Add a dummy querry. Querries are not yet read from COPRI but compiled into the app.
{ "q1", new QuestionModel()} // Add a dummy query. Queries are not yet read from COPRI but compiled into the app.
})
: new MiniSurveyModel(),
co2Saving: bikeInfo.co2saving);
@ -106,6 +106,7 @@ namespace TINK.Model.Connector.Updater
LockModel.ILockIt,
bikeInfo.GetWheelType(),
bikeInfo.GetTypeOfBike(),
bikeInfo.GetAaRideType(),
bikeInfo.description),
DriveFactory.Create(bikeInfo?.bike_type),
dataSource,
@ -129,7 +130,7 @@ namespace TINK.Model.Connector.Updater
}
catch (ArgumentException ex)
{
// Contructor reported invalid arguemts (missing lock id, ....).
// Constructor reported invalid arguments (missing lock id, ....).
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. Invalid response detected. Available bike with id {bikeInfo.bike} skipped. {ex.Message}");
return null;
}
@ -184,6 +185,7 @@ namespace TINK.Model.Connector.Updater
LockModel.ILockIt,
bikeInfo.GetWheelType(),
bikeInfo.GetTypeOfBike(),
bikeInfo.GetAaRideType(),
bikeInfo.description),
DriveFactory.Create(bikeInfo?.bike_type),
dataSource,
@ -214,6 +216,7 @@ namespace TINK.Model.Connector.Updater
LockModel.Sigo,
bikeInfo.GetWheelType(),
bikeInfo.GetTypeOfBike(),
bikeInfo.GetAaRideType(),
bikeInfo.description),
DriveFactory.Create(bikeInfo?.bike_type),
dataSource,
@ -238,7 +241,7 @@ namespace TINK.Model.Connector.Updater
}
catch (ArgumentException ex)
{
// Contructor reported invalid arguemts (missing lock id, ....).
// Constructor reported invalid arguments (missing lock id, ....).
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoReservedOrBooked)} argument. Invalid response detected. Reserved bike with id {bikeInfo.bike} skipped. {ex.Message}");
return null;
}
@ -255,6 +258,7 @@ namespace TINK.Model.Connector.Updater
LockModel.ILockIt,
bikeInfo.GetWheelType(),
bikeInfo.GetTypeOfBike(),
bikeInfo.GetAaRideType(),
bikeInfo.description),
DriveFactory.Create(bikeInfo?.bike_type),
dataSource,
@ -278,29 +282,8 @@ namespace TINK.Model.Connector.Updater
bikeInfo.GetGroup());
case LockModel.BordComputer:
return new BikeInfo(
new Bike(
bikeInfo.bike,
LockModel.BordComputer,
bikeInfo.GetWheelType(),
bikeInfo.GetTypeOfBike(),
bikeInfo.description),
DriveFactory.Create(bikeInfo?.bike_type),
dataSource,
bikeInfo.GetIsDemo(),
bikeInfo.GetGroup(),
bikeInfo.station,
bikeInfo.GetOperatorUri(),
#if !NOTARIFFDESCRIPTION
bikeInfo.rental_description != null
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
#else
Create((TINK.Repository.Response.TariffDescription)null),
#endif
bikeInfo.GetFrom(),
mailAddress,
bikeInfo.timeCode);
throw new NotSupportedException($"Bikes with lock model of type {lockModel} are no more supported.");
default:
return new Bikes.BikeInfoNS.CopriLock.BikeInfo(
new Bike(
@ -308,6 +291,7 @@ namespace TINK.Model.Connector.Updater
LockModel.Sigo,
bikeInfo.GetWheelType(),
bikeInfo.GetTypeOfBike(),
bikeInfo.GetAaRideType(),
bikeInfo.description),
DriveFactory.Create(bikeInfo?.bike_type),
DataSource.Copri,

View file

@ -1,17 +1,14 @@
using System;
using System.Collections.Generic;
using Serilog;
using TINK.Model.Bikes;
using TINK.Model.Bikes.BikeInfoNS.BC;
using TINK.Model.State;
using TINK.Model.Station;
using TINK.Model.Station.Operator;
using TINK.Model.Stations;
using TINK.Model.Stations.StationNS.Operator;
using TINK.Model.User.Account;
using TINK.Repository.Exception;
using TINK.Repository.Response;
using TINK.Repository.Response.Stations;
using TINK.Services.CopriApi;
using Xamarin.Forms;
using BikeInfo = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfo;
using IBikeInfoMutable = TINK.Model.Bikes.BikeInfoNS.BC.IBikeInfoMutable;
namespace TINK.Model.Connector.Updater
@ -31,7 +28,7 @@ namespace TINK.Model.Connector.Updater
=> bike.State.Load(InUseStateEnum.Disposable, notifyLevel: notifyLevel);
/// <summary>
/// Gets all statsion for station provider and add them into station list.
/// Gets all station for station provider and add them into station list.
/// </summary>
/// <param name="p_oStationList">List of stations to update.</param>
public static StationDictionary GetStationsAllMutable(this StationsAvailableResponse stationsAllResponse)
@ -57,7 +54,7 @@ namespace TINK.Model.Connector.Updater
string.Format("Station id {0} is not unique.", station.Value.station), stationsAllResponse);
}
stations.Add(new Station.Station(
stations.Add(new Stations.StationNS.Station(
station.Value.station,
station.Value.GetGroup(),
station.Value.GetPosition(),
@ -89,7 +86,7 @@ namespace TINK.Model.Connector.Updater
new ResourceUrls(response.tariff_info_html, response.bike_info_html, response.agb_html, response.privacy_html, response.impress_html));
/// <summary> Gets account object from login response.</summary>
/// <param name="merchantId">Needed to extract cookie from autorization response.</param>
/// <param name="merchantId">Needed to extract cookie from authorization response.</param>
/// <param name="loginResponse">Response to get session cookie and debug level from.</param>
/// <param name="mail">Mail address needed to construct a complete account object (is not part of response).</param>
/// <param name="password">Password needed to construct a complete account object (is not part of response).</param>

View file

@ -1,11 +1,11 @@
using System.Collections.Generic;
using System.Collections.Generic;
using TINK.Model.Connector;
using TINK.ViewModel.Map;
using TINK.ViewModel.Settings;
namespace TINK.Model
{
/// <summary> Holds collecion of filters to filter options (TINK, Konrad, ....). </summary>
/// <summary> Holds collection of filters to filter options (TINK, Konrad, ....). </summary>
/// <remarks> Former name: FilterCollection.</remarks>
public static class GroupFilterHelper
{

View file

@ -7,7 +7,7 @@ using TINK.Model.Connector;
using TINK.Model.Device;
using TINK.Model.Services.CopriApi.ServerUris;
using TINK.Model.Settings;
using TINK.Model.Station;
using TINK.Model.Stations.StationNS;
using TINK.Services;
using TINK.Services.BluetoothLock;
using TINK.Settings;
@ -46,15 +46,15 @@ namespace TINK.Model
/// <summary> Name of the station which is selected. </summary>
IStation SelectedStation { get; set; }
/// <summary>Polling periode.</summary>
/// <summary>Polling period.</summary>
PollingParameters Polling { get; set; }
TimeSpan ExpiresAfter { get; set; }
/// <summary> Holds status about whants new page. </summary>
/// <summary> Holds status about whats new page. </summary>
WhatsNew WhatsNew { get; }
/// <summary> Gets whether device is connected to internet or not. </summary>
/// <summary> Gets whether device is connected to Internet or not. </summary>
bool GetIsConnected();
/// <summary> Action to post to GUI thread.</summary>
@ -69,7 +69,7 @@ namespace TINK.Model
/// <summary>Settings determining the startup behavior of the app.</summary>
IStartupSettings StartupSettings { get; }
/// <summary> Value indicating whether map is centerted to current position or not. </summary>
/// <summary> Value indicating whether map is centered to current position or not. </summary>
bool CenterMapToCurrentLocation { get; set; }
/// <summary> Holds the map area where user is or was located or null if position is unknown. </summary>
@ -98,7 +98,7 @@ namespace TINK.Model
/// <summary> Holds the different lock service implementations.</summary>
LocksServicesContainerMutable LocksServices { get; }
/// <summary> Holds the flavor of the app, i.e. specifies if app is sharee.bike, Mein konrad or Lastenrad Bayern.</summary>
/// <summary> Holds the flavor of the app, i.e. specifies if app is sharee.bike, Mein konrad or LastenRad Bayern.</summary>
AppFlavor Flavor { get; }
/// <summary> Holds available app themes.</summary>
@ -113,7 +113,7 @@ namespace TINK.Model
/// <summary> Holds the external path. </summary>
string ExternalFolder { get; }
/// <summary> Holds the stations availalbe. </summary>
/// <summary> Holds the stations centered. </summary>
IEnumerable<IStation> Stations { get; set; }
/// <summary> Holds the Urs to query resources from. </summary>

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
@ -25,7 +25,7 @@ namespace TINK.Model.Logging
if (directoryExistsChecker == null)
{
throw new ArgumentException($"Can not instantiate {nameof(LoggingDirectoryManager)}- object. Directory existance checker delegate can not be null.");
throw new ArgumentException($"Can not instantiate {nameof(LoggingDirectoryManager)}- object. Directory existence checker delegate can not be null.");
}
if (directoryCreator == null)
@ -42,7 +42,7 @@ namespace TINK.Model.Logging
if (string.IsNullOrEmpty(directorySeparatorChar.ToString()))
{
throw new ArgumentException($"Can not instantiate {nameof(LoggingDirectoryManager)}- object. Directory separtor character can not be null or empty.");
throw new ArgumentException($"Can not instantiate {nameof(LoggingDirectoryManager)}- object. Directory separator character can not be null or empty.");
}
if (p_iRetainedFilesCountLimit < 1)

View file

@ -1,9 +1,9 @@

namespace TINK.Model
{
public class NullPostion : IPosition
public class NullPosition : IPosition
{
internal NullPostion() { }
internal NullPosition() { }
public double Latitude => double.NaN;

View file

@ -6,6 +6,6 @@ namespace TINK.Model
public static IPosition Create(double latitude = double.NaN, double longitude = double.NaN)
=> Position.GetIsValid(longitude, latitude)
? new Position(latitude, longitude) as IPosition
: new NullPostion();
: new NullPosition();
}
}

View file

@ -194,7 +194,7 @@ namespace TINK.Model.Settings
}
/// <summary> Sets whether polling is on or off and the periode if polling is on. </summary>
/// <summary> Sets whether polling is on or off and the period if polling is on. </summary>
/// <param name="settingsJSON">Dictionary to write entries to.</param>
public static Dictionary<string, string> SetPollingParameters(
this IDictionary<string, string> targetDictionary,
@ -210,19 +210,19 @@ namespace TINK.Model.Settings
}).ToDictionary(key => key.Key, value => value.Value);
}
/// <summary> Get whether polling is on or off and the periode if polling is on. </summary>
/// <summary> Get whether polling is on or off and the period if polling is on. </summary>
/// <param name="settingsJSON">Dictionary holding parameters from JSON.</param>
/// <returns>Polling parameters.</returns>
public static PollingParameters GetPollingParameters(this IDictionary<string, string> settingsJSON)
{
// Check if dictionary contains entry for periode.
if (settingsJSON.TryGetValue($"{typeof(PollingParameters).Name}_{typeof(TimeSpan).Name}", out string periode)
// Check if dictionary contains entry for period.
if (settingsJSON.TryGetValue($"{typeof(PollingParameters).Name}_{typeof(TimeSpan).Name}", out string period)
&& settingsJSON.TryGetValue($"{typeof(PollingParameters).Name}_{typeof(bool).Name}", out string active)
&& !string.IsNullOrEmpty(periode)
&& !string.IsNullOrEmpty(period)
&& !string.IsNullOrEmpty(active))
{
return new PollingParameters(
JsonConvert.DeserializeObject<TimeSpan>(periode),
JsonConvert.DeserializeObject<TimeSpan>(period),
JsonConvert.DeserializeObject<bool>(active));
}

View file

@ -16,15 +16,15 @@ namespace TINK.Settings
false);
/// <summary> Constructs a polling parameter object. </summary>
/// <param name="periode">Polling periode.</param>
/// <param name="period">Polling period.</param>
/// <param name="activated">True if polling is activated.</param>
public PollingParameters(TimeSpan periode, bool activated)
public PollingParameters(TimeSpan period, bool activated)
{
Periode = periode; // Can not be null because is a struct.
Periode = period; // Can not be null because is a struct.
IsActivated = activated;
}
/// <summary>Holds the polling periode.</summary>
/// <summary>Holds the polling period.</summary>
public TimeSpan Periode { get; }
/// <summary> Holds value whether polling is activated or not.</summary>

View file

@ -18,7 +18,7 @@ namespace TINK.Model.Settings
public const bool DEFAULTREPOTLEVEL = false;
/// <summary> Gets the type of the default geolocation service. </summary>
/// <remarks> Swtiched from GeolocationService (GeolocationAccuracyMediumService) to GeolocationAccuracyHighService in app version 3.0.290.</remarks>
/// <remarks> Switched from GeolocationService (GeolocationAccuracyMediumService) to GeolocationAccuracyHighService in app version 3.0.290.</remarks>
public static Type DefaultLocationService => typeof(GeolocationAccuracyHighService);
// Default value of the expires after entry. Controls the expiration time of the cache values.
@ -54,8 +54,8 @@ namespace TINK.Model.Settings
bool? isSiteCachingOn = null,
string activeTheme = null)
{
GroupFilterMapPage = groupFilterMapPage ?? new GroupFilterMapPage(); // Default behaviour: No filtering.
GroupFilterSettings = groupFilterSettings ?? new GroupFilterSettings(); // Default behaviour: No filtering.
GroupFilterMapPage = groupFilterMapPage ?? new GroupFilterMapPage(); // Default behavior: No filtering.
GroupFilterSettings = groupFilterSettings ?? new GroupFilterSettings(); // Default behavior: No filtering.
StartupSettings = startupSettings ?? new StartupSettings();
ActiveUri = GetActiveUri(activeUri);
PollingParameters = pollingParameters ?? PollingParameters.Default;
@ -64,7 +64,7 @@ namespace TINK.Model.Settings
ExpiresAfter = expiresAfter ?? DEFAULTEXPIRESAFTER;
ActiveLockService = activeLockService ?? LocksServicesContainerMutable.DefaultLocksservice;
ConnectTimeout = connectTimeout ?? new TimeSpan(0, 0, TimeOutProvider.DEFAULT_BLUETOOTHCONNECT_TIMEOUTSECONDS); // Try one sec. to connect.
ActiveGeolocationService = activeGeolocationService ?? DefaultLocationService.Name;
ActiveGeolocationService = activeGeolocationService ?? DefaultLocationService.FullName;
CenterMapToCurrentLocation = centerMapToCurrentLocation ?? GetCenterMapToCurrentLocation(activeUri);
MapSpan = mapSpan;
LogToExternalFolder = logToExternalFolder ?? false;
@ -78,7 +78,7 @@ namespace TINK.Model.Settings
/// <summary> Holds the filters loaded from settings. </summary>
public IGroupFilterSettings GroupFilterSettings { get; }
/// <summary> Holds the stettings determining app startup behavior. </summary>
/// <summary> Holds the settings determining app startup behavior. </summary>
public IStartupSettings StartupSettings { get; }
/// <summary> Holds the uri to connect to. </summary>
@ -102,7 +102,7 @@ namespace TINK.Model.Settings
/// <summary> Gets the geolocation service to use.</summary>
public string ActiveGeolocationService { get; }
/// <summary> True if map is centered to current positon, false if not to center map.</summary>
/// <summary> True if map is centered to current position, false if not to center map.</summary>
public bool CenterMapToCurrentLocation { get; }
/// <summary> Holds the map area to display. </summary>
@ -121,7 +121,7 @@ namespace TINK.Model.Settings
public static bool GetCenterMapToCurrentLocation(Uri activeUri)
{
// TINK does not require acess to current location. Deactivate center map to current location for this reason.
// TINK does not require access to current location. Deactivate center map to current location for this reason.
return !GetActiveUri(activeUri).Host.GetIsCopri();
}
}

View file

@ -1,4 +1,4 @@
using System;
using System;
namespace TINK.Model.State
{
@ -262,7 +262,7 @@ namespace TINK.Model.State
if (_RemainingTime.HasValue == false)
{
// Value was not yet querried.
// Do querry before returning object.
// Do query before returning object.
_StateInfo.GetIsStillReserved(out _RemainingTime);
}

View file

@ -1,8 +1,9 @@
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using TINK.Model.Stations.StationNS;
namespace TINK.Model.Station
namespace TINK.Model.Stations
{
public class StationDictionary : IEnumerable<IStation>
{
@ -31,7 +32,7 @@ namespace TINK.Model.Station
}
/// <summary>
/// Deteermines whether a station by given key exists.
/// Determines whether a station by given key exists.
/// </summary>
/// <param name="key">Key to check.</param>
/// <returns>True if station exists.</returns>

View file

@ -1,7 +1,7 @@
using System.Collections.Generic;
using TINK.Model.Station.Operator;
using System.Collections.Generic;
using TINK.Model.Stations.StationNS.Operator;
namespace TINK.Model.Station
namespace TINK.Model.Stations.StationNS
{
public interface IStation
{

View file

@ -1,7 +1,7 @@
using System.Collections.Generic;
using TINK.Model.Station.Operator;
using System.Collections.Generic;
using TINK.Model.Stations.StationNS.Operator;
namespace TINK.Model.Station
namespace TINK.Model.Stations.StationNS
{
/// <summary> Holds object representing null station.</summary>
public class NullStation : IStation

View file

@ -1,6 +1,6 @@
using Xamarin.Forms;
using Xamarin.Forms;
namespace TINK.Model.Station.Operator
namespace TINK.Model.Stations.StationNS.Operator
{
/// <summary> Holds operator related data.</summary>
public class Data : IData

View file

@ -1,6 +1,6 @@
using Xamarin.Forms;
using Xamarin.Forms;
namespace TINK.Model.Station.Operator
namespace TINK.Model.Stations.StationNS.Operator
{
public interface IData
{

View file

@ -1,8 +1,8 @@
using System;
using System;
using System.Collections.Generic;
using TINK.Model.Station.Operator;
using TINK.Model.Stations.StationNS.Operator;
namespace TINK.Model.Station
namespace TINK.Model.Stations.StationNS
{
/// <summary> Holds station info. </summary>
public class Station : IStation

View file

@ -13,7 +13,7 @@ using TINK.Model.Device;
using TINK.Model.Logging;
using TINK.Model.Services.CopriApi.ServerUris;
using TINK.Model.Settings;
using TINK.Model.Station;
using TINK.Model.Stations.StationNS;
using TINK.Model.User.Account;
using TINK.Services;
using TINK.Services.BluetoothLock;
@ -42,7 +42,7 @@ namespace TINK.Model
public static string MerchantId { get; private set; }
/// <summary>
/// Holds status about whants new page.
/// Holds status about whats new page.
/// </summary>
public WhatsNew WhatsNew { get; private set; }
@ -65,7 +65,7 @@ namespace TINK.Model
set => m_oFilterDictionaryMapPage = value ?? new GroupFilterMapPage();
}
/// <summary> Value indicating whether map is centerted to current position or not. </summary>
/// <summary> Value indicating whether map is centered to current position or not. </summary>
public bool CenterMapToCurrentLocation { get; set; }
/// <summary> Holds the map area to display when starting app for first time/ when center map to is off. </summary>
@ -123,7 +123,7 @@ namespace TINK.Model
/// <summary>
/// Update connector from filters when
/// - login state changes
/// - view is toggled (TINK to Kornrad and vice versa)
/// - view is toggled (TINK to Konrad and vice versa)
/// </summary>
public void UpdateConnector()
{
@ -133,7 +133,7 @@ namespace TINK.Model
m_oConnector.Connector);
}
/// <summary>Polling periode.</summary>
/// <summary>Polling period.</summary>
public PollingParameters Polling { get; set; }
public TimeSpan ExpiresAfter { get; set; }
@ -155,7 +155,7 @@ namespace TINK.Model
/// <param name="accountStore"></param>
/// <param name="passwordValidator"></param>
/// <param name="p_oConnectorFactory"></param>
/// <param name="geolocationService">Null in productive context. Service to querry geoloation for testing purposes. Parameter can be made optional.</param>
/// <param name="geolocationService">Null in productive context. Service to query geolocation for testing purposes. Parameter can be made optional.</param>
/// <param name="locksService">Null in productive context. Service to control locks/ get locks information for testing proposes. Parameter can be made optional.</param>
/// <param name="device">Object allowing platform specific operations.</param>
/// <param name="specialFolder"></param>
@ -303,7 +303,7 @@ namespace TINK.Model
throw new ArgumentException($"Can not instantiate {nameof(TinkApp)}- object. Polling parameters must never be null.");
Polling = (lastVersion != null && lastVersion < new Version(3, 0, 358))
? PollingParameters.Default // Default polling periode was 10s up to 3.0.357. Is 60s for later versions.
? PollingParameters.Default // Default polling period was 10s up to 3.0.357. Is 60s for later versions.
: settings.PollingParameters;
AppVersion = currentVersion ?? new Version(3, 0, 122);
@ -342,7 +342,7 @@ namespace TINK.Model
/// <summary> Holds delegate to determine whether device is connected or not.</summary>
private readonly Func<bool> isConnectedFunc;
/// <summary> Gets whether device is connected to internet or not. </summary>
/// <summary> Gets whether device is connected to Internet or not. </summary>
public bool GetIsConnected() => isConnectedFunc();
/// <summary> Holds the folder where settings files are stored. </summary>
@ -365,8 +365,8 @@ namespace TINK.Model
/// <summary> Name of the station which is selected. </summary>
public IStation SelectedStation { get; set; } = new NullStation();
/// <summary> Holds the stations availalbe. </summary>
public IEnumerable<IStation> Stations { get; set; } = new List<Station.Station>();
/// <summary> Holds the stations centered. </summary>
public IEnumerable<IStation> Stations { get; set; } = new List<Station>();
public IResourceUrls ResourceUrls { get; set; } = new ResourceUrls();

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
@ -10,15 +10,15 @@ namespace TINK.Model.User.Account
{
None = 0, // No extra permissions.
PickCopriServer = 2, // Allows user to switch COPRI server.
ManageCopriCacheExpiration = 4, // Allows to manage the livetime of COPRI cache entries.
ManagePolling = 8, // Turn polling off or on and set pollig frequency.
PickLockServiceImplementation = 16, // Allows to pick the implementation which controls bluetooth lock mangement.
ManageCopriCacheExpiration = 4, // Allows to manage the live time of COPRI cache entries.
ManagePolling = 8, // Turn polling off or on and set polling frequency.
PickLockServiceImplementation = 16, // Allows to pick the implementation which controls bluetooth lock management.
PickLocationServiceImplementation = 32, // Allows to pick the implementation which gets location information.
PickLoggingLevel = 64, // Allows to select the logging level.
ShowDiagnostics = 128, // Turns on display of diagnostics.
SwitchNoSiteCaching = 1024, // Allows to turn off/ on caching of sites displayed in app hosted by COPRI
ReportLevel = 2048, // Allows extent to show error messages.
SwitchTheme = 4096, // Allows user to switch theme (sharee.bike, Meinkonrad, Lastenrad Bayern)
SwitchTheme = 4096, // Allows user to switch theme (sharee.bike, Mein konrad, LastenRad Bayern)
All = PickCopriServer +
ManageCopriCacheExpiration +
ManagePolling +
@ -57,7 +57,7 @@ namespace TINK.Model.User.Account
/// <param name="mail">Mail address of the account holder.</param>
/// <param name="password">Password.</param>
/// <param name="sessionCookie">Session cookie from copri.</param>
/// <param name="bikeGroup">Group holdig info about Group (TINK, Konrad, ...)</param>
/// <param name="bikeGroup">Group holding info about Group (TINK, Konrad, ...)</param>
/// <param name="p_iDebugLevel">Flag which controls display of debug settings.</param>
public Account(
string mail,
@ -87,7 +87,7 @@ namespace TINK.Model.User.Account
/// <summary>Password of to authenticate.</summary>
public string Pwd { get; }
/// <summary>True if user acknowleged agbs.</summary>
/// <summary>True if user acknowledged AGBs.</summary>
public bool IsAgbAcknowledged { get; }
/// <summary>Session cookie used to sign in to copri.</summary>

View file

@ -683,8 +683,8 @@ namespace TINK.Model
new List<AppFlavor> { AppFlavor.MeinKonrad, AppFlavor.ShareeBike }
},
{
new Version(3, 0, 362),
AppResources.ChangeLog_3_0_362_MK_SB,
new Version(3, 0, 363),
AppResources.ChangeLog_3_0_363_MK_SB,
new List<AppFlavor> { AppFlavor.MeinKonrad, AppFlavor.ShareeBike }
},
};
@ -693,7 +693,7 @@ namespace TINK.Model
/// <param name="currentVersion">Current version of the app.</param>
/// <param name="lastVersion">Version of app which was used before this session, null if app is installed for the first time.</param>
/// <param name="shownInVersion">Null or version in which whats new dialog was shown last. Used to determine if AGB dialog has to be shown.</param>
/// <param name="flavor">Flavor of the app, i.e. specified if app is sharee.bike, Lastenrad Bayern, ...</param>
/// <param name="flavor">Flavor of the app, i.e. specified if app is sharee.bike, LastenRad Bayern, ...</param>
/// <param name="platform">Platform on which app is running.</param>
/// <param name="messages">Messages to inject for testing.</param>
public WhatsNew(
@ -727,7 +727,7 @@ namespace TINK.Model
IsShowRequired = true;
}
/// <summary> Gets or sets value whehter whats new was alreay shonw in current settion or not. </summary>
/// <summary> Gets or sets value whether whats new was already shown in current session or not. </summary>
public bool WasShownInCurrentSession { get; set; }
/// <summary> Holds the information in which version of the app the whats new dialog has been shown.</summary>
@ -736,10 +736,10 @@ namespace TINK.Model
/// <summary> Holds information whether whats new page was already shown or not.</summary>
public bool IsShowRequired { get; }
/// <summary> True if info about modified agb has to be displayed. </summary>
/// <summary> True if info about modified AGB has to be displayed. </summary>
public bool IsShowAgbRequired => (WasShownVersion ?? AGBMODIFIEDBUILD) < AGBMODIFIEDBUILD;
/// <summary> Get the whats new text depening of version gap.</summary>
/// <summary> Get the whats new text depending of version gap.</summary>
/// <param name="messages">Messages to process.</param>
public IDictionary<Version, string> WhatsNewText { get; }
}

View file

@ -781,6 +781,18 @@ namespace TINK.MultilingualResources {
}
}
/// <summary>
/// Looks up a localized string similar to - Bikes that must be returned to the starting station are marked as such with an icon and the station id.&lt;br/&gt;
///- What used to be called &apos;return bike&apos; is now called &apos;end rental&apos;. Always make sure to end your chargeable rental!&lt;br/&gt;
///- Bug fixes&lt;br/&gt;
///- Package updates.
/// </summary>
public static string ChangeLog_3_0_363_MK_SB {
get {
return ResourceManager.GetString("ChangeLog_3_0_363_MK_SB", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to We have fixed some bugs. Enjoy the ride!.
/// </summary>
@ -2406,6 +2418,15 @@ namespace TINK.MultilingualResources {
}
}
/// <summary>
/// Looks up a localized string similar to Circular drives only!.
/// </summary>
public static string MessageAaRideTypeInfoTitle {
get {
return ResourceManager.GetString("MessageAaRideTypeInfoTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Log out.
/// </summary>
@ -2552,7 +2573,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Rental charges.
/// Looks up a localized string similar to Rental costs.
/// </summary>
public static string MessageBikesManagementTariffDescriptionFeeEuroPerHour {
get {
@ -2579,7 +2600,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Max. charges.
/// Looks up a localized string similar to Max. costs.
/// </summary>
public static string MessageBikesManagementTariffDescriptionMaxFeeEuroPerDay {
get {

View file

@ -475,7 +475,7 @@ Bitte App neu starten, um Radinfos zu bekommen.</value>
<value>Gratis Nutzung</value>
</data>
<data name="MessageBikesManagementTariffDescriptionMaxFeeEuroPerDay" xml:space="preserve">
<value>Max. Gebühr</value>
<value>Max. Kosten</value>
</data>
<data name="MessageBikesManagementTariffDescriptionEuroPerHour" xml:space="preserve">
<value>€/Std.</value>
@ -1165,6 +1165,15 @@ Treten Sie an das Rad heran, schalten Sie Bluetooth und Standortdienste ein und
&lt;br/&gt;
Außerdem:&lt;br/&gt;
- Kleinere Fehlerbehebungen&lt;br/&gt;
- Paketaktualisierungen</value>
</data>
<data name="MessageAaRideTypeInfoTitle" xml:space="preserve">
<value>Nur Kreisfahrten!</value>
</data>
<data name="ChangeLog_3_0_363_MK_SB" xml:space="preserve">
<value>- Räder, die an der Startstation zurückgegeben werden müssen, sind als solche mit einem Symbol und der Stations-ID gekennzeichnet&lt;br/&gt;
- Was früher als "Fahrrad zurückgeben" bezeichnet wurde, heißt jetzt "Miete beenden". Vergewissern Sie sich immer, dass Sie Ihre kostenpflichtige Miete beenden!&lt;br/&gt;
- Fehlerbehebungen&lt;br/&gt;
- Paketaktualisierungen</value>
</data>
</root>

View file

@ -581,7 +581,7 @@ Please restart app in order to get bike info.</value>
<value>€/hour</value>
</data>
<data name="MessageBikesManagementTariffDescriptionFeeEuroPerHour" xml:space="preserve">
<value>Rental charges</value>
<value>Rental costs</value>
</data>
<data name="MessageBikesManagementTariffDescriptionFreeTimePerSession" xml:space="preserve">
<value>Free use</value>
@ -590,7 +590,7 @@ Please restart app in order to get bike info.</value>
<value>hour(s)/day</value>
</data>
<data name="MessageBikesManagementTariffDescriptionMaxFeeEuroPerDay" xml:space="preserve">
<value>Max. charges</value>
<value>Max. costs</value>
</data>
<data name="MessageBikesManagementTariffDescriptionTariffHeader" xml:space="preserve">
<value>Tariff</value>
@ -1254,6 +1254,15 @@ Approach the bike, turn on Bluetooth and Location services and try again.</value
&lt;br/&gt;
Also:&lt;br/&gt;
- Minor bug fixes&lt;br/&gt;
- Package updates</value>
</data>
<data name="MessageAaRideTypeInfoTitle" xml:space="preserve">
<value>Circular drives only!</value>
</data>
<data name="ChangeLog_3_0_363_MK_SB" xml:space="preserve">
<value>- Bikes that must be returned to the starting station are marked as such with an icon and the station id.&lt;br/&gt;
- What used to be called 'return bike' is now called 'end rental'. Always make sure to end your chargeable rental!&lt;br/&gt;
- Bug fixes&lt;br/&gt;
- Package updates</value>
</data>
</root>

View file

@ -20,8 +20,7 @@
</trans-unit>
<trans-unit id="ActionCloseAndReturn" translate="yes" xml:space="preserve">
<source>Close lock &amp; end rental</source>
<target state="needs-review-translation">Schloss schließen &amp; Miete beenden</target>
<note from="MultilingualUpdate" annotates="source" priority="2">Please verify the translations accuracy as the source string was updated after it was translated.</note>
<target state="translated">Schloss schließen &amp; Miete beenden</target>
</trans-unit>
<trans-unit id="ActionOpen" translate="yes" xml:space="preserve">
<source>Open lock</source>
@ -41,8 +40,7 @@
</trans-unit>
<trans-unit id="ActionReturn" translate="yes" xml:space="preserve">
<source>End rental</source>
<target state="needs-review-translation">Miete beenden</target>
<note from="MultilingualUpdate" annotates="source" priority="2">Please verify the translations accuracy as the source string was updated after it was translated.</note>
<target state="translated">Miete beenden</target>
</trans-unit>
<trans-unit id="MarkingMapPage" translate="yes" xml:space="preserve">
<source>Bike Locations</source>
@ -307,8 +305,7 @@ Bitte melden Sie sich erneut an.</target>
</trans-unit>
<trans-unit id="ActionLoginRegister" translate="yes" xml:space="preserve">
<source>Register for free</source>
<target state="needs-review-translation">Kostenlos registrieren</target>
<note from="MultilingualUpdate" annotates="source" priority="2">Please verify the translations accuracy as the source string was updated after it was translated.</note>
<target state="translated">Kostenlos registrieren</target>
</trans-unit>
<trans-unit id="MarkingLoginEmailAddressLabel" translate="yes" xml:space="preserve">
<source>E-mail</source>
@ -628,16 +625,17 @@ Bitte App neu starten, um Radinfos zu bekommen.</target>
<target state="translated">Abo-Preis</target>
</trans-unit>
<trans-unit id="MessageBikesManagementTariffDescriptionFeeEuroPerHour" translate="yes" xml:space="preserve">
<source>Rental charges</source>
<source>Rental costs</source>
<target state="translated">Mietkosten</target>
<note from="MultilingualUpdate" annotates="source" priority="2">Please verify the translations accuracy as the source string was updated after it was translated.</note>
</trans-unit>
<trans-unit id="MessageBikesManagementTariffDescriptionFreeTimePerSession" translate="yes" xml:space="preserve">
<source>Free use</source>
<target state="translated">Gratis Nutzung</target>
</trans-unit>
<trans-unit id="MessageBikesManagementTariffDescriptionMaxFeeEuroPerDay" translate="yes" xml:space="preserve">
<source>Max. charges</source>
<target state="needs-review-translation">Max. Gebühr</target>
<source>Max. costs</source>
<target state="translated">Max. Kosten</target>
<note from="MultilingualUpdate" annotates="source" priority="2">Please verify the translations accuracy as the source string was updated after it was translated.</note>
</trans-unit>
<trans-unit id="MessageBikesManagementTariffDescriptionEuroPerHour" translate="yes" xml:space="preserve">
@ -729,7 +727,7 @@ Bitte kontaktieren sie den Betreiber!</target>
</trans-unit>
<trans-unit id="ChangeLog3_0_227" translate="yes" xml:space="preserve">
<source>Feedback dialog added which is shown after ending rental.</source>
<target state="needs-review-translation">Seite zur Eingabe von Rückmeldungen hinzugefügt, der nach Rückgabe eines Rads angezeigt wird.</target>
<target state="translated">Seite zur Eingabe von Rückmeldungen hinzugefügt, der nach Rückgabe eines Rads angezeigt wird.</target>
<note from="MultilingualUpdate" annotates="source" priority="2">Please verify the translations accuracy as the source string was updated after it was translated.</note>
</trans-unit>
<trans-unit id="ActivityTextConnectionStateOffline" translate="yes" xml:space="preserve">
@ -784,7 +782,7 @@ Layout Anzeige Radnamen und nummern verbessert.</target>
</trans-unit>
<trans-unit id="ChangeLog3_0_237" translate="yes" xml:space="preserve">
<source>Hard- and software information send to backend when ending rental.</source>
<target state="needs-review-translation">Hard- und software information werden an Backend übermittelt bei Radrückgabe.</target>
<target state="translated">Hard- und software information werden an Backend übermittelt bei Radrückgabe.</target>
<note from="MultilingualUpdate" annotates="source" priority="2">Please verify the translations accuracy as the source string was updated after it was translated.</note>
</trans-unit>
<trans-unit id="ChangeLog3_0_239" translate="yes" xml:space="preserve">
@ -875,8 +873,7 @@ Kleinere Verbesserungen.</target>
</trans-unit>
<trans-unit id="MessageErrorQueryLocationTitle" translate="yes" xml:space="preserve">
<source>Error query location!</source>
<target state="needs-review-translation">Fehler bei Standortabfrage!</target>
<note from="MultilingualUpdate" annotates="source" priority="2">Please verify the translations accuracy as the source string was updated after it was translated.</note>
<target state="translated">Fehler bei Standortabfrage!</target>
</trans-unit>
<trans-unit id="MessageErrorQueryLocationMessage" translate="yes" xml:space="preserve">
<source>Closing the lock and ending the rental is not possible.</source>
@ -884,7 +881,7 @@ Kleinere Verbesserungen.</target>
</trans-unit>
<trans-unit id="MessageErrorQueryLocationStartTitle" translate="yes" xml:space="preserve">
<source>Error start query location!</source>
<target state="needs-review-translation">Fehler beim Start der Standortabfrage!</target>
<target state="translated">Fehler beim Start der Standortabfrage!</target>
<note from="MultilingualUpdate" annotates="source" priority="2">Please verify the translations accuracy as the source string was updated after it was translated.</note>
</trans-unit>
<trans-unit id="ActivityTextErrorQueryLocationWhenAny" translate="yes" xml:space="preserve">
@ -1239,12 +1236,12 @@ Kleinere Fehlerbehebungen.
</trans-unit>
<trans-unit id="ActionContactMailAppReleated" translate="yes" xml:space="preserve">
<source>Feedback about the app</source>
<target state="needs-review-translation">Rückmeldung zur App</target>
<target state="translated">Rückmeldung zur App</target>
<note from="MultilingualUpdate" annotates="source" priority="2">Please verify the translations accuracy as the source string was updated after it was translated.</note>
</trans-unit>
<trans-unit id="MiscContactMailAppReleatedSubject" translate="yes" xml:space="preserve">
<source>{0}-app releated request</source>
<target state="needs-review-translation">{0}-App Anfrage</target>
<target state="translated">{0}-App Anfrage</target>
<note from="MultilingualBuild" annotates="source" priority="2">Subject of contact mail to ("Feedback about the app").</note>
<note from="MultilingualUpdate" annotates="source" priority="2">Please verify the translations accuracy as the source string was updated after it was translated.</note>
</trans-unit>
@ -1567,7 +1564,7 @@ Wichtig: Schicken Sie eine E-Mail an den Betreiber (ansonsten läuft Ihre kosten
</trans-unit>
<trans-unit id="MarkingNoNetworkConnection" translate="yes" xml:space="preserve">
<source>Oops, there is no Internet connection.</source>
<target state="needs-review-translation">Ups, es ist keine Internetverbindung vorhanden.</target>
<target state="translated">Ups, es ist keine Internetverbindung vorhanden.</target>
<note from="MultilingualUpdate" annotates="source" priority="2">Please verify the translations accuracy as the source string was updated after it was translated.</note>
</trans-unit>
<trans-unit id="ChangeLog_3_0_358_MK_SB" translate="yes" xml:space="preserve">
@ -1614,6 +1611,21 @@ Also:&lt;br/&gt;
&lt;br/&gt;
Außerdem:&lt;br/&gt;
- Kleinere Fehlerbehebungen&lt;br/&gt;
- Paketaktualisierungen</target>
</trans-unit>
<trans-unit id="MessageAaRideTypeInfoTitle" translate="yes" xml:space="preserve">
<source>Circular drives only!</source>
<target state="translated">Nur Kreisfahrten!</target>
<note from="MultilingualUpdate" annotates="source" priority="2">Please verify the translations accuracy as the source string was updated after it was translated.</note>
</trans-unit>
<trans-unit id="ChangeLog_3_0_363_MK_SB" translate="yes" xml:space="preserve">
<source>- Bikes that must be returned to the starting station are marked as such with an icon and the station id.&lt;br/&gt;
- What used to be called 'return bike' is now called 'end rental'. Always make sure to end your chargeable rental!&lt;br/&gt;
- Bug fixes&lt;br/&gt;
- Package updates</source>
<target state="translated">- Räder, die an der Startstation zurückgegeben werden müssen, sind als solche mit einem Symbol und der Stations-ID gekennzeichnet&lt;br/&gt;
- Was früher als "Fahrrad zurückgeben" bezeichnet wurde, heißt jetzt "Miete beenden". Vergewissern Sie sich immer, dass Sie Ihre kostenpflichtige Miete beenden!&lt;br/&gt;
- Fehlerbehebungen&lt;br/&gt;
- Paketaktualisierungen</target>
</trans-unit>
</group>

View file

@ -13,6 +13,7 @@ using TINK.Model.Logging;
using TINK.Repository.Exception;
using TINK.Repository.Request;
using TINK.Repository.Response;
using TINK.Repository.Response.Stations;
namespace TINK.Repository
{
@ -24,7 +25,7 @@ namespace TINK.Repository
/// <summary> Initializes a instance of the copri calls https object. </summary>
/// <param name="copriHost">Host to connect to. </param>
/// <param name="appContextInfo">Provides app related info (app name and version, merchantid) to pass to COPRI.</param>
/// <param name="appContextInfo">Provides app related info (app name and version, merchant id) to pass to COPRI.</param>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
/// <param name="smartDevice">Holds info about smart device.</param>
/// <param name="sessionCookie">Session cookie if user is logged in, null otherwise.</param>
@ -50,7 +51,7 @@ namespace TINK.Repository
/// <summary> Holds the URL for rest calls.</summary>
private Uri m_oCopriHost;
/// <summary> Spacifies name and version of app. </summary>
/// <summary> Specifies name and version of app. </summary>
private string UserAgent { get; }
/// <summary> Returns true because value requested form copri server are returned. </summary>
@ -63,7 +64,7 @@ namespace TINK.Repository
public string SessionCookie => requestBuilder.SessionCookie;
/// <summary> Logs user in. </summary>
/// <param name="mailAddress">Mailaddress of user to log in.</param>
/// <param name="mailAddress">Mail address of user to log in.</param>
/// <param name="password">Password to log in.</param>
/// <param name="deviceId">Id specifying user and hardware.</param>
/// <remarks>Response which holds auth cookie <see cref="ResponseBase.authcookie"/></remarks>
@ -87,7 +88,7 @@ namespace TINK.Repository
public async Task<BikesAvailableResponse> GetBikesAvailableAsync()
=> await GetBikesAvailableAsync(m_oCopriHost.AbsoluteUri, requestBuilder.GetBikesAvailable(), UserAgent);
/// <summary> Gets a list of bikes reserved/ booked by acctive user. </summary>
/// <summary> Gets a list of bikes reserved/ booked by active user. </summary>
/// <returns>Response holding list of bikes.</returns>
public async Task<BikesReservedOccupiedResponse> GetBikesOccupiedAsync()
{
@ -127,7 +128,7 @@ namespace TINK.Repository
requestBuilder.DoReserve(bikeId),
UserAgent);
/// <summary> Gets canel booking request response.</summary>
/// <summary> Gets cancel booking request response.</summary>
/// <param name="bikeId">Id of the bike to book.</param>
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <returns>Response on cancel booking request.</returns>
@ -183,13 +184,13 @@ namespace TINK.Repository
requestBuilder.UpateLockingState(bikeId, state, location, batteryLevel, versionInfo),
UserAgent);
/// <summary> Gets booking request request. </summary>
/// <summary> Gets booking request. </summary>
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <param name="bikeId">Id of the bike to book.</param>
/// <param name="guid">Used to publish GUID from app to copri. Used for initial setup of bike in copri.</param>
/// <param name="batteryPercentage">Holds the filling level percentage of the battery.</param>
/// <param name="nextAction">If not null next locking action which is performed after booking.</param>
/// <returns>Requst on booking request.</returns>
/// <returns>Request on booking request.</returns>
public async Task<ReservationBookingResponse> DoBookAsync(
Uri operatorUri,
string bikeId,
@ -296,7 +297,7 @@ namespace TINK.Repository
copriHost,
command,
userAgent,
displayCommand); // Do not include password into exception output when an error occurres.
displayCommand); // Do not include password into exception output when an error occurs.
}
catch (System.Exception l_oException)
{
@ -437,7 +438,7 @@ namespace TINK.Repository
#endif
}
/// <summary> Gets a list of bikes reserved/ booked by acctive user from Copri.</summary>
/// <summary> Gets a list of bikes reserved/ booked by active user from Copri.</summary>
/// <param name="copriHost">URL of the copri host to connect to.</param>
/// <param name="command">Command to post.</param>
/// <returns>Response holding list of bikes.</returns>
@ -785,8 +786,8 @@ namespace TINK.Repository
#endif
}
/// <summary> http get- request.</summary>
/// <param name="Url">Ulr to get info from.</param>
/// <summary> Https get- request.</summary>
/// <param name="Url">Url to get info from.</param>
/// <returns>response from server</returns>
public static async Task<string> Get(string Url)
{
@ -804,7 +805,7 @@ namespace TINK.Repository
return result;
}
/// <summary> http- post request.</summary>
/// <summary> Https- post request.</summary>
/// <param name="command">Command to send.</param>
/// <param name="displayCommand">Command to display/ log used for error handling.</param>
/// <param name="uRL">Address of server to communicate with.</param>
@ -838,7 +839,7 @@ namespace TINK.Repository
#if !WINDOWS_UWP
var l_strHost = uRL;
// Returns a http request.
// Returns a https request.
var request = WebRequest.CreateHttp(l_strHost);
request.Method = "POST";

View file

@ -5,12 +5,13 @@ using TINK.Model.Bikes.BikeInfoNS.BluetoothLock;
using TINK.Model.Connector;
using TINK.Repository.Request;
using TINK.Repository.Response;
using TINK.Repository.Response.Stations;
namespace TINK.Repository
{
public class CopriCallsMemory : ICopriServer
public class CopriCallsMemory : ICopriServer
{
/// <summary> Part in file specifying apiserver.</summary>
/// <summary> Part in file specifying api server.</summary>
private static string CopriDevelHostUri = @"https://tinkwwp.copri-bike.de/APIjsonserver";
public const string DO_AUTH_Unknown_User_FILE = @"
@ -1335,7 +1336,7 @@ namespace TINK.Repository
}
/// <summary>
/// Gets a list of bikes reserved/ booked by acctive user from Copri.
/// Gets a list of bikes reserved/ booked by active user from Copri.
/// </summary>
/// <param name="p_strSessionCookie">Cookie to authenticate user.</param>
/// <returns>Response holding list of bikes.</returns>
@ -1343,7 +1344,7 @@ namespace TINK.Repository
{
try
{
requestBuilder.GetBikesOccupied(); // Non mock implementation if ICopriServer call this member as well. To ensure comparable behaviour this member is called here as well.
requestBuilder.GetBikesOccupied(); // Non mock implementation if ICopriServer call this member as well. To ensure comparable behavior this member is called here as well.
}
catch (NotSupportedException)
{
@ -1673,7 +1674,7 @@ namespace TINK.Repository
=> null;
/// <summary>
/// Gets a list of bikes reserved/ booked by acctive user from Copri.
/// Gets a list of bikes reserved/ booked by active user from Copri.
/// </summary>
/// <param name="sessionCookie">Cookie to authenticate user.</param>
/// <param name="SampleSet">Sample set to use.</param>

View file

@ -8,6 +8,7 @@ using TINK.Model.Device;
using TINK.Model.Services.CopriApi;
using TINK.Repository.Request;
using TINK.Repository.Response;
using TINK.Repository.Response.Stations;
namespace TINK.Repository
{

View file

@ -3,9 +3,9 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock;
using TINK.Model.Connector;
using TINK.Model.Device;
using TINK.Repository.Request;
using TINK.Repository.Response;
using TINK.Repository.Response.Stations;
namespace TINK.Repository
{
@ -13,7 +13,7 @@ namespace TINK.Repository
public interface ICopriServerBase
{
/// <summary> Logs user in. </summary>
/// <param name="mailAddress">Mailaddress of user to log in.</param>
/// <param name="mailAddress">Mail address of user to log in.</param>
/// <param name="password">Password to log in.</param>
/// <param name="deviceId">Id specifying user and hardware.</param>
/// <remarks>Response which holds auth cookie <see cref="ResponseBase.authcookie"/></remarks>
@ -34,7 +34,7 @@ namespace TINK.Repository
string bikeId,
Uri operatorUri);
/// <summary> Cancels reservation of bik. </summary>
/// <summary> Cancels reservation of bike. </summary>
/// <param name="bikeId">Id of the bike to reserve.</param>
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <returns>Response on cancel reservation request.</returns>
@ -162,7 +162,7 @@ namespace TINK.Repository
/// <returns>Response holding list of bikes.</returns>
Task<BikesAvailableResponse> GetBikesAvailableAsync();
/// <summary> Gets a list of bikes reserved/ booked by acctive user from Copri.</summary>
/// <summary> Gets a list of bikes reserved/ booked by active user from Copri.</summary>
/// <returns>Response holding list of bikes.</returns>
Task<BikesReservedOccupiedResponse> GetBikesOccupiedAsync();
}

View file

@ -15,10 +15,10 @@ namespace TINK.Repository.Request
string SessionCookie { get; }
/// <summary> Gets request to log user in. </summary>
/// <param name="mailAddress">Mailaddress of user to log in.</param>
/// <param name="mailAddress">Mail address of user to log in.</param>
/// <param name="password">Password to log in.</param>
/// <param name="deviceId">Id specifying user and hardware.</param>
/// <remarks>Requst which holds auth cookie <see cref="RequstBase.authcookie"/></remarks>
/// <remarks>Request which holds auth cookie <see cref="RequstBase.authcookie"/></remarks>
string DoAuthorization(
string mailAddress,
string password,
@ -37,7 +37,7 @@ namespace TINK.Repository.Request
/// <returns>Request to query list of bikes available.</returns>
string GetBikesAvailable();
/// <summary> Gets a list of bikes reserved/ booked by acctive user from Copri.</summary>
/// <summary> Gets a list of bikes reserved/ booked by active user from Copri.</summary>
/// <returns>Request to query list of bikes occupied.</returns>
string GetBikesOccupied();

View file

@ -81,7 +81,7 @@ namespace TINK.Repository.Request
SmartDevice.GetSmartDeviceParameters() +
UiIsoLanguageNameParameter;
/// <summary> Gets a list of bikes reserved/ booked by acctive user from Copri.</summary>
/// <summary> Gets a list of bikes reserved/ booked by active user from Copri.</summary>
/// <returns>Request to query list of bikes occupied.</returns>
public string GetBikesOccupied()
=> throw new NotSupportedException();

View file

@ -78,7 +78,7 @@ namespace TINK.Repository.Request
AuthCookieParameter +
UiIsoLanguageNameParameter;
/// <summary> Gets a list of bikes reserved/ booked by acctive user from Copri.</summary>
/// <summary> Gets a list of bikes reserved/ booked by active user from Copri.</summary>
/// <returns>Request to query list of bikes occupied.</returns>
public string GetBikesOccupied()
=> "request=user_bikes_occupied&system=all&genkey=1" +

View file

@ -1,4 +1,4 @@
using System.Runtime.Serialization;
using System.Runtime.Serialization;
namespace TINK.Repository.Response
{
@ -27,7 +27,7 @@ namespace TINK.Repository.Response
public string station { get; private set; }
/// <summary>
/// Holds the localized (german) description of the bike.
/// Holds the localized (German) description of the bike.
/// </summary>
[DataMember]
public string description { get; private set; }
@ -78,6 +78,12 @@ namespace TINK.Repository.Response
/// <summary> Describes type of the bike.</summary>
public BikeType bike_type { get; private set; }
/// <summary>
/// Holds whether bike is a AA bike (bike must be always returned a the same station) or AB bike (start and end stations can be different stations).
/// </summary>
[DataMember]
public string aa_ride { get; private set; }
/// <summary> Loading state of motor battery in % ]0..100[. </summary>
[DataMember]
public string bike_charge { get; private set; }

View file

@ -1,4 +1,4 @@
using System.Runtime.Serialization;
using System.Runtime.Serialization;
namespace TINK.Repository.Response
{
@ -40,7 +40,7 @@ namespace TINK.Repository.Response
public string charge_current_percent { get; private set; }
/// <summary>
/// Holds the maximum chargeing level of the battery in bars.
/// Holds the maximum charging level of the battery in bars.
/// </summary>
[DataMember]
public string charge_max_bars { get; private set; }

View file

@ -1,4 +1,4 @@
using System.Linq;
using System.Linq;
using TINK.MultilingualResources;
using TINK.Repository.Exception;
@ -80,7 +80,7 @@ namespace TINK.Repository.Response
/// <summary>Gets if a call to reserve bike succeeded or not by checking a booking response.</summary>
/// <param name="bikeId">Id of bike which should be booked.</param>
/// <param name="sessionCookie">Sessiong cookie of logged in user.</param>
/// <param name="sessionCookie">Session cookie of logged in user.</param>
/// <param name="bookingResponse">Response to check.</param>
/// <returns></returns>
public static BikeInfoReservedOrBooked GetIsReserveResponseOk(

View file

@ -0,0 +1,27 @@
using System.Runtime.Serialization;
namespace TINK.Repository.Response.Stations.Station
{
/// <summary>
/// Holds info about operator data.
/// </summary>
[DataContract]
public class OperatorData
{
[DataMember]
public string operator_name { get; private set; }
[DataMember]
public string operator_phone { get; private set; }
[DataMember]
public string operator_hours { get; private set; }
[DataMember]
public string operator_email { get; private set; }
[DataMember]
public string operator_color { get; private set; }
}
}

View file

@ -0,0 +1,32 @@
using System.Runtime.Serialization;
namespace TINK.Repository.Response.Stations.Station
{
/// <summary>
/// Holds info about a single station.
/// </summary>
[DataContract]
public class StationInfo
{
/// <summary>
/// Unique id of the station.
/// </summary>
[DataMember]
public string station { get; private set; }
[DataMember]
public string[] station_group { get; private set; }
[DataMember]
public string description { get; private set; }
/// <summary>
/// Position of the station.
/// </summary>
[DataMember]
public Position gps { get; private set; }
[DataMember]
public OperatorData operator_data { get; private set; }
}
}

View file

@ -0,0 +1,19 @@
using System.Collections.Generic;
using System.Runtime.Serialization;
using TINK.Repository.Response.Stations.Station;
namespace TINK.Repository.Response.Stations
{
/// <summary>
/// Holds the information about all stations and is used for deserialization of copri answer.
/// </summary>
[DataContract]
public class StationsAvailableResponse : ResponseBase
{
/// <summary>
/// Dictionary of bikes.
/// </summary>
[DataMember]
public Dictionary<string, StationInfo> stations { get; private set; }
}
}

View file

@ -1,69 +0,0 @@
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace TINK.Repository.Response
{
/// <summary>
/// Holds the information about all stations and is used for deserialization of copri answer.
/// </summary>
[DataContract]
public class StationsAvailableResponse : ResponseBase
{
/// <summary>
/// Holds info about a single station.
/// </summary>
[DataContract]
public class StationInfo
{
/// <summary>
/// Holds info about opertor data.
/// </summary>
[DataContract]
public class OperatorData
{
[DataMember]
public string operator_name { get; private set; }
[DataMember]
public string operator_phone { get; private set; }
[DataMember]
public string operator_hours { get; private set; }
[DataMember]
public string operator_email { get; private set; }
[DataMember]
public string operator_color { get; private set; }
}
/// <summary>
/// Unique id of the station.
/// </summary>
[DataMember]
public string station { get; private set; }
[DataMember]
public string[] station_group { get; private set; }
[DataMember]
public string description { get; private set; }
/// <summary>
/// Position of the station.
/// </summary>
[DataMember]
public Position gps { get; private set; }
[DataMember]
public OperatorData operator_data { get; private set; }
}
/// <summary>
/// Dictionary of bikes.
/// </summary>
[DataMember]
public Dictionary<string, StationInfo> stations { get; private set; }
}
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@ -10,13 +10,13 @@ using TINK.Services.BluetoothLock.Tdo;
namespace TINK.Services.BluetoothLock
{
/// <summary>
/// Facke locks service implementation which simulates locks which are in reach.
/// Fake locks service implementation which simulates locks which are in reach.
/// </summary>
public class LocksServiceInReach : ILocksServiceFake
{
private IEnumerable<LockInfoTdo> LocksInfo { get; set; } = new List<LockInfoTdo>();
/// <summary> Holds timeout values for series of connecting attemps to a lock or multiple locks. </summary>
/// <summary> Holds timeout values for series of connecting attempts to a lock or multiple locks. </summary>
public ITimeOutProvider TimeOut { get; set; }
/// <summary> Connects to lock.</summary>
@ -45,7 +45,7 @@ namespace TINK.Services.BluetoothLock
switch (bikeInfo.State.Value)
{
case InUseStateEnum.Disposable:
case InUseStateEnum.FeedbackPending: // State feedback pending does not exist for bluetooth locks but maches from bluetooth perspective state disposable.
case InUseStateEnum.FeedbackPending: // State feedback pending does not exist for bluetooth locks but matches from bluetooth perspective state disposable.
switch (lockInfo.State)
{
case LockingState.Open:

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@ -9,13 +9,13 @@ using TINK.Services.BluetoothLock.Tdo;
namespace TINK.Services.BluetoothLock
{
/// <summary>
/// Facke locks service implementation which simulates locks which are out of reach.
/// Fake locks service implementation which simulates locks which are out of reach.
/// </summary>
public class LocksServiceOutOfReach : ILocksServiceFake
{
private IEnumerable<LockInfoTdo> LocksInfo { get; set; } = new List<LockInfoTdo>();
/// <summary> Holds timeout values for series of connecting attemps to a lock or multiple locks. </summary>
/// <summary> Holds timeout values for series of connecting attempts to a lock or multiple locks. </summary>
public ITimeOutProvider TimeOut { get; set; }
/// <summary> Connects to lock.</summary>
@ -26,7 +26,7 @@ namespace TINK.Services.BluetoothLock
return await Task.FromResult(new LockInfoTdo.Builder { Id = authInfo.Id, Guid = authInfo.Guid, State = null }.Build());
}
/// <summary> No info availalbe because no lock is in reach.</summary>
/// <summary> No info centered because no lock is in reach.</summary>
/// <param name="connectTimeout">Timeout for connect operation of a single lock.</param>
/// <returns>Empty collection.</returns>
public async Task<IEnumerable<LockInfoTdo>> GetLocksStateAsync(IEnumerable<LockInfoAuthTdo> locksInfo, TimeSpan connectTimeout) => await Task.FromResult(LocksInfo);

View file

@ -9,6 +9,7 @@ using TINK.Model.Device;
using TINK.Repository;
using TINK.Repository.Request;
using TINK.Repository.Response;
using TINK.Repository.Response.Stations;
namespace TINK.Model.Services.CopriApi
{
@ -18,7 +19,7 @@ namespace TINK.Model.Services.CopriApi
/// <summary> Object which manages stored copri answers. </summary>
private ICopriCache CacheServer { get; }
/// <summary> Communicates whith copri server. </summary>
/// <summary> Communicates with copri server. </summary>
private ICopriServer HttpsServer { get; }
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
@ -30,9 +31,9 @@ namespace TINK.Model.Services.CopriApi
/// <summary> Gets the merchant id.</summary>
public string MerchantId => HttpsServer.MerchantId;
/// <summary> Constructs copri provider object to connet to https using a cache objet. </summary>
/// <summary> Constructs copri provider object to connect to https using a cache object. </summary>
/// <param name="copriHost"></param>
/// <param name="appContextInfo">Provides app related info (app name and version, merchantid) to pass to COPRI.</param>
/// <param name="appContextInfo">Provides app related info (app name and version, merchant id) to pass to COPRI.</param>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
/// <param name="smartDevice">Holds info about smart device.</param>
/// <param name="sessionCookie">Cookie of user if a user is logged in, false otherwise.</param>
@ -68,7 +69,7 @@ namespace TINK.Model.Services.CopriApi
try
{
Log.ForContext<CopriProviderHttps>().Debug($"Querrying bikes available from copri.");
Log.ForContext<CopriProviderHttps>().Debug($"Querying bikes available from copri.");
var bikesAvailableResponse = await HttpsServer.GetBikesAvailableAsync();
return new Result<BikesAvailableResponse>(
typeof(CopriCallsHttps),
@ -78,13 +79,13 @@ namespace TINK.Model.Services.CopriApi
catch (Exception exception)
{
// Return response from cache.
Log.ForContext<CopriProviderHttps>().Debug("An error occurred querrying bikes available. {Exception}.", exception);
Log.ForContext<CopriProviderHttps>().Debug("An error occurred querying bikes available. {Exception}.", exception);
var bikesAvailableResponse = await CacheServer.GetBikesAvailableAsync();
return new Result<BikesAvailableResponse>(typeof(CopriCallsMonkeyStore), bikesAvailableResponse, bikesAvailableResponse.GetGeneralData(), exception);
}
}
/// <summary> Gets a list of bikes reserved/ booked by acctive user. </summary>
/// <summary> Gets a list of bikes reserved/ booked by active user. </summary>
/// <param name="sessionCookie">Cookie to authenticate user.</param>
/// <returns>Response holding list of bikes.</returns>
public async Task<Result<BikesReservedOccupiedResponse>> GetBikesOccupied(bool fromCache = false)
@ -101,7 +102,7 @@ namespace TINK.Model.Services.CopriApi
try
{
Log.ForContext<CopriProviderHttps>().Debug($"Querrying bikes occupied from copri.");
Log.ForContext<CopriProviderHttps>().Debug($"Querying bikes occupied from copri.");
var bikesOccupiedResponse = await HttpsServer.GetBikesOccupiedAsync();
return new Result<BikesReservedOccupiedResponse>(
typeof(CopriCallsHttps),
@ -112,7 +113,7 @@ namespace TINK.Model.Services.CopriApi
catch (Exception exception)
{
// Return response from cache.
Log.ForContext<CopriProviderHttps>().Debug("An error occurred querrying bikes occupied. {Exception}.", exception);
Log.ForContext<CopriProviderHttps>().Debug("An error occurred querying bikes occupied. {Exception}.", exception);
var bikesOccupiedResponse = await CacheServer.GetBikesOccupiedAsync();
return new Result<BikesReservedOccupiedResponse>(typeof(CopriCallsMonkeyStore), bikesOccupiedResponse, bikesOccupiedResponse.GetGeneralData(), exception);
}
@ -134,7 +135,7 @@ namespace TINK.Model.Services.CopriApi
try
{
Log.ForContext<CopriProviderHttps>().Debug($"Querrying stations from copri.");
Log.ForContext<CopriProviderHttps>().Debug($"Querying stations from copri.");
var stations = await HttpsServer.GetStationsAsync();
@ -146,7 +147,7 @@ namespace TINK.Model.Services.CopriApi
catch (Exception exception)
{
// Return response from cache.
Log.ForContext<CopriProviderHttps>().Debug("An error occurred querrying stations. {Exception}.", exception);
Log.ForContext<CopriProviderHttps>().Debug("An error occurred querying stations. {Exception}.", exception);
var stationsResponse = await CacheServer.GetStationsAsync();
return new Result<StationsAvailableResponse>(typeof(CopriCallsMonkeyStore), stationsResponse, stationsResponse.GetGeneralData(), exception);
}

View file

@ -7,6 +7,7 @@ using TINK.Model.Device;
using TINK.Repository;
using TINK.Repository.Request;
using TINK.Repository.Response;
using TINK.Repository.Response.Stations;
using TINK.Services.CopriApi.Exception;
namespace TINK.Model.Services.CopriApi

View file

@ -1,7 +1,8 @@

using System.Threading.Tasks;
using TINK.Repository;
using TINK.Repository.Response;
using TINK.Repository.Response.Stations;
namespace TINK.Model.Services.CopriApi
{
@ -16,7 +17,7 @@ namespace TINK.Model.Services.CopriApi
/// <returns>Response holding list of bikes.</returns>
Task<Result<BikesAvailableResponse>> GetBikesAvailable(bool fromCache = false);
/// <summary> Gets a list of bikes reserved/ booked by acctive user from Copri.</summary>
/// <summary> Gets a list of bikes reserved/ booked by active user from Copri.</summary>
/// <returns>Response holding list of bikes.</returns>
Task<Result<BikesReservedOccupiedResponse>> GetBikesOccupied(bool fromCache = false);

View file

@ -1,5 +1,6 @@
using TINK.Repository;
using TINK.Repository.Response;
using TINK.Repository.Response.Stations;
namespace TINK.Model.Services.CopriApi
{

View file

@ -112,7 +112,7 @@ namespace TINK.Services.CopriApi
if (lockingState == null)
{
// User did not take bike out of the station
throw new BikeStillInStationException("Booking was cancelled because bike is still in station.");
throw new BikeStillInStationException("Booking was canceled because bike is still in station.");
}
// Upate booking state.

View file

@ -1,4 +1,4 @@
using System;
using System;
using TINK.Services.CopriApi;
namespace TINK.Model.Services.CopriApi
@ -10,7 +10,7 @@ namespace TINK.Model.Services.CopriApi
/// </summary>
/// <param name="source">Type of source (data provider).</param>
/// <param name="response">Requested data (bikes, station).</param>
/// <param name="generalData">General data (common to all respones).</param>
/// <param name="generalData">General data (common to all responses).</param>
public Result(
Type source,
T response,

View file

@ -1,5 +1,5 @@
using TINK.Model.Bikes;
using TINK.Model.Station;
using TINK.Model.Bikes;
using TINK.Model.Stations;
namespace TINK.Model.Services.CopriApi
{

View file

@ -30,7 +30,7 @@ namespace TINK.Services.Geolocation
/// <summary> Gets the current location.</summary>
/// <param name="cancellationToken">Token to cancel request for geolocation.</param>
/// <param name="timeStamp">Time when geolocation is of interest. Is used to determine whether cached geoloation can be used or not.</param>
/// <param name="timeStamp">Time when geolocation is of interest. Is used to determine whether cached geolocation can be used or not.</param>
public async Task<IGeolocation> GetAsync(CancellationToken? cancellationToken = null, DateTime? timeStamp = null)
{
try

Some files were not shown because too many files have changed in this diff Show more