Version 3.0.362

This commit is contained in:
Anja 2023-04-05 15:02:10 +02:00
parent cba4da9357
commit 4ff3307997
128 changed files with 3954 additions and 3193 deletions

View file

@ -77,7 +77,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.0" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.1" />
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
<PackageReference Include="MonkeyCache">
<Version>1.6.3</Version>
@ -86,7 +86,7 @@
<Version>1.6.3</Version>
</PackageReference>
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="PCLCrypto" Version="2.0.147" />
<PackageReference Include="PCLStorage" Version="1.0.2" />
<PackageReference Include="PInvoke.BCrypt" Version="0.7.124" />
@ -185,7 +185,7 @@
<Version>1.0.0.16</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.RecyclerView">
<Version>1.2.1.9</Version>
<Version>1.3.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.Auth" Version="1.7.0" />
<PackageReference Include="Xamarin.Build.Download" Version="0.11.4" />
@ -195,9 +195,9 @@
<PackageReference Include="Xamarin.Essentials">
<Version>1.7.5</Version>
</PackageReference>
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2545" />
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2578" />
<PackageReference Include="Xamarin.Forms.AppLinks">
<Version>5.0.0.2545</Version>
<Version>5.0.0.2578</Version>
</PackageReference>
<PackageReference Include="Xamarin.Forms.GoogleMaps">
<Version>5.0.0</Version>

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.361" android:versionCode="361">
<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">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="31" />
<!-- Google Maps related permissions -->
<!-- Permission to receive remote notifications from Google Play Services -->

File diff suppressed because it is too large Load diff

View file

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

View file

@ -120,7 +120,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Bcl.Build" Version="1.0.21" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.0" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.1" />
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
<PackageReference Include="MonkeyCache">
<Version>1.6.3</Version>
@ -129,7 +129,7 @@
<Version>1.6.3</Version>
</PackageReference>
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="PCLCrypto" Version="2.0.147" />
<PackageReference Include="PCLStorage" Version="1.0.2" />
<PackageReference Include="Plugin.BluetoothLE">
@ -220,7 +220,7 @@
<Version>0.7.124</Version>
</PackageReference>
<PackageReference Include="Xamarin.Forms">
<Version>5.0.0.2545</Version>
<Version>5.0.0.2578</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>

View file

@ -338,9 +338,9 @@ namespace TINK
/// <summary>
/// Service container to manage geolocation services.
/// </summary>
public static IServicesContainer<IGeolocation> LocationServicesContainer { get; }
= new ServicesContainerMutableT<IGeolocation>(
new HashSet<IGeolocation> {
public static IServicesContainer<IGeolocationService> LocationServicesContainer { get; }
= new ServicesContainerMutableT<IGeolocationService>(
new HashSet<IGeolocationService> {
new LastKnownGeolocationService(DependencyService.Get<IGeolodationDependent>()),
new SimulatedGeolocationService(DependencyService.Get<IGeolodationDependent>()),
new GeolocationAccuracyMediumService(DependencyService.Get<IGeolodationDependent>()),

View file

@ -22,7 +22,7 @@
<Folder Include="Services\BluetoothLock\Crypto\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Serilog" Version="2.12.0" />
</ItemGroup>
<ItemGroup>

View file

@ -77,7 +77,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.0" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.1" />
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
<PackageReference Include="MonkeyCache">
<Version>1.6.3</Version>
@ -86,7 +86,7 @@
<Version>1.6.3</Version>
</PackageReference>
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="PCLCrypto" Version="2.0.147" />
<PackageReference Include="PCLStorage" Version="1.0.2" />
<PackageReference Include="PInvoke.BCrypt" Version="0.7.124" />
@ -185,7 +185,7 @@
<Version>1.0.0.16</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.RecyclerView">
<Version>1.2.1.9</Version>
<Version>1.3.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.Auth" Version="1.7.0" />
<PackageReference Include="Xamarin.Build.Download" Version="0.11.4" />
@ -195,9 +195,9 @@
<PackageReference Include="Xamarin.Essentials">
<Version>1.7.5</Version>
</PackageReference>
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2545" />
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2578" />
<PackageReference Include="Xamarin.Forms.AppLinks">
<Version>5.0.0.2545</Version>
<Version>5.0.0.2578</Version>
</PackageReference>
<PackageReference Include="Xamarin.Forms.GoogleMaps">
<Version>5.0.0</Version>

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.361" android:versionCode="361">
<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">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="31" />
<!-- Google Maps related permissions -->
<!-- Permission to receive remote notifications from Google Play Services -->

File diff suppressed because it is too large Load diff

View file

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

View file

@ -1,7 +1,7 @@
{
"images" : [
{
"filename" : "StationMarkerOpenBlue.svg",
"filename" : "StationMarkerOpenBlue.pdf",
"idiom" : "universal"
},
{

View file

@ -0,0 +1,69 @@
%PDF-1.5
%µí®û
4 0 obj
<< /Length 5 0 R
/Filter /FlateDecode
>>
stream
xœm<EFBFBD>An1E÷>(c8FŽP<C5BD>”dÑ,ÒÞ_*¶‡E”j¤™ÿÌüïÅóÁñÅÇ£< a÷Ajð.~nðùEpû-ÜPIÂ÷€S[A©b8œáYJw`ÁÆ2Ü™z‰ÿNÃêð ÜQ&Å8>},nT¡zLû ¢I»ÎŒ:v•ZQ]w£]÷€ûìî<C3AC>¡2ªy,ÀŒ$=YÑ°á Ô¹Í&BÕe©%Næ6;néc:mȦ¸žšœ„LK^7•ô<E280A2>%^+þWúZ.åaqV²
endstream
endobj
5 0 obj
206
endobj
3 0 obj
<<
/ExtGState <<
/a0 << /CA 1 /ca 1 >>
>>
>>
endobj
2 0 obj
<< /Type /Page % 1
/Parent 1 0 R
/MediaBox [ 0 0 29.393326 37.5 ]
/Contents 4 0 R
/Group <<
/Type /Group
/S /Transparency
/I true
/CS /DeviceRGB
>>
/Resources 3 0 R
>>
endobj
1 0 obj
<< /Type /Pages
/Kids [ 2 0 R ]
/Count 1
>>
endobj
6 0 obj
<< /Producer (cairo 1.17.4 (https://cairographics.org))
/Creator <FEFF0049006E006B0073006300610070006500200031002E0031002E00320020002800680074007400700073003A002F002F0069006E006B00730063006100700065002E006F007200670029>
/CreationDate (D:20230323095234+01'00)
>>
endobj
7 0 obj
<< /Type /Catalog
/Pages 1 0 R
>>
endobj
xref
0 8
0000000000 65535 f
0000000617 00000 n
0000000392 00000 n
0000000320 00000 n
0000000015 00000 n
0000000298 00000 n
0000000682 00000 n
0000000965 00000 n
trailer
<< /Size 8
/Root 7 0 R
/Info 6 0 R
>>
startxref
1017
%%EOF

View file

@ -1,7 +1,7 @@
{
"images" : [
{
"filename" : "StationMarkerOpenGreen.svg",
"filename" : "StationMarkerOpenGreen.pdf",
"idiom" : "universal"
},
{

View file

@ -1,7 +1,7 @@
{
"images" : [
{
"filename" : "StationMarkerOpenLightBlue.svg",
"filename" : "StationMarkerOpenLightBlue.pdf",
"idiom" : "universal"
},
{

View file

@ -0,0 +1,69 @@
%PDF-1.5
%µí®û
4 0 obj
<< /Length 5 0 R
/Filter /FlateDecode
>>
stream
xœm<EFBFBD>An1E÷>(c8FŽP<C5BD>”dÑ,ÒÞ_*¶‡E”j¤™ÿÌüïÅóÁñÅÇ£< a÷Ajð.~nðùEpû-ÜPIÂ÷€S[A©b8œáYJw`ÁÆ2Ü™z‰ÿNÃêð ÜQ&Å8>},nT¡zLû ¢I»ÎŒ:v•ZQ]w£]÷€ûìî<C3AC>¡2ªy,ÀŒ$=YÑ°á Ô¹Í&BÕe©%Næ6;néc:mȦ¸žšœ„LK^7•ô<E280A2>%^+þWúZ.åaqV²
endstream
endobj
5 0 obj
206
endobj
3 0 obj
<<
/ExtGState <<
/a0 << /CA 1 /ca 1 >>
>>
>>
endobj
2 0 obj
<< /Type /Page % 1
/Parent 1 0 R
/MediaBox [ 0 0 29.393326 37.5 ]
/Contents 4 0 R
/Group <<
/Type /Group
/S /Transparency
/I true
/CS /DeviceRGB
>>
/Resources 3 0 R
>>
endobj
1 0 obj
<< /Type /Pages
/Kids [ 2 0 R ]
/Count 1
>>
endobj
6 0 obj
<< /Producer (cairo 1.17.4 (https://cairographics.org))
/Creator <FEFF0049006E006B0073006300610070006500200031002E0031002E00320020002800680074007400700073003A002F002F0069006E006B00730063006100700065002E006F007200670029>
/CreationDate (D:20230323095234+01'00)
>>
endobj
7 0 obj
<< /Type /Catalog
/Pages 1 0 R
>>
endobj
xref
0 8
0000000000 65535 f
0000000617 00000 n
0000000392 00000 n
0000000320 00000 n
0000000015 00000 n
0000000298 00000 n
0000000682 00000 n
0000000965 00000 n
trailer
<< /Size 8
/Root 7 0 R
/Info 6 0 R
>>
startxref
1017
%%EOF

View file

@ -1,7 +1,7 @@
{
"images" : [
{
"filename" : "StationMarkerOpenRed.svg",
"filename" : "StationMarkerOpenRed.pdf",
"idiom" : "universal"
},
{

View file

@ -0,0 +1,69 @@
%PDF-1.5
%µí®û
4 0 obj
<< /Length 5 0 R
/Filter /FlateDecode
>>
stream
xœm<EFBFBD>An1E÷>(c8FŽP<C5BD>”dÑ,ÒÞ_*¶‡E”j¤™ÿÌüïÅóÁñÅÇ£< a÷Ajð.~nðùEpû-ÜPIÂ÷€S[A©b8œáYJw`ÁÆ2Ü™z‰ÿNÃêð ÜQ&Å8>},nT¡zLû ¢I»ÎŒ:v•ZQ]w£]÷€ûìî<C3AC>¡2ªy,ÀŒ$=YÑ°á Ô¹Í&BÕe©%Næ6;néc:mȦ¸žšœ„LK^7•ô<E280A2>%^+þWúZ.åaqV²
endstream
endobj
5 0 obj
206
endobj
3 0 obj
<<
/ExtGState <<
/a0 << /CA 1 /ca 1 >>
>>
>>
endobj
2 0 obj
<< /Type /Page % 1
/Parent 1 0 R
/MediaBox [ 0 0 29.393326 37.5 ]
/Contents 4 0 R
/Group <<
/Type /Group
/S /Transparency
/I true
/CS /DeviceRGB
>>
/Resources 3 0 R
>>
endobj
1 0 obj
<< /Type /Pages
/Kids [ 2 0 R ]
/Count 1
>>
endobj
6 0 obj
<< /Producer (cairo 1.17.4 (https://cairographics.org))
/Creator <FEFF0049006E006B0073006300610070006500200031002E0031002E00320020002800680074007400700073003A002F002F0069006E006B00730063006100700065002E006F007200670029>
/CreationDate (D:20230323095234+01'00)
>>
endobj
7 0 obj
<< /Type /Catalog
/Pages 1 0 R
>>
endobj
xref
0 8
0000000000 65535 f
0000000617 00000 n
0000000392 00000 n
0000000320 00000 n
0000000015 00000 n
0000000298 00000 n
0000000682 00000 n
0000000965 00000 n
trailer
<< /Size 8
/Root 7 0 R
/Info 6 0 R
>>
startxref
1017
%%EOF

View file

@ -121,7 +121,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Bcl.Build" Version="1.0.21" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.0" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.1" />
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
<PackageReference Include="MonkeyCache">
<Version>1.6.3</Version>
@ -130,7 +130,7 @@
<Version>1.6.3</Version>
</PackageReference>
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="PCLCrypto" Version="2.0.147" />
<PackageReference Include="PCLStorage" Version="1.0.2" />
<PackageReference Include="Plugin.BluetoothLE">
@ -221,7 +221,7 @@
<Version>0.7.124</Version>
</PackageReference>
<PackageReference Include="Xamarin.Forms">
<Version>5.0.0.2545</Version>
<Version>5.0.0.2578</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
@ -294,25 +294,25 @@
<ImageAsset Include="Media.xcassets\LaunchImages.launchimage\Contents.json">
<Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Media.xcassets\Open_Blue.imageset\StationMarkerOpenBlue.svg">
<ImageAsset Include="Media.xcassets\Open_Blue.imageset\StationMarkerOpenBlue.pdf">
<Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Media.xcassets\Open_Blue.imageset\Contents.json">
<Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Media.xcassets\Open_Green.imageset\StationMarkerOpenGreen.svg">
<ImageAsset Include="Media.xcassets\Open_Green.imageset\StationMarkerOpenGreen.pdf">
<Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Media.xcassets\Open_Green.imageset\Contents.json">
<Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Media.xcassets\Open_LightBlue.imageset\StationMarkerOpenLightBlue.svg">
<ImageAsset Include="Media.xcassets\Open_LightBlue.imageset\StationMarkerOpenLightBlue.pdf">
<Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Media.xcassets\Open_LightBlue.imageset\Contents.json">
<Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Media.xcassets\Open_Red.imageset\StationMarkerOpenRed.svg">
<ImageAsset Include="Media.xcassets\Open_Red.imageset\StationMarkerOpenRed.pdf">
<Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Media.xcassets\Open_Red.imageset\Contents.json">

View file

@ -336,9 +336,9 @@ namespace TINK
/// <summary>
/// Service container to manage geolocation services.
/// </summary>
public static IServicesContainer<IGeolocation> LocationServicesContainer { get; }
= new ServicesContainerMutableT<IGeolocation>(
new HashSet<IGeolocation> {
public static IServicesContainer<IGeolocationService> LocationServicesContainer { get; }
= new ServicesContainerMutableT<IGeolocationService>(
new HashSet<IGeolocationService> {
new LastKnownGeolocationService(DependencyService.Get<IGeolodationDependent>()),
new SimulatedGeolocationService(DependencyService.Get<IGeolodationDependent>()),
new GeolocationAccuracyMediumService(DependencyService.Get<IGeolodationDependent>()),

View file

@ -43,7 +43,6 @@
WidthRequest="320"
HeightRequest="800"
x:Name="MyMap"
MyLocationEnabled="True"
MapType="Street">
<maps:Map.Behaviors>
<bindings:BindingPinsBehavior Value="{Binding Pins}"/>

View file

@ -31,9 +31,6 @@ namespace TINK.View.Map
public MapPage()
{
InitializeComponent();
MyMap.UiSettings.MyLocationButtonEnabled = true;
}
/// <summary>
@ -211,6 +208,24 @@ namespace TINK.View.Map
isInitializationStarted = false;
return;
}
try
{
Log.ForContext<MapPage>().Verbose("Setting map settings.");
//show current user position (blue dot) and enable button for centering map manually.
MyMap.UiSettings.MyLocationButtonEnabled = MapPageViewModel.IsLocationPermissionGranted;
MyMap.IsShowingUser = MapPageViewModel.IsLocationPermissionGranted;
//disable +/- buttons
MyMap.UiSettings.ZoomControlsEnabled = false;
}
catch (Exception exception)
{
Log.ForContext<MapPage>().Verbose("Setting map settings failed. {Exception}", exception);
isInitializationStarted = false;
return;
}
}
/// <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.hauffware.sharee" android:versionName="3.0.361" android:versionCode="361">
<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">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="31" />
<!-- Google Maps related permissions -->
<!-- Permission to receive remote notifications from Google Play Services -->

File diff suppressed because it is too large Load diff

View file

@ -77,7 +77,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.0" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.1" />
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
<PackageReference Include="MonkeyCache">
<Version>1.6.3</Version>
@ -86,7 +86,7 @@
<Version>1.6.3</Version>
</PackageReference>
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="PCLCrypto" Version="2.0.147" />
<PackageReference Include="PCLStorage" Version="1.0.2" />
<PackageReference Include="PInvoke.BCrypt" Version="0.7.124" />
@ -185,7 +185,7 @@
<Version>1.0.0.16</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.RecyclerView">
<Version>1.2.1.9</Version>
<Version>1.3.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.Auth" Version="1.7.0" />
<PackageReference Include="Xamarin.Build.Download" Version="0.11.4" />
@ -195,9 +195,9 @@
<PackageReference Include="Xamarin.Essentials">
<Version>1.7.5</Version>
</PackageReference>
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2545" />
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2578" />
<PackageReference Include="Xamarin.Forms.AppLinks">
<Version>5.0.0.2545</Version>
<Version>5.0.0.2578</Version>
</PackageReference>
<PackageReference Include="Xamarin.Forms.GoogleMaps">
<Version>5.0.0</Version>

View file

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

View file

@ -121,7 +121,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Bcl.Build" Version="1.0.21" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.0" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.1" />
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
<PackageReference Include="MonkeyCache">
<Version>1.6.3</Version>
@ -130,7 +130,7 @@
<Version>1.6.3</Version>
</PackageReference>
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="PCLCrypto" Version="2.0.147" />
<PackageReference Include="PCLStorage" Version="1.0.2" />
<PackageReference Include="Plugin.BluetoothLE">
@ -221,7 +221,7 @@
<Version>0.7.124</Version>
</PackageReference>
<PackageReference Include="Xamarin.Forms">
<Version>5.0.0.2545</Version>
<Version>5.0.0.2578</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>

View file

@ -345,9 +345,9 @@ namespace TINK
/// <summary>
/// Service container to manage geolocation services.
/// </summary>
public static IServicesContainer<IGeolocation> LocationServicesContainer { get; }
= new ServicesContainerMutableT<IGeolocation>(
new HashSet<IGeolocation> {
public static IServicesContainer<IGeolocationService> LocationServicesContainer { get; }
= new ServicesContainerMutableT<IGeolocationService>(
new HashSet<IGeolocationService> {
new LastKnownGeolocationService(DependencyService.Get<IGeolodationDependent>()),
new SimulatedGeolocationService(DependencyService.Get<IGeolodationDependent>()),
new GeolocationAccuracyMediumService(DependencyService.Get<IGeolodationDependent>()),

View file

@ -41,7 +41,6 @@
WidthRequest="320"
HeightRequest="800"
x:Name="MyMap"
MyLocationEnabled="True"
MapType="Street">
<maps:Map.Behaviors>
<bindings:BindingPinsBehavior Value="{Binding Pins}"/>

View file

@ -31,9 +31,6 @@ namespace TINK.View.Map
public MapPage()
{
InitializeComponent();
MyMap.UiSettings.MyLocationButtonEnabled = true;
}
/// <summary>
@ -211,6 +208,25 @@ namespace TINK.View.Map
isInitializationStarted = false;
return;
}
try
{
Log.ForContext<MapPage>().Verbose("Setting map settings.");
//show current user position (blue dot) and enable button for centering map manually.
MyMap.UiSettings.MyLocationButtonEnabled = MapPageViewModel.IsLocationPermissionGranted;
MyMap.IsShowingUser = MapPageViewModel.IsLocationPermissionGranted;
//disable +/- buttons
MyMap.UiSettings.ZoomControlsEnabled = false;
}
catch (Exception exception)
{
Log.ForContext<MapPage>().Verbose("Setting map settings failed. {Exception}", exception);
isInitializationStarted = false;
return;
}
}
/// <summary>

View file

@ -1,6 +1,6 @@
namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
{
public interface IBikeInfoMutable : BikeInfoNS.BC.IBikeInfoMutable
public interface IBikeInfoMutable : BC.IBikeInfoMutable
{
ILockInfoMutable LockInfo { get; }
}

View file

@ -1,4 +1,5 @@
using System;
using TINK.Services.Geolocation;
namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
{
@ -20,6 +21,14 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
byte[] Seed { get; }
/// <summary> Timestamp of the last locking state change.</summary>
DateTime? LastLockingStateChange { get; }
/// <summary>
/// Gets or sets the current location of the bike, null if location is unknown.
/// </summary>
IGeolocation Location { get; set; }
/// <summary>
/// Gets the version info of the locks.
/// </summary>

View file

@ -1,4 +1,5 @@
using System;
using TINK.Services.Geolocation;
namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
{
@ -7,16 +8,24 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
/// <summary> Lock info object. </summary>
private LockInfo LockInfo { get; set; }
/// <summary>
/// Delegate to create time stamp.
/// </summary>
private Func<DateTime> _nowDelegate;
/// <summary> Constructs a bluetooth lock info object. </summary>
/// <param name="id">Id of lock must always been known when constructing an lock info object.</param>
/// <param name="nowDelegate">Delegate to create time stamp if null DateTime.Now is used.</param>
public LockInfoMutable(
int id,
Guid guid,
byte[] userKey,
byte[] adminKey,
byte[] seed,
LockingState state)
LockingState state,
Func<DateTime> nowDelegate = null)
{
_nowDelegate = nowDelegate ?? (() => DateTime.Now);
LockInfo = new LockInfo.Builder() { Id = id, Guid = guid, UserKey = userKey, AdminKey = adminKey, Seed = seed, State = state }.Build();
}
@ -35,12 +44,34 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
public byte[] AdminKey => LockInfo.AdminKey;
/// <summary>
/// Gets or sets the locking state.
/// </summary>
public LockingState State
{
get => LockInfo.State;
set => LockInfo = new LockInfo.Builder(LockInfo) { State = value }.Build();
set
{
if (LockInfo.State == value)
{
// State does not change, nothing to do.
return;
}
Location = null; // Invalidate location.
LastLockingStateChange = _nowDelegate(); // Get time stamp when state change happened.
LockInfo = new LockInfo.Builder(LockInfo) { State = value }.Build();
}
}
/// <summary> Gets the timestamp of the last locking state change.</summary>
public DateTime? LastLockingStateChange { get; private set; }
/// <summary>
/// Gets or sets the current location of the bike, null if location is unknown.
/// </summary>
public IGeolocation Location { get; set; }
/// <summary> Holds the percentage of lock battery.</summary>
public double BatteryPercentage { get; set; } = double.NaN;

View file

@ -1,7 +1,10 @@
using System;
using System;
namespace TINK.Model
{
/// <summary>
/// Holds a exact position.
/// </summary>
public interface IPosition : IEquatable<IPosition>
{
double Latitude { get; }

View file

@ -409,7 +409,7 @@ namespace TINK.Model.Settings
return targetDictionary.Union(new Dictionary<string, string>
{
{ typeof(IGeolocation).Name, activeGeolocationService },
{ typeof(IGeolocationService).Name, activeGeolocationService },
}).ToDictionary(key => key.Key, value => value.Value);
}
@ -419,7 +419,7 @@ namespace TINK.Model.Settings
public static string GetActiveGeolocationService(this IDictionary<string, string> settingsJSON)
{
// Get uri of corpi server.
if (!settingsJSON.TryGetValue(typeof(IGeolocation).Name, out string activeGeolocationService)
if (!settingsJSON.TryGetValue(typeof(IGeolocationService).Name, out string activeGeolocationService)
|| string.IsNullOrEmpty(activeGeolocationService))
{
// File holds no entry.

View file

@ -176,7 +176,7 @@ namespace TINK.Model
string merchantId,
IBluetoothLE bluetoothService,
ILocationPermission locationPermissionsService,
IServicesContainer<IGeolocation> locationServicesContainer,
IServicesContainer<IGeolocationService> locationServicesContainer,
ILocksService locksService,
ISmartDevice device,
ISpecialFolder specialFolder,
@ -406,7 +406,7 @@ namespace TINK.Model
public LocksServicesContainerMutable LocksServices { get; set; }
/// <summary> Holds available app themes.</summary>
public IServicesContainer<IGeolocation> GeolocationServices { get; }
public IServicesContainer<IGeolocationService> GeolocationServices { get; }
/// <summary> Holds the flavor of the app, i.e. specifies if app is sharee.bike, Mein konrad or Lastenrad Bayern.</summary>
public AppFlavor Flavor { get; private set; }

View file

@ -672,16 +672,21 @@ namespace TINK.Model
new Version(3, 0, 356),
AppResources.ChangeLog3_0_231
},
{
{
new Version(3, 0, 360),
AppResources.ChangeLog_3_0_358_MK_SB,
new List<AppFlavor> { AppFlavor.MeinKonrad, AppFlavor.ShareeBike }
},
{
{
new Version(3, 0, 361),
AppResources.ChangeLog_3_0_361_MK_SB,
new List<AppFlavor> { AppFlavor.MeinKonrad, AppFlavor.ShareeBike }
},
{
new Version(3, 0, 362),
AppResources.ChangeLog_3_0_362_MK_SB,
new List<AppFlavor> { AppFlavor.MeinKonrad, AppFlavor.ShareeBike }
},
};
/// <summary> Manges the whats new information.</summary>

View file

@ -88,7 +88,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Close lock &amp; return bike.
/// Looks up a localized string similar to Close lock &amp; end rental.
/// </summary>
public static string ActionCloseAndReturn {
get {
@ -97,7 +97,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Feedback about the App.
/// Looks up a localized string similar to Feedback about the app.
/// </summary>
public static string ActionContactMailAppReleated {
get {
@ -115,7 +115,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Give Feedback.
/// Looks up a localized string similar to Give feedback.
/// </summary>
public static string ActionGiveFeedback {
get {
@ -142,7 +142,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Register.
/// Looks up a localized string similar to Register for free.
/// </summary>
public static string ActionLoginRegister {
get {
@ -187,7 +187,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Return bike.
/// Looks up a localized string similar to End rental.
/// </summary>
public static string ActionReturn {
get {
@ -331,7 +331,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to No web error on updating locking status..
/// Looks up a localized string similar to Internet must be available for updating lock status. Please establish an Internet connection!.
/// </summary>
public static string ActivityTextErrorNoWebUpdateingLockstate {
get {
@ -466,7 +466,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Loading reserved/ booked bikes....
/// Looks up a localized string similar to Loading reserved/rented bikes....
/// </summary>
public static string ActivityTextMyBikesLoadingBikes {
get {
@ -565,7 +565,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Returning bike....
/// Looks up a localized string similar to Ending rental....
/// </summary>
public static string ActivityTextReturningBike {
get {
@ -610,7 +610,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Starting bike return....
/// Looks up a localized string similar to Starting end rental....
/// </summary>
public static string ActivityTextStartReturningBike {
get {
@ -766,6 +766,21 @@ namespace TINK.MultilingualResources {
}
}
/// <summary>
/// Looks up a localized string similar to Some terms have been standardized, e.g:&lt;br/&gt;
///- what used to be called &apos;return bike&apos; is now always called &apos;end rental&apos;.&lt;br/&gt;
///- The &apos;operator&apos; is the group of people responsible for the bike fleet, who will be contacted if necessary.&lt;br/&gt;
///&lt;br/&gt;
///Also:&lt;br/&gt;
///- Minor bug fixes&lt;br/&gt;
///- Package updates.
/// </summary>
public static string ChangeLog_3_0_362_MK_SB {
get {
return ResourceManager.GetString("ChangeLog_3_0_362_MK_SB", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to We have fixed some bugs. Enjoy the ride!.
/// </summary>
@ -960,7 +975,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Feedback dialog added which is shown after returning bike..
/// Looks up a localized string similar to Feedback dialog added which is shown after ending rental..
/// </summary>
public static string ChangeLog3_0_227 {
get {
@ -1017,7 +1032,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Hard- and software information send to backend when returning bike..
/// Looks up a localized string similar to Hard- and software information send to backend when ending rental..
/// </summary>
public static string ChangeLog3_0_237 {
get {
@ -1387,6 +1402,17 @@ namespace TINK.MultilingualResources {
}
}
/// <summary>
/// Looks up a localized string similar to We could not assign the bike to any station. For this we need your location information while you are standing right next to the bike. Only then your rental can be terminated!
///
///Approach the bike, turn on Bluetooth and Location services and try again..
/// </summary>
public static string Error_ReturnBike_Station_Location_Message {
get {
return ResourceManager.GetString("Error_ReturnBike_Station_Location_Message", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Failed to query available bikes..
/// </summary>
@ -1415,12 +1441,13 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Unfortunately, it is still not possible to establish a connection between your mobile device and the bike lock. Please contact customer support.
/// Looks up a localized string similar to It is still not possible to establish a connection between your mobile device and the bike lock. Please contact operator!
///
///As a last resort, please close the lock by hand AND contact customer support so that they can terminate your chargeable rental. To do this:
///1. close the app,
///2. press the button at the top of the lock briefly and quickly release it as soon as it starts flashing,
///3. wait until the lock is completely closed and remains closed..
///Alternative:
///1. close app,
///2. press the button at the top of the lock briefly and release it as soon as it starts flashing,
///3. make sure that the lock is completely closed and remains closed.
///4. send e-mail to operator (otherwise your chargeable rental will continue!): Problem description, Drop-off station..
/// </summary>
public static string ErrorBookedSearchMessageEscalationLevel2 {
get {
@ -1457,7 +1484,7 @@ namespace TINK.MultilingualResources {
/// <summary>
/// Looks up a localized string similar to Lock cannot be closed until bike is near.
///Please try again to close bike or report bike to support!.
///Please try again to close bike or report bike to operator!.
/// </summary>
public static string ErrorCloseLockOutOfReachStateReservedMessage {
get {
@ -1493,7 +1520,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Please try to lock again or report bike to support!
/// Looks up a localized string similar to Please try to lock again or report bike to operator!
///{0}.
/// </summary>
public static string ErrorCloseLockUnkErrorMessage {
@ -1512,7 +1539,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Internet must be reachable to connect to lock of rented bike..
/// Looks up a localized string similar to Internet must be reachable to connect to lock of rented bike. Please establish an Internet connection!.
/// </summary>
public static string ErrorConnectLockRentedBikeNoWebMessage {
get {
@ -1521,7 +1548,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Internet must be reachable to connect to lock of reserved bike..
/// Looks up a localized string similar to Internet must be reachable to connect to lock of reserved bike. Please establish an Internet connection!.
/// </summary>
public static string ErrorConnectLockReservedBikeNoWebMessage {
get {
@ -1539,7 +1566,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Please turn Location on, otherwise lock cannot be connected..
/// Looks up a localized string similar to Please turn location services on, otherwise lock cannot be connected..
/// </summary>
public static string ErrorFindLockLocationOff {
get {
@ -1611,11 +1638,11 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to The lock could not be opened correctly. Please try again.
/// Looks up a localized string similar to The lock could not be opened correctly. Try again!
///
///Attention! Your rental has already started.
///
///If the lock still won&apos;t open, make sure the lock is closed and return the bike. Please report it to the support!.
///If the lock still won&apos;t open, make sure the lock is closed and end rental.
///Important: Send an email to the operator (otherwise your paid rental will continue!) with: Problem description, bike number, drop-off station..
/// </summary>
public static string ErrorOpenLockBoldStatusIsUnknownMessage {
get {
@ -1678,10 +1705,20 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Returning bike at an unknown location is not possible.
///Bike can be returned if
/// Looks up a localized string similar to End rental at an unknown location is not possible.
///Getting geolocation failed..
/// </summary>
public static string ErrorReturnBikeLockClosedGetGPSExceptionMessage {
get {
return ResourceManager.GetString("ErrorReturnBikeLockClosedGetGPSExceptionMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to End rental at an unknown location is not possible.
///Rental can be ended if
///- location information is available when closing lock
///- bike is in reach and location information is available when pressing button &quot;Return bike&quot;.
///- bike is in reach and location information is available when pressing button &quot;End rental&quot;.
/// </summary>
public static string ErrorReturnBikeLockClosedNoGPSMessage {
get {
@ -1690,8 +1727,18 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Returning bike at an unknown location is not possible.
///Bike can only be returned if bike is in reach and location information is available..
/// Looks up a localized string similar to End rental at an unknown location is not possible.
///Start getting geolocation failed..
/// </summary>
public static string ErrorReturnBikeLockClosedStartGetGPSExceptionMessage {
get {
return ResourceManager.GetString("ErrorReturnBikeLockClosedStartGetGPSExceptionMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to End rental at an unknown location is not possible.
///Rental can only be ended if bike is in reach and location information is available..
/// </summary>
public static string ErrorReturnBikeLockOpenNoGPSMessage {
get {
@ -1700,7 +1747,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Returning bike outside of station is not possible. Distance to station {0} is {1} m..
/// Looks up a localized string similar to End rental outside of station is not possible. Distance to station {0} is {1} m..
/// </summary>
public static string ErrorReturnBikeNotAtStationMessage {
get {
@ -1709,7 +1756,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Internet must be available when returning the bike..
/// Looks up a localized string similar to Internet must be available when ending rental. Please establish an Internet connection!.
/// </summary>
public static string ErrorReturnBikeNoWebMessage {
get {
@ -1718,7 +1765,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Connection error when returning the bike!.
/// Looks up a localized string similar to Connection error when ending rental..
/// </summary>
public static string ErrorReturnBikeNoWebTitle {
get {
@ -1727,7 +1774,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Error returning bike!.
/// Looks up a localized string similar to Error at ending rental!.
/// </summary>
public static string ErrorReturnBikeTitle {
get {
@ -1763,7 +1810,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Opening mail app failed..
/// Looks up a localized string similar to Opening mail app failed. Make sure you have a mail app installed on your mobile device!.
/// </summary>
public static string ErrorSupportmailMailingFailed {
get {
@ -1772,7 +1819,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Opening phone app failed..
/// Looks up a localized string similar to Opening phone app failed. Make sure you have a phone app installed on your mobile device!.
/// </summary>
public static string ErrorSupportmailPhoningFailed {
get {
@ -1781,7 +1828,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to The rental of bike No. {0} has failed..
/// Looks up a localized string similar to The rental of bike {0} has failed..
/// </summary>
public static string ExceptionTextRentingBikeFailedGeneral {
get {
@ -1790,7 +1837,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to The rental of bike No. {0} has failed, the bike is currently unavailable.{1}.
/// Looks up a localized string similar to The rental of bike {0} has failed, the bike is currently unavailable. {1}.
/// </summary>
public static string ExceptionTextRentingBikeFailedUnavailalbe {
get {
@ -1799,7 +1846,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to The reservation of bike no. {0} has failed..
/// Looks up a localized string similar to The reservation of bike {0} has failed..
/// </summary>
public static string ExceptionTextReservationBikeFailedGeneral {
get {
@ -1808,7 +1855,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to The reservation of bike No. {0} has failed, the bike is currently unavailable.{1}.
/// Looks up a localized string similar to The reservation of bike {0} has failed, the bike is currently unavailable. {1}.
/// </summary>
public static string ExceptionTextReservationBikeFailedUnavailalbe {
get {
@ -1826,7 +1873,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Is WIFI available/ mobile network available and mobile data activated / ... ?.
/// Looks up a localized string similar to Is WIFI/mobile network available and mobile data activated?.
/// </summary>
public static string ExceptionTextWebConnectFailureException {
get {
@ -1900,7 +1947,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Contact Operator..
/// Looks up a localized string similar to Contact operator..
/// </summary>
public static string MarkingBikeSharingOperatorNoOperatorInfoAvailable {
get {
@ -2153,7 +2200,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to At least 8 characters.
/// Looks up a localized string similar to At least eight characters.
/// </summary>
public static string MarkingLoginPasswordLabel {
get {
@ -2198,7 +2245,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to There are currently no bicycles reserved/booked on user {0}..
/// Looks up a localized string similar to There are currently no bikes reserved/rented by user {0}..
/// </summary>
public static string MarkingMyBikesNoBikesReservedRented {
get {
@ -2207,7 +2254,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Oops, there is no internet connection..
/// Looks up a localized string similar to Oops, there is no Internet connection..
/// </summary>
public static string MarkingNoNetworkConnection {
get {
@ -2243,7 +2290,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Bike successfully returned!.
/// Looks up a localized string similar to Rental successfully ended!.
/// </summary>
public static string MarkingReturnBikeMainMessage {
get {
@ -2270,7 +2317,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Show/ hide.
/// Looks up a localized string similar to Show/hide.
/// </summary>
public static string MarkingShowHideBikesOfType {
get {
@ -2505,7 +2552,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Rental fees.
/// Looks up a localized string similar to Rental charges.
/// </summary>
public static string MessageBikesManagementTariffDescriptionFeeEuroPerHour {
get {
@ -2532,7 +2579,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Max. fee.
/// Looks up a localized string similar to Max. charges.
/// </summary>
public static string MessageBikesManagementTariffDescriptionMaxFeeEuroPerDay {
get {
@ -2606,7 +2653,7 @@ namespace TINK.MultilingualResources {
/// <summary>
/// Looks up a localized string similar to This version of the {0} App is not compatible with server detected.
///Please contact the support for help..
///Please contact operator for help..
/// </summary>
public static string MessageCopriVersionIsOutdated {
get {
@ -2663,7 +2710,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Error Start Query Location!.
/// Looks up a localized string similar to Error start query location!.
/// </summary>
public static string MessageErrorQueryLocationStartTitle {
get {
@ -2672,7 +2719,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Error Query Location!.
/// Looks up a localized string similar to Error query location!.
/// </summary>
public static string MessageErrorQueryLocationTitle {
get {
@ -2781,7 +2828,7 @@ namespace TINK.MultilingualResources {
/// <summary>
/// Looks up a localized string similar to Session has expired.
///Please login to app once again..
///Please log in again..
/// </summary>
public static string MessageMapPageErrorAuthcookieUndefined {
get {
@ -2790,7 +2837,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to An error occurred switching from cargo bikes/ city bikes.
/// Looks up a localized string similar to An error occurred switching between cargo and city bikes.
///{0}.
/// </summary>
public static string MessageMapPageErrorSwitch {
@ -2818,7 +2865,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Are you enjoying the {0}-App?.
/// Looks up a localized string similar to Are you enjoying the {0}-app?.
/// </summary>
public static string MessageRateMail {
get {
@ -2845,7 +2892,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to A rental of bike {0} was rejected because the maximum allowed number of {1} reservations/ rentals had already been made..
/// Looks up a localized string similar to A rental of bike {0} was rejected because the maximum allowed number of {1} reservations/rentals had already been made..
/// </summary>
public static string MessageRentingBikeErrorTooManyReservationsRentals {
get {
@ -2854,7 +2901,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to A reservation of bike {0} was rejected because the maximum allowed number of {1} reservations/ rentals had already been made..
/// Looks up a localized string similar to A reservation of bike {0} was rejected because the maximum allowed number of {1} reservations/rentals had already been made..
/// </summary>
public static string MessageReservationBikeErrorTooManyReservationsRentals {
get {
@ -2926,7 +2973,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to {0}-App Releated Request.
/// Looks up a localized string similar to {0}-app releated request.
/// </summary>
public static string MiscContactMailAppReleatedSubject {
get {
@ -2971,7 +3018,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Close lock and return bike {0}?.
/// Looks up a localized string similar to Close lock and end rental of bike {0}?.
/// </summary>
public static string QuestionCloseLockAndReturnBike {
get {
@ -2998,7 +3045,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Return bike {0}?.
/// Looks up a localized string similar to End rental of bike {0}?.
/// </summary>
public static string QuestionReturnBike {
get {
@ -3036,7 +3083,7 @@ namespace TINK.MultilingualResources {
/// <summary>
/// Looks up a localized string similar to I hereby consent to the transmission of my log file.
///
///The log file contains your app usage data as well as system information. The data will only be used for diagnostic purposes or to improve the app..
///The log file contains your app usage data as well as system information. The data will only be used for diagnostic purposes or to improve the app and then deleted..
/// </summary>
public static string QuestionSupportmailAttachment {
get {
@ -3045,7 +3092,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to Does your request/ comment relate to the {0}-app or to a more general subject?.
/// Looks up a localized string similar to Does your request/comment relate to the {0}-app or to a more general subject?.
/// </summary>
public static string QuestionSupportmailSubject {
get {
@ -3135,7 +3182,7 @@ namespace TINK.MultilingualResources {
}
/// <summary>
/// Looks up a localized string similar to The remaining power of the bike battery was low recently. Please check it on the bike display before riding. The bike can be returned within 5 minutes free of charge..
/// Looks up a localized string similar to The remaining power of the bike battery was low recently. Please check it on the bike display before riding. The rental can be canceled within 5 minutes free of charge..
/// </summary>
public static string StatusTextLowBatteryLevel {
get {

View file

@ -43,7 +43,7 @@
<value>Radstandorte</value>
</data>
<data name="MessageLoginWelcome" xml:space="preserve">
<value>Benutzer {0} erfolgreich angemeldet.</value>
<value>Nutzer {0} erfolgreich angemeldet.</value>
</data>
<data name="MessageLoginWelcomeTitle" xml:space="preserve">
<value>Willkommen!</value>
@ -58,13 +58,13 @@
<value>Angemeldet als {0} bei {1}.</value>
</data>
<data name="MarkingLoggedInStateInfoNotLoggedIn" xml:space="preserve">
<value>Kein Benutzer angemeldet.</value>
<value>Kein Nutzer angemeldet.</value>
</data>
<data name="MessageAppVersionIsOutdated" xml:space="preserve">
<value>Diese Version der {0} App ist veraltet. Bitte auf aktuelle Version aktualisieren.</value>
</data>
<data name="QuestionSupportmailSubject" xml:space="preserve">
<value>Betrifft die Anfrage/ Anmerkung die {0}-App oder ein allgemeines Thema?</value>
<value>Betrifft die Anfrage/Anmerkung die {0}-App oder ein allgemeines Thema?</value>
</data>
<data name="QuestionSupportmailAnswerApp" xml:space="preserve">
<value>{0}-App Anfrage</value>
@ -100,22 +100,22 @@
<value>Tarife</value>
</data>
<data name="ErrorCloseLockBoldBlockedMessage" xml:space="preserve">
<value>Schloss ist blockiert. Bitte sicherstellen, dass keine Speiche oder ein anderer Gegenstand das Schloss blockiert und Vorgang wiederholen.</value>
<value>Schloss ist blockiert. Bitte stellen Sie sicher, dass keine Speiche oder ein anderer Gegenstand das Schloss blockiert und wiederholen Sie den Vorgang.</value>
</data>
<data name="ErrorCloseLockMovingMessage" xml:space="preserve">
<value>Schloss kann erst geschlossen werden, wenn Rad nicht mehr bewegt wird. Bitte Rad abstellen und Vorgang wiederholen.</value>
</data>
<data name="ErrorBookedSearchMessage" xml:space="preserve">
<value>Ihr mobiles Gerät verbindet sich nicht mit dem Fahrradschloss. Bitte treten Sie möglichst nah an das Rad heran und probieren Sie es erneut. </value>
<value>Ihr mobiles Gerät verbindet sich nicht mit dem Schloss. Bitte treten Sie möglichst nah an das Rad heran und probieren Sie es erneut. </value>
</data>
<data name="ErrorReservedSearchMessage" xml:space="preserve">
<value>Ihr mobiles Gerät verbindet sich nicht mit dem Fahrradschloss. Bitte treten Sie möglichst nah an das Rad heran und probieren Sie es erneut. </value>
<value>Ihr mobiles Gerät verbindet sich nicht mit dem Schloss. Bitte treten Sie möglichst nah an das Rad heran und probieren Sie es erneut. </value>
</data>
<data name="ActivityTextBikesAtStationGetBikes" xml:space="preserve">
<value>Lade Räder an Station...</value>
</data>
<data name="ActivityTextMyBikesLoadingBikes" xml:space="preserve">
<value>Lade meine Räder...</value>
<value>Lade reservierte/gemietete Räder...</value>
</data>
<data name="ActivityTextSearchBikes" xml:space="preserve">
<value>Suche Schlösser...</value>
@ -127,29 +127,29 @@
<value>Lade Stationen und Räder...</value>
</data>
<data name="ErrorReturnBikeNotAtStationMessage" xml:space="preserve">
<value>Rückgabe ausserhalb von Station nicht möglich. Entfernung zur Station {0} ist {1} m.</value>
<value>Rückgabe außerhalb einer Station nicht möglich. Entfernung zur nächsten Station {0} beträgt {1} m.</value>
</data>
<data name="ErrorReturnBikeTitle" xml:space="preserve">
<value>Fehler bei Radrückgabe!</value>
<value>Fehler beim Beenden der Miete!</value>
</data>
<data name="ErrorReturnBikeLockClosedNoGPSMessage" xml:space="preserve">
<value>Fahrradrückgabe an unbekanntem Standort nicht möglich.
Eine Radrückgabe ist möglich, wenn
- beim Schliessen des Schlosses Standortinformation verfügbar ist
- beim Drücken von "Rad zurückgeben" das Rad in Reichweite ist und Standortinformation verfügbar ist.</value>
<value>Beenden der Miete an unbekanntem Standort nicht möglich.
Ein Mietende ist möglich, wenn
- beim Schließen des Schlosses Standortinformation verfügbar ist
- beim Drücken von "Miete beenden" das Rad in Reichweite ist und Standortinformation verfügbar ist</value>
</data>
<data name="ErrorReturnBikeLockOpenNoGPSMessage" xml:space="preserve">
<value>Fahrradrückgabe an unbekanntem Standort nicht möglich.
Eine Radrückgabe ist nur möglich, wenn das Rad in Reichweite ist und Standortinformation verfügbar ist.</value>
<value>Beenden der Miete an unbekanntem Standort nicht möglich.
Mietende ist nur möglich, wenn das Rad in Reichweite ist und Standortinformation verfügbar ist.</value>
</data>
<data name="ErrorSupportmailCreateAttachment" xml:space="preserve">
<value>Mailanhang konnte nich erzeugt werden.</value>
<value>Anhang konnte nich erzeugt werden.</value>
</data>
<data name="ErrorSupportmailMailingFailed" xml:space="preserve">
<value>Mailapp konnte nicht geöffnet werden.</value>
<value>Mailapp konnte nicht geöffnet werden. Stellen Sie sicher, dass auf Ihrem mobilen Gerät eine Mailapp installiert und eingerichtet ist!</value>
</data>
<data name="ErrorSupportmailPhoningFailed" xml:space="preserve">
<value>Telefonapp konnte nicht geöffnet werden.</value>
<value>Telefonapp konnte nicht geöffnet werden. Stellen Sie sicher, dass auf Ihrem mobilen Gerät eine Telefonapp installiert ist!</value>
</data>
<data name="MessageAnswerOk" xml:space="preserve">
<value>OK</value>
@ -158,7 +158,7 @@ Eine Radrückgabe ist nur möglich, wenn das Rad in Reichweite ist und Standorti
<value>Fragen? Hinweise?</value>
</data>
<data name="MessageRateMail" xml:space="preserve">
<value>Gefällt die {0}-App?</value>
<value>Gefällt Ihnen die {0}-App?</value>
</data>
<data name="MessageWaring" xml:space="preserve">
<value>Warnung</value>
@ -172,14 +172,14 @@ Eine Radrückgabe ist nur möglich, wenn das Rad in Reichweite ist und Standorti
<data name="QuestionSupportmailAttachment" xml:space="preserve">
<value>Hiermit stimme ich der Übermittlung meiner Protokolldatei zu.
Die Protokolldatei enthält Ihre App-Nutzungsdaten sowie Systeminformationen. Die Daten werden ausschließlich für Diagnosezwecke bzw. Verbesserung der App verwendet.</value>
Die Protokolldatei enthält Ihre App-Nutzungsdaten sowie Systeminformationen. Die Daten werden ausschließlich für Diagnosezwecke bzw. Verbesserung der App verwendet und werden anschließend gelöscht.</value>
</data>
<data name="QuestionTitle" xml:space="preserve">
<value>Frage</value>
</data>
<data name="MessageMapPageErrorAuthcookieUndefined" xml:space="preserve">
<value>Sitzung ist abgelaufen.
Bitte erneut in App anmelden.</value>
Bitte melden Sie sich erneut an.</value>
</data>
<data name="StatusTextReservationExpiredCodeMaxReservationTime" xml:space="preserve">
<value>Code ist {0}, max. Reservierungszeit von {1} Min. abgelaufen.
@ -209,7 +209,7 @@ Bitte erneut in App anmelden.</value>
</value>
</data>
<data name="StatusTextAvailable" xml:space="preserve">
<value>Frei.</value>
<value>Verfügbar.</value>
</data>
<data name="StatusTextBookedCodeLocationSince" xml:space="preserve">
<value>Code {0}, Standort {1}, gemietet seit {2}.
@ -234,7 +234,7 @@ Bitte erneut in App anmelden.</value>
<value>Passwort vergessen</value>
</data>
<data name="ActionLoginRegister" xml:space="preserve">
<value>Registrieren</value>
<value>Kostenlos registrieren</value>
</data>
<data name="MarkingLoginEmailAddressLabel" xml:space="preserve">
<value>E-Mail</value>
@ -243,7 +243,7 @@ Bitte erneut in App anmelden.</value>
<value>E-Mail</value>
</data>
<data name="MarkingLoginPasswordLabel" xml:space="preserve">
<value>Mindestens 8 Zeichen</value>
<value>Mindestens acht Zeichen</value>
</data>
<data name="MarkingLoginPasswordPlaceholder" xml:space="preserve">
<value>Passwort</value>
@ -270,45 +270,45 @@ Bitte erneut in App anmelden.</value>
<value>Fehler bei der Anmeldung!</value>
</data>
<data name="MessageLoginRecoverPassword" xml:space="preserve">
<value>Bitte mit dem Internet verbinden zum Wiederherstellen des Passworts.</value>
<value>Zur Wiederherstellung des Passworts bitte mit dem Internet verbinden.</value>
</data>
<data name="MessageLoginRegisterNoNet" xml:space="preserve">
<value>Bitte mit dem Internet verbinden zum Registrieren.</value>
<value>Zur Registrierung bitte mit dem Internet verbinden.</value>
</data>
<data name="MessageTitleHint" xml:space="preserve">
<value>Hinweis</value>
</data>
<data name="ErrorOpenLockStillClosedMessage" xml:space="preserve">
<value>Nach Versuch Schloss zu öffnen wird Status geschlossen zurückgemeldet.</value>
<value>Nach Versuch das Schloss zu öffnen, wird Status "geschlossen" zurückgemeldet.</value>
</data>
<data name="ErrorOpenLockOutOfReachMessage" xml:space="preserve">
<value>Schloss kann erst geöffnet werden, wenn Rad in der Nähe ist.</value>
</data>
<data name="ErrorCloseLockOutOfReachMessage" xml:space="preserve">
<value>Schloss kann erst geschlossen werden, wenn das Rad in der Nähe ist. </value>
<value>Schloss kann erst geschlossen werden, wenn Rad in der Nähe ist. </value>
</data>
<data name="ErrorCloseLockOutOfReachStateReservedMessage" xml:space="preserve">
<value>Schloss kann erst geschlossen werden, wenn das Rad in der Nähe ist.
Bitte Schließen nochmals versuchen oder Rad dem Support melden!</value>
<value>Schloss kann erst geschlossen werden, wenn Rad in der Nähe ist.
Bitte Schließen nochmals versuchen oder Rad dem Betreiber melden!</value>
</data>
<data name="ErrorCloseLockTitle" xml:space="preserve">
<value>Schloss kann nicht geschlossen werden!</value>
</data>
<data name="ErrorCloseLockStillOpenMessage" xml:space="preserve">
<value>Nach Versuch Schloss zu schließen wird Status geöffnet zurückgemeldet.</value>
<value>Nach Versuch Schloss zu schließen, wird Status "offen" zurückgemeldet.</value>
</data>
<data name="ErrorCloseLockUnexpectedStateMessage" xml:space="preserve">
<value>Schloss meldet Status "{0}".</value>
</data>
<data name="ErrorCloseLockUnkErrorMessage" xml:space="preserve">
<value>Bitte schließen nochmals versuchen oder Rad dem Support melden!
<value>Bitte Schließen nochmals versuchen oder Rad dem Betreiber melden!
{0}</value>
</data>
<data name="MessageBikesManagementLocationPermission" xml:space="preserve">
<value>Bitte Standortfreigabe erlauben, damit Fahrradschloss/ Schlösser verwaltet werden können.</value>
<value>Bitte Standortfreigabe erlauben, damit Schloss/-schlösser verwaltet werden können.</value>
</data>
<data name="MessageBikesManagementLocationPermissionOpenDialog" xml:space="preserve">
<value>Bitte Standortfreigabe erlauben, damit Fahrradschloss/ Schlösser verwaltet werden können.
<value>Bitte Standortfreigabe erlauben, damit Radschloss/-schlösser verwaltet werden können.
Freigabedialog öffen?</value>
</data>
<data name="MessageCenterMapLocationPermissionOpenDialog" xml:space="preserve">
@ -316,7 +316,7 @@ Freigabedialog öffen?</value>
Freigabedialog öffen?</value>
</data>
<data name="MessageBikesManagementLocationActivation" xml:space="preserve">
<value>Bitte Standort aktivieren, damit Fahrradschloss gefunden werden kann!</value>
<value>Bitte Standort aktivieren, damit Schloss gefunden werden kann!</value>
</data>
<data name="MessageAnswerNo" xml:space="preserve">
<value>Nein</value>
@ -325,7 +325,7 @@ Freigabedialog öffen?</value>
<value>Ja</value>
</data>
<data name="MessageBikesManagementBluetoothActivation" xml:space="preserve">
<value>Bitte Bluetooth aktivieren, damit Fahrradschloss/ Schlösser verwaltet werden können.</value>
<value>Bitte Bluetooth aktivieren, damit Schloss/-schlösser verwaltet werden können.</value>
</data>
<data name="ActionSearchLock" xml:space="preserve">
<value>Schloss suchen</value>
@ -334,28 +334,28 @@ Freigabedialog öffen?</value>
<value>Einen Moment bitte...</value>
</data>
<data name="ActivityTextOpeningLock" xml:space="preserve">
<value>&lt;h4&gt;&lt;b&gt;Schloss öffnet.&lt;br/&gt;Bitte warten Sie bis es komplett geöffnet ist.&lt;/b&gt;&lt;/h4&gt;</value>
<value>&lt;h4&gt;&lt;b&gt;Schloss öffnet.&lt;br/&gt;Bitte warten Sie, bis es komplett geöffnet ist.&lt;/b&gt;&lt;/h4&gt;</value>
</data>
<data name="ActivityTextStartingUpdater" xml:space="preserve">
<value>Starte Aktualisierung...</value>
<value>Aktualisiere...</value>
</data>
<data name="ActivityTextStartingUpdatingLockingState" xml:space="preserve">
<value>Aktualisiere Schlossstatus...</value>
</data>
<data name="ActivityTextReadingChargingLevel" xml:space="preserve">
<value>Lese Akkustatus...</value>
<value>Lese Akkustand...</value>
</data>
<data name="ActivityTextErrorStatusUpdateingLockstate" xml:space="preserve">
<value>Statusfehler beim Aktualisieren des Schlossstatusses.</value>
<value>Statusfehler beim Aktualisieren des Schlossstatus.</value>
</data>
<data name="ActivityTextErrorConnectionUpdateingLockstate" xml:space="preserve">
<value>Verbingungsfehler beim Aktualisieren des Schlossstatusses.</value>
<value>Verbingungsfehler beim Aktualisieren des Schlossstatus.</value>
</data>
<data name="ActivityTextErrorNoWebUpdateingLockstate" xml:space="preserve">
<value>Kein Netz beim Aktualisieren des Schlossstatusses.</value>
<value>Um den Schlossstatus zu aktualisieren, wird Internet benötigt. Bitte stellen Sie eine Internetverbindung her!</value>
</data>
<data name="ActivityTextClosingLock" xml:space="preserve">
<value>&lt;h4&gt;&lt;b&gt;Schloss schließt.&lt;br/&gt;Bitte warten Sie bis es komplett geschlossen ist.&lt;/b&gt;&lt;/h4&gt;</value>
<value>&lt;h4&gt;&lt;b&gt;Schloss schließt.&lt;br/&gt;Bitte warten Sie, bis es komplett geschlossen ist.&lt;/b&gt;&lt;/h4&gt;</value>
</data>
<data name="ChangeLog3_0_203" xml:space="preserve">
<value>Aktualisierrt auf aktuelle Schloss-Firmware.</value>
@ -378,10 +378,10 @@ Zielplatform Android 11.</value>
<value>Reserviere Rad...</value>
</data>
<data name="ActivityTextErrorReadingChargingLevelGeneral" xml:space="preserve">
<value>Akkustatus kann nicht gelesen werden.</value>
<value>Akkustand kann nicht gelesen werden.</value>
</data>
<data name="ActivityTextErrorReadingChargingLevelOutOfReach" xml:space="preserve">
<value>Akkustatus kann erst gelesen werden, wenn Rad in der Nähe ist.</value>
<value>Akkuladestand kann erst gelesen werden, wenn Rad in der Nähe ist.</value>
</data>
<data name="ActivityTextRentingBike" xml:space="preserve">
<value>Miete Rad...</value>
@ -393,10 +393,10 @@ Zielplatform Android 11.</value>
<value>Fehler beim Mieten des Rads!</value>
</data>
<data name="MessageRentingBikeErrorTooManyReservationsRentals" xml:space="preserve">
<value>Eine Miete des Rads {0} wurde abgelehnt, weil die maximal erlaubte Anzahl von {1} Reservierungen/ Buchungen bereits getätigt wurden.</value>
<value>Eine Miete des Rads {0} wurde abgelehnt, weil die maximal erlaubte Anzahl von {1} Reservierungen/Mieten bereits getätigt wurden.</value>
</data>
<data name="MessageReservationBikeErrorTooManyReservationsRentals" xml:space="preserve">
<value>Eine Reservierung des Rads {0} wurde abgelehnt, weil die maximal erlaubte Anzahl von {1} Reservierungen/ Buchungen bereits getätigt wurden.</value>
<value>Eine Reservierung des Rads {0} wurde abgelehnt, weil die maximal erlaubte Anzahl von {1} Reservierungen/Mieten bereits getätigt wurden.</value>
</data>
<data name="MessageErrorLockIsClosedThreeLines" xml:space="preserve">
<value>Achtung: Schloss wird geschlossen!
@ -408,16 +408,16 @@ Zielplatform Android 11.</value>
{0}</value>
</data>
<data name="ExceptionTextRentingBikeFailedGeneral" xml:space="preserve">
<value>Die Miete des Fahrads Nr. {0} ist fehlgeschlagen.</value>
<value>Die Miete des Rads {0} ist fehlgeschlagen.</value>
</data>
<data name="ExceptionTextRentingBikeFailedUnavailalbe" xml:space="preserve">
<value>Die Miete des Rads Nr. {0} ist fehlgeschlagen, das Rad ist momentan nicht erreichbar.{1}</value>
<value>Die Miete des Rads {0} ist fehlgeschlagen, das Rad ist momentan nicht erreichbar.{1}</value>
</data>
<data name="ExceptionTextReservationBikeFailedGeneral" xml:space="preserve">
<value>Die Reservierung des Fahrads Nr. {0} ist fehlgeschlagen.</value>
<value>Die Reservierung des Rads {0} ist fehlgeschlagen.</value>
</data>
<data name="ExceptionTextReservationBikeFailedUnavailalbe" xml:space="preserve">
<value>Die Reservierung des Rads Nr. {0} ist fehlgeschlagen, das Rad ist momentan nicht erreichbar.{1}</value>
<value>Die Reservierung des Rads {0} ist fehlgeschlagen, das Rad ist momentan nicht erreichbar.{1}</value>
</data>
<data name="ChangeLog3_0_208" xml:space="preserve">
<value>Kleinere Fehlerbehebungen.</value>
@ -430,8 +430,8 @@ Zielplatform Android 11.</value>
</data>
<data name="MarkingBikeInfoErrorStateDisposableClosedDetected" xml:space="preserve">
<value>Ungülitiger Status von Rad {0} erkannt.
Ein nicht reserviertes oder gemietetes Rad sollte immer getrennt sein .
Bitte App neu starten um Rad Infos zu bekommen.</value>
Ein nicht reserviertes oder gemietetes Rad sollte immer getrennt sein.
Bitte App neu starten, um Radinfos zu bekommen.</value>
</data>
<data name="MarkingBikeInfoErrorStateUnknownDetected" xml:space="preserve">
<value>Ungültiger Mietstatus von Rad {0} erkannt.
@ -442,13 +442,13 @@ Bitte App neu starten um Rad Infos zu bekommen.</value>
<value>Reservierung aufheben...</value>
</data>
<data name="QuestionCancelReservation" xml:space="preserve">
<value>Reservierung für Fahrrad {0} aufheben?</value>
<value>Reservierung für Rad {0} aufheben?</value>
</data>
<data name="ChangeLog3_0_209" xml:space="preserve">
<value>Kleinere Fehlerbehebung: Verbindung wird getrennt, sobald Rad verfügbar ist.</value>
</data>
<data name="QuestionReserveBike" xml:space="preserve">
<value>Fahrrad {0} kostenlos für {1} Min. reservieren?</value>
<value>Rad {0} kostenlos für {1} Min. reservieren?</value>
</data>
<data name="ActivityTextErrorDeserializationException" xml:space="preserve">
<value>Verbindungsfehler: Deserialisierung fehlgeschlagen.</value>
@ -469,7 +469,7 @@ Bitte App neu starten um Rad Infos zu bekommen.</value>
<value>Abo-Preis</value>
</data>
<data name="MessageBikesManagementTariffDescriptionFeeEuroPerHour" xml:space="preserve">
<value>Mietgebühren</value>
<value>Mietkosten</value>
</data>
<data name="MessageBikesManagementTariffDescriptionFreeTimePerSession" xml:space="preserve">
<value>Gratis Nutzung</value>
@ -524,7 +524,7 @@ Bitte App neu starten um Rad Infos zu bekommen.</value>
</data>
<data name="MessageCopriVersionIsOutdated" xml:space="preserve">
<value>Diese Version der {0} App ist nicht kompatibel mit dem erkannten Server.
Bitte kontaktieren sie den Support!</value>
Bitte kontaktieren sie den Betreiber!</value>
</data>
<data name="ChangeLog3_0_224" xml:space="preserve">
<value>Aktualisiert auf aktuelle Serverversion.</value>
@ -539,7 +539,7 @@ Bitte kontaktieren sie den Support!</value>
<value>Verbindungsfehler. Statusbeschreibung: {0}.</value>
</data>
<data name="ActivityTextErrorWebExceptionGeneralError" xml:space="preserve">
<value>Verbindungsfehler. Status statucode: {0}.</value>
<value>Verbindungsfehler. Statuscode: {0}.</value>
</data>
<data name="ChangeLog3_0_227" xml:space="preserve">
<value>Seite zur Eingabe von Rückmeldungen hinzugefügt, der nach Rückgabe eines Rads angezeigt wird.</value>
@ -548,7 +548,7 @@ Bitte kontaktieren sie den Support!</value>
<value>Offline.</value>
</data>
<data name="ActivityTextException" xml:space="preserve">
<value>Cache Daten.</value>
<value>Cache genutzt.</value>
</data>
<data name="ErrorReturnSubmitFeedbackMessage" xml:space="preserve">
<value>Ihre Rückmeldung konnte nicht an den Server übermittelt werden.</value>
@ -573,7 +573,7 @@ Fehlerhandling verbessert.</value>
<value>Veraltetes Objekt durch aktuelles ersetzt.</value>
</data>
<data name="ErrorOpenLockTitle" xml:space="preserve">
<value>Fehler beim Schloss Öffnen!</value>
<value>Fehler beim Öffnen des Schlosses!</value>
</data>
<data name="ChangeLog3_0_236" xml:space="preserve">
<value>Anzeige von Stationsnamen statt Nummern.
@ -602,7 +602,7 @@ Layout Anzeige Radnamen und nummern verbessert.</value>
<value>{0} &lt;u&gt;kontaktieren&lt;/u&gt;.</value>
</data>
<data name="MarkingLoginRequiredToRerserve" xml:space="preserve">
<value>Bitte Anmelden um Fahrräder zu reservieren! &lt;font color="blue"&gt;&lt;u&gt;Hier&lt;/u&gt;&lt;/font&gt; tippen, um auf Anmeldeseite zu wechseln.</value>
<value>Bitte Anmelden, um Räder zu reservieren! &lt;font color="blue"&gt;&lt;u&gt;Hier&lt;/u&gt;&lt;/font&gt; tippen, um auf Anmeldeseite zu wechseln.</value>
</data>
<data name="MarkingContactNoStationInfoAvailableNoButton" xml:space="preserve">
<value>Betreiber kontaktieren?</value>
@ -611,7 +611,7 @@ Layout Anzeige Radnamen und nummern verbessert.</value>
<value>Auf der Kontaktseite werden Kontaktinformationen betreiberspezifisch angezeigt.</value>
</data>
<data name="MarkingSelectStationPage" xml:space="preserve">
<value>Station Auswählen</value>
<value>Station auswählen</value>
</data>
<data name="ActionSelectStation" xml:space="preserve">
<value>Station auswählen</value>
@ -629,7 +629,7 @@ Layout Anzeige Radnamen und nummern verbessert.</value>
<value>Betreiber: {0}.</value>
</data>
<data name="MarkingBikeSharingOperatorNoOperatorInfoAvailable" xml:space="preserve">
<value>Betreiber Kontaktieren.</value>
<value>Betreiber kontaktieren.</value>
</data>
<data name="MiniSurveyAskForAnswer" xml:space="preserve">
<value>Bitte eine Antwort auswählen.</value>
@ -669,23 +669,23 @@ Kleinere Verbesserungen.</value>
<value>Start Standortabfrage...</value>
</data>
<data name="QuestionCloseLockAndReturnBike" xml:space="preserve">
<value>Fahrrad {0} abschließen und zurückgeben?</value>
<value>Rad {0} abschließen und Miete beenden?</value>
</data>
<data name="QuestionReturnBike" xml:space="preserve">
<value>Fahrrad {0} zurückgeben?
<value>Miete von Rad {0} beenden?
</value>
</data>
<data name="ActivityTextReturningBike" xml:space="preserve">
<value>Gebe Rad zurück...</value>
<value>Beende Miete...</value>
</data>
<data name="QuestionOpenLockAndBookBike" xml:space="preserve">
<value>Fahrrad {0} mieten und Schloss öffnen?</value>
<value>Rad {0} mieten und Schloss öffnen?</value>
</data>
<data name="ErrorReturnBikeNoWebMessage" xml:space="preserve">
<value>Internet muss erreichbar sein beim Zurückgeben des Rads.</value>
<value>Um die Miete zu beenden, wird Internet benötigt. Bitte stellen Sie eine Internetverbindung her!</value>
</data>
<data name="ErrorReturnBikeNoWebTitle" xml:space="preserve">
<value>Verbingungsfehler beim Zurückgeben des Rads!</value>
<value>Verbingungsfehler beim Beenden der Miete!</value>
</data>
<data name="ChangeLog3_0_244" xml:space="preserve">
<value>Abschließen von Rad und Radrückgabe beschleunigt.</value>
@ -730,20 +730,20 @@ Anzeige von Statusinformationen erweitert.
Fehlerbehebung: Supportmails können wieder verschickt werden.</value>
</data>
<data name="MessageMapPageErrorSwitch" xml:space="preserve">
<value>Beim Umschalten zwischen Lasten-/ Stadträdern ist ein Fehler aufgetreten.
<value>Beim Umschalten zwischen Lasten- und Stadträdern ist ein Fehler aufgetreten.
{0}</value>
</data>
<data name="MessageErrorSelectBikeNoBikeFound" xml:space="preserve">
<value>Kein Fahrrad mit Id {0} gefunden.</value>
<value>Kein Rad mit ID {0} gefunden.</value>
</data>
<data name="MessageErrorSelectBikeTitle" xml:space="preserve">
<value>Fehler beim Rad Wählen!</value>
<value>Fehler beim Auswählen des Rads!</value>
</data>
<data name="ChangeLog3_0_277" xml:space="preserve">
<value>Fehlerbehebung: App schließt sich nicht mehr auf Fahrrad Wählen-Seite.</value>
</data>
<data name="ErrorBookedSearchMessageEscalationLevel1" xml:space="preserve">
<value>Ihr mobiles Gerät verbindet sich immer noch nicht mit dem Fahrradschloss. Bitte starten Sie die App oder sogar Ihr mobiles Gerät neu und wiederholen Sie den Vorgang.</value>
<value>Ihr mobiles Gerät verbindet sich immer noch nicht mit dem Schloss. Bitte starten Sie die App oder sogar Ihr mobiles Gerät neu und wiederholen Sie den Vorgang.</value>
</data>
<data name="MessageAnswerCancel" xml:space="preserve">
<value>Abbrechen</value>
@ -755,12 +755,13 @@ Fehlerbehebung: Supportmails können wieder verschickt werden.</value>
<value>Fehler beim Verbinden mit Schloss!</value>
</data>
<data name="ErrorBookedSearchMessageEscalationLevel2" xml:space="preserve">
<value>Es kann leider weiterhin keine Verbindung zwischen Ihrem mobilen Gerät und dem Fahrradschloss aufgebaut werden. Bitte kontaktieren Sie den Kundensupport.
<value>Es kann weiterhin keine Verbindung zwischen Ihrem mobilen Gerät und dem Schloss aufgebaut werden. Rufen Sie den Betreiber an!
Als aller letzten Ausweg das Schloss bitte per Hand schließen UND den Kundensupport zu kontaktieren, damit dieser Ihre kostenpflichtige Miete beenden kann. Dazu:
Alternativ:
1. App schließen,
2. auf den Knopf oben am Schloss kurz drücken und schnell loslassen sobald bis dieser zu blinken beginnt,
3. warten, bis das Schloss vollständig geschlossen ist und geschlossen bleibt. </value>
2. auf den Knopf oben am Schloss kurz drücken und sofort loslassen, sobald Knopf zu blinken beginnt,
3. sicherstellen, dass das Schloss vollständig geschlossen ist und geschlossen bleibt.
4. E-Mail an Betreiber schicken (ansonsten läuft Ihre kostenpflichtige Miete weiter!): Problembeschreibung, Rad-ID, Abgabestation.</value>
</data>
<data name="ChangeLog3_0_278" xml:space="preserve">
<value>Hinweise hinzugefügt, um das Schließen des Schlosses zu erleichtern, falls dies nicht beim ersten Versuch gelingt.</value>
@ -778,16 +779,16 @@ Als aller letzten Ausweg das Schloss bitte per Hand schließen UND den Kundensup
<value>Schloss kann erst gefunden werden, wenn reserviertes Rad in der Nähe ist.</value>
</data>
<data name="MessageErrorConnectTitle" xml:space="preserve">
<value>Fehler bei Verbinden mit Schloss!</value>
<value>Fehler beim Verbinden mit Schloss!</value>
</data>
<data name="ErrorConnectLockGeneralErrorMessage" xml:space="preserve">
<value>Kommunikationsfehler bei Schlosssuche.</value>
</data>
<data name="ErrorConnectLockRentedBikeNoWebMessage" xml:space="preserve">
<value>Internet muss erreichbar sein um Verbindung mit Schloss für gemietetes Rad herzustellen.</value>
<value>Internet muss erreichbar sein, um Verbindung mit Schloss für gemietetes Rad herzustellen. Bitte stellen Sie eine Internetverbindung her!</value>
</data>
<data name="ErrorConnectLockReservedBikeNoWebMessage" xml:space="preserve">
<value>Internet muss erreichbar sein um Verbindung mit Schloss für reserviertes Rad herzustellen.</value>
<value>Internet muss erreichbar sein, um Verbindung mit Schloss für reserviertes Rad herzustellen. Bitte stellen Sie eine Internetverbindung her!</value>
</data>
<data name="ErrorFindLockReservedBikeNoStausMessage" xml:space="preserve">
<value>Schlossstatus des reservierten Rads konnte nicht ermittelt werden.</value>
@ -796,12 +797,12 @@ Als aller letzten Ausweg das Schloss bitte per Hand schließen UND den Kundensup
<value>Bitte Bluetooth anschalten, anderenfalls ist eine Verbindung mit dem Schloss nicht möglich.</value>
</data>
<data name="ErrorFindLockLocationPermissionMissing" xml:space="preserve">
<value>Bitte Standort-Zugriffsfreigabe erteilen, anderenfalls ist eine Verbindung mit dem Schloss nicht möglich.
<value>Bitte Standortfreigabe erteilen, anderenfalls ist eine Verbindung mit dem Schloss nicht möglich.
</value>
</data>
<data name="ErrorFindLockLocationOff" xml:space="preserve">
<value>Bitte Standortbestimmung aktivieren, anderenfalls ist eine Verbindung mit dem Schloss nicht möglich.</value>
<value>Bitte Standortdienste aktivieren, anderenfalls ist eine Verbindung mit dem Schloss nicht möglich.</value>
</data>
<data name="ChangeLog3_0_280" xml:space="preserve">
<value>Fehlermeldungen verbessert für die Fälle, dass
@ -810,14 +811,14 @@ Als aller letzten Ausweg das Schloss bitte per Hand schließen UND den Kundensup
- die Standorterkennung deaktiviert ist.</value>
</data>
<data name="ErrorReservedSearchMessageEscalationLevel1" xml:space="preserve">
<value>Ihr mobiles Gerät verbindet sich immer noch nicht mit dem Fahrradschloss. Bitte starten Sie die App oder sogar Ihr mobiles Gerät neu und wiederholen Sie den Vorgang.</value>
<value>Ihr mobiles Gerät verbindet sich weiterhin nicht mit dem Schloss. Bitte starten Sie die App oder sogar Ihr mobiles Gerät neu und wiederholen Sie den Vorgang.</value>
</data>
<data name="ChangeLog3_0_282" xml:space="preserve">
<value>Freigabe-Erlaubnisanfragen unter iOS ausführlicher formuliert.
Hinweise, um das Verbinden Schlosses zu erleichtern, falls dies nicht beim ersten Versuch gelingt, erweitert.</value>
</data>
<data name="ExceptionTextSessionExpired" xml:space="preserve">
<value>Die Sitzung ist abgelaufen. Bitte neu anmelden.</value>
<value>Die Sitzung ist abgelaufen. Bitte melden Sie sich erneut an.</value>
</data>
<data name="ActivityTextAuthcookieNotDefinedException" xml:space="preserve">
<value>Auth. abgelaufen</value>
@ -829,17 +830,17 @@ Hinweise, um das Verbinden Schlosses zu erleichtern, falls dies nicht beim erste
<value>Abmelden</value>
</data>
<data name="MessageAccountPageManagePersonalData" xml:space="preserve">
<value>Persönliche Daten Verwalten</value>
<value>Persönliche Daten verwalten</value>
</data>
<data name="ChangeLog3_0_285" xml:space="preserve">
<value>Framework aktualisiert.
Activity Indicator zu Konto-Verwaltungsseiten hinzugefügt und Logging erweitert.</value>
</data>
<data name="ActivityTextStartReturningBike" xml:space="preserve">
<value>Starte Rückgabe...</value>
<value>Starte Miete beenden...</value>
</data>
<data name="ExceptionTextWebConnectFailureException" xml:space="preserve">
<value>Ist WLAN verfügbar/ Mobilfunknetz vefügbar und mobile Daten aktiviert / ... ?</value>
<value>Ist WLAN/Mobilfunknetz vefügbar und mobile Daten aktiviert?</value>
</data>
<data name="ChangeLog3_0_289" xml:space="preserve">
<value>Flyout-Menü Überschift verschönert.</value>
@ -867,7 +868,7 @@ Kleinere Fehlerbehebungen.
<value>Protokollierungsstufe</value>
</data>
<data name="MarkingShowHideBikesOfType" xml:space="preserve">
<value>Ausblenden/ Einblenden</value>
<value>Ein-/Ausblenden</value>
</data>
<data name="MarkingVerboseErrorMessage" xml:space="preserve">
<value>Ausführliche Fehlermeldungen</value>
@ -904,7 +905,7 @@ Kleinere Fehlerbehebungen.
<value>Neues Schloss unterstützt.</value>
</data>
<data name="ActionGiveFeedback" xml:space="preserve">
<value>Rückmeldung Geben</value>
<value>Rückmeldung geben</value>
</data>
<data name="ActionContactMailAppReleated" xml:space="preserve">
<value>Rückmeldung zur App</value>
@ -929,7 +930,7 @@ Kleinere Fehlerbehebungen.
<value>Verbingungsfehler beim Aufheben der Reservierung!</value>
</data>
<data name="MessageOpeningLockErrorConnectionTitle" xml:space="preserve">
<value>Verbindungsfehler beim Schlossöffnen!</value>
<value>Verbindungsfehler beim Öffnen des Schlosses!</value>
</data>
<data name="ActivityTextSubmittingFeedback" xml:space="preserve">
<value>Sende Rückmeldung...</value>
@ -950,13 +951,13 @@ Kleinere Fehlerbehebungen.
<value>Rad ist in Ordnung</value>
</data>
<data name="MarkingReturnBikeErrorDescriptionInputPlaceholder" xml:space="preserve">
<value>Bitte Zustand/ Defekt hier beschreiben.</value>
<value>Bitte Zustand/Defekt hier beschreiben.</value>
</data>
<data name="MarkingReturnBikeFeedbackInputPlaceholder" xml:space="preserve">
<value>Bei Bedarf bitte hier Rückmeldung eingeben.</value>
</data>
<data name="MarkingReturnBikeMainMessage" xml:space="preserve">
<value>Fahrrad erfolgreich zurückgegeben!</value>
<value>Rad erfolgreich zurückgegeben!</value>
</data>
<data name="MarkingDriveBatteryTitel" xml:space="preserve">
<value>Aktueller Akkuladestand:</value>
@ -965,10 +966,10 @@ Kleinere Fehlerbehebungen.
<value>Für Mein konrad Nutzer: Anzeige des Akkuladestands für E-Bikes und Abfrage des Ladestands nach Radrückgabe.</value>
</data>
<data name="StatusTextLowBatteryLevel" xml:space="preserve">
<value>Die verbleibende Ladung des Fahrradakkus war zuletzt niedrig. Bitte überprüfen Sie diese vor der Fahrt auf dem Fahrraddisplay. Das Rad kann innerhalb 5 Minuten kostenlos zurückgegeben werden.</value>
<value>Die verbleibende Ladung des Fahrradakkus war zuletzt niedrig. Bitte überprüfen Sie diese vor der Fahrt auf dem Fahrraddisplay. Die Miete kann innerhalb 5 Minuten kostenlos abgebrochen werden.</value>
</data>
<data name="StatusTextCopriLock" xml:space="preserve">
<value>Zur Fahrpause schließen Sie das Fahrradschloss manuell, nicht über die App. Zum Beenden der kostenpflichtigen Miete schieben Sie das Rad in eine zugelassene Station und bestätigen das Mietende in der App; das Schloss schließt automatisch.</value>
<value>Zur Fahrpause schließen Sie das Schloss manuell, nicht über die App. Zum Beenden der kostenpflichtigen Miete schieben Sie das Rad in eine zugelassene Station und bestätigen das Mietende in der App; das Schloss schließt automatisch.</value>
</data>
<data name="ChangeLog3_0_335" xml:space="preserve">
<value>Sharee.bike Design verbessert.</value>
@ -977,7 +978,7 @@ Kleinere Fehlerbehebungen.
<value>Für Lastenrad Bayern Nutzende: Akkuladestand für E-Bikes wird angezeigt.</value>
</data>
<data name="ChangeLog3_0_337_MK" xml:space="preserve">
<value>Sie werden nun informiert, wenn die Ladung des Fahrradakkus zuletzt als sehr niedrig angegeben wurde. Um die Zuverlässigkeit der Akkustandanzeige in der App zu gewährleisten, geben Sie bitte am Ende Ihrer Fahrt mit einem E-Lastenrad den aktuellen Ladestand in die App ein.</value>
<value>Sie werden nun informiert, wenn die Ladung des Radakkus zuletzt als sehr niedrig angegeben wurde. Um die Zuverlässigkeit der Akkustandanzeige in der App zu gewährleisten, geben Sie bitte am Ende Ihrer Fahrt mit einem E-Lastenrad den aktuellen Ladestand in die App ein.</value>
</data>
<data name="ChangeLog3_0_337_SB" xml:space="preserve">
<value>Die App hat ein neues Design! --- Sie sind Beta-Tester? Geben Sie uns jederzeit hilfreiche Rückmeldung über 'Kontakt - Rückmeldung zur App'. Sie sind noch kein Beta-Tester? Werden Sie es und erhalten Sie tolle neue Features vor allen anderen!</value>
@ -1012,7 +1013,7 @@ Außerdem: Kleine Grafiken lassen auf einen Blick erkennen um was für einen Rad
<value>Einwilligung</value>
</data>
<data name="PlaceholderFindBike" xml:space="preserve">
<value>Fahrrad-Nummer hier eingeben</value>
<value>Rad-Nummer hier eingeben</value>
</data>
<data name="ChangeLog3_0_339_MK" xml:space="preserve">
<value>Die Lastenräder aus den Vororten zeigen nun ihre Heimatstation im Namen an. Diese Räder müssen dort wieder abgeben werden!
@ -1109,10 +1110,10 @@ Probieren Sie es aus!</value>
<value>Zum Aktualisieren ziehen.</value>
</data>
<data name="MarkingBikesAtStationNoBikesAvailable" xml:space="preserve">
<value>Momentan sind keine Fahrräder an dieser Station verfügbar.</value>
<value>Momentan sind keine Räder an dieser Station verfügbar.</value>
</data>
<data name="MarkingMyBikesNoBikesReservedRented" xml:space="preserve">
<value>Momentan sind keine Fahrräder auf Benutzer {0} reserviert/ gebucht.</value>
<value>Momentan sind keine Räder von Nutzer {0} reserviert/gemietet.</value>
</data>
<data name="MessageTitleInformation" xml:space="preserve">
<value>Information</value>
@ -1125,7 +1126,8 @@ Probieren Sie es aus!</value>
Achtung! Ihre Miete hat bereits begonnen.
Wenn sich das Schloss weiterhin nicht öffnen lässt, vergewissern Sie sich, dass das Schloss geschlossen ist und geben Sie das Rad zurück. Bitte melden Sie es dem Support!</value>
Wenn sich das Schloss weiterhin nicht öffnen lässt, vergewissern Sie sich, dass das Schloss geschlossen ist und geben Sie das Rad zurück.
Wichtig: Schicken Sie eine E-Mail an den Betreiber (ansonsten läuft Ihre kostenpflichtige Miete weiter!): Problembeschreibung, Radnummer, Abgabestation.</value>
</data>
<data name="ErrorOpenLockStillClosedTitle" xml:space="preserve">
<value>Schloss kann nicht geöffnet werden!</value>
@ -1143,4 +1145,26 @@ Wenn sich das Schloss weiterhin nicht öffnen lässt, vergewissern Sie sich, das
<data name="ChangeLog_3_0_361_MK_SB" xml:space="preserve">
<value>Wenn Sie ein Rad reserviert oder gemietet haben, wird dies Ihnen nun auf der Kartenseite als Symbol angezeigt. Ein Klick darauf führt Sie direkt zur Seite 'Meine Räder'. Wir haben außerdem kleine Designänderungen vorgenommen.</value>
</data>
<data name="ErrorReturnBikeLockClosedStartGetGPSExceptionMessage" xml:space="preserve">
<value>Beenden der Miete an unbekanntem Standort is nicht möglich.
Fehler beim Start der Standortabfrage!</value>
</data>
<data name="ErrorReturnBikeLockClosedGetGPSExceptionMessage" xml:space="preserve">
<value>Beenden der Miete an unbekanntem Standort is nicht möglich.
Fehler bei der Standortabfrage!</value>
</data>
<data name="Error_ReturnBike_Station_Location_Message" xml:space="preserve">
<value>Wir konnten das Rad keiner Station zuordnen. Dazu benötigen wir Ihre Standortinformationen, während Sie direkt neben dem Rad stehen. Nur dann kann Ihre Miete beendet werden!
Treten Sie an das Rad heran, schalten Sie Bluetooth und Standortdienste ein und versuchen Sie es erneut.</value>
</data>
<data name="ChangeLog_3_0_362_MK_SB" xml:space="preserve">
<value>Einige Bezeichnungen wurden vereinheitlicht, z.B:&lt;br/&gt;
- was bisher unter 'Rad zurückgeben' lief, heißt nun immer 'Miete beenden'.&lt;br/&gt;
- der 'Betreiber' ist die für die Radflotte zuständige Personengruppe, zu der bei Bedarf Kontakt aufgenommen wird.&lt;br/&gt;
&lt;br/&gt;
Außerdem:&lt;br/&gt;
- Kleinere Fehlerbehebungen&lt;br/&gt;
- Paketaktualisierungen</value>
</data>
</root>

View file

@ -127,7 +127,7 @@
<value>Close lock</value>
</data>
<data name="ActionCloseAndReturn" xml:space="preserve">
<value>Close lock &amp; return bike</value>
<value>Close lock &amp; end rental</value>
</data>
<data name="ActionOpen" xml:space="preserve">
<value>Open lock</value>
@ -142,7 +142,7 @@
<value>Reserve bike</value>
</data>
<data name="ActionReturn" xml:space="preserve">
<value>Return bike</value>
<value>End rental</value>
</data>
<data name="ActivityTextMapLoadingStationsAndBikes" xml:space="preserve">
<value>Loading Stations and Bikes...</value>
@ -160,29 +160,29 @@
<value>Your mobile device does not connect to the bike lock. Please step as close as possible to the bike and try again.</value>
</data>
<data name="ErrorReturnBikeLockClosedNoGPSMessage" xml:space="preserve">
<value>Returning bike at an unknown location is not possible.
Bike can be returned if
<value>End rental at an unknown location is not possible.
Rental can be ended if
- location information is available when closing lock
- bike is in reach and location information is available when pressing button "Return bike"</value>
- bike is in reach and location information is available when pressing button "End rental"</value>
</data>
<data name="ErrorReturnBikeLockOpenNoGPSMessage" xml:space="preserve">
<value>Returning bike at an unknown location is not possible.
Bike can only be returned if bike is in reach and location information is available.</value>
<value>End rental at an unknown location is not possible.
Rental can only be ended if bike is in reach and location information is available.</value>
</data>
<data name="ErrorReturnBikeNotAtStationMessage" xml:space="preserve">
<value>Returning bike outside of station is not possible. Distance to station {0} is {1} m.</value>
<value>End rental outside of station is not possible. Distance to station {0} is {1} m.</value>
</data>
<data name="ErrorReturnBikeTitle" xml:space="preserve">
<value>Error returning bike!</value>
<value>Error at ending rental!</value>
</data>
<data name="ErrorSupportmailCreateAttachment" xml:space="preserve">
<value>Attachment could not be created.</value>
</data>
<data name="ErrorSupportmailMailingFailed" xml:space="preserve">
<value>Opening mail app failed.</value>
<value>Opening mail app failed. Make sure you have a mail app installed on your mobile device!</value>
</data>
<data name="ErrorSupportmailPhoningFailed" xml:space="preserve">
<value>Opening phone app failed.</value>
<value>Opening phone app failed. Make sure you have a phone app installed on your mobile device!</value>
</data>
<data name="MarkingAbout" xml:space="preserve">
<value>Legal Information</value>
@ -243,13 +243,13 @@ Bike can only be returned if bike is in reach and location information is avail
</data>
<data name="MessageMapPageErrorAuthcookieUndefined" xml:space="preserve">
<value>Session has expired.
Please login to app once again.</value>
Please log in again.</value>
</data>
<data name="MessagePhoneMail" xml:space="preserve">
<value>Urgent questions?</value>
</data>
<data name="MessageRateMail" xml:space="preserve">
<value>Are you enjoying the {0}-App?</value>
<value>Are you enjoying the {0}-app?</value>
</data>
<data name="MessageWaring" xml:space="preserve">
<value>Warning</value>
@ -269,10 +269,10 @@ Please login to app once again.</value>
<data name="QuestionSupportmailAttachment" xml:space="preserve">
<value>I hereby consent to the transmission of my log file.
The log file contains your app usage data as well as system information. The data will only be used for diagnostic purposes or to improve the app.</value>
The log file contains your app usage data as well as system information. The data will only be used for diagnostic purposes or to improve the app and then deleted.</value>
</data>
<data name="QuestionSupportmailSubject" xml:space="preserve">
<value>Does your request/ comment relate to the {0}-app or to a more general subject?</value>
<value>Does your request/comment relate to the {0}-app or to a more general subject?</value>
</data>
<data name="QuestionTitle" xml:space="preserve">
<value>Question</value>
@ -284,7 +284,7 @@ The log file contains your app usage data as well as system information. The dat
<value>Centering map...</value>
</data>
<data name="ActivityTextMyBikesLoadingBikes" xml:space="preserve">
<value>Loading reserved/ booked bikes...</value>
<value>Loading reserved/rented bikes...</value>
</data>
<data name="ActivityTextSearchBikes" xml:space="preserve">
<value>Searching locks...</value>
@ -338,7 +338,7 @@ The log file contains your app usage data as well as system information. The dat
<value>Password forgotten</value>
</data>
<data name="ActionLoginRegister" xml:space="preserve">
<value>Register</value>
<value>Register for free</value>
</data>
<data name="MarkingLoginEmailAddressLabel" xml:space="preserve">
<value>E-mail</value>
@ -357,7 +357,7 @@ The log file contains your app usage data as well as system information. The dat
</value>
</data>
<data name="MarkingLoginPasswordLabel" xml:space="preserve">
<value>At least 8 characters</value>
<value>At least eight characters</value>
</data>
<data name="MarkingLoginPasswordPlaceholder" xml:space="preserve">
<value>Password</value>
@ -394,7 +394,7 @@ The log file contains your app usage data as well as system information. The dat
</data>
<data name="ErrorCloseLockOutOfReachStateReservedMessage" xml:space="preserve">
<value>Lock cannot be closed until bike is near.
Please try again to close bike or report bike to support!</value>
Please try again to close bike or report bike to operator!</value>
</data>
<data name="ErrorCloseLockTitle" xml:space="preserve">
<value>Lock can not be closed!</value>
@ -406,7 +406,7 @@ Please try again to close bike or report bike to support!</value>
<value>Lock reports state "{0}".</value>
</data>
<data name="ErrorCloseLockUnkErrorMessage" xml:space="preserve">
<value>Please try to lock again or report bike to support!
<value>Please try to lock again or report bike to operator!
{0}</value>
</data>
<data name="MessageBikesManagementLocationPermission" xml:space="preserve">
@ -457,7 +457,7 @@ Open sharing dialog?</value>
<value>Connection error on updating locking status.</value>
</data>
<data name="ActivityTextErrorNoWebUpdateingLockstate" xml:space="preserve">
<value>No web error on updating locking status.</value>
<value>Internet must be available for updating lock status. Please establish an Internet connection!</value>
</data>
<data name="ActivityTextClosingLock" xml:space="preserve">
<value>&lt;h4&gt;&lt;b&gt;Lock is closing.&lt;br/&gt;Please wait until it is completely closed.&lt;/b&gt;&lt;/h4&gt;</value>
@ -501,10 +501,10 @@ Targets Android 11.</value>
<value>Error when renting the bike!</value>
</data>
<data name="MessageRentingBikeErrorTooManyReservationsRentals" xml:space="preserve">
<value>A rental of bike {0} was rejected because the maximum allowed number of {1} reservations/ rentals had already been made.</value>
<value>A rental of bike {0} was rejected because the maximum allowed number of {1} reservations/rentals had already been made.</value>
</data>
<data name="MessageReservationBikeErrorTooManyReservationsRentals" xml:space="preserve">
<value>A reservation of bike {0} was rejected because the maximum allowed number of {1} reservations/ rentals had already been made.</value>
<value>A reservation of bike {0} was rejected because the maximum allowed number of {1} reservations/rentals had already been made.</value>
</data>
<data name="MessageErrorLockIsClosedThreeLines" xml:space="preserve">
<value>Attention: Lock is closed!
@ -516,16 +516,16 @@ Targets Android 11.</value>
{0}</value>
</data>
<data name="ExceptionTextRentingBikeFailedGeneral" xml:space="preserve">
<value>The rental of bike No. {0} has failed.</value>
<value>The rental of bike {0} has failed.</value>
</data>
<data name="ExceptionTextRentingBikeFailedUnavailalbe" xml:space="preserve">
<value>The rental of bike No. {0} has failed, the bike is currently unavailable.{1}</value>
<value>The rental of bike {0} has failed, the bike is currently unavailable. {1}</value>
</data>
<data name="ExceptionTextReservationBikeFailedGeneral" xml:space="preserve">
<value>The reservation of bike no. {0} has failed.</value>
<value>The reservation of bike {0} has failed.</value>
</data>
<data name="ExceptionTextReservationBikeFailedUnavailalbe" xml:space="preserve">
<value>The reservation of bike No. {0} has failed, the bike is currently unavailable.{1}</value>
<value>The reservation of bike {0} has failed, the bike is currently unavailable. {1}</value>
</data>
<data name="ChangeLog3_0_208" xml:space="preserve">
<value>Minor fixes.</value>
@ -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 fees</value>
<value>Rental charges</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. fee</value>
<value>Max. charges</value>
</data>
<data name="MessageBikesManagementTariffDescriptionTariffHeader" xml:space="preserve">
<value>Tariff</value>
@ -633,7 +633,7 @@ Please restart app in order to get bike info.</value>
</data>
<data name="MessageCopriVersionIsOutdated" xml:space="preserve">
<value>This version of the {0} App is not compatible with server detected.
Please contact the support for help.</value>
Please contact operator for help.</value>
</data>
<data name="ChangeLog3_0_224" xml:space="preserve">
<value>Updated for latest server version.</value>
@ -647,7 +647,7 @@ Please contact the support for help.</value>
<value>Connection error. Status description: {0}.</value>
</data>
<data name="ChangeLog3_0_227" xml:space="preserve">
<value>Feedback dialog added which is shown after returning bike.</value>
<value>Feedback dialog added which is shown after ending rental.</value>
</data>
<data name="ActivityTextConnectionStateOffline" xml:space="preserve">
<value>Offline.</value>
@ -681,11 +681,11 @@ Error handling improved.</value>
<value>Ensure that no obstacle prevents lock from opening and try again.</value>
</data>
<data name="ErrorOpenLockBoldStatusIsUnknownMessage" xml:space="preserve">
<value>The lock could not be opened correctly. Please try again.
<value>The lock could not be opened correctly. Try again!
Attention! Your rental has already started.
If the lock still won't open, make sure the lock is closed and return the bike. Please report it to the support!</value>
If the lock still won't open, make sure the lock is closed and end rental.
Important: Send an email to the operator (otherwise your paid rental will continue!) with: Problem description, bike number, drop-off station.</value>
</data>
<data name="ErrorOpenLockStillClosedTitle" xml:space="preserve">
<value>Lock can not be opened!</value>
@ -696,7 +696,7 @@ Error message when opening lock fails improved.
Layout of bike names and id display improved.</value>
</data>
<data name="ChangeLog3_0_237" xml:space="preserve">
<value>Hard- and software information send to backend when returning bike.</value>
<value>Hard- and software information send to backend when ending rental.</value>
</data>
<data name="ChangeLog3_0_239" xml:space="preserve">
<value>Bugfix: Bike description is displayed correctly again.</value>
@ -741,7 +741,7 @@ Layout of bike names and id display improved.</value>
<value>Operator: {0}.</value>
</data>
<data name="MarkingBikeSharingOperatorNoOperatorInfoAvailable" xml:space="preserve">
<value>Contact Operator.</value>
<value>Contact operator.</value>
</data>
<data name="MiniSurveyAskForAnswer" xml:space="preserve">
<value>Select an answer please.</value>
@ -775,28 +775,28 @@ Minor fixes.</value>
<value>Closing the lock and ending the rental is not possible.</value>
</data>
<data name="MessageErrorQueryLocationStartTitle" xml:space="preserve">
<value>Error Start Query Location!</value>
<value>Error start query location!</value>
</data>
<data name="MessageErrorQueryLocationTitle" xml:space="preserve">
<value>Error Query Location!</value>
<value>Error query location!</value>
</data>
<data name="QuestionCloseLockAndReturnBike" xml:space="preserve">
<value>Close lock and return bike {0}?</value>
<value>Close lock and end rental of bike {0}?</value>
</data>
<data name="ActivityTextReturningBike" xml:space="preserve">
<value>Returning bike...</value>
<value>Ending rental...</value>
</data>
<data name="QuestionReturnBike" xml:space="preserve">
<value>Return bike {0}?</value>
<value>End rental of bike {0}?</value>
</data>
<data name="ChangeLog3_0_244" xml:space="preserve">
<value>Closing lock and returning bike speeded up.</value>
</data>
<data name="ErrorReturnBikeNoWebMessage" xml:space="preserve">
<value>Internet must be available when returning the bike.</value>
<value>Internet must be available when ending rental. Please establish an Internet connection!</value>
</data>
<data name="ErrorReturnBikeNoWebTitle" xml:space="preserve">
<value>Connection error when returning the bike!</value>
<value>Connection error when ending rental.</value>
</data>
<data name="ChangeLog3_0_249" xml:space="preserve">
<value>Third-party components updated.</value>
@ -838,7 +838,7 @@ Display of status information extended.
Bugfix: Sending support mails works again. </value>
</data>
<data name="MessageMapPageErrorSwitch" xml:space="preserve">
<value>An error occurred switching from cargo bikes/ city bikes.
<value>An error occurred switching between cargo and city bikes.
{0}</value>
</data>
<data name="MessageErrorSelectBikeNoBikeFound" xml:space="preserve">
@ -863,12 +863,13 @@ Bugfix: Sending support mails works again. </value>
<value>Error when connecting with lock!</value>
</data>
<data name="ErrorBookedSearchMessageEscalationLevel2" xml:space="preserve">
<value>Unfortunately, it is still not possible to establish a connection between your mobile device and the bike lock. Please contact customer support.
<value>It is still not possible to establish a connection between your mobile device and the bike lock. Please contact operator!
As a last resort, please close the lock by hand AND contact customer support so that they can terminate your chargeable rental. To do this:
1. close the app,
2. press the button at the top of the lock briefly and quickly release it as soon as it starts flashing,
3. wait until the lock is completely closed and remains closed.</value>
Alternative:
1. close app,
2. press the button at the top of the lock briefly and release it as soon as it starts flashing,
3. make sure that the lock is completely closed and remains closed.
4. send e-mail to operator (otherwise your chargeable rental will continue!): Problem description, Drop-off station.</value>
</data>
<data name="ChangeLog3_0_278" xml:space="preserve">
<value>Hints added to ease closing of lock in case closing does not succeed on first try.</value>
@ -892,10 +893,10 @@ As a last resort, please close the lock by hand AND contact customer support so
<value>Communication error during lock search.</value>
</data>
<data name="ErrorConnectLockRentedBikeNoWebMessage" xml:space="preserve">
<value>Internet must be reachable to connect to lock of rented bike.</value>
<value>Internet must be reachable to connect to lock of rented bike. Please establish an Internet connection!</value>
</data>
<data name="ErrorConnectLockReservedBikeNoWebMessage" xml:space="preserve">
<value>Internet must be reachable to connect to lock of reserved bike.</value>
<value>Internet must be reachable to connect to lock of reserved bike. Please establish an Internet connection!</value>
</data>
<data name="ErrorFindLockReservedBikeNoStausMessage" xml:space="preserve">
<value>Lock status of the reserved bike could not be determined.</value>
@ -907,7 +908,7 @@ As a last resort, please close the lock by hand AND contact customer support so
<value>Please grant location permissions, otherwise lock cannot be connected.</value>
</data>
<data name="ErrorFindLockLocationOff" xml:space="preserve">
<value>Please turn Location on, otherwise lock cannot be connected.</value>
<value>Please turn location services on, otherwise lock cannot be connected.</value>
</data>
<data name="ChangeLog3_0_280" xml:space="preserve">
<value>Errormessages improved for szenarios when
@ -942,10 +943,10 @@ Hints to ease connecting to lock in case connecting does not succeed on first tr
Activity indicator added account management pages and logging extended.</value>
</data>
<data name="ActivityTextStartReturningBike" xml:space="preserve">
<value>Starting bike return...</value>
<value>Starting end rental...</value>
</data>
<data name="ExceptionTextWebConnectFailureException" xml:space="preserve">
<value>Is WIFI available/ mobile network available and mobile data activated / ... ?</value>
<value>Is WIFI/mobile network available and mobile data activated?</value>
</data>
<data name="ChangeLog3_0_289" xml:space="preserve">
<value>Flyout menu header improved.</value>
@ -972,7 +973,7 @@ Minor bugfixes.</value>
<value>Logging level</value>
</data>
<data name="MarkingShowHideBikesOfType" xml:space="preserve">
<value>Show/ hide</value>
<value>Show/hide</value>
</data>
<data name="MarkingVerboseErrorMessage" xml:space="preserve">
<value>Verbose error messages</value>
@ -1009,13 +1010,13 @@ Minor bugfixes.</value>
<value>Support for new lock type added.</value>
</data>
<data name="ActionGiveFeedback" xml:space="preserve">
<value>Give Feedback</value>
<value>Give feedback</value>
</data>
<data name="ActionContactMailAppReleated" xml:space="preserve">
<value>Feedback about the App</value>
<value>Feedback about the app</value>
</data>
<data name="MiscContactMailAppReleatedSubject" xml:space="preserve">
<value>{0}-App Releated Request</value>
<value>{0}-app releated request</value>
<comment>Subject of contact mail to ("Feedback about the app").</comment>
</data>
<data name="MessageReservingBikeErrorConnectionTitle" xml:space="preserve">
@ -1061,7 +1062,7 @@ Minor bugfixes.</value>
<value>Please enter feedback here if needed.</value>
</data>
<data name="MarkingReturnBikeMainMessage" xml:space="preserve">
<value>Bike successfully returned!</value>
<value>Rental successfully ended!</value>
</data>
<data name="MarkingDriveBatteryTitel" xml:space="preserve">
<value>Current battery level:</value>
@ -1070,7 +1071,7 @@ Minor bugfixes.</value>
<value>For Mein konrad users: Battery charging level is displayed for ebikes and is queried after return of bike.</value>
</data>
<data name="StatusTextLowBatteryLevel" xml:space="preserve">
<value>The remaining power of the bike battery was low recently. Please check it on the bike display before riding. The bike can be returned within 5 minutes free of charge.</value>
<value>The remaining power of the bike battery was low recently. Please check it on the bike display before riding. The rental can be canceled within 5 minutes free of charge.</value>
</data>
<data name="StatusTextCopriLock" xml:space="preserve">
<value>At pausing ride, you close the bike lock manually, not via the app. To end the chargeable rental, slide the bike into an authorized station and confirm the end of the rental in the app; the lock closes automatically.</value>
@ -1215,7 +1216,7 @@ Try it out!</value>
<value>There are currently no bicycles available at this station.</value>
</data>
<data name="MarkingMyBikesNoBikesReservedRented" xml:space="preserve">
<value>There are currently no bicycles reserved/booked on user {0}.</value>
<value>There are currently no bikes reserved/rented by user {0}.</value>
</data>
<data name="MessageTitleInformation" xml:space="preserve">
<value>Information</value>
@ -1228,9 +1229,31 @@ Try it out!</value>
<value>Minor improvements.</value>
</data>
<data name="MarkingNoNetworkConnection" xml:space="preserve">
<value>Oops, there is no internet connection.</value>
<value>Oops, there is no Internet connection.</value>
</data>
<data name="ChangeLog_3_0_361_MK_SB" xml:space="preserve">
<value>If you have reserved or rented a bike, this will now be shown to you as an icon on the map page. Clicking on it will take you directly to the 'My bikes' page. We have also made small design changes.</value>
</data>
<data name="ErrorReturnBikeLockClosedStartGetGPSExceptionMessage" xml:space="preserve">
<value>End rental at an unknown location is not possible.
Start getting geolocation failed.</value>
</data>
<data name="ErrorReturnBikeLockClosedGetGPSExceptionMessage" xml:space="preserve">
<value>End rental at an unknown location is not possible.
Getting geolocation failed.</value>
</data>
<data name="Error_ReturnBike_Station_Location_Message" xml:space="preserve">
<value>We could not assign the bike to any station. For this we need your location information while you are standing right next to the bike. Only then your rental can be terminated!
Approach the bike, turn on Bluetooth and Location services and try again.</value>
</data>
<data name="ChangeLog_3_0_362_MK_SB" xml:space="preserve">
<value>Some terms have been standardized, e.g:&lt;br/&gt;
- what used to be called 'return bike' is now always called 'end rental'.&lt;br/&gt;
- The 'operator' is the group of people responsible for the bike fleet, who will be contacted if necessary.&lt;br/&gt;
&lt;br/&gt;
Also:&lt;br/&gt;
- Minor bug fixes&lt;br/&gt;
- Package updates</value>
</data>
</root>

View file

@ -19,8 +19,9 @@
<target state="final">Schloss schließen</target>
</trans-unit>
<trans-unit id="ActionCloseAndReturn" translate="yes" xml:space="preserve">
<source>Close lock &amp; return bike</source>
<target state="final">Schloss schließen &amp; Miete beenden</target>
<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>
</trans-unit>
<trans-unit id="ActionOpen" translate="yes" xml:space="preserve">
<source>Open lock</source>
@ -39,8 +40,9 @@
<target state="final">Rad reservieren</target>
</trans-unit>
<trans-unit id="ActionReturn" translate="yes" xml:space="preserve">
<source>Return bike</source>
<target state="final">Miete beenden</target>
<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>
</trans-unit>
<trans-unit id="MarkingMapPage" translate="yes" xml:space="preserve">
<source>Bike Locations</source>
@ -48,7 +50,7 @@
</trans-unit>
<trans-unit id="MessageLoginWelcome" translate="yes" xml:space="preserve">
<source>User {0} successfully logged in.</source>
<target state="final">Benutzer {0} erfolgreich angemeldet.</target>
<target state="translated">Nutzer {0} erfolgreich angemeldet.</target>
</trans-unit>
<trans-unit id="MessageLoginWelcomeTitle" translate="yes" xml:space="preserve">
<source>Welcome!</source>
@ -68,15 +70,15 @@
</trans-unit>
<trans-unit id="MarkingLoggedInStateInfoNotLoggedIn" translate="yes" xml:space="preserve">
<source>No user logged in.</source>
<target state="final">Kein Benutzer angemeldet.</target>
<target state="translated">Kein Nutzer angemeldet.</target>
</trans-unit>
<trans-unit id="MessageAppVersionIsOutdated" translate="yes" xml:space="preserve">
<source>This version of the {0} App is outdated. Please update to the latest version.</source>
<target state="final">Diese Version der {0} App ist veraltet. Bitte auf aktuelle Version aktualisieren.</target>
</trans-unit>
<trans-unit id="QuestionSupportmailSubject" translate="yes" xml:space="preserve">
<source>Does your request/ comment relate to the {0}-app or to a more general subject?</source>
<target state="final">Betrifft die Anfrage/ Anmerkung die {0}-App oder ein allgemeines Thema?</target>
<source>Does your request/comment relate to the {0}-app or to a more general subject?</source>
<target state="translated">Betrifft die Anfrage/Anmerkung die {0}-App oder ein allgemeines Thema?</target>
</trans-unit>
<trans-unit id="QuestionSupportmailAnswerApp" translate="yes" xml:space="preserve">
<source>{0} app request</source>
@ -124,7 +126,7 @@
</trans-unit>
<trans-unit id="ErrorCloseLockBoldBlockedMessage" translate="yes" xml:space="preserve">
<source>Lock is blocked. Please ensure that no spoke or any other obstacle prevents the lock from closing and try again.</source>
<target state="translated">Schloss ist blockiert. Bitte sicherstellen, dass keine Speiche oder ein anderer Gegenstand das Schloss blockiert und Vorgang wiederholen.</target>
<target state="translated">Schloss ist blockiert. Bitte stellen Sie sicher, dass keine Speiche oder ein anderer Gegenstand das Schloss blockiert und wiederholen Sie den Vorgang.</target>
</trans-unit>
<trans-unit id="ErrorCloseLockMovingMessage" translate="yes" xml:space="preserve">
<source>Lock can only be closed if bike is not moving. Please park bike and try again.</source>
@ -132,19 +134,19 @@
</trans-unit>
<trans-unit id="ErrorBookedSearchMessage" translate="yes" xml:space="preserve">
<source>Your mobile device does not connect to the bike lock. Please step as close as possible to the bike and try again.</source>
<target state="translated">Ihr mobiles Gerät verbindet sich nicht mit dem Fahrradschloss. Bitte treten Sie möglichst nah an das Rad heran und probieren Sie es erneut. </target>
<target state="translated">Ihr mobiles Gerät verbindet sich nicht mit dem Schloss. Bitte treten Sie möglichst nah an das Rad heran und probieren Sie es erneut. </target>
</trans-unit>
<trans-unit id="ErrorReservedSearchMessage" translate="yes" xml:space="preserve">
<source>Your mobile device does not connect to the bike lock. Please step as close as possible to the bike and try again.</source>
<target state="translated">Ihr mobiles Gerät verbindet sich nicht mit dem Fahrradschloss. Bitte treten Sie möglichst nah an das Rad heran und probieren Sie es erneut. </target>
<target state="translated">Ihr mobiles Gerät verbindet sich nicht mit dem Schloss. Bitte treten Sie möglichst nah an das Rad heran und probieren Sie es erneut. </target>
</trans-unit>
<trans-unit id="ActivityTextBikesAtStationGetBikes" translate="yes" xml:space="preserve">
<source>Loading bikes located at station...</source>
<target state="translated">Lade Räder an Station...</target>
</trans-unit>
<trans-unit id="ActivityTextMyBikesLoadingBikes" translate="yes" xml:space="preserve">
<source>Loading reserved/ booked bikes...</source>
<target state="translated">Lade meine Räder...</target>
<source>Loading reserved/rented bikes...</source>
<target state="translated">Lade reservierte/gemietete Räder...</target>
</trans-unit>
<trans-unit id="ActivityTextSearchBikes" translate="yes" xml:space="preserve">
<source>Searching locks...</source>
@ -159,40 +161,40 @@
<target state="translated">Lade Stationen und Räder...</target>
</trans-unit>
<trans-unit id="ErrorReturnBikeNotAtStationMessage" translate="yes" xml:space="preserve">
<source>Returning bike outside of station is not possible. Distance to station {0} is {1} m.</source>
<target state="translated">Rückgabe ausserhalb von Station nicht möglich. Entfernung zur Station {0} ist {1} m.</target>
<source>End rental outside of station is not possible. Distance to station {0} is {1} m.</source>
<target state="translated">Rückgabe außerhalb einer Station nicht möglich. Entfernung zur nächsten Station {0} beträgt {1} m.</target>
</trans-unit>
<trans-unit id="ErrorReturnBikeTitle" translate="yes" xml:space="preserve">
<source>Error returning bike!</source>
<target state="translated">Fehler bei Radrückgabe!</target>
<source>Error at ending rental!</source>
<target state="translated">Fehler beim Beenden der Miete!</target>
</trans-unit>
<trans-unit id="ErrorReturnBikeLockClosedNoGPSMessage" translate="yes" xml:space="preserve">
<source>Returning bike at an unknown location is not possible.
Bike can be returned if
<source>End rental at an unknown location is not possible.
Rental can be ended if
- location information is available when closing lock
- bike is in reach and location information is available when pressing button "Return bike"</source>
<target state="translated">Fahrradrückgabe an unbekanntem Standort nicht möglich.
Eine Radrückgabe ist möglich, wenn
- beim Schliessen des Schlosses Standortinformation verfügbar ist
- beim Drücken von "Rad zurückgeben" das Rad in Reichweite ist und Standortinformation verfügbar ist.</target>
- bike is in reach and location information is available when pressing button "End rental"</source>
<target state="translated">Beenden der Miete an unbekanntem Standort nicht möglich.
Ein Mietende ist möglich, wenn
- beim Schließen des Schlosses Standortinformation verfügbar ist
- beim Drücken von "Miete beenden" das Rad in Reichweite ist und Standortinformation verfügbar ist</target>
</trans-unit>
<trans-unit id="ErrorReturnBikeLockOpenNoGPSMessage" translate="yes" xml:space="preserve">
<source>Returning bike at an unknown location is not possible.
Bike can only be returned if bike is in reach and location information is available.</source>
<target state="translated">Fahrradrückgabe an unbekanntem Standort nicht möglich.
Eine Radrückgabe ist nur möglich, wenn das Rad in Reichweite ist und Standortinformation verfügbar ist.</target>
<source>End rental at an unknown location is not possible.
Rental can only be ended if bike is in reach and location information is available.</source>
<target state="translated">Beenden der Miete an unbekanntem Standort nicht möglich.
Mietende ist nur möglich, wenn das Rad in Reichweite ist und Standortinformation verfügbar ist.</target>
</trans-unit>
<trans-unit id="ErrorSupportmailCreateAttachment" translate="yes" xml:space="preserve">
<source>Attachment could not be created.</source>
<target state="translated">Mailanhang konnte nich erzeugt werden.</target>
<target state="translated">Anhang konnte nich erzeugt werden.</target>
</trans-unit>
<trans-unit id="ErrorSupportmailMailingFailed" translate="yes" xml:space="preserve">
<source>Opening mail app failed.</source>
<target state="translated">Mailapp konnte nicht geöffnet werden.</target>
<source>Opening mail app failed. Make sure you have a mail app installed on your mobile device!</source>
<target state="translated">Mailapp konnte nicht geöffnet werden. Stellen Sie sicher, dass auf Ihrem mobilen Gerät eine Mailapp installiert und eingerichtet ist!</target>
</trans-unit>
<trans-unit id="ErrorSupportmailPhoningFailed" translate="yes" xml:space="preserve">
<source>Opening phone app failed.</source>
<target state="translated">Telefonapp konnte nicht geöffnet werden.</target>
<source>Opening phone app failed. Make sure you have a phone app installed on your mobile device!</source>
<target state="translated">Telefonapp konnte nicht geöffnet werden. Stellen Sie sicher, dass auf Ihrem mobilen Gerät eine Telefonapp installiert ist!</target>
</trans-unit>
<trans-unit id="MessageAnswerOk" translate="yes" xml:space="preserve">
<source>OK</source>
@ -203,8 +205,8 @@ Eine Radrückgabe ist nur möglich, wenn das Rad in Reichweite ist und Standorti
<target state="translated">Fragen? Hinweise?</target>
</trans-unit>
<trans-unit id="MessageRateMail" translate="yes" xml:space="preserve">
<source>Are you enjoying the {0}-App?</source>
<target state="translated">Gefällt die {0}-App?</target>
<source>Are you enjoying the {0}-app?</source>
<target state="translated">Gefällt Ihnen die {0}-App?</target>
</trans-unit>
<trans-unit id="MessageWaring" translate="yes" xml:space="preserve">
<source>Warning</source>
@ -221,10 +223,10 @@ Eine Radrückgabe ist nur möglich, wenn das Rad in Reichweite ist und Standorti
<trans-unit id="QuestionSupportmailAttachment" translate="yes" xml:space="preserve">
<source>I hereby consent to the transmission of my log file.
The log file contains your app usage data as well as system information. The data will only be used for diagnostic purposes or to improve the app.</source>
The log file contains your app usage data as well as system information. The data will only be used for diagnostic purposes or to improve the app and then deleted.</source>
<target state="translated">Hiermit stimme ich der Übermittlung meiner Protokolldatei zu.
Die Protokolldatei enthält Ihre App-Nutzungsdaten sowie Systeminformationen. Die Daten werden ausschließlich für Diagnosezwecke bzw. Verbesserung der App verwendet.</target>
Die Protokolldatei enthält Ihre App-Nutzungsdaten sowie Systeminformationen. Die Daten werden ausschließlich für Diagnosezwecke bzw. Verbesserung der App verwendet und werden anschließend gelöscht.</target>
</trans-unit>
<trans-unit id="QuestionTitle" translate="yes" xml:space="preserve">
<source>Question</source>
@ -232,9 +234,9 @@ Die Protokolldatei enthält Ihre App-Nutzungsdaten sowie Systeminformationen. Di
</trans-unit>
<trans-unit id="MessageMapPageErrorAuthcookieUndefined" translate="yes" xml:space="preserve">
<source>Session has expired.
Please login to app once again.</source>
Please log in again.</source>
<target state="translated">Sitzung ist abgelaufen.
Bitte erneut in App anmelden.</target>
Bitte melden Sie sich erneut an.</target>
</trans-unit>
<trans-unit id="StatusTextReservationExpiredCodeMaxReservationTime" translate="yes" xml:space="preserve">
<source>Code {0}, max. reservation time of {1} min. expired.</source>
@ -273,7 +275,7 @@ Bitte erneut in App anmelden.</target>
</trans-unit>
<trans-unit id="StatusTextAvailable" translate="yes" xml:space="preserve">
<source>Available.</source>
<target state="translated">Frei.</target>
<target state="translated">Verfügbar.</target>
</trans-unit>
<trans-unit id="StatusTextBookedCodeLocationSince" translate="yes" xml:space="preserve">
<source>Code {0}, location {1}, rented since {2}.</source>
@ -304,8 +306,9 @@ Bitte erneut in App anmelden.</target>
<target state="translated">Passwort vergessen</target>
</trans-unit>
<trans-unit id="ActionLoginRegister" translate="yes" xml:space="preserve">
<source>Register</source>
<target state="translated">Registrieren</target>
<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>
</trans-unit>
<trans-unit id="MarkingLoginEmailAddressLabel" translate="yes" xml:space="preserve">
<source>E-mail</source>
@ -316,8 +319,8 @@ Bitte erneut in App anmelden.</target>
<target state="translated">E-Mail</target>
</trans-unit>
<trans-unit id="MarkingLoginPasswordLabel" translate="yes" xml:space="preserve">
<source>At least 8 characters</source>
<target state="translated">Mindestens 8 Zeichen</target>
<source>At least eight characters</source>
<target state="translated">Mindestens acht Zeichen</target>
</trans-unit>
<trans-unit id="MarkingLoginPasswordPlaceholder" translate="yes" xml:space="preserve">
<source>Password</source>
@ -354,11 +357,11 @@ Bitte erneut in App anmelden.</target>
</trans-unit>
<trans-unit id="MessageLoginRecoverPassword" translate="yes" xml:space="preserve">
<source>Please connect to Internet to recover the password.</source>
<target state="translated">Bitte mit dem Internet verbinden zum Wiederherstellen des Passworts.</target>
<target state="translated">Zur Wiederherstellung des Passworts bitte mit dem Internet verbinden.</target>
</trans-unit>
<trans-unit id="MessageLoginRegisterNoNet" translate="yes" xml:space="preserve">
<source>Please connect to Internet to register.</source>
<target state="translated">Bitte mit dem Internet verbinden zum Registrieren.</target>
<target state="translated">Zur Registrierung bitte mit dem Internet verbinden.</target>
</trans-unit>
<trans-unit id="MessageTitleHint" translate="yes" xml:space="preserve">
<source>Hint</source>
@ -366,7 +369,7 @@ Bitte erneut in App anmelden.</target>
</trans-unit>
<trans-unit id="ErrorOpenLockStillClosedMessage" translate="yes" xml:space="preserve">
<source>After try to open lock state closed is reported.</source>
<target state="translated">Nach Versuch Schloss zu öffnen wird Status geschlossen zurückgemeldet.</target>
<target state="translated">Nach Versuch das Schloss zu öffnen, wird Status "geschlossen" zurückgemeldet.</target>
</trans-unit>
<trans-unit id="ErrorOpenLockOutOfReachMessage" translate="yes" xml:space="preserve">
<source>Lock cannot be opened until bike is near.</source>
@ -374,13 +377,13 @@ Bitte erneut in App anmelden.</target>
</trans-unit>
<trans-unit id="ErrorCloseLockOutOfReachMessage" translate="yes" xml:space="preserve">
<source>Lock cannot be closed until bike is near.</source>
<target state="translated">Schloss kann erst geschlossen werden, wenn das Rad in der Nähe ist. </target>
<target state="translated">Schloss kann erst geschlossen werden, wenn Rad in der Nähe ist. </target>
</trans-unit>
<trans-unit id="ErrorCloseLockOutOfReachStateReservedMessage" translate="yes" xml:space="preserve">
<source>Lock cannot be closed until bike is near.
Please try again to close bike or report bike to support!</source>
<target state="translated">Schloss kann erst geschlossen werden, wenn das Rad in der Nähe ist.
Bitte Schließen nochmals versuchen oder Rad dem Support melden!</target>
Please try again to close bike or report bike to operator!</source>
<target state="translated">Schloss kann erst geschlossen werden, wenn Rad in der Nähe ist.
Bitte Schließen nochmals versuchen oder Rad dem Betreiber melden!</target>
</trans-unit>
<trans-unit id="ErrorCloseLockTitle" translate="yes" xml:space="preserve">
<source>Lock can not be closed!</source>
@ -388,26 +391,26 @@ Bitte Schließen nochmals versuchen oder Rad dem Support melden!</target>
</trans-unit>
<trans-unit id="ErrorCloseLockStillOpenMessage" translate="yes" xml:space="preserve">
<source>After try to close lock state open is reported.</source>
<target state="translated">Nach Versuch Schloss zu schließen wird Status geöffnet zurückgemeldet.</target>
<target state="translated">Nach Versuch Schloss zu schließen, wird Status "offen" zurückgemeldet.</target>
</trans-unit>
<trans-unit id="ErrorCloseLockUnexpectedStateMessage" translate="yes" xml:space="preserve">
<source>Lock reports state "{0}".</source>
<target state="translated">Schloss meldet Status "{0}".</target>
</trans-unit>
<trans-unit id="ErrorCloseLockUnkErrorMessage" translate="yes" xml:space="preserve">
<source>Please try to lock again or report bike to support!
<source>Please try to lock again or report bike to operator!
{0}</source>
<target state="translated">Bitte schließen nochmals versuchen oder Rad dem Support melden!
<target state="translated">Bitte Schließen nochmals versuchen oder Rad dem Betreiber melden!
{0}</target>
</trans-unit>
<trans-unit id="MessageBikesManagementLocationPermission" translate="yes" xml:space="preserve">
<source>Please allow location sharing so that bike lock/locks can be managed.</source>
<target state="translated">Bitte Standortfreigabe erlauben, damit Fahrradschloss/ Schlösser verwaltet werden können.</target>
<target state="translated">Bitte Standortfreigabe erlauben, damit Schloss/-schlösser verwaltet werden können.</target>
</trans-unit>
<trans-unit id="MessageBikesManagementLocationPermissionOpenDialog" translate="yes" xml:space="preserve">
<source>Please allow location sharing so that bike lock/locks can be managed.
Open sharing dialog?</source>
<target state="translated">Bitte Standortfreigabe erlauben, damit Fahrradschloss/ Schlösser verwaltet werden können.
<target state="translated">Bitte Standortfreigabe erlauben, damit Radschloss/-schlösser verwaltet werden können.
Freigabedialog öffen?</target>
</trans-unit>
<trans-unit id="MessageCenterMapLocationPermissionOpenDialog" translate="yes" xml:space="preserve">
@ -418,7 +421,7 @@ Freigabedialog öffen?</target>
</trans-unit>
<trans-unit id="MessageBikesManagementLocationActivation" translate="yes" xml:space="preserve">
<source>Please activate location so that bike lock can be found!</source>
<target state="translated">Bitte Standort aktivieren, damit Fahrradschloss gefunden werden kann!</target>
<target state="translated">Bitte Standort aktivieren, damit Schloss gefunden werden kann!</target>
</trans-unit>
<trans-unit id="MessageAnswerNo" translate="yes" xml:space="preserve">
<source>No</source>
@ -430,7 +433,7 @@ Freigabedialog öffen?</target>
</trans-unit>
<trans-unit id="MessageBikesManagementBluetoothActivation" translate="yes" xml:space="preserve">
<source>Please enable Bluetooth to manage bike lock/locks.</source>
<target state="translated">Bitte Bluetooth aktivieren, damit Fahrradschloss/ Schlösser verwaltet werden können.</target>
<target state="translated">Bitte Bluetooth aktivieren, damit Schloss/-schlösser verwaltet werden können.</target>
</trans-unit>
<trans-unit id="ActionSearchLock" translate="yes" xml:space="preserve">
<source>Search lock</source>
@ -442,11 +445,11 @@ Freigabedialog öffen?</target>
</trans-unit>
<trans-unit id="ActivityTextOpeningLock" translate="yes" xml:space="preserve">
<source><bpt id="1">&lt;h4&gt;</bpt><bpt id="2">&lt;b&gt;</bpt>Lock is opening.&lt;br/&gt;Please wait until it is completely open.<ept id="2">&lt;/b&gt;</ept><ept id="1">&lt;/h4&gt;</ept></source>
<target state="translated"><bpt id="1">&lt;h4&gt;</bpt><bpt id="2">&lt;b&gt;</bpt>Schloss öffnet.&lt;br/&gt;Bitte warten Sie bis es komplett geöffnet ist.<ept id="2">&lt;/b&gt;</ept><ept id="1">&lt;/h4&gt;</ept></target>
<target state="translated"><bpt id="1">&lt;h4&gt;</bpt><bpt id="2">&lt;b&gt;</bpt>Schloss öffnet.&lt;br/&gt;Bitte warten Sie, bis es komplett geöffnet ist.<ept id="2">&lt;/b&gt;</ept><ept id="1">&lt;/h4&gt;</ept></target>
</trans-unit>
<trans-unit id="ActivityTextStartingUpdater" translate="yes" xml:space="preserve">
<source>Updating...</source>
<target state="translated">Starte Aktualisierung...</target>
<target state="translated">Aktualisiere...</target>
</trans-unit>
<trans-unit id="ActivityTextStartingUpdatingLockingState" translate="yes" xml:space="preserve">
<source>Updating lock state...</source>
@ -454,23 +457,23 @@ Freigabedialog öffen?</target>
</trans-unit>
<trans-unit id="ActivityTextReadingChargingLevel" translate="yes" xml:space="preserve">
<source>Reading charging level...</source>
<target state="translated">Lese Akkustatus...</target>
<target state="translated">Lese Akkustand...</target>
</trans-unit>
<trans-unit id="ActivityTextErrorStatusUpdateingLockstate" translate="yes" xml:space="preserve">
<source>Status error on updating lock state.</source>
<target state="translated">Statusfehler beim Aktualisieren des Schlossstatusses.</target>
<target state="translated">Statusfehler beim Aktualisieren des Schlossstatus.</target>
</trans-unit>
<trans-unit id="ActivityTextErrorConnectionUpdateingLockstate" translate="yes" xml:space="preserve">
<source>Connection error on updating locking status.</source>
<target state="translated">Verbingungsfehler beim Aktualisieren des Schlossstatusses.</target>
<target state="translated">Verbingungsfehler beim Aktualisieren des Schlossstatus.</target>
</trans-unit>
<trans-unit id="ActivityTextErrorNoWebUpdateingLockstate" translate="yes" xml:space="preserve">
<source>No web error on updating locking status.</source>
<target state="translated">Kein Netz beim Aktualisieren des Schlossstatusses.</target>
<source>Internet must be available for updating lock status. Please establish an Internet connection!</source>
<target state="translated">Um den Schlossstatus zu aktualisieren, wird Internet benötigt. Bitte stellen Sie eine Internetverbindung her!</target>
</trans-unit>
<trans-unit id="ActivityTextClosingLock" translate="yes" xml:space="preserve">
<source><bpt id="1">&lt;h4&gt;</bpt><bpt id="2">&lt;b&gt;</bpt>Lock is closing.&lt;br/&gt;Please wait until it is completely closed.<ept id="2">&lt;/b&gt;</ept><ept id="1">&lt;/h4&gt;</ept></source>
<target state="translated"><bpt id="1">&lt;h4&gt;</bpt><bpt id="2">&lt;b&gt;</bpt>Schloss schließt.&lt;br/&gt;Bitte warten Sie bis es komplett geschlossen ist.<ept id="2">&lt;/b&gt;</ept><ept id="1">&lt;/h4&gt;</ept></target>
<target state="translated"><bpt id="1">&lt;h4&gt;</bpt><bpt id="2">&lt;b&gt;</bpt>Schloss schließt.&lt;br/&gt;Bitte warten Sie, bis es komplett geschlossen ist.<ept id="2">&lt;/b&gt;</ept><ept id="1">&lt;/h4&gt;</ept></target>
</trans-unit>
<trans-unit id="ChangeLog3_0_203" translate="yes" xml:space="preserve">
<source>Updated to latest lock firmware.</source>
@ -502,11 +505,11 @@ Zielplatform Android 11.</target>
</trans-unit>
<trans-unit id="ActivityTextErrorReadingChargingLevelGeneral" translate="yes" xml:space="preserve">
<source>Battery status cannot be read.</source>
<target state="translated">Akkustatus kann nicht gelesen werden.</target>
<target state="translated">Akkustand kann nicht gelesen werden.</target>
</trans-unit>
<trans-unit id="ActivityTextErrorReadingChargingLevelOutOfReach" translate="yes" xml:space="preserve">
<source>Battery status can only be read when bike is nearby.</source>
<target state="translated">Akkustatus kann erst gelesen werden, wenn Rad in der Nähe ist.</target>
<target state="translated">Akkuladestand kann erst gelesen werden, wenn Rad in der Nähe ist.</target>
</trans-unit>
<trans-unit id="ActivityTextRentingBike" translate="yes" xml:space="preserve">
<source>Renting bike...</source>
@ -521,12 +524,12 @@ Zielplatform Android 11.</target>
<target state="translated">Fehler beim Mieten des Rads!</target>
</trans-unit>
<trans-unit id="MessageRentingBikeErrorTooManyReservationsRentals" translate="yes" xml:space="preserve">
<source>A rental of bike {0} was rejected because the maximum allowed number of {1} reservations/ rentals had already been made.</source>
<target state="translated">Eine Miete des Rads {0} wurde abgelehnt, weil die maximal erlaubte Anzahl von {1} Reservierungen/ Buchungen bereits getätigt wurden.</target>
<source>A rental of bike {0} was rejected because the maximum allowed number of {1} reservations/rentals had already been made.</source>
<target state="translated">Eine Miete des Rads {0} wurde abgelehnt, weil die maximal erlaubte Anzahl von {1} Reservierungen/Mieten bereits getätigt wurden.</target>
</trans-unit>
<trans-unit id="MessageReservationBikeErrorTooManyReservationsRentals" translate="yes" xml:space="preserve">
<source>A reservation of bike {0} was rejected because the maximum allowed number of {1} reservations/ rentals had already been made.</source>
<target state="translated">Eine Reservierung des Rads {0} wurde abgelehnt, weil die maximal erlaubte Anzahl von {1} Reservierungen/ Buchungen bereits getätigt wurden.</target>
<source>A reservation of bike {0} was rejected because the maximum allowed number of {1} reservations/rentals had already been made.</source>
<target state="translated">Eine Reservierung des Rads {0} wurde abgelehnt, weil die maximal erlaubte Anzahl von {1} Reservierungen/Mieten bereits getätigt wurden.</target>
</trans-unit>
<trans-unit id="MessageErrorLockIsClosedThreeLines" translate="yes" xml:space="preserve">
<source>Attention: Lock is closed!
@ -543,20 +546,20 @@ Zielplatform Android 11.</target>
{0}</target>
</trans-unit>
<trans-unit id="ExceptionTextRentingBikeFailedGeneral" translate="yes" xml:space="preserve">
<source>The rental of bike No. {0} has failed.</source>
<target state="translated">Die Miete des Fahrads Nr. {0} ist fehlgeschlagen.</target>
<source>The rental of bike {0} has failed.</source>
<target state="translated">Die Miete des Rads {0} ist fehlgeschlagen.</target>
</trans-unit>
<trans-unit id="ExceptionTextRentingBikeFailedUnavailalbe" translate="yes" xml:space="preserve">
<source>The rental of bike No. {0} has failed, the bike is currently unavailable.{1}</source>
<target state="translated">Die Miete des Rads Nr. {0} ist fehlgeschlagen, das Rad ist momentan nicht erreichbar.{1}</target>
<source>The rental of bike {0} has failed, the bike is currently unavailable. {1}</source>
<target state="translated">Die Miete des Rads {0} ist fehlgeschlagen, das Rad ist momentan nicht erreichbar.{1}</target>
</trans-unit>
<trans-unit id="ExceptionTextReservationBikeFailedGeneral" translate="yes" xml:space="preserve">
<source>The reservation of bike no. {0} has failed.</source>
<target state="translated">Die Reservierung des Fahrads Nr. {0} ist fehlgeschlagen.</target>
<source>The reservation of bike {0} has failed.</source>
<target state="translated">Die Reservierung des Rads {0} ist fehlgeschlagen.</target>
</trans-unit>
<trans-unit id="ExceptionTextReservationBikeFailedUnavailalbe" translate="yes" xml:space="preserve">
<source>The reservation of bike No. {0} has failed, the bike is currently unavailable.{1}</source>
<target state="translated">Die Reservierung des Rads Nr. {0} ist fehlgeschlagen, das Rad ist momentan nicht erreichbar.{1}</target>
<source>The reservation of bike {0} has failed, the bike is currently unavailable. {1}</source>
<target state="translated">Die Reservierung des Rads {0} ist fehlgeschlagen, das Rad ist momentan nicht erreichbar.{1}</target>
</trans-unit>
<trans-unit id="ChangeLog3_0_208" translate="yes" xml:space="preserve">
<source>Minor fixes.</source>
@ -575,8 +578,8 @@ Zielplatform Android 11.</target>
Bike should always be disconnected when not reserved or rented.
Please restart app in order to get bike info.</source>
<target state="translated">Ungülitiger Status von Rad {0} erkannt.
Ein nicht reserviertes oder gemietetes Rad sollte immer getrennt sein .
Bitte App neu starten um Rad Infos zu bekommen.</target>
Ein nicht reserviertes oder gemietetes Rad sollte immer getrennt sein.
Bitte App neu starten, um Radinfos zu bekommen.</target>
</trans-unit>
<trans-unit id="MarkingBikeInfoErrorStateUnknownDetected" translate="yes" xml:space="preserve">
<source>Unknown status for bike {0} detected.</source>
@ -590,7 +593,7 @@ Bitte App neu starten um Rad Infos zu bekommen.</target>
</trans-unit>
<trans-unit id="QuestionCancelReservation" translate="yes" xml:space="preserve">
<source>Cancel reservation for bike {0}?</source>
<target state="translated">Reservierung für Fahrrad {0} aufheben?</target>
<target state="translated">Reservierung für Rad {0} aufheben?</target>
</trans-unit>
<trans-unit id="ChangeLog3_0_209" translate="yes" xml:space="preserve">
<source>Minor fix: Bikes are disconnected as soon as becoming disposable.</source>
@ -598,7 +601,7 @@ Bitte App neu starten um Rad Infos zu bekommen.</target>
</trans-unit>
<trans-unit id="QuestionReserveBike" translate="yes" xml:space="preserve">
<source>Reserve bike {0} free of charge for {1} min?</source>
<target state="translated">Fahrrad {0} kostenlos für {1} Min. reservieren?</target>
<target state="translated">Rad {0} kostenlos für {1} Min. reservieren?</target>
</trans-unit>
<trans-unit id="ActivityTextErrorDeserializationException" translate="yes" xml:space="preserve">
<source>Connection error: Deserialization failed.</source>
@ -625,16 +628,17 @@ Bitte App neu starten um Rad Infos zu bekommen.</target>
<target state="translated">Abo-Preis</target>
</trans-unit>
<trans-unit id="MessageBikesManagementTariffDescriptionFeeEuroPerHour" translate="yes" xml:space="preserve">
<source>Rental fees</source>
<target state="translated">Mietgebühren</target>
<source>Rental charges</source>
<target state="translated">Mietkosten</target>
</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. fee</source>
<target state="translated">Max. Gebühr</target>
<source>Max. charges</source>
<target state="needs-review-translation">Max. Gebühr</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">
<source>€/hour</source>
@ -698,9 +702,9 @@ Bitte App neu starten um Rad Infos zu bekommen.</target>
</trans-unit>
<trans-unit id="MessageCopriVersionIsOutdated" translate="yes" xml:space="preserve">
<source>This version of the {0} App is not compatible with server detected.
Please contact the support for help.</source>
Please contact operator for help.</source>
<target state="translated">Diese Version der {0} App ist nicht kompatibel mit dem erkannten Server.
Bitte kontaktieren sie den Support!</target>
Bitte kontaktieren sie den Betreiber!</target>
</trans-unit>
<trans-unit id="ChangeLog3_0_224" translate="yes" xml:space="preserve">
<source>Updated for latest server version.</source>
@ -721,11 +725,12 @@ Bitte kontaktieren sie den Support!</target>
</trans-unit>
<trans-unit id="ActivityTextErrorWebExceptionGeneralError" translate="yes" xml:space="preserve">
<source>Connection error. Status code: {0}.</source>
<target state="translated">Verbindungsfehler. Status statucode: {0}.</target>
<target state="translated">Verbindungsfehler. Statuscode: {0}.</target>
</trans-unit>
<trans-unit id="ChangeLog3_0_227" translate="yes" xml:space="preserve">
<source>Feedback dialog added which is shown after returning bike.</source>
<target state="translated">Seite zur Eingabe von Rückmeldungen hinzugefügt, der nach Rückgabe eines Rads angezeigt wird.</target>
<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>
<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">
<source>Offline.</source>
@ -733,7 +738,7 @@ Bitte kontaktieren sie den Support!</target>
</trans-unit>
<trans-unit id="ActivityTextException" translate="yes" xml:space="preserve">
<source>Cache used.</source>
<target state="translated">Cache Daten.</target>
<target state="translated">Cache genutzt.</target>
</trans-unit>
<trans-unit id="ErrorReturnSubmitFeedbackMessage" translate="yes" xml:space="preserve">
<source>Your feedback could not be send to server successfully.</source>
@ -767,7 +772,7 @@ Fehlerhandling verbessert.</target>
</trans-unit>
<trans-unit id="ErrorOpenLockTitle" translate="yes" xml:space="preserve">
<source>Error while opening lock!</source>
<target state="translated">Fehler beim Schloss Öffnen!</target>
<target state="translated">Fehler beim Öffnen des Schlosses!</target>
</trans-unit>
<trans-unit id="ChangeLog3_0_236" translate="yes" xml:space="preserve">
<source>Stations names instead descriptions shown on page title.
@ -778,8 +783,9 @@ Fehlermeldung beim Öffnen von Schloss verbessert.
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 returning bike.</source>
<target state="translated">Hard- und software information werden an Backend übermittelt bei Radrückgabe.</target>
<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>
<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">
<source>Bugfix: Bike description is displayed correctly again.</source>
@ -807,7 +813,7 @@ Layout Anzeige Radnamen und nummern verbessert.</target>
</trans-unit>
<trans-unit id="MarkingLoginRequiredToRerserve" translate="yes" xml:space="preserve">
<source>Please login to reserve bikes! Tap <bpt id="1">&lt;font color="blue"&gt;</bpt><bpt id="2">&lt;u&gt;</bpt>here<ept id="2">&lt;/u&gt;</ept><ept id="1">&lt;/font&gt;</ept> to switch to login page.</source>
<target state="translated">Bitte Anmelden um Fahrräder zu reservieren! <bpt id="1">&lt;font color="blue"&gt;</bpt><bpt id="2">&lt;u&gt;</bpt>Hier<ept id="2">&lt;/u&gt;</ept><ept id="1">&lt;/font&gt;</ept> tippen, um auf Anmeldeseite zu wechseln.</target>
<target state="translated">Bitte Anmelden, um Räder zu reservieren! <bpt id="1">&lt;font color="blue"&gt;</bpt><bpt id="2">&lt;u&gt;</bpt>Hier<ept id="2">&lt;/u&gt;</ept><ept id="1">&lt;/font&gt;</ept> tippen, um auf Anmeldeseite zu wechseln.</target>
</trans-unit>
<trans-unit id="MarkingContactNoStationInfoAvailableNoButton" translate="yes" xml:space="preserve">
<source>Contact operator?</source>
@ -819,7 +825,7 @@ Layout Anzeige Radnamen und nummern verbessert.</target>
</trans-unit>
<trans-unit id="MarkingSelectStationPage" translate="yes" xml:space="preserve">
<source>Select Station</source>
<target state="translated">Station Auswählen</target>
<target state="translated">Station auswählen</target>
</trans-unit>
<trans-unit id="ActionSelectStation" translate="yes" xml:space="preserve">
<source>Select station</source>
@ -842,8 +848,8 @@ Layout Anzeige Radnamen und nummern verbessert.</target>
<target state="translated">Betreiber: {0}.</target>
</trans-unit>
<trans-unit id="MarkingBikeSharingOperatorNoOperatorInfoAvailable" translate="yes" xml:space="preserve">
<source>Contact Operator.</source>
<target state="translated">Betreiber Kontaktieren.</target>
<source>Contact operator.</source>
<target state="translated">Betreiber kontaktieren.</target>
</trans-unit>
<trans-unit id="MiniSurveyAskForAnswer" translate="yes" xml:space="preserve">
<source>Select an answer please.</source>
@ -868,16 +874,18 @@ Kleinere Verbesserungen.</target>
<target state="translated">Abfrage Standort...</target>
</trans-unit>
<trans-unit id="MessageErrorQueryLocationTitle" translate="yes" xml:space="preserve">
<source>Error Query Location!</source>
<target state="translated">Fehler bei Standortabfrage!</target>
<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>
</trans-unit>
<trans-unit id="MessageErrorQueryLocationMessage" translate="yes" xml:space="preserve">
<source>Closing the lock and ending the rental is not possible.</source>
<target state="translated">Schloss schließen und Miete beenden ist nicht möglich.</target>
</trans-unit>
<trans-unit id="MessageErrorQueryLocationStartTitle" translate="yes" xml:space="preserve">
<source>Error Start Query Location!</source>
<target state="translated">Fehler beim Start der Standortabfrage!</target>
<source>Error start query location!</source>
<target state="needs-review-translation">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">
<source>No location info available. Activate your device's location services.</source>
@ -896,29 +904,29 @@ Kleinere Verbesserungen.</target>
<target state="translated">Start Standortabfrage...</target>
</trans-unit>
<trans-unit id="QuestionCloseLockAndReturnBike" translate="yes" xml:space="preserve">
<source>Close lock and return bike {0}?</source>
<target state="translated">Fahrrad {0} abschließen und zurückgeben?</target>
<source>Close lock and end rental of bike {0}?</source>
<target state="translated">Rad {0} abschließen und Miete beenden?</target>
</trans-unit>
<trans-unit id="QuestionReturnBike" translate="yes" xml:space="preserve">
<source>Return bike {0}?</source>
<target state="translated">Fahrrad {0} zurückgeben?
<source>End rental of bike {0}?</source>
<target state="translated">Miete von Rad {0} beenden?
</target>
</trans-unit>
<trans-unit id="ActivityTextReturningBike" translate="yes" xml:space="preserve">
<source>Returning bike...</source>
<target state="translated">Gebe Rad zurück...</target>
<source>Ending rental...</source>
<target state="translated">Beende Miete...</target>
</trans-unit>
<trans-unit id="QuestionOpenLockAndBookBike" translate="yes" xml:space="preserve">
<source>Rent bike {0} and open lock?</source>
<target state="translated">Fahrrad {0} mieten und Schloss öffnen?</target>
<target state="translated">Rad {0} mieten und Schloss öffnen?</target>
</trans-unit>
<trans-unit id="ErrorReturnBikeNoWebMessage" translate="yes" xml:space="preserve">
<source>Internet must be available when returning the bike.</source>
<target state="translated">Internet muss erreichbar sein beim Zurückgeben des Rads.</target>
<source>Internet must be available when ending rental. Please establish an Internet connection!</source>
<target state="translated">Um die Miete zu beenden, wird Internet benötigt. Bitte stellen Sie eine Internetverbindung her!</target>
</trans-unit>
<trans-unit id="ErrorReturnBikeNoWebTitle" translate="yes" xml:space="preserve">
<source>Connection error when returning the bike!</source>
<target state="translated">Verbingungsfehler beim Zurückgeben des Rads!</target>
<source>Connection error when ending rental.</source>
<target state="translated">Verbingungsfehler beim Beenden der Miete!</target>
</trans-unit>
<trans-unit id="ChangeLog3_0_244" translate="yes" xml:space="preserve">
<source>Closing lock and returning bike speeded up.</source>
@ -981,18 +989,18 @@ Anzeige von Statusinformationen erweitert.
Fehlerbehebung: Supportmails können wieder verschickt werden.</target>
</trans-unit>
<trans-unit id="MessageMapPageErrorSwitch" translate="yes" xml:space="preserve">
<source>An error occurred switching from cargo bikes/ city bikes.
<source>An error occurred switching between cargo and city bikes.
{0}</source>
<target state="translated">Beim Umschalten zwischen Lasten-/ Stadträdern ist ein Fehler aufgetreten.
<target state="translated">Beim Umschalten zwischen Lasten- und Stadträdern ist ein Fehler aufgetreten.
{0}</target>
</trans-unit>
<trans-unit id="MessageErrorSelectBikeNoBikeFound" translate="yes" xml:space="preserve">
<source>No bike with id {0} found.</source>
<target state="translated">Kein Fahrrad mit Id {0} gefunden.</target>
<target state="translated">Kein Rad mit ID {0} gefunden.</target>
</trans-unit>
<trans-unit id="MessageErrorSelectBikeTitle" translate="yes" xml:space="preserve">
<source>Error Selecting Bike!</source>
<target state="translated">Fehler beim Rad Wählen!</target>
<target state="translated">Fehler beim Auswählen des Rads!</target>
</trans-unit>
<trans-unit id="ChangeLog3_0_277" translate="yes" xml:space="preserve">
<source>Bugfix: No more closing of app on Select Bike page.</source>
@ -1000,7 +1008,7 @@ Fehlerbehebung: Supportmails können wieder verschickt werden.</target>
</trans-unit>
<trans-unit id="ErrorBookedSearchMessageEscalationLevel1" translate="yes" xml:space="preserve">
<source>Your mobile device still does not connect to the bike lock. Please restart the app or even your mobile device and repeat the process.</source>
<target state="translated">Ihr mobiles Gerät verbindet sich immer noch nicht mit dem Fahrradschloss. Bitte starten Sie die App oder sogar Ihr mobiles Gerät neu und wiederholen Sie den Vorgang.</target>
<target state="translated">Ihr mobiles Gerät verbindet sich immer noch nicht mit dem Schloss. Bitte starten Sie die App oder sogar Ihr mobiles Gerät neu und wiederholen Sie den Vorgang.</target>
</trans-unit>
<trans-unit id="MessageAnswerCancel" translate="yes" xml:space="preserve">
<source>Cancel</source>
@ -1015,18 +1023,20 @@ Fehlerbehebung: Supportmails können wieder verschickt werden.</target>
<target state="translated">Fehler beim Verbinden mit Schloss!</target>
</trans-unit>
<trans-unit id="ErrorBookedSearchMessageEscalationLevel2" translate="yes" xml:space="preserve">
<source>Unfortunately, it is still not possible to establish a connection between your mobile device and the bike lock. Please contact customer support.
<source>It is still not possible to establish a connection between your mobile device and the bike lock. Please contact operator!
As a last resort, please close the lock by hand AND contact customer support so that they can terminate your chargeable rental. To do this:
1. close the app,
2. press the button at the top of the lock briefly and quickly release it as soon as it starts flashing,
3. wait until the lock is completely closed and remains closed.</source>
<target state="translated">Es kann leider weiterhin keine Verbindung zwischen Ihrem mobilen Gerät und dem Fahrradschloss aufgebaut werden. Bitte kontaktieren Sie den Kundensupport.
Alternative:
1. close app,
2. press the button at the top of the lock briefly and release it as soon as it starts flashing,
3. make sure that the lock is completely closed and remains closed.
4. send e-mail to operator (otherwise your chargeable rental will continue!): Problem description, Drop-off station.</source>
<target state="translated">Es kann weiterhin keine Verbindung zwischen Ihrem mobilen Gerät und dem Schloss aufgebaut werden. Rufen Sie den Betreiber an!
Als aller letzten Ausweg das Schloss bitte per Hand schließen UND den Kundensupport zu kontaktieren, damit dieser Ihre kostenpflichtige Miete beenden kann. Dazu:
Alternativ:
1. App schließen,
2. auf den Knopf oben am Schloss kurz drücken und schnell loslassen sobald bis dieser zu blinken beginnt,
3. warten, bis das Schloss vollständig geschlossen ist und geschlossen bleibt. </target>
2. auf den Knopf oben am Schloss kurz drücken und sofort loslassen, sobald Knopf zu blinken beginnt,
3. sicherstellen, dass das Schloss vollständig geschlossen ist und geschlossen bleibt.
4. E-Mail an Betreiber schicken (ansonsten läuft Ihre kostenpflichtige Miete weiter!): Problembeschreibung, Rad-ID, Abgabestation.</target>
</trans-unit>
<trans-unit id="ChangeLog3_0_278" translate="yes" xml:space="preserve">
<source>Hints added to ease closing of lock in case closing does not succeed on first try.</source>
@ -1050,19 +1060,19 @@ Als aller letzten Ausweg das Schloss bitte per Hand schließen UND den Kundensup
</trans-unit>
<trans-unit id="MessageErrorConnectTitle" translate="yes" xml:space="preserve">
<source>Error when connecting to lock!</source>
<target state="translated">Fehler bei Verbinden mit Schloss!</target>
<target state="translated">Fehler beim Verbinden mit Schloss!</target>
</trans-unit>
<trans-unit id="ErrorConnectLockGeneralErrorMessage" translate="yes" xml:space="preserve">
<source>Communication error during lock search.</source>
<target state="translated">Kommunikationsfehler bei Schlosssuche.</target>
</trans-unit>
<trans-unit id="ErrorConnectLockRentedBikeNoWebMessage" translate="yes" xml:space="preserve">
<source>Internet must be reachable to connect to lock of rented bike.</source>
<target state="translated">Internet muss erreichbar sein um Verbindung mit Schloss für gemietetes Rad herzustellen.</target>
<source>Internet must be reachable to connect to lock of rented bike. Please establish an Internet connection!</source>
<target state="translated">Internet muss erreichbar sein, um Verbindung mit Schloss für gemietetes Rad herzustellen. Bitte stellen Sie eine Internetverbindung her!</target>
</trans-unit>
<trans-unit id="ErrorConnectLockReservedBikeNoWebMessage" translate="yes" xml:space="preserve">
<source>Internet must be reachable to connect to lock of reserved bike.</source>
<target state="translated">Internet muss erreichbar sein um Verbindung mit Schloss für reserviertes Rad herzustellen.</target>
<source>Internet must be reachable to connect to lock of reserved bike. Please establish an Internet connection!</source>
<target state="translated">Internet muss erreichbar sein, um Verbindung mit Schloss für reserviertes Rad herzustellen. Bitte stellen Sie eine Internetverbindung her!</target>
</trans-unit>
<trans-unit id="ErrorFindLockReservedBikeNoStausMessage" translate="yes" xml:space="preserve">
<source>Lock status of the reserved bike could not be determined.</source>
@ -1074,13 +1084,13 @@ Als aller letzten Ausweg das Schloss bitte per Hand schließen UND den Kundensup
</trans-unit>
<trans-unit id="ErrorFindLockLocationPermissionMissing" translate="yes" xml:space="preserve">
<source>Please grant location permissions, otherwise lock cannot be connected.</source>
<target state="translated">Bitte Standort-Zugriffsfreigabe erteilen, anderenfalls ist eine Verbindung mit dem Schloss nicht möglich.
<target state="translated">Bitte Standortfreigabe erteilen, anderenfalls ist eine Verbindung mit dem Schloss nicht möglich.
</target>
</trans-unit>
<trans-unit id="ErrorFindLockLocationOff" translate="yes" xml:space="preserve">
<source>Please turn Location on, otherwise lock cannot be connected.</source>
<target state="translated">Bitte Standortbestimmung aktivieren, anderenfalls ist eine Verbindung mit dem Schloss nicht möglich.</target>
<source>Please turn location services on, otherwise lock cannot be connected.</source>
<target state="translated">Bitte Standortdienste aktivieren, anderenfalls ist eine Verbindung mit dem Schloss nicht möglich.</target>
</trans-unit>
<trans-unit id="ChangeLog3_0_280" translate="yes" xml:space="preserve">
<source>Errormessages improved for szenarios when
@ -1094,7 +1104,7 @@ Als aller letzten Ausweg das Schloss bitte per Hand schließen UND den Kundensup
</trans-unit>
<trans-unit id="ErrorReservedSearchMessageEscalationLevel1" translate="yes" xml:space="preserve">
<source>Your mobile device still does not connect to the bike lock. Please restart the app or even your mobile device and repeat the process.</source>
<target state="translated">Ihr mobiles Gerät verbindet sich immer noch nicht mit dem Fahrradschloss. Bitte starten Sie die App oder sogar Ihr mobiles Gerät neu und wiederholen Sie den Vorgang.</target>
<target state="translated">Ihr mobiles Gerät verbindet sich weiterhin nicht mit dem Schloss. Bitte starten Sie die App oder sogar Ihr mobiles Gerät neu und wiederholen Sie den Vorgang.</target>
</trans-unit>
<trans-unit id="ChangeLog3_0_282" translate="yes" xml:space="preserve">
<source>Permission requests messages on iOS formulated in more detail.
@ -1104,7 +1114,7 @@ Hinweise, um das Verbinden Schlosses zu erleichtern, falls dies nicht beim erste
</trans-unit>
<trans-unit id="ExceptionTextSessionExpired" translate="yes" xml:space="preserve">
<source>The session has expired. Please register again.</source>
<target state="translated">Die Sitzung ist abgelaufen. Bitte neu anmelden.</target>
<target state="translated">Die Sitzung ist abgelaufen. Bitte melden Sie sich erneut an.</target>
</trans-unit>
<trans-unit id="ActivityTextAuthcookieNotDefinedException" translate="yes" xml:space="preserve">
<source>Auth. expired</source>
@ -1120,7 +1130,7 @@ Hinweise, um das Verbinden Schlosses zu erleichtern, falls dies nicht beim erste
</trans-unit>
<trans-unit id="MessageAccountPageManagePersonalData" translate="yes" xml:space="preserve">
<source>Manage personal data</source>
<target state="translated">Persönliche Daten Verwalten</target>
<target state="translated">Persönliche Daten verwalten</target>
</trans-unit>
<trans-unit id="ChangeLog3_0_285" translate="yes" xml:space="preserve">
<source>Framework updated.
@ -1129,12 +1139,12 @@ Activity indicator added account management pages and logging extended.</source>
Activity Indicator zu Konto-Verwaltungsseiten hinzugefügt und Logging erweitert.</target>
</trans-unit>
<trans-unit id="ActivityTextStartReturningBike" translate="yes" xml:space="preserve">
<source>Starting bike return...</source>
<target state="translated">Starte Rückgabe...</target>
<source>Starting end rental...</source>
<target state="translated">Starte Miete beenden...</target>
</trans-unit>
<trans-unit id="ExceptionTextWebConnectFailureException" translate="yes" xml:space="preserve">
<source>Is WIFI available/ mobile network available and mobile data activated / ... ?</source>
<target state="translated">Ist WLAN verfügbar/ Mobilfunknetz vefügbar und mobile Daten aktiviert / ... ?</target>
<source>Is WIFI/mobile network available and mobile data activated?</source>
<target state="translated">Ist WLAN/Mobilfunknetz vefügbar und mobile Daten aktiviert?</target>
</trans-unit>
<trans-unit id="ChangeLog3_0_289" translate="yes" xml:space="preserve">
<source>Flyout menu header improved.</source>
@ -1172,8 +1182,8 @@ Kleinere Fehlerbehebungen.
<target state="translated">Protokollierungsstufe</target>
</trans-unit>
<trans-unit id="MarkingShowHideBikesOfType" translate="yes" xml:space="preserve">
<source>Show/ hide</source>
<target state="translated">Ausblenden/ Einblenden</target>
<source>Show/hide</source>
<target state="translated">Ein-/Ausblenden</target>
</trans-unit>
<trans-unit id="MarkingVerboseErrorMessage" translate="yes" xml:space="preserve">
<source>Verbose error messages</source>
@ -1224,17 +1234,19 @@ Kleinere Fehlerbehebungen.
<target state="translated">Neues Schloss unterstützt.</target>
</trans-unit>
<trans-unit id="ActionGiveFeedback" translate="yes" xml:space="preserve">
<source>Give Feedback</source>
<target state="translated">Rückmeldung Geben</target>
<source>Give feedback</source>
<target state="translated">Rückmeldung geben</target>
</trans-unit>
<trans-unit id="ActionContactMailAppReleated" translate="yes" xml:space="preserve">
<source>Feedback about the App</source>
<target state="translated">Rückmeldung zur App</target>
<source>Feedback about the app</source>
<target state="needs-review-translation">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="translated">{0}-App Anfrage</target>
<source>{0}-app releated request</source>
<target state="needs-review-translation">{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>
<trans-unit id="MessageReservingBikeErrorConnectionTitle" translate="yes" xml:space="preserve">
<source>Connection error when reserving the bike!</source>
@ -1258,7 +1270,7 @@ Kleinere Fehlerbehebungen.
</trans-unit>
<trans-unit id="MessageOpeningLockErrorConnectionTitle" translate="yes" xml:space="preserve">
<source>Connection error when opening the lock!</source>
<target state="translated">Verbindungsfehler beim Schlossöffnen!</target>
<target state="translated">Verbindungsfehler beim Öffnen des Schlosses!</target>
</trans-unit>
<trans-unit id="ActivityTextSubmittingFeedback" translate="yes" xml:space="preserve">
<source>Submitting feedback...</source>
@ -1286,15 +1298,15 @@ Kleinere Fehlerbehebungen.
</trans-unit>
<trans-unit id="MarkingReturnBikeErrorDescriptionInputPlaceholder" translate="yes" xml:space="preserve">
<source>Please describe condition/defect here.</source>
<target state="translated">Bitte Zustand/ Defekt hier beschreiben.</target>
<target state="translated">Bitte Zustand/Defekt hier beschreiben.</target>
</trans-unit>
<trans-unit id="MarkingReturnBikeFeedbackInputPlaceholder" translate="yes" xml:space="preserve">
<source>Please enter feedback here if needed.</source>
<target state="translated">Bei Bedarf bitte hier Rückmeldung eingeben.</target>
</trans-unit>
<trans-unit id="MarkingReturnBikeMainMessage" translate="yes" xml:space="preserve">
<source>Bike successfully returned!</source>
<target state="translated">Fahrrad erfolgreich zurückgegeben!</target>
<source>Rental successfully ended!</source>
<target state="translated">Rad erfolgreich zurückgegeben!</target>
</trans-unit>
<trans-unit id="MarkingDriveBatteryTitel" translate="yes" xml:space="preserve">
<source>Current battery level:</source>
@ -1305,12 +1317,12 @@ Kleinere Fehlerbehebungen.
<target state="translated">Für Mein konrad Nutzer: Anzeige des Akkuladestands für E-Bikes und Abfrage des Ladestands nach Radrückgabe.</target>
</trans-unit>
<trans-unit id="StatusTextLowBatteryLevel" translate="yes" xml:space="preserve">
<source>The remaining power of the bike battery was low recently. Please check it on the bike display before riding. The bike can be returned within 5 minutes free of charge.</source>
<target state="translated">Die verbleibende Ladung des Fahrradakkus war zuletzt niedrig. Bitte überprüfen Sie diese vor der Fahrt auf dem Fahrraddisplay. Das Rad kann innerhalb 5 Minuten kostenlos zurückgegeben werden.</target>
<source>The remaining power of the bike battery was low recently. Please check it on the bike display before riding. The rental can be canceled within 5 minutes free of charge.</source>
<target state="translated">Die verbleibende Ladung des Fahrradakkus war zuletzt niedrig. Bitte überprüfen Sie diese vor der Fahrt auf dem Fahrraddisplay. Die Miete kann innerhalb 5 Minuten kostenlos abgebrochen werden.</target>
</trans-unit>
<trans-unit id="StatusTextCopriLock" translate="yes" xml:space="preserve">
<source>At pausing ride, you close the bike lock manually, not via the app. To end the chargeable rental, slide the bike into an authorized station and confirm the end of the rental in the app; the lock closes automatically.</source>
<target state="translated">Zur Fahrpause schließen Sie das Fahrradschloss manuell, nicht über die App. Zum Beenden der kostenpflichtigen Miete schieben Sie das Rad in eine zugelassene Station und bestätigen das Mietende in der App; das Schloss schließt automatisch.</target>
<target state="translated">Zur Fahrpause schließen Sie das Schloss manuell, nicht über die App. Zum Beenden der kostenpflichtigen Miete schieben Sie das Rad in eine zugelassene Station und bestätigen das Mietende in der App; das Schloss schließt automatisch.</target>
</trans-unit>
<trans-unit id="ChangeLog3_0_335" translate="yes" xml:space="preserve">
<source>Sharee.bike design improved.</source>
@ -1322,7 +1334,7 @@ Kleinere Fehlerbehebungen.
</trans-unit>
<trans-unit id="ChangeLog3_0_337_MK" translate="yes" xml:space="preserve">
<source>You will now be informed if the charge of the bike battery was last indicated as very low. To ensure the reliability of the battery level indicator in the app, please enter the current charge level in the app at the end of your ride with an e-bike.</source>
<target state="translated">Sie werden nun informiert, wenn die Ladung des Fahrradakkus zuletzt als sehr niedrig angegeben wurde. Um die Zuverlässigkeit der Akkustandanzeige in der App zu gewährleisten, geben Sie bitte am Ende Ihrer Fahrt mit einem E-Lastenrad den aktuellen Ladestand in die App ein.</target>
<target state="translated">Sie werden nun informiert, wenn die Ladung des Radakkus zuletzt als sehr niedrig angegeben wurde. Um die Zuverlässigkeit der Akkustandanzeige in der App zu gewährleisten, geben Sie bitte am Ende Ihrer Fahrt mit einem E-Lastenrad den aktuellen Ladestand in die App ein.</target>
</trans-unit>
<trans-unit id="ChangeLog3_0_337_SB" translate="yes" xml:space="preserve">
<source>The app has a new design! --- You are a beta tester? Give us helpful feedback anytime via Contact - Feedback about the App. Not a beta tester yet? Become one and get great new features before anyone else!</source>
@ -1374,7 +1386,7 @@ Außerdem: Kleine Grafiken lassen auf einen Blick erkennen um was für einen Rad
</trans-unit>
<trans-unit id="PlaceholderFindBike" translate="yes" xml:space="preserve">
<source>Enter bike number here</source>
<target state="translated">Fahrrad-Nummer hier eingeben</target>
<target state="translated">Rad-Nummer hier eingeben</target>
</trans-unit>
<trans-unit id="ChangeLog3_0_339_MK" translate="yes" xml:space="preserve">
<source>The cargo bikes from the suburbs now show their home station in their name. These bikes must be returned there!
@ -1518,11 +1530,11 @@ Probieren Sie es aus!</target>
</trans-unit>
<trans-unit id="MarkingBikesAtStationNoBikesAvailable" translate="yes" xml:space="preserve">
<source>There are currently no bicycles available at this station.</source>
<target state="translated">Momentan sind keine Fahrräder an dieser Station verfügbar.</target>
<target state="translated">Momentan sind keine Räder an dieser Station verfügbar.</target>
</trans-unit>
<trans-unit id="MarkingMyBikesNoBikesReservedRented" translate="yes" xml:space="preserve">
<source>There are currently no bicycles reserved/booked on user {0}.</source>
<target state="translated">Momentan sind keine Fahrräder auf Benutzer {0} reserviert/ gebucht.</target>
<source>There are currently no bikes reserved/rented by user {0}.</source>
<target state="translated">Momentan sind keine Räder von Nutzer {0} reserviert/gemietet.</target>
</trans-unit>
<trans-unit id="MessageTitleInformation" translate="yes" xml:space="preserve">
<source>Information</source>
@ -1533,16 +1545,17 @@ Probieren Sie es aus!</target>
<target state="translated">Kleine Verbesserungen.</target>
</trans-unit>
<trans-unit id="ErrorOpenLockBoldStatusIsUnknownMessage" translate="yes" xml:space="preserve">
<source>The lock could not be opened correctly. Please try again.
<source>The lock could not be opened correctly. Try again!
Attention! Your rental has already started.
If the lock still won't open, make sure the lock is closed and return the bike. Please report it to the support!</source>
If the lock still won't open, make sure the lock is closed and end rental.
Important: Send an email to the operator (otherwise your paid rental will continue!) with: Problem description, bike number, drop-off station.</source>
<target state="translated">Das Schloss konnte nicht korrekt geöffnet werden. Bitte versuchen Sie es erneut.
Achtung! Ihre Miete hat bereits begonnen.
Wenn sich das Schloss weiterhin nicht öffnen lässt, vergewissern Sie sich, dass das Schloss geschlossen ist und geben Sie das Rad zurück. Bitte melden Sie es dem Support!</target>
Wenn sich das Schloss weiterhin nicht öffnen lässt, vergewissern Sie sich, dass das Schloss geschlossen ist und geben Sie das Rad zurück.
Wichtig: Schicken Sie eine E-Mail an den Betreiber (ansonsten läuft Ihre kostenpflichtige Miete weiter!): Problembeschreibung, Radnummer, Abgabestation.</target>
</trans-unit>
<trans-unit id="ErrorOpenLockStillClosedTitle" translate="yes" xml:space="preserve">
<source>Lock can not be opened!</source>
@ -1553,8 +1566,9 @@ Wenn sich das Schloss weiterhin nicht öffnen lässt, vergewissern Sie sich, das
<target state="translated">Stellen Sie sicher, dass kein Hindernis das Öffnen des Schlosses verhindert und versuchen Sie es erneut.</target>
</trans-unit>
<trans-unit id="MarkingNoNetworkConnection" translate="yes" xml:space="preserve">
<source>Oops, there is no internet connection.</source>
<target state="translated">Ups, es ist keine Internetverbindung vorhanden.</target>
<source>Oops, there is no Internet connection.</source>
<target state="needs-review-translation">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">
<source>New functions:<bpt id="1">&lt;ul&gt;</bpt><bpt id="2">&lt;li&gt;</bpt>If your device is not connected to the Internet, this is now displayed at the top.<ept id="2">&lt;/li&gt;</ept><bpt id="3">&lt;li&gt;</bpt>You can now update your bike view by dragging from top to bottom. Especially useful after you reconnect to the Internet.<ept id="3">&lt;/li&gt;</ept><ept id="1">&lt;/ul&gt;</ept>
@ -1566,6 +1580,42 @@ Wenn sich das Schloss weiterhin nicht öffnen lässt, vergewissern Sie sich, das
<source>If you have reserved or rented a bike, this will now be shown to you as an icon on the map page. Clicking on it will take you directly to the 'My bikes' page. We have also made small design changes.</source>
<target state="translated">Wenn Sie ein Rad reserviert oder gemietet haben, wird dies Ihnen nun auf der Kartenseite als Symbol angezeigt. Ein Klick darauf führt Sie direkt zur Seite 'Meine Räder'. Wir haben außerdem kleine Designänderungen vorgenommen.</target>
</trans-unit>
<trans-unit id="ErrorReturnBikeLockClosedStartGetGPSExceptionMessage" translate="yes" xml:space="preserve">
<source>End rental at an unknown location is not possible.
Start getting geolocation failed.</source>
<target state="translated">Beenden der Miete an unbekanntem Standort is nicht möglich.
Fehler beim Start der Standortabfrage!</target>
</trans-unit>
<trans-unit id="ErrorReturnBikeLockClosedGetGPSExceptionMessage" translate="yes" xml:space="preserve">
<source>End rental at an unknown location is not possible.
Getting geolocation failed.</source>
<target state="translated">Beenden der Miete an unbekanntem Standort is nicht möglich.
Fehler bei der Standortabfrage!</target>
</trans-unit>
<trans-unit id="Error_ReturnBike_Station_Location_Message" translate="yes" xml:space="preserve">
<source>We could not assign the bike to any station. For this we need your location information while you are standing right next to the bike. Only then your rental can be terminated!
Approach the bike, turn on Bluetooth and Location services and try again.</source>
<target state="translated">Wir konnten das Rad keiner Station zuordnen. Dazu benötigen wir Ihre Standortinformationen, während Sie direkt neben dem Rad stehen. Nur dann kann Ihre Miete beendet werden!
Treten Sie an das Rad heran, schalten Sie Bluetooth und Standortdienste ein und versuchen Sie es erneut.</target>
</trans-unit>
<trans-unit id="ChangeLog_3_0_362_MK_SB" translate="yes" xml:space="preserve">
<source>Some terms have been standardized, e.g:&lt;br/&gt;
- what used to be called 'return bike' is now always called 'end rental'.&lt;br/&gt;
- The 'operator' is the group of people responsible for the bike fleet, who will be contacted if necessary.&lt;br/&gt;
&lt;br/&gt;
Also:&lt;br/&gt;
- Minor bug fixes&lt;br/&gt;
- Package updates</source>
<target state="translated">Einige Bezeichnungen wurden vereinheitlicht, z.B:&lt;br/&gt;
- was bisher unter 'Rad zurückgeben' lief, heißt nun immer 'Miete beenden'.&lt;br/&gt;
- der 'Betreiber' ist die für die Radflotte zuständige Personengruppe, zu der bei Bedarf Kontakt aufgenommen wird.&lt;br/&gt;
&lt;br/&gt;
Außerdem:&lt;br/&gt;
- Kleinere Fehlerbehebungen&lt;br/&gt;
- Paketaktualisierungen</target>
</trans-unit>
</group>
</body>
</file>

View file

@ -0,0 +1,36 @@
using System;
namespace TINK.Services.Geolocation
{
public class Geolocation : IGeolocation
{
private Geolocation() { }
public DateTimeOffset Timestamp { get; private set; }
public double Latitude { get; private set; }
public double Longitude { get; private set; }
public double? Accuracy { get; private set; }
public class Builder
{
public DateTimeOffset Timestamp { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
public double? Accuracy { get; set; }
public Geolocation Build()
=> new Geolocation() {
Timestamp = Timestamp,
Latitude = Latitude,
Longitude = Longitude,
Accuracy = Accuracy};
}
}
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Threading;
using System.Threading.Tasks;
using Serilog;
@ -7,7 +7,7 @@ using Xamarin.Essentials;
namespace TINK.Services.Geolocation
{
public abstract class GeolocationService : IGeolocation
public abstract class GeolocationService : IGeolocationService
{
/// <summary> Timeout for geolocation request operations.</summary>
private const int GEOLOCATIONREQUEST_TIMEOUT_MS = 5000;
@ -31,14 +31,14 @@ 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>
public async Task<Location> GetAsync(CancellationToken? cancellationToken = null, DateTime? timeStamp = null)
public async Task<IGeolocation> GetAsync(CancellationToken? cancellationToken = null, DateTime? timeStamp = null)
{
try
{
var request = new GeolocationRequest(Accuracy, TimeSpan.FromMilliseconds(GEOLOCATIONREQUEST_TIMEOUT_MS));
return cancellationToken.HasValue
? await Xamarin.Essentials.Geolocation.GetLocationAsync(request, cancellationToken.Value)
: await Xamarin.Essentials.Geolocation.GetLocationAsync(request);
? (await Xamarin.Essentials.Geolocation.GetLocationAsync(request, cancellationToken.Value)).ToGeolocation()
: (await Xamarin.Essentials.Geolocation.GetLocationAsync(request)).ToGeolocation();
}
catch (FeatureNotSupportedException fnsEx)
{

View file

@ -1,21 +1,15 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using TINK.Model.Device;
using Xamarin.Essentials;
using System;
namespace TINK.Services.Geolocation
{
/// <summary> Query geolocation. </summary>
public interface IGeolocation : IGeolodationDependent
public interface IGeolocation
{
/// <summary> Gets the current location.</summary>
/// <param name="cancellationToken">Token to cancel request for geolocation. If null request can not be cancels and times out after GeolocationService.GEOLOCATIONREQUEST_TIMEOUT_MS if geolocation is not available.</param>
/// <param name="timeStamp">Time when geolocation is of interest. Is used to determine for some implementations whether cached geoloation can be used or not.</param>
/// <returns></returns>
Task<Location> GetAsync(CancellationToken? cancellationToken = null, DateTime? timeStamp = null);
/// <summary> If true location data returned is simulated.</summary>
bool IsSimulation { get; }
double Latitude { get; }
double Longitude { get; }
double? Accuracy { get; }
DateTimeOffset Timestamp { get; }
}
}

View file

@ -0,0 +1,21 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using TINK.Model.Device;
using Xamarin.Essentials;
namespace TINK.Services.Geolocation
{
/// <summary> Query geolocation. </summary>
public interface IGeolocationService : IGeolodationDependent
{
/// <summary> Gets the current location.</summary>
/// <param name="cancellationToken">Token to cancel request for geolocation. If null request can not be cancels and times out after GeolocationService.GEOLOCATIONREQUEST_TIMEOUT_MS if geolocation is not available.</param>
/// <param name="timeStamp">Time when geolocation is of interest. Is used to determine for some implementations whether cached geoloation can be used or not.</param>
/// <returns></returns>
Task<IGeolocation> GetAsync(CancellationToken? cancellationToken = null, DateTime? timeStamp = null);
/// <summary> If true location data returned is simulated.</summary>
bool IsSimulation { get; }
}
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Threading;
using System.Threading.Tasks;
using Serilog;
@ -7,7 +7,7 @@ using Xamarin.Essentials;
namespace TINK.Services.Geolocation
{
public class LastKnownGeolocationService : IGeolocation
public class LastKnownGeolocationService : IGeolocationService
{
private IGeolodationDependent Dependent { get; }
@ -19,12 +19,12 @@ namespace TINK.Services.Geolocation
/// <summary> Gets the current location.</summary>
/// <param name="cancelationToken">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>
public async Task<Location> GetAsync(CancellationToken? cancelationToken = null, DateTime? timeStamp = null)
public async Task<IGeolocation> GetAsync(CancellationToken? cancelationToken = null, DateTime? timeStamp = null)
{
Location location;
IGeolocation location;
try
{
location = await Xamarin.Essentials.Geolocation.GetLastKnownLocationAsync();
location = (await Xamarin.Essentials.Geolocation.GetLastKnownLocationAsync()).ToGeolocation();
}
catch (FeatureNotSupportedException fnsEx)
{

View file

@ -0,0 +1,21 @@
using Xamarin.Essentials;
namespace TINK.Services.Geolocation
{
public static class LocationHelper
{
/// <summary>
/// Converts Xamarin.Essentials Location object to Geolocatin object.
/// </summary>
/// <param name="location"></param>
/// <returns></returns>
public static IGeolocation ToGeolocation(this Location location)
=> new Geolocation.Builder
{
Latitude = location.Latitude,
Longitude = location.Longitude,
Accuracy = location.Accuracy,
Timestamp = location.Timestamp,
}.Build();
}
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Threading;
using System.Threading.Tasks;
using TINK.Model.Device;
@ -6,7 +6,7 @@ using Xamarin.Essentials;
namespace TINK.Services.Geolocation
{
public class SimulatedGeolocationService : IGeolocation
public class SimulatedGeolocationService : IGeolocationService
{
private IGeolodationDependent Dependent { get; }
@ -18,9 +18,13 @@ namespace TINK.Services.Geolocation
/// <summary> Gets the current location.</summary>
/// <param name="cancelToken">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>
public async Task<Location> GetAsync(CancellationToken? cancelToken = null, DateTime? timeStamp = null)
public async Task<IGeolocation> GetAsync(CancellationToken? cancelToken = null, DateTime? timeStamp = null)
{
return await Task.FromResult(new Location(47.976634, 7.825490) { Accuracy = 0, Timestamp = timeStamp ?? DateTime.Now }); ;
return await Task.FromResult(new Geolocation.Builder {
Latitude = 47.976634,
Longitude = 7.825490,
Accuracy = 0,
Timestamp = timeStamp ?? DateTime.Now }.Build()); ;
}
/// <summary> If true location data returned is simulated.</summary>

View file

@ -26,7 +26,7 @@
<ItemGroup>
<PackageReference Include="MonkeyCache" Version="1.6.3" />
<PackageReference Include="MonkeyCache.FileStore" Version="1.6.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Plugin.BLE" Version="2.1.3" />
<PackageReference Include="Plugin.BluetoothLE" Version="6.3.0.19" />
<PackageReference Include="Plugin.Permissions" Version="6.0.1" />
@ -45,7 +45,7 @@
<PackageReference Include="Xam.Plugin.Connectivity" Version="3.2.0" />
<PackageReference Include="Xam.Plugins.Messaging" Version="5.2.0" />
<PackageReference Include="Xamarin.Essentials" Version="1.7.5" />
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2545" />
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2578" />
<PackageReference Include="Xamarin.Forms.GoogleMaps" Version="5.0.0" />
</ItemGroup>
<ItemGroup>

View file

@ -1,4 +1,4 @@
using System;
using System;
using TINK.Model.Connector;
using TINK.Model.Device;
using TINK.Model.User;
@ -17,7 +17,7 @@ namespace TINK.ViewModel.Bikes.Bike
public static BikeViewModelBase Create(
Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory,
IGeolocation geolocation,
IGeolocationService geolocationService,
ILocksService lockService,
Action<string> bikeRemoveDelegate,
Func<IPollingUpdateTaskManager> viewUpdateManager,
@ -34,7 +34,7 @@ namespace TINK.ViewModel.Bikes.Bike
return new BluetoothLock.BikeViewModel(
isConnectedDelegate,
connectorFactory,
geolocation,
geolocationService,
lockService,
bikeRemoveDelegate,
viewUpdateManager,

View file

@ -27,7 +27,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
/// <summary> Notifies GUI about changes. </summary>
public override event PropertyChangedEventHandler PropertyChanged;
private IGeolocation Geolocation { get; }
private IGeolocationService GeolocationService { get; }
private ILocksService LockService { get; }
@ -91,7 +91,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
public BikeViewModel(
Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory,
IGeolocation geolocation,
IGeolocationService geolocationService,
ILocksService lockService,
Action<string> bikeRemoveDelegate,
Func<IPollingUpdateTaskManager> viewUpdateManager,
@ -117,7 +117,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
selectedBike,
isConnectedDelegate,
connectorFactory,
geolocation,
geolocationService,
lockService,
viewUpdateManager,
smartDevice,
@ -129,8 +129,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
viewService,
bikesViewModel);
Geolocation = geolocation
?? throw new ArgumentException($"Can not instantiate {this.GetType().Name}-object. Parameter {nameof(geolocation)} can not be null.");
GeolocationService = geolocationService
?? throw new ArgumentException($"Can not instantiate {this.GetType().Name}-object. Parameter {nameof(geolocationService)} can not be null.");
LockService = lockService
?? throw new ArgumentException($"Can not instantiate {this.GetType().Name}-object. Parameter {nameof(lockService)} can not be null.");
@ -156,7 +156,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
Bike,
IsConnectedDelegate,
ConnectorFactory,
Geolocation,
GeolocationService,
LockService,
ViewUpdateManager,
SmartDevice,
@ -208,7 +208,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
// No state change occurred (same instance is returned).
return;
}
RaisePropertyChangedEvent(
lastHandler,
lastStateText,

View file

@ -1,4 +1,4 @@
using System;
using System;
using TINK.Model.Connector;
using TINK.Model.Device;
using TINK.Model.User;
@ -22,7 +22,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
bool isCopriButtonVisible,
Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory,
IGeolocation geolocation,
IGeolocationService geolocation,
ILocksService lockService,
Func<IPollingUpdateTaskManager> viewUpdateManager,
ISmartDevice smartDevice,
@ -30,14 +30,14 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
IBikesViewModel bikesViewModel,
IUser activeUser) : base(selectedBike, buttonText, isCopriButtonVisible, isConnectedDelegate, connectorFactory, viewUpdateManager, smartDevice, viewService, bikesViewModel, activeUser)
{
Geolocation = geolocation
GeolocationService = geolocation
?? throw new ArgumentException($"Can not construct {GetType().Name}-object. Parameter {nameof(geolocation)} must not be null.");
LockService = lockService
?? throw new ArgumentException($"Can not construct {GetType().Name}-object. Parameter {nameof(lockService)} must not be null.");
}
protected IGeolocation Geolocation { get; }
protected IGeolocationService GeolocationService { get; }
protected ILocksService LockService { get; }

View file

@ -15,7 +15,6 @@ using TINK.Services.BluetoothLock;
using TINK.Services.BluetoothLock.Exception;
using TINK.Services.Geolocation;
using TINK.View;
using Xamarin.Essentials;
namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
@ -27,7 +26,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
IBikeInfoMutable selectedBike,
Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory,
IGeolocation geolocation,
IGeolocationService geolocation,
ILocksService lockService,
Func<IPollingUpdateTaskManager> viewUpdateManager,
ISmartDevice smartDevice,
@ -62,24 +61,69 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
BikesViewModel.IsIdle = false;
var ctsLocation = new CancellationTokenSource();
Task<Location> currentLocationTask = null;
var timeStamp = DateTime.Now;
Task<IGeolocation> currentLocationTask = null;
// Try getting geolocation which was requested when closing lock.
IGeolocation currentLocation = SelectedBike.LockInfo.Location;
var lastConfimredLockStateTimeStamp = SelectedBike.LockInfo.LastLockingStateChange;
// Check if bike is around.
var deviceState = LockService[SelectedBike.LockInfo.Id].GetDeviceState();
if (deviceState == DeviceState.Connected)
// Check if
// - geolocation is already available
// - or if bike is in reach so that geolocation makes sense
if (currentLocation == null && deviceState != DeviceState.Connected)
{
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationStart; // Bluetooth is in reach
// Geolocation information is missing and can not be queried.
Log.ForContext<BookedClosed>().Information("User selected booked bike {bike} but returning failed. COPRI returned an error.", SelectedBike);
await ViewService.DisplayAlert(
AppResources.ErrorReturnBikeTitle,
AppResources.Error_ReturnBike_Station_Location_Message,
AppResources.MessageAnswerOk);
// Disconnect lock.
BikesViewModel.ActionText = AppResources.ActivityTextDisconnectingLock;
try
{
SelectedBike.LockInfo.State = await LockService.DisconnectAsync(SelectedBike.LockInfo.Id, SelectedBike.LockInfo.Guid);
}
catch (Exception exception)
{
Log.ForContext<BookedClosed>().Error("Lock can not be disconnected. {Exception}", exception);
BikesViewModel.ActionText = AppResources.ActivityTextErrorDisconnect;
}
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
// Check if quering geolocation is required.
if (currentLocation == null)
{
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationStart;
// Start getting geolocation.
try
{
currentLocationTask = Geolocation.GetAsync(ctsLocation.Token, timeStamp);
currentLocationTask = GeolocationService.GetAsync(ctsLocation.Token, DateTime.Now);
}
catch (Exception ex)
{
// No location information available.
Log.ForContext<BookedClosed>().Information("Getting geolocation when returning bike {Bike} failed. {Exception}", SelectedBike, ex);
await ViewService.DisplayAlert(
AppResources.ErrorReturnBikeTitle,
AppResources.ErrorReturnBikeLockClosedStartGetGPSExceptionMessage,
AppResources.MessageAnswerOk);
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return this;
}
}
@ -119,10 +163,11 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
await ViewUpdateManager().StopUpdatePeridically();
// Check if bike is around.
Location currentLocation = null;
// Get geolocation if
// - geolocation was not available when closing lock
// - bike is around (lock is connected via bluetooth)
LocationDto currentLocationDto = null;
if (deviceState == DeviceState.Connected)
if (currentLocation == null)
{
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocation;
try
@ -134,24 +179,32 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
// No location information available.
Log.ForContext<BookedClosed>().Information("Returning closed bike {Bike} is not possible. Cancel geolocation query failed. {Exception}", SelectedBike, ex);
await ViewService.DisplayAlert(
AppResources.ErrorReturnBikeTitle,
AppResources.ErrorReturnBikeLockClosedGetGPSExceptionMessage,
AppResources.MessageAnswerOk);
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
await ViewUpdateManager().StartUpdateAyncPeridically();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return this;
}
currentLocationDto = currentLocation != null
? new LocationDto.Builder
{
Latitude = currentLocation.Latitude,
Longitude = currentLocation.Longitude,
Accuracy = currentLocation.Accuracy ?? double.NaN,
Age = timeStamp.Subtract(currentLocation.Timestamp.DateTime),
}.Build()
: null;
}
else
{
// Bluetooth out of reach. Lock state is no more known.
SelectedBike.LockInfo.State = LockingState.UnknownDisconnected;
lastConfimredLockStateTimeStamp = DateTime.Now;
}
currentLocationDto = currentLocation != null
? new LocationDto.Builder
{
Latitude = currentLocation.Latitude,
Longitude = currentLocation.Longitude,
Accuracy = currentLocation.Accuracy ?? double.NaN,
Age = lastConfimredLockStateTimeStamp is DateTime lastLockState ? lastLockState.Subtract(currentLocation.Timestamp.DateTime) : TimeSpan.MaxValue,
}.Build()
: null;
BikesViewModel.ActionText = AppResources.ActivityTextReturningBike;
IsConnected = IsConnectedDelegate();
@ -229,7 +282,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
Log.ForContext<BookedClosed>().Information("User returned bike {bike} successfully.", SelectedBike);
@ -289,7 +342,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
#endif
if (bookingFinished != null && bookingFinished.MiniSurvey.Questions.Count > 0)
@ -302,7 +355,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
/// <summary> Open bike and update COPRI lock state. </summary>
@ -384,7 +437,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
BikesViewModel.ActionText = AppResources.ActivityTextReadingChargingLevel;
@ -454,7 +507,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
}
}

View file

@ -24,7 +24,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
IBikeInfoMutable selectedBike,
Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory,
IGeolocation geolocation,
IGeolocationService geolocation,
ILocksService lockService,
Func<IPollingUpdateTaskManager> viewUpdateManager,
ISmartDevice smartDevice,
@ -240,7 +240,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
}
}

View file

@ -16,7 +16,6 @@ using TINK.Services.BluetoothLock.Exception;
using TINK.Services.Geolocation;
using TINK.Services.Logging;
using TINK.View;
using Xamarin.Essentials;
namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
@ -27,7 +26,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
IBikeInfoMutable selectedBike,
Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory,
IGeolocation geolocation,
IGeolocationService geolocation,
ILocksService lockService,
Func<IPollingUpdateTaskManager> viewUpdateManager,
ISmartDevice smartDevice,
@ -66,11 +65,11 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
// Start getting geolocation.
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationStart;
var ctsLocation = new CancellationTokenSource();
Task<Location> currentLocationTask = null;
Task<IGeolocation> currentLocationTask = null;
var timeStamp = DateTime.Now;
try
{
currentLocationTask = Geolocation.GetAsync(ctsLocation.Token, timeStamp);
currentLocationTask = GeolocationService.GetAsync(ctsLocation.Token, timeStamp);
}
catch (Exception ex)
{
@ -88,7 +87,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
// Ask whether to really return bike?
@ -168,7 +167,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
// Close lock
@ -255,7 +254,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
// Check locking state.
@ -307,12 +306,12 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
// Get geolocation information.
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocation;
Location currentLocation = null;
IGeolocation currentLocation = null;
try
{
var task = await Task.WhenAny(new List<Task> { currentLocationTask });
@ -335,7 +334,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
// Notify COPRI about end of rental: "request=booking_update ... "&state=available" ... &lock_state=locked ..."
@ -428,7 +427,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
Log.ForContext<BookedOpen>().Information("User returned bike {bike} successfully.", SelectedBike);
@ -488,7 +487,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
#endif
@ -501,7 +500,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
/// <summary> Close lock in order to pause ride and update COPRI lock state.</summary>
@ -518,11 +517,11 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
// Start getting geolocation.
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationStart;
var ctsLocation = new CancellationTokenSource();
Task<Location> currentLocationTask = null;
Task<IGeolocation> currentLocationTask = null;
var timeStamp = DateTime.Now;
try
{
currentLocationTask = Geolocation.GetAsync(ctsLocation.Token, timeStamp);
currentLocationTask = GeolocationService.GetAsync(ctsLocation.Token, timeStamp);
}
catch (Exception ex)
{
@ -606,12 +605,12 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
// Get geoposition.
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocation;
Location currentLocation = null;
IGeolocation currentLocation = null;
try
{
await Task.WhenAny(new List<Task> { currentLocationTask });
@ -625,6 +624,9 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
BikesViewModel.ActionText = AppResources.ActivityTextErrorQueryLocationWhenAny;
}
// Keep geolocation where closing action occurred.
SelectedBike.LockInfo.Location = currentLocation;
// Lock list to avoid multiple taps while copri action is pending.
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdatingLockingState;
@ -673,7 +675,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
}
}

View file

@ -26,7 +26,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
IBikeInfoMutable selectedBike,
Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory,
IGeolocation geolocation,
IGeolocationService geolocation,
ILocksService lockService,
Func<IPollingUpdateTaskManager> viewUpdateManager,
ISmartDevice smartDevice,
@ -136,7 +136,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
BikesViewModel.ActionText = AppResources.ActivityTextReadingChargingLevel;
@ -206,7 +206,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
/// <summary> Close lock in order to pause ride and update COPRI lock state.</summary>
@ -220,11 +220,11 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
// Start getting geolocation.
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationStart;
var ctsLocation = new CancellationTokenSource();
Task<Location> currentLocationTask = null;
Task<IGeolocation> currentLocationTask = null;
var timeStamp = DateTime.Now;
try
{
currentLocationTask = Geolocation.GetAsync(ctsLocation.Token, timeStamp);
currentLocationTask = GeolocationService.GetAsync(ctsLocation.Token, timeStamp);
}
catch (Exception ex)
{
@ -307,12 +307,12 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
// Get geoposition.
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocation;
Location currentLocation = null;
IGeolocation currentLocation = null;
try
{
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
@ -374,7 +374,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
}
}

View file

@ -25,7 +25,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
IBikeInfoMutable selectedBike,
Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory,
IGeolocation geolocation,
IGeolocationService geolocation,
ILocksService lockService,
Func<IPollingUpdateTaskManager> viewUpdateManager,
ISmartDevice smartDevice,
@ -160,7 +160,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
SelectedBike.LockInfo.State = result?.State?.GetLockingState() ?? LockingState.UnknownDisconnected;
@ -174,7 +174,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
SelectedBike.LockInfo.Guid = result?.Guid ?? new Guid();
@ -212,7 +212,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
Log.ForContext<DisposableDisconnected>().Information("User selected recently requested bike {bike} in order to book.", SelectedBike);
@ -254,7 +254,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
// Unlock bike.
@ -323,7 +323,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
if (SelectedBike.LockInfo.State != LockingState.Open)
@ -334,7 +334,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
BikesViewModel.ActionText = AppResources.ActivityTextReadingChargingLevel;
@ -404,7 +404,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
/// <summary> Requst is not supported, button should be disabled. </summary>

View file

@ -37,7 +37,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
IBikeInfoMutable selectedBike,
Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory,
IGeolocation geolocation,
IGeolocationService geolocation,
ILocksService lockService,
Func<IPollingUpdateTaskManager> viewUpdateManager,
ISmartDevice smartDevice,
@ -142,7 +142,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
// Disconnect lock.
@ -162,7 +162,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
// Lock list to avoid multiple taps while copri action is pending.
@ -255,7 +255,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
// Update status text and unlock list of bikes because no more action is pending.
BikesViewModel.ActionText = string.Empty; // Todo: Move this statement in front of finally block because in catch block BikesViewModel.ActionText is already set to empty.
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
Log.ForContext<DisposableOpen>().Information("User reserved bike {bike} successfully.", SelectedBike);
@ -267,7 +267,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
// Update status text and unlock list of bikes because no more action is pending.
BikesViewModel.ActionText = string.Empty; // Todo: Move this statement in front of finally block because in catch block BikesViewModel.ActionText is already set to empty.
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
/// <summary> Requst is not supported, button should be disabled. </summary>

View file

@ -30,7 +30,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
IBikeInfoMutable selectedBike,
Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory,
IGeolocation geolocation,
IGeolocationService geolocation,
ILocksService lockService,
Func<IPollingUpdateTaskManager> viewUpdateManager,
ISmartDevice smartDevice,
@ -131,7 +131,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
Log.ForContext<BikesViewModel>().Information("User canceled reservation of bike {l_oId} successfully.", SelectedBike.Id);
@ -153,7 +153,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
/// <summary> Open lock and book bike. </summary>
@ -219,7 +219,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
// Unlock bike.
@ -288,7 +288,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
if (SelectedBike.LockInfo.State != LockingState.Open)
@ -299,7 +299,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
BikesViewModel.ActionText = AppResources.ActivityTextReadingChargingLevel;
@ -369,7 +369,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
}
}

View file

@ -24,7 +24,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
IBikeInfoMutable selectedBike,
Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory,
IGeolocation geolocation,
IGeolocationService geolocation,
ILocksService lockService,
Func<IPollingUpdateTaskManager> viewUpdateManager,
ISmartDevice smartDevice,
@ -124,7 +124,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
Log.ForContext<ReservedDisconnected>().Information("User canceled reservation of bike {l_oId} successfully.", SelectedBike.Id);
@ -133,7 +133,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
/// <summary> Connect to reserved bike ask whether to book bike bike or not and if yes open lock. </summary>
@ -340,7 +340,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
Log.ForContext<ReservedDisconnected>().Information("User selected recently requested bike {bike} in order to book.", SelectedBike);
@ -382,7 +382,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
// Unlock bike.
@ -451,7 +451,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
if (SelectedBike.LockInfo.State != LockingState.Open)
@ -462,7 +462,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
BikesViewModel.ActionText = AppResources.ActivityTextReadingChargingLevel;
@ -534,7 +534,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
}
}

View file

@ -29,7 +29,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
IBikeInfoMutable selectedBike,
Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory,
IGeolocation geolocation,
IGeolocationService geolocation,
ILocksService lockService,
Func<IPollingUpdateTaskManager> viewUpdateManager,
ISmartDevice smartDevice,
@ -152,7 +152,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
Log.ForContext<ReservedOpen>().Information("User booked bike {bike} successfully.", SelectedBike);
@ -162,7 +162,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
// Close lock and cancel reservation.
@ -220,7 +220,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
BikesViewModel.ActionText = AppResources.ActivityTextCancelingReservation;
@ -268,7 +268,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
Log.ForContext<ReservedOpen>().Information("User canceled reservation of bike {l_oId} successfully.", SelectedBike.Id);
@ -290,7 +290,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true; // Unlock GUI
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
/// <summary> Manage sound/ alarm settings. </summary>
@ -364,7 +364,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
exception.Message,
"OK");
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
// Switch off alarm.
@ -395,7 +395,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
exception.Message,
"OK");
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
finally
{

View file

@ -26,7 +26,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
IBikeInfoMutable selectedBike,
Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory,
IGeolocation geolocation,
IGeolocationService geolocation,
ILocksService lockService,
Func<IPollingUpdateTaskManager> viewUpdateManager,
ISmartDevice smartDevice,
@ -132,7 +132,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
BikesViewModel.ActionText = AppResources.ActivityTextReadingChargingLevel;
@ -202,7 +202,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
/// <summary> Close lock in order to pause ride and update COPRI lock state.</summary>
@ -220,11 +220,11 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
// Start getting geolocation.
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocationStart;
var ctsLocation = new CancellationTokenSource();
Task<Location> currentLocationTask = null;
Task<IGeolocation> currentLocationTask = null;
var timeStamp = DateTime.Now;
try
{
currentLocationTask = Geolocation.GetAsync(ctsLocation.Token, timeStamp);
currentLocationTask = GeolocationService.GetAsync(ctsLocation.Token, timeStamp);
}
catch (Exception ex)
{
@ -307,12 +307,12 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
// Get geoposition.
BikesViewModel.ActionText = AppResources.ActivityTextQueryLocation;
Location currentLocation = null;
IGeolocation currentLocation = null;
try
{
await Task.WhenAny(new List<Task> { currentLocationTask ?? Task.CompletedTask });
@ -374,7 +374,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewUpdateManager().StartUpdateAyncPeridically();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.IsIdle = true;
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, GeolocationService, LockService, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
}
}
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using Serilog;
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock;
using TINK.Model.Connector;
@ -18,7 +18,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
/// <param name="selectedBike"></param>
/// <param name="isConnectedDelegate"></param>
/// <param name="connectorFactory"></param>
/// <param name="bikeRemoveDelegate"></param>
/// <param name="geolocation"></param>
/// <param name="viewUpdateManager"></param>
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...)</param>
/// <param name="viewService"></param>
@ -28,7 +28,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
Model.Bikes.BikeInfoNS.BC.IBikeInfoMutable selectedBike,
Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory,
IGeolocation geolocation,
IGeolocationService geolocation,
ILocksService lockService,
Func<IPollingUpdateTaskManager> viewUpdateManager,
ISmartDevice smartDevice,
@ -36,7 +36,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
IBikesViewModel bikesViewModel,
IUser activeUser)
{
if (!(selectedBike is Model.Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable selectedBluetoothLockBike))
if (!(selectedBike is IBikeInfoMutable selectedBluetoothLockBike))
return null;
switch (selectedBluetoothLockBike.State.Value)

View file

@ -36,7 +36,7 @@ namespace TINK.ViewModel.Bikes
/// <summary> Provides a connector object.</summary>
protected Func<bool, IConnector> ConnectorFactory { get; }
protected IGeolocation Geolocation { get; }
protected IGeolocationService GeolocationService { get; }
/// <summary> Provides a connector object.</summary>
protected ILocksService LockService { get; }
@ -99,7 +99,7 @@ namespace TINK.ViewModel.Bikes
string runtimPlatform,
Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory,
IGeolocation geolocation,
IGeolocationService geolocation,
ILocksService lockService,
TINK.Settings.PollingParameters polling,
Action<SendOrPostCallback, object> postAction,
@ -123,7 +123,7 @@ namespace TINK.ViewModel.Bikes
ConnectorFactory = connectorFactory
?? throw new ArgumentException("Can not instantiate bikes page view model- object. No connector available.");
Geolocation = geolocation
GeolocationService = geolocation
?? throw new ArgumentException("Can not instantiate bikes page view model- object. No geolocation object available.");
LockService = lockService
@ -182,7 +182,7 @@ namespace TINK.ViewModel.Bikes
var bikeViewModel = BikeViewModelFactory.Create(
IsConnectedDelegate,
ConnectorFactory,
Geolocation,
GeolocationService,
LockService,
(id) => Remove(id),
() => m_oViewUpdateManager,

View file

@ -79,7 +79,7 @@ namespace TINK.ViewModel.BikesAtStation
IStation selectedStation,
Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory,
IGeolocation geolocation,
IGeolocationService geolocation,
ILocksService lockService,
PollingParameters polling,
Action<string> openUrlInExternalBrowser,
@ -306,7 +306,7 @@ namespace TINK.ViewModel.BikesAtStation
}
}
if (Geolocation.IsGeolcationEnabled == false)
if (GeolocationService.IsGeolcationEnabled == false)
{
await ViewService.DisplayAlert(
AppResources.MessageTitleHint,

View file

@ -22,7 +22,6 @@ using TINK.MultilingualResources;
using TINK.Repository;
using TINK.Services.Geolocation;
using TINK.Model.State;
using TINK.ViewModel.Map;
namespace TINK.ViewModel.Contact
{
@ -86,7 +85,7 @@ namespace TINK.ViewModel.Contact
/// <summary> False if user tabed on station marker to show bikes at a given station.</summary>
private bool isMapPageEnabled = false;
IGeolocation GeolocationService { get; }
IGeolocationService GeolocationService { get; }
/// <summary> False if user tabed on station marker to show bikes at a given station.</summary>
public bool IsMapPageEnabled
@ -111,7 +110,7 @@ namespace TINK.ViewModel.Contact
ITinkApp tinkApp,
ILocationPermission permissionsService,
Plugin.BLE.Abstractions.Contracts.IBluetoothLE bluetoothService,
IGeolocation geolocationService,
IGeolocationService geolocationService,
Action<MapSpan> moveToRegionDelegate,
IViewService viewService,
INavigation navigation)
@ -162,7 +161,7 @@ namespace TINK.ViewModel.Contact
/// <summary>
/// One time setup: Sets pins into map and connects to events.
/// </summary>
private async void InitializePins(StationDictionary stations)
private void InitializePins(StationDictionary stations)
{
// Add pins to stations.
Log.ForContext<SelectStationPageViewModel>().Debug($"Request to draw {stations.Count} pins.");
@ -309,7 +308,7 @@ namespace TINK.ViewModel.Contact
{
ActionText = AppResources.ActivityTextCenterMap;
Location currentLocation = null;
IGeolocation currentLocation = null;
try
{
currentLocation = TinkApp.CenterMapToCurrentLocation
@ -428,7 +427,7 @@ namespace TINK.ViewModel.Contact
public static void MoveAndScale(
Action<MapSpan> moveToRegionDelegate,
Uri activeUri,
Location currentLocation = null)
IGeolocation currentLocation = null)
{
if (currentLocation != null)
{

View file

@ -124,7 +124,7 @@ namespace TINK.ViewModel.FindBike
string runtimPlatform,
Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory,
IGeolocation geolocation,
IGeolocationService geolocation,
ILocksService lockService,
IEnumerable<IStation> stations,
PollingParameters polling,
@ -331,7 +331,7 @@ namespace TINK.ViewModel.FindBike
}
// Location state
if (Geolocation.IsGeolcationEnabled == false)
if (GeolocationService.IsGeolcationEnabled == false)
{
await ViewService.DisplayAlert(
AppResources.MessageTitleHint,

View file

@ -27,13 +27,6 @@ using TINK.Repository;
using TINK.Services.Geolocation;
using TINK.Model.State;
using TINK.ViewModel.Bikes;
using Location = Xamarin.Essentials.Location;
#if !TRYNOTBACKSTYLE
#endif
@ -63,8 +56,6 @@ namespace TINK.ViewModel.Map
/// </summary>
private ILocationPermission PermissionsService { get; }
private IGeolocation Geolocation { get; }
/// <summary>
/// Service to manage bluetooth stack.
/// </summary>
@ -110,7 +101,7 @@ namespace TINK.ViewModel.Map
/// <summary> False if user tabed on station marker to show bikes at a given station.</summary>
private bool isMapPageEnabled = false;
IGeolocation GeolocationService { get; }
IGeolocationService GeolocationService { get; }
/// <summary> False if user tabed on station marker to show bikes at a given station.</summary>
public bool IsMapPageEnabled
@ -135,7 +126,7 @@ namespace TINK.ViewModel.Map
ITinkApp tinkApp,
ILocationPermission permissionsService,
Plugin.BLE.Abstractions.Contracts.IBluetoothLE bluetoothService,
IGeolocation geolocationService,
IGeolocationService geolocationService,
Action<MapSpan> moveToRegionDelegate,
IViewService viewService,
INavigation navigation)
@ -197,6 +188,27 @@ namespace TINK.ViewModel.Map
set { m_oNavigationMasterDetail = value; }
}
#endif
/// <summary>
/// Counts the number of reserved or occupied bikes -> visualized in MyBikes-Icon
/// </summary>
public void GetMyBikesCount(BikeCollection bikesAll)
{
int MyBikesCount = 0;
Log.ForContext<MapPageViewModel>().Debug($"Number of reserved or rented bikes is extracted.");
if (bikesAll != null)
{
foreach (var bike in bikesAll)
{
if (bike.State.Value.IsOccupied())
{
MyBikesCount = MyBikesCount + 1;
continue;
}
}
}
MyBikesCountText = MyBikesCount > 0 ? string.Format(MyBikesCount.ToString()) : string.Empty;
}
public Command<PinClickedEventArgs> PinClickedCommand => new Command<PinClickedEventArgs>(
args =>
@ -243,7 +255,6 @@ namespace TINK.ViewModel.Map
{
Log.ForContext<MapPageViewModel>().Debug($"Starting update of stations pins color for {stationsColorList.Count} stations...");
int MyBikesCount = 0;
// Update colors of pins.
for (int pinIndex = 0; pinIndex < stationsColorList.Count; pinIndex++)
{
@ -253,11 +264,6 @@ namespace TINK.ViewModel.Map
: "Open"; // there is no station marker. Use open marker.
var colorPartPrefix = GetRessourceNameColorPart(stationsColorList[pinIndex]);
if (colorPartPrefix == "Blue" || colorPartPrefix == "LightBlue")
{
MyBikesCount = MyBikesCount + 1;
};
var name = $"{indexPartPrefix.ToString().PadLeft(2, '0')}_{colorPartPrefix}{(DeviceInfo.Platform == DevicePlatform.Android ? ".png" : string.Empty)}";
try
{
@ -273,8 +279,6 @@ namespace TINK.ViewModel.Map
Pins[pinIndex].IsVisible = true;
}
MyBikesCountText = MyBikesCount > 0 ? string.Format(MyBikesCount.ToString()) : string.Empty;
var pinsCount = Pins.Count;
for (int pinIndex = stationsColorList.Count; pinIndex < pinsCount; pinIndex++)
{
@ -343,6 +347,10 @@ namespace TINK.ViewModel.Map
IsProcessWithRunningProcessView = true;
IsNavBarVisible = false;
// Get and expose status of location permission
GetLocationPermissionStatus();
// Process map page.
Polling = TinkApp.Polling;
@ -350,7 +358,7 @@ namespace TINK.ViewModel.Map
$"{(Polling != null && Polling.IsActivated ? $"Map page is appearing. Update periode is {Polling.Periode.TotalSeconds} sec." : "Map page is appearing. Polling is off.")}" +
$"Current UI language is {Thread.CurrentThread.CurrentUICulture.Name}.");
// Update map page filter
// Update map page filter
ActiveFilterMap = TinkApp.GroupFilterMapPage;
ActionText = AppResources.ActivityTextMapLoadingStationsAndBikes;
@ -393,6 +401,9 @@ namespace TINK.ViewModel.Map
Log.ForContext<MapPageViewModel>().Verbose("Update pins color done.");
// Load MyBikes Count -> MyBikes Icon/Button
GetMyBikesCount(resultStationsAndBikes.Response.Bikes);
// Move and scale before getting stations and bikes which takes some time.
ActionText = AppResources.ActivityTextCenterMap;
@ -460,6 +471,22 @@ namespace TINK.ViewModel.Map
}
}
/// <summary>
/// IsLocationPermissionGranted = true, if Location Permissions granted.
/// </summary>
private async void GetLocationPermissionStatus()
{
Log.ForContext<MapPageViewModel>().Verbose("Check Location permissions.");
var status = await PermissionsService.CheckStatusAsync();
IsLocationPermissionGranted = status == Status.Granted ? true : false;
Log.ForContext<MapPageViewModel>().Verbose("Location permissions: {0}.", status);
}
/// <summary>
/// Exposes IsLocationPermissionGranted.
/// </summary>
public bool IsLocationPermissionGranted{ get; set;}
/// <summary>
/// Invoked when the auth cookie is not defined.
/// </summary>
@ -536,7 +563,7 @@ namespace TINK.ViewModel.Map
/// </summary>
private async Task<Model.Map.IMapSpan> GetFromLocationService(Status status)
{
Location currentLocation = null;
IGeolocation currentLocation = null;
try
{
currentLocation = await GeolocationService.GetAsync();
@ -627,6 +654,9 @@ namespace TINK.ViewModel.Map
Log.ForContext<MapPageViewModel>().Error("Getting bikes and stations in polling context failed with exception {Exception}.", exception);
}
// Load MyBikes Count -> MyBikes Icon/Button
GetMyBikesCount(resultStationsAndBikes.Response.Bikes);
// Check if there are alreay any pins to the map.
// If no initialze pins.
if (Pins.Count <= 0)

View file

@ -76,7 +76,7 @@ namespace TINK.ViewModel.MyBikes
string runtimPlatform,
Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory,
IGeolocation geolocation,
IGeolocationService geolocation,
ILocksService lockService,
IEnumerable<IStation> stations,
PollingParameters p_oPolling,
@ -194,7 +194,7 @@ namespace TINK.ViewModel.MyBikes
}
// Location state
if (Geolocation.IsGeolcationEnabled == false)
if (GeolocationService.IsGeolcationEnabled == false)
{
await ViewService.DisplayAlert(
AppResources.MessageTitleHint,

View file

@ -65,7 +65,7 @@ namespace TINK.ViewModel
/// <summary> Reference on the tink app instance. </summary>
private ITinkApp TinkApp { get; }
IServicesContainer<IGeolocation> GeoloctionServicesContainer { get; }
IServicesContainer<IGeolocationService> GeoloctionServicesContainer { get; }
/// <summary> Constructs a settings page view model object.</summary>
/// <param name="tinkApp"> Reference to tink app model.</param>
@ -73,7 +73,7 @@ namespace TINK.ViewModel
/// <param name="viewService">Interface to view</param>
public SettingsPageViewModel(
ITinkApp tinkApp,
IServicesContainer<IGeolocation> geoloctionServicesContainer,
IServicesContainer<IGeolocationService> geoloctionServicesContainer,
IViewService viewService)
{
TinkApp = tinkApp

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Threading;
using System.Threading.Tasks;
using TINK.Services.Geolocation;
@ -6,10 +6,10 @@ using Xamarin.Essentials;
namespace TestFramework.Model.Services.Geolocation
{
public class GeolocationMock : IGeolocation
public class GeolocationMock : IGeolocationService
{
public Task<Location> GetAsync(CancellationToken? cancelToken = null, DateTime? timeStamp = null)
public Task<IGeolocation> GetAsync(CancellationToken? cancelToken = null, DateTime? timeStamp = null)
{
throw new NotImplementedException();
}

View file

@ -1,10 +1,13 @@
using System;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using NSubstitute;
using NUnit.Framework;
using Plugin.BLE.Abstractions.Contracts;
using TINK.Services.BluetoothLock;
using TINK.Services.BluetoothLock.BLE;
using TINK.Services.BluetoothLock.Exception;
using TINK.Services.BluetoothLock.Tdo;
namespace TestLockItBLE.Services.BluetoothLock.BLE
@ -64,5 +67,77 @@ namespace TestLockItBLE.Services.BluetoothLock.BLE
await disconnectedDevice.Received().ReconnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
}
[Test]
public void TestConnect_Connected_InvalidArgs()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<TINK.Model.Device.ICipher>();
var exception = Assert.Throws<AggregateException>(
() => { var lockIt = LockItEventBased.Authenticate(device, null, adapter, cipher).Result; },
"If connected no auth is requied.");
Assert.That(exception.InnerExceptions.Count > 0);
Assert.That(exception.InnerExceptions[0], Is.InstanceOf<BluetoothDisconnectedException>());
}
[Test]
public void TestConnect_Connected()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<TINK.Model.Device.ICipher>();
var auth = Substitute.For<ICharacteristic>();
var lockControl = Substitute.For<IService>();
var authTdo = new LockInfoAuthTdo.Builder
{
Id = 12,
K_seed = new byte[] { (byte)'i', (byte)'V', (byte)'F', (byte)'m', (byte)'u', (byte)'T', (byte)'n', (byte)'K', (byte)'q', (byte)'E', (byte)'Y', (byte)'h', (byte)'m', (byte)'T', (byte)'l', (byte)'e' },
K_u = new byte[16]
}.Build();
device.State.Returns(Plugin.BLE.Abstractions.DeviceState.Connected);
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(lockControl));
lockControl.GetCharacteristicAsync(Arg.Any<Guid>()).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(true)); // Write COPRI seed to lock
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult(new byte[8])); // Read lock seed
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(true)); // Write COPRI seed to lock
device.Name.Returns("Origin");
Assert.AreEqual(
"Origin",
LockItEventBased.Authenticate(device, authTdo, adapter, cipher).Result.Name,
"If connected no auth is requied.");
}
[Test]
public void TestAuth()
{
var authTdo = new LockInfoAuthTdo.Builder
{
Id = 12,
K_seed = new byte[] { (byte)'c', (byte)'b', (byte)'z', (byte)'b', (byte)'y', (byte)'I', (byte)'q', (byte)'j', (byte)'v', (byte)'L', (byte)'V', (byte)'I', (byte)'t', (byte)'C', (byte)'B', (byte)'I' },
K_u = new byte[16]
}.Build();
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<TINK.Model.Device.ICipher>();
// Use factory to create LockIt-object.
var exception = Assert.Throws<AggregateException>(
() => { var lockIt = LockItEventBased.Authenticate(device, authTdo, adapter, cipher).Result; },
"If connected no auth is requied.");
Assert.That(exception.InnerExceptions.Count > 0);
Assert.That(exception.InnerExceptions[0], Is.InstanceOf<BluetoothDisconnectedException>());
}
}
}

View file

@ -12,7 +12,7 @@
<ItemGroup>
<PackageReference Include="NSubstitute" Version="5.0.0" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.3.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.4.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
</ItemGroup>

View file

@ -13,7 +13,7 @@
<ItemGroup>
<PackageReference Include="nunit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.3.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.4.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
</ItemGroup>

View file

@ -1,7 +1,8 @@
using System;
using System;
using System.Linq;
using NUnit.Framework;
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock;
using TINK.Services.Geolocation;
namespace TestTINKLib.Fixtures.ObjectTests.Bike.BluetoothLock
{
@ -62,5 +63,60 @@ namespace TestTINKLib.Fixtures.ObjectTests.Bike.BluetoothLock
Assert.IsTrue((new byte[] { 1, 12 }).SequenceEqual(lockInfo.Seed));
Assert.AreEqual(LockingState.Closed, lockInfo.State);
}
[Test]
public void TestLastLockingStateChange()
=> Assert.That(
new LockInfoMutable(1, new Guid(), null, null, null, LockingState.Open, () => new DateTime(2023, 03, 13)).LastLockingStateChange,
Is.Null);
[Test]
public void TestLastLockingStateChangeCangeCtor()
{
var lockInfo = new LockInfoMutable(1, new Guid(), null, null, null, LockingState.Open, () => new DateTime(2023, 03, 13));
lockInfo.State = LockingState.Closed;
Assert.That(
lockInfo.LastLockingStateChange,
Is.EqualTo(new DateTime(2023, 03, 13)));
}
[Test]
public void TestLocationCtor()
=> Assert.That(
new LockInfoMutable(1, new Guid(), null, null, null, LockingState.Open, () => new DateTime(2023, 03, 13)).Location,
Is.Null);
[Test]
public void TestLocation()
{
var lockInfo = new LockInfoMutable(1, new Guid(), null, null, null, LockingState.Open, () => new DateTime(2023, 03, 13));
lockInfo.Location = new Geolocation.Builder { Latitude = 47.99, Longitude = 7.78}.Build();
// Veryfy that location is kept because bike might be returned later.
Assert.That(
lockInfo.Location.Latitude,
Is.EqualTo(47.99).Within(0.001));
Assert.That(
lockInfo.Location.Longitude,
Is.EqualTo(7.78).Within(0.001));
}
[Test]
public void TestLocationStateChange()
{
var lockInfo = new LockInfoMutable(1, new Guid(), null, null, null, LockingState.Open, () => new DateTime(2023, 03, 13));
lockInfo.Location = new Geolocation.Builder { Latitude = 47.99, Longitude = 7.78 }.Build();
lockInfo.State = LockingState.Closed;
// Veryfy that location is kept because bike might be returned later.
Assert.That(
lockInfo.Location,
Is.Null);
}
}
}

View file

@ -1,7 +1,7 @@
using System.Threading.Tasks;
using System.Threading.Tasks;
using Newtonsoft.Json;
using NSubstitute;
using NUnit.Framework;
using Rhino.Mocks;
using TINK.Model.Connector;
using TINK.Model.Services.CopriApi;
using TINK.Repository;
@ -87,15 +87,14 @@ namespace TestTINKLib.Fixtures.ObjectTests.Connector.Query
[Test]
public async Task TestGetStations_StationsFromCache()
{
var server = MockRepository.GenerateMock<ICachedCopriServer>();
server.Stub(x => x.GetStations(Arg<bool>.Matches(fromCache => fromCache == false))).Return(Task.Run(() => new Result<StationsAvailableResponse>(
var server = Substitute.For<ICachedCopriServer>();
server.GetStations(false).Returns(Task.Run(() => new Result<StationsAvailableResponse>(
typeof(CopriCallsMonkeyStore),
JsonConvert.DeserializeObject<StationsAvailableResponse>(STATIONSALL),
new GeneralData(),
new System.Exception("Bang when getting stations..."))));
server.Stub(x => x.GetBikesAvailable(Arg<bool>.Matches(fromCache => fromCache == true))).Return(Task.Run(() => new Result<BikesAvailableResponse>(
server.GetBikesAvailable(true).Returns(Task.Run(() => new Result<BikesAvailableResponse>(
typeof(CopriCallsMonkeyStore),
JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLE),
new GeneralData())));
@ -111,20 +110,20 @@ namespace TestTINKLib.Fixtures.ObjectTests.Connector.Query
[Test]
public async Task TestGetStations_BikesAvailableFromCache()
{
var server = MockRepository.GenerateMock<ICachedCopriServer>();
var server = Substitute.For<ICachedCopriServer>();
server.Stub(x => x.GetStations(Arg<bool>.Matches(fromCache => fromCache == false))).Return(Task.Run(() => new Result<StationsAvailableResponse>(
server.GetStations(false).Returns(Task.Run(() => new Result<StationsAvailableResponse>(
typeof(CopriCallsHttps),
JsonConvert.DeserializeObject<StationsAvailableResponse>(STATIONSALLEMPTY),
new GeneralData())));
server.Stub(x => x.GetBikesAvailable(Arg<bool>.Matches(fromCache => fromCache == false))).Return(Task.Run(() => new Result<BikesAvailableResponse>(
server.GetBikesAvailable(false).Returns(Task.Run(() => new Result<BikesAvailableResponse>(
typeof(CopriCallsMonkeyStore),
JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLE),
new GeneralData(),
new System.Exception("Bang when getting bikes..."))));
server.Stub(x => x.GetStations(Arg<bool>.Matches(fromCache => fromCache == true))).Return(Task.Run(() => new Result<StationsAvailableResponse>(
server.GetStations(true).Returns(Task.Run(() => new Result<StationsAvailableResponse>(
typeof(CopriCallsMonkeyStore),
JsonConvert.DeserializeObject<StationsAvailableResponse>(STATIONSALL),
new GeneralData())));
@ -141,21 +140,18 @@ namespace TestTINKLib.Fixtures.ObjectTests.Connector.Query
[Test]
public async Task TestGetStations()
{
var server = MockRepository.GenerateMock<ICachedCopriServer>();
var server = Substitute.For<ICachedCopriServer>();
server.Stub(x => x.GetStations(Arg<bool>.Matches(fromCache => fromCache == false))).Return(Task.Run(() => new Result<StationsAvailableResponse>(
server.GetStations(false).Returns(Task.Run(() => new Result<StationsAvailableResponse>(
typeof(CopriCallsHttps),
JsonConvert.DeserializeObject<StationsAvailableResponse>(STATIONSALL),
new GeneralData())));
server.Stub(x => x.GetBikesAvailable(Arg<bool>.Matches(fromCache => fromCache == false))).Return(Task.Run(() => new Result<BikesAvailableResponse>(
server.GetBikesAvailable(false).Returns(Task.Run(() => new Result<BikesAvailableResponse>(
typeof(CopriCallsHttps),
JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLE),
new GeneralData())));
server.Stub(x => x.AddToCache(Arg<Result<StationsAvailableResponse>>.Is.Anything));
server.Stub(x => x.AddToCache(Arg<Result<BikesAvailableResponse>>.Is.Anything));
var result = await new CachedQuery(server).GetBikesAndStationsAsync();
Assert.AreEqual(3, result.Response.StationsAll.Count);
@ -167,15 +163,13 @@ namespace TestTINKLib.Fixtures.ObjectTests.Connector.Query
[Test]
public async Task TestGetBikes()
{
var server = MockRepository.GenerateMock<ICachedCopriServer>();
var server = Substitute.For<ICachedCopriServer>();
server.Stub(x => x.GetBikesAvailable()).Return(Task.Run(() => new Result<BikesAvailableResponse>(
server.GetBikesAvailable().Returns(Task.Run(() => new Result<BikesAvailableResponse>(
typeof(CopriCallsHttps),
JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLE),
new GeneralData())));
server.Stub(x => x.AddToCache(Arg<Result<BikesAvailableResponse>>.Is.Anything));
var result = await new CachedQuery(server).GetBikesAsync();
Assert.AreEqual(1, result.Response.Count);
@ -186,7 +180,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Connector.Query
[Test]
public async Task TestGetBikesOccupied()
{
var server = MockRepository.GenerateMock<ICachedCopriServer>();
var server = Substitute.For<ICachedCopriServer>();
var result = await new CachedQuery(server).GetBikesOccupiedAsync();

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Threading.Tasks;
using Newtonsoft.Json;
using NSubstitute;
@ -294,5 +294,346 @@ namespace TestShareeLib.Model.Connector
bikesResponse.Response.Count,
Is.EqualTo(1));
}
private const string BIKESAVAILABLE = @"{
""copri_version"" : ""4.1.0.0"",
""bikes"" : {},
""response_state"" : ""OK"",
""apiserver"" : ""https://app.tink-konstanz.de"",
""authcookie"" : """",
""response"" : ""bikes_available"",
""bikes"" : {
""2352"" : {
""description"" : ""Cargo Long"",
""state"" : ""available"",
""bike"" : ""1"",
""gps"" : { ""latitude"": ""47.669888"", ""longitude"": ""9.167749"" },
""station"" : ""9""
}
}
}";
private const string BIKESAVAILABLEEMPTY = @"{
""copri_version"" : ""4.1.0.0"",
""bikes"" : {},
""response_state"" : ""OK"",
""apiserver"" : ""https://app.tink-konstanz.de"",
""authcookie"" : """",
""response"" : ""bikes_available"",
""bikes"" : {
}
}";
private const string BIKESOCCUPIED = @"{
""authcookie"" : ""6103_f782a208d9399291ba8d086b5dcc2509_12345678"",
""debuglevel"" : ""2"",
""user_group"" : [ ""TINK"" ],
""user_id"" : ""javaminister@gmail.com"",
""response"" : ""user_bikes_occupied"",
""response_state"" : ""OK"",
""response_text"" : ""Die Liste der reservierten und gebuchten Fahrräder wurde erfolgreich geladen"",
""apiserver"" : ""https://tinkwwp.copri-bike.de"",
""bikes_occupied"" : {
""89004"" : {
""start_time"" : ""2018-01-27 17:33:00.989464+01"",
""station"" : ""9"",
""unit_price"" : ""2.00"",
""tariff_description"": {
""free_hours"" : ""0.5"",
""name"" : ""TINK Tarif"",
""max_eur_per_day"" : ""9.00""
},
""timeCode"" : ""2061"",
""description"" : ""Cargo Long"",
""bike"" : ""4"",
""total_price"" : ""20.00"",
""state"" : ""requested"",
""real_hours"" : ""66.05"",
""bike_group"" : [ ""TINK"" ],
""now_time"" : ""2018-01-30 11:36:45"",
""request_time"" : ""2018-01-27 17:33:00.989464+01"",
""computed_hours"" : ""10.0""
}
}
}";
private const string STATIONSALL = @"{
""copri_version"" : ""4.1.0.0"",
""stations"" : {
""5"" : {
""station"" : ""5"",
""bike_soll"" : ""0"",
""bike_ist"" : ""7"",
""station_group"" : [ ""TINK"" ],
""gps"" : { ""latitude"": ""47.66756"", ""longitude"": ""9.16477"" },
""state"" : ""available"",
""description"" : """"
},
""13"" : {
""station"" : ""13"",
""bike_soll"" : ""4"",
""bike_ist"" : ""1"",
""station_group"" : [ ""TINK"" ],
""gps"" : { ""latitude"": ""47.657756"", ""longitude"": ""9.176084"" },
""state"" : ""available"",
""description"" : """"
},
""30"" : {
""station"" : ""30"",
""bike_soll"" : ""5"",
""bike_ist"" : ""0"",
""station_group"" : [ ""TINK"", ""Konrad"" ],
""gps"" : { ""latitude"": ""47.657766"", ""longitude"": ""9.176094"" },
""state"" : ""available"",
""description"" : ""Test für Stadtradstation""
}
},
""user_group"" : [ ""Konrad"", ""TINK"" ],
""response_state"" : ""OK"",
""authcookie"" : ""6103_f782a208d9399291ba8d086b5dcc2509_12345678"",
""debuglevel"" : ""2"",
""response"" : ""stations_all"",
""user_id"" : ""javaminister@gmail.com"",
""apiserver"" : ""https://tinkwwp.copri-bike.de""
}";
private const string STATIONSALLEMPTY = @"{
""copri_version"" : ""4.1.0.0"",
""stations"" : {
},
""user_group"" : [ ""Konrad"", ""TINK"" ],
""response_state"" : ""OK"",
""authcookie"" : ""6103_f782a208d9399291ba8d086b5dcc2509_12345678"",
""debuglevel"" : ""2"",
""response"" : ""stations_all"",
""user_id"" : ""javaminister@gmail.com"",
""apiserver"" : ""https://tinkwwp.copri-bike.de""
}";
[Test]
public async Task TestGetStations_StationsFromCache()
{
var server = Substitute.For<ICachedCopriServer>();
server.GetStations(false).Returns(Task.Run(() => new Result<StationsAvailableResponse>(
typeof(CopriCallsMonkeyStore),
JsonConvert.DeserializeObject<StationsAvailableResponse>(STATIONSALL),
new GeneralData(),
new System.Exception("Bang when getting stations..."))));
server.GetBikesAvailable(true).Returns(Task.Run(() => new Result<BikesAvailableResponse>(
typeof(CopriCallsMonkeyStore),
JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLE),
new GeneralData())));
server.GetBikesOccupied(true).Returns(Task.Run(() => new Result<BikesReservedOccupiedResponse>(
typeof(CopriCallsMonkeyStore),
JsonConvert.DeserializeObject<BikesReservedOccupiedResponse>(BIKESOCCUPIED),
new GeneralData())));
var result = await new CachedQueryLoggedIn(server, "123", "a@b", () => DateTime.Now).GetBikesAndStationsAsync();
Assert.AreEqual(3, result.Response.StationsAll.Count);
Assert.AreEqual(2, result.Response.Bikes.Count);
Assert.AreEqual(typeof(CopriCallsMonkeyStore), result.Source);
Assert.AreEqual("Bang when getting stations...", result.Exception.Message);
}
[Test]
public async Task TestGetStations_BikesAvailableFromCache()
{
var server = Substitute.For<ICachedCopriServer>();
server.GetStations(false).Returns(Task.Run(() => new Result<StationsAvailableResponse>(
typeof(CopriCallsHttps),
JsonConvert.DeserializeObject<StationsAvailableResponse>(STATIONSALLEMPTY),
new GeneralData())));
server.GetBikesAvailable(false).Returns(Task.Run(() => new Result<BikesAvailableResponse>(
typeof(CopriCallsMonkeyStore),
JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLE),
new GeneralData(),
new System.Exception("Bang when getting bikes..."))));
server.GetBikesOccupied(true).Returns(Task.Run(() => new Result<BikesReservedOccupiedResponse>(
typeof(CopriCallsMonkeyStore),
JsonConvert.DeserializeObject<BikesReservedOccupiedResponse>(BIKESOCCUPIED),
new GeneralData())));
server.GetStations(true).Returns(Task.Run(() => new Result<StationsAvailableResponse>(
typeof(CopriCallsMonkeyStore),
JsonConvert.DeserializeObject<StationsAvailableResponse>(STATIONSALL),
new GeneralData())));
var result = await new CachedQueryLoggedIn(server, "123", "a@b", () => DateTime.Now).GetBikesAndStationsAsync();
Assert.AreEqual(3, result.Response.StationsAll.Count);
Assert.AreEqual(2, result.Response.Bikes.Count);
Assert.AreEqual(typeof(CopriCallsMonkeyStore), result.Source);
Assert.AreEqual("Bang when getting bikes...", result.Exception.Message);
}
[Test]
public async Task TestGetStations_BikesOccupiedFromCache()
{
var server = Substitute.For<ICachedCopriServer>();
server.GetStations(false).Returns(Task.Run(() => new Result<StationsAvailableResponse>(
typeof(CopriCallsHttps),
JsonConvert.DeserializeObject<StationsAvailableResponse>(STATIONSALLEMPTY),
new GeneralData())));
server.GetBikesAvailable(false).Returns(Task.Run(() => new Result<BikesAvailableResponse>(
typeof(CopriCallsHttps),
JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLEEMPTY),
new GeneralData())));
server.GetBikesOccupied(false).Returns(Task.Run(() => new Result<BikesReservedOccupiedResponse>(
typeof(CopriCallsMonkeyStore),
JsonConvert.DeserializeObject<BikesReservedOccupiedResponse>(BIKESOCCUPIED),
new GeneralData(),
new System.Exception("Bang when getting bikes occupied..."))));
server.GetBikesAvailable(true).Returns(Task.Run(() => new Result<BikesAvailableResponse>(
typeof(CopriCallsMonkeyStore),
JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLE),
new GeneralData())));
server.GetStations(true).Returns(Task.Run(() => new Result<StationsAvailableResponse>(
typeof(CopriCallsMonkeyStore),
JsonConvert.DeserializeObject<StationsAvailableResponse>(STATIONSALL),
new GeneralData())));
var result = await new CachedQueryLoggedIn(server, "123", "a@b", () => DateTime.Now).GetBikesAndStationsAsync();
Assert.AreEqual(3, result.Response.StationsAll.Count);
Assert.AreEqual(2, result.Response.Bikes.Count);
Assert.AreEqual(typeof(CopriCallsMonkeyStore), result.Source);
Assert.AreEqual("Bang when getting bikes occupied...", result.Exception.Message);
}
[Test]
public async Task TestGetStations()
{
var server = Substitute.For<ICachedCopriServer>();
server.GetStations(false).Returns(Task.Run(() => new Result<StationsAvailableResponse>(
typeof(CopriCallsHttps),
JsonConvert.DeserializeObject<StationsAvailableResponse>(STATIONSALL),
new GeneralData())));
server.GetBikesAvailable(false).Returns(Task.Run(() => new Result<BikesAvailableResponse>(
typeof(CopriCallsHttps),
JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLE),
new GeneralData())));
server.GetBikesOccupied(false).Returns(Task.Run(() => new Result<BikesReservedOccupiedResponse>(
typeof(CopriCallsHttps),
JsonConvert.DeserializeObject<BikesReservedOccupiedResponse>(BIKESOCCUPIED),
new GeneralData())));
var result = await new CachedQueryLoggedIn(server, "123", "a@b", () => DateTime.Now).GetBikesAndStationsAsync();
Assert.AreEqual(3, result.Response.StationsAll.Count);
Assert.AreEqual(2, result.Response.Bikes.Count);
Assert.AreEqual(typeof(CopriCallsHttps), result.Source);
Assert.IsNull(result.Exception);
}
[Test]
public async Task TestGetBikes_BikesAvailableFromCache()
{
var server = Substitute.For<ICachedCopriServer>();
server.GetBikesAvailable().Returns(Task.Run(() => new Result<BikesAvailableResponse>(
typeof(CopriCallsMonkeyStore),
JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLE),
new GeneralData(),
new System.Exception("Bang, bikes avail..."))));
server.GetBikesOccupied(true).Returns(Task.Run(() => new Result<BikesReservedOccupiedResponse>(
typeof(CopriCallsHttps),
JsonConvert.DeserializeObject<BikesReservedOccupiedResponse>(BIKESOCCUPIED),
new GeneralData())));
var result = await new CachedQueryLoggedIn(server, "123", "a@b", () => DateTime.Now).GetBikesAsync();
Assert.AreEqual(2, result.Response.Count);
Assert.AreEqual(typeof(CopriCallsMonkeyStore), result.Source);
Assert.AreEqual("Bang, bikes avail...", result.Exception.Message);
}
[Test]
public async Task TestGetBikes_BikesOccupiedFromCache()
{
var server = Substitute.For<ICachedCopriServer>();
server.GetBikesAvailable(false).Returns(Task.Run(() => new Result<BikesAvailableResponse>(
typeof(CopriCallsHttps),
JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLEEMPTY),
new GeneralData())));
server.GetBikesOccupied(false).Returns(Task.Run(() => new Result<BikesReservedOccupiedResponse>(
typeof(CopriCallsMonkeyStore),
JsonConvert.DeserializeObject<BikesReservedOccupiedResponse>(BIKESOCCUPIED),
new GeneralData(),
new System.Exception("Bang, error bikes occupied"))));
server.GetBikesAvailable(true).Returns(Task.Run(() => new Result<BikesAvailableResponse>(
typeof(CopriCallsMonkeyStore),
JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLE),
new GeneralData())));
var result = await new CachedQueryLoggedIn(server, "123", "a@b", () => DateTime.Now).GetBikesAsync();
Assert.AreEqual(2, result.Response.Count);
Assert.AreEqual(typeof(CopriCallsMonkeyStore), result.Source);
Assert.AreEqual("Bang, error bikes occupied", result.Exception.Message);
}
[Test]
public async Task TestGetBikes()
{
var server = Substitute.For<ICachedCopriServer>();
server.GetBikesAvailable().Returns(Task.Run(() => new Result<BikesAvailableResponse>(
typeof(CopriCallsHttps),
JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLE),
new GeneralData())));
server.GetBikesOccupied().Returns(Task.Run(() => new Result<BikesReservedOccupiedResponse>(
typeof(CopriCallsHttps),
JsonConvert.DeserializeObject<BikesReservedOccupiedResponse>(BIKESOCCUPIED),
new GeneralData())));
var result = await new CachedQueryLoggedIn(server, "123", "a@b", () => DateTime.Now).GetBikesAsync();
Assert.AreEqual(2, result.Response.Count);
Assert.AreEqual(typeof(CopriCallsHttps), result.Source);
Assert.IsNull(result.Exception);
}
[Test]
public async Task TestGetBikesOccupied()
{
var server = Substitute.For<ICachedCopriServer>();
server.GetBikesAvailable().Returns(Task.Run(() => new Result<BikesAvailableResponse>(
typeof(CopriCallsHttps),
JsonConvert.DeserializeObject<BikesAvailableResponse>("{}"),
new GeneralData())));
server.GetBikesOccupied().Returns(Task.Run(() => new Result<BikesReservedOccupiedResponse>(
typeof(CopriCallsHttps),
JsonConvert.DeserializeObject<BikesReservedOccupiedResponse>(BIKESOCCUPIED),
new GeneralData())));
var result = await new CachedQueryLoggedIn(server, "123", "a@b", () => DateTime.Now).GetBikesOccupiedAsync();
Assert.AreEqual(1, result.Response.Count);
Assert.AreEqual(typeof(CopriCallsHttps), result.Source);
Assert.IsNull(result.Exception);
}
}
}

View file

@ -1,8 +1,9 @@
using System;
using System;
using System.Threading.Tasks;
using Newtonsoft.Json;
using NSubstitute;
using NSubstitute.ReceivedExtensions;
using NUnit.Framework;
using Rhino.Mocks;
using TINK.Model.Connector;
using TINK.Repository;
using TINK.Repository.Exception;
@ -17,9 +18,9 @@ namespace TestTINKLib.Fixtures.ObjectTests.Connector
[Test]
public void TestDoLogout()
{
var l_oServer = MockRepository.GenerateStub<ICopriServer>();
var l_oServer = Substitute.For<ICopriServer>();
l_oServer.Stub(x => x.DoAuthoutAsync()).Return(Task.Run(() => JsonConvert.DeserializeObject<AuthorizationoutResponse>("{ \"response_state\" : \"OK\", \"authcookie\" : \"1\"}")));
l_oServer.DoAuthoutAsync().Returns(Task.Run(() => JsonConvert.DeserializeObject<AuthorizationoutResponse>("{ \"response_state\" : \"OK\", \"authcookie\" : \"1\"}")));
var l_oCmd = new CommandLoggedIn(l_oServer, "MeinKeks", "EMehl", () => DateTime.Now);
@ -28,7 +29,8 @@ namespace TestTINKLib.Fixtures.ObjectTests.Connector
l_oCmd.DoLogout().Wait();
l_oServer.AssertWasCalled(x => x.DoAuthoutAsync());
l_oServer.Received().DoAuthoutAsync();
Assert.IsNotNull(l_oEventArgs);
}
@ -36,9 +38,9 @@ namespace TestTINKLib.Fixtures.ObjectTests.Connector
[Test]
public void TestDoLogout_AuthcookieNotDefined()
{
var l_oServer = MockRepository.GenerateStub<ICopriServer>();
var l_oServer = Substitute.For<ICopriServer>();
l_oServer.Stub(x => x.DoAuthoutAsync()).Throw(new AuthcookieNotDefinedException("Testing action", JsonConvert.DeserializeObject<ResponseBase>(@"{ ""response_state"" : ""Some inner error description""}")));
l_oServer.When(x => x.DoAuthoutAsync()).Throw(new AuthcookieNotDefinedException("Testing action", JsonConvert.DeserializeObject<ResponseBase>(@"{ ""response_state"" : ""Some inner error description""}")));
var l_oCmd = new CommandLoggedIn(l_oServer, "MeinKeks", "EMehl", () => DateTime.Now);
@ -47,7 +49,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Connector
l_oCmd.DoLogout().Wait();
l_oServer.AssertWasCalled(x => x.DoAuthoutAsync());
l_oServer.Received().DoAuthoutAsync();
Assert.IsNotNull(l_oEventArgs);
}
@ -55,9 +57,9 @@ namespace TestTINKLib.Fixtures.ObjectTests.Connector
[Test]
public void TestDoLogout_Exception()
{
var l_oServer = MockRepository.GenerateStub<ICopriServer>();
var l_oServer = Substitute.For<ICopriServer>();
l_oServer.Stub(x => x.DoAuthoutAsync()).Throw(new System.Exception("Sometheing went wrong."));
l_oServer.When(x => x.DoAuthoutAsync()).Throw(new System.Exception("Sometheing went wrong."));
var l_oCmd = new CommandLoggedIn(l_oServer, "MeinKeks", "EMehl", () => DateTime.Now);
@ -66,7 +68,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Connector
Assert.Throws<AggregateException>(() => l_oCmd.DoLogout().Wait());
l_oServer.AssertWasCalled(x => x.DoAuthoutAsync());
l_oServer.Received().DoAuthoutAsync();
Assert.IsNull(l_oEventArgs);
}
}

View file

@ -1,6 +1,6 @@
using System;
using System;
using NSubstitute;
using NUnit.Framework;
using Rhino.Mocks;
using TINK.Model.Connector;
using TINK.Model.Services.CopriApi;
using TINK.Repository;
@ -16,7 +16,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Connector
[Test]
public void TestCommandFactory()
{
var l_oCopri = MockRepository.GenerateStub<ICachedCopriServer>();
var l_oCopri = Substitute.For<ICachedCopriServer>();
// Construct not logged in version of connector.
var l_oCommand = new TINK.Model.Connector.Connector(
@ -36,7 +36,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Connector
[Test]
public void TestCommandFactory_LoggedIn()
{
var l_oCopri = MockRepository.GenerateStub<ICachedCopriServer>();
var l_oCopri = Substitute.For<ICachedCopriServer>();
var l_oCommand = new TINK.Model.Connector.Connector(
new System.Uri("http://1.2.3.4"),
@ -55,7 +55,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Connector
[Test]
public void TestQueryFactory_CachedServer()
{
var l_oCopri = MockRepository.GenerateStub<ICachedCopriServer>();
var l_oCopri = Substitute.For<ICachedCopriServer>();
var l_oQuery = new TINK.Model.Connector.Connector(
new Uri("http://1.2.3.4"),
@ -74,7 +74,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Connector
[Test]
public void TestQueryFactory_LoggedIn()
{
var l_oCopri = MockRepository.GenerateStub<ICachedCopriServer>();
var l_oCopri = Substitute.For<ICachedCopriServer>();
var l_oQuery = new TINK.Model.Connector.Connector(
new System.Uri("http://1.2.3.4"),

View file

@ -1,6 +1,6 @@
using System;
using NSubstitute;
using NUnit.Framework;
using Rhino.Mocks;
using TINK.Model.Connector;
using TINK.Repository;
@ -15,7 +15,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Connector
[Test]
public void TestCommandFactory()
{
var l_oCopri = MockRepository.GenerateStub<ICopriServer>();
var l_oCopri = Substitute.For<ICopriServer>();
// Construct not logged in version of connector.
var l_oCommand = new ConnectorCache(
@ -34,7 +34,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Connector
[Test]
public void TestCommandFactory_LoggedIn()
{
var l_oCopri = MockRepository.GenerateStub<ICopriServer>();
var l_oCopri = Substitute.For<ICopriServer>();
var l_oCommand = new ConnectorCache(
new AppContextInfo("MyMerchId", "MyApp", new Version(1, 2)),
@ -52,7 +52,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Connector
[Test]
public void TestQueryFactory_CachedServer()
{
var l_oCopri = MockRepository.GenerateStub<ICopriServer>();
var l_oCopri = Substitute.For<ICopriServer>();
var l_oQuery = new ConnectorCache(
new AppContextInfo("MyMerchId", "MyApp", new Version(1, 2)),
@ -70,7 +70,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Connector
[Test]
public void TestQueryFactory_LoggedIn()
{
var l_oCopri = MockRepository.GenerateStub<ICopriServer>();
var l_oCopri = Substitute.For<ICopriServer>();
var l_oQuery = new ConnectorCache(
new AppContextInfo("MyMerchId", "MyApp", new Version(1, 2)),

View file

@ -1,7 +1,7 @@
using System.Threading.Tasks;
using System.Threading.Tasks;
using Newtonsoft.Json;
using NSubstitute;
using NUnit.Framework;
using Rhino.Mocks;
using TINK.Repository;
using TINK.Repository.Response;
@ -71,10 +71,10 @@ namespace TestTINKLib.Fixtures.ObjectTests.Query
[Test]
public async Task TestGetStations()
{
var server = MockRepository.GenerateMock<ICopriServer>();
var server = Substitute.For<ICopriServer>();
server.Stub(x => x.GetStationsAsync()).Return(Task.Run(() => JsonConvert.DeserializeObject<StationsAvailableResponse>(STATIONSALL)));
server.Stub(x => x.GetBikesAvailableAsync()).Return(Task.Run(() => JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLE)));
server.GetStationsAsync().Returns(Task.Run(() => JsonConvert.DeserializeObject<StationsAvailableResponse>(STATIONSALL)));
server.GetBikesAvailableAsync().Returns(Task.Run(() => JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLE)));
var result = await new TINK.Model.Connector.Query(server).GetBikesAndStationsAsync();
@ -87,9 +87,9 @@ namespace TestTINKLib.Fixtures.ObjectTests.Query
[Test]
public async Task TestGetBikes()
{
var server = MockRepository.GenerateMock<ICopriServer>();
var server = Substitute.For<ICopriServer>();
server.Stub(x => x.GetBikesAvailableAsync()).Return(Task.Run(() => JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLE)));
server.GetBikesAvailableAsync().Returns(Task.Run(() => JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLE)));
var result = await new TINK.Model.Connector.Query(server).GetBikesAsync();
@ -101,7 +101,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Query
[Test]
public async Task TestGetBikesOccupied()
{
var server = MockRepository.GenerateMock<ICopriServer>();
var server = Substitute.For<ICopriServer>();
var result = await new TINK.Model.Connector.Query(server).GetBikesOccupiedAsync();

View file

@ -1,9 +1,8 @@
using System;
using System;
using System.Threading.Tasks;
using Newtonsoft.Json;
using NSubstitute;
using NUnit.Framework;
using Rhino.Mocks;
using TINK.Model.Connector;
using TINK.Repository;
using TINK.Repository.Response;
@ -108,11 +107,11 @@ namespace TestTINKLib.Fixtures.ObjectTests.Connector
[Test]
public async Task TestGetStations()
{
var server = MockRepository.GenerateMock<ICopriServer>();
var server = Substitute.For<ICopriServer>();
server.Stub(x => x.GetStationsAsync()).Return(Task.Run(() => JsonConvert.DeserializeObject<StationsAvailableResponse>(STATIONSALL)));
server.Stub(x => x.GetBikesAvailableAsync()).Return(Task.Run(() => JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLE)));
server.Stub(x => x.GetBikesOccupiedAsync()).Return(Task.Run(() => JsonConvert.DeserializeObject<BikesReservedOccupiedResponse>(BIKESOCCUPIED)));
server.GetStationsAsync().Returns(Task.Run(() => JsonConvert.DeserializeObject<StationsAvailableResponse>(STATIONSALL)));
server.GetBikesAvailableAsync().Returns(Task.Run(() => JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLE)));
server.GetBikesOccupiedAsync().Returns(Task.Run(() => JsonConvert.DeserializeObject<BikesReservedOccupiedResponse>(BIKESOCCUPIED)));
var result = await new QueryLoggedIn(server, "123", "a@b", () => DateTime.Now).GetBikesAndStationsAsync();
@ -125,10 +124,10 @@ namespace TestTINKLib.Fixtures.ObjectTests.Connector
[Test]
public async Task TestGetBikes()
{
var server = MockRepository.GenerateMock<ICopriServer>();
var server = Substitute.For<ICopriServer>();
server.Stub(x => x.GetBikesAvailableAsync()).Return(Task.Run(() => JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLE)));
server.Stub(x => x.GetBikesOccupiedAsync()).Return(Task.Run(() => JsonConvert.DeserializeObject<BikesReservedOccupiedResponse>(BIKESOCCUPIED)));
server.GetBikesAvailableAsync().Returns(Task.Run(() => JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLE)));
server.GetBikesOccupiedAsync().Returns(Task.Run(() => JsonConvert.DeserializeObject<BikesReservedOccupiedResponse>(BIKESOCCUPIED)));
var result = await new QueryLoggedIn(server, "123", "a@b", () => DateTime.Now).GetBikesAsync();

View file

@ -1,7 +1,7 @@
using System;
using System;
using System.Collections.Generic;
using NSubstitute;
using NUnit.Framework;
using Rhino.Mocks;
using TINK.Model.State;
@ -28,8 +28,8 @@ namespace TestTINKLib
public void TestConstructCopy()
{
// State is available.
var l_oSource = MockRepository.GenerateStub<IStateInfo>();
l_oSource.Stub(x => x.Value).Return(InUseStateEnum.Disposable);
var l_oSource = Substitute.For<IStateInfo>();
l_oSource.Value.Returns(InUseStateEnum.Disposable);
var l_oState = new StateInfoMutable(state: l_oSource);
@ -39,11 +39,11 @@ namespace TestTINKLib
Assert.IsNull(l_oState.Code);
// State is requested.
l_oSource = MockRepository.GenerateStub<IStateInfo>();
l_oSource.Stub(x => x.Value).Return(InUseStateEnum.Reserved);
l_oSource.Stub(x => x.From).Return(new DateTime(2018, 1, 4, 17, 26, 0));
l_oSource.Stub(x => x.MailAddress).Return("who@the");
l_oSource.Stub(x => x.Code).Return("323");
l_oSource = Substitute.For<IStateInfo>();
l_oSource.Value.Returns(InUseStateEnum.Reserved);
l_oSource.From.Returns(new DateTime(2018, 1, 4, 17, 26, 0));
l_oSource.MailAddress.Returns("who@the");
l_oSource.Code.Returns("323");
l_oState = new StateInfoMutable(() => new DateTime(2018, 1, 4, 17, 30, 1), l_oSource);
@ -54,11 +54,11 @@ namespace TestTINKLib
Assert.AreEqual("323", l_oState.Code);
// State is booked.
l_oSource = MockRepository.GenerateStub<IStateInfo>();
l_oSource.Stub(x => x.Value).Return(InUseStateEnum.Booked);
l_oSource.Stub(x => x.From).Return(new DateTime(2018, 1, 4, 17, 00, 0));
l_oSource.Stub(x => x.MailAddress).Return("who@the");
l_oSource.Stub(x => x.Code).Return("323");
l_oSource = Substitute.For<IStateInfo>();
l_oSource.Value.Returns(InUseStateEnum.Booked);
l_oSource.From.Returns(new DateTime(2018, 1, 4, 17, 00, 0));
l_oSource.MailAddress.Returns("who@the");
l_oSource.Code.Returns("323");
l_oState = new StateInfoMutable(() => new DateTime(2018, 1, 4, 17, 30, 1), l_oSource);
@ -185,4 +185,4 @@ namespace TestTINKLib
Assert.IsNull(l_oState.Code);
}
}
}
}

View file

@ -43,7 +43,7 @@ namespace TestShareeLib.UseCases.Login
merchantId: "MyMerchId",
bluetoothService: Substitute.For<IBluetoothLE>(),
locationPermissionsService: permissions,
locationServicesContainer: Substitute.For<IServicesContainer<IGeolocation>>(),
locationServicesContainer: Substitute.For<IServicesContainer<IGeolocationService>>(),
locksService: locksService, // Cipher
device: device,
specialFolder: specialFolder,

View file

@ -48,7 +48,7 @@ namespace TestTINKLib.Fixtures.UseCases.Logout
merchantId: "MyMerchId",
bluetoothService: Substitute.For<IBluetoothLE>(),
locationPermissionsService: permissions,
locationServicesContainer: Substitute.For<IServicesContainer<IGeolocation>>(),
locationServicesContainer: Substitute.For<IServicesContainer<IGeolocationService>>(),
locksService: locksService, // Cipher
device: device,
specialFolder: specialFolder,

View file

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using NSubstitute;
using NUnit.Framework;
using Plugin.BLE.Abstractions.Contracts;
@ -8,8 +9,11 @@ using TestFramework.Model.Services.Geolocation;
using TestFramework.Model.User.Account;
using TestFramework.Services.BluetoothLock;
using TINK.Model;
using TINK.Model.Bikes;
using TINK.Model.Connector;
using TINK.Model.Settings;
using TINK.Model.Station;
using TINK.Model.User;
using TINK.Repository;
using TINK.Services;
using TINK.Services.Geolocation;
@ -23,6 +27,24 @@ namespace TestTINKLib.Fixtures.UseCases.SelectStation
[TestFixture]
public class TestTinkApp
{
/// <summary>
/// Get all bikes at a given station from copri.
/// </summary>
private static async Task<BikeCollectionMutable> GetBikesAtStation(
User user,
TINK.Model.Connector.IConnector connector,
IEnumerable<IStation> stations,
string selectedStationId)
{
var l_oBikesAtStation = new BikeCollectionMutable();
var l_oBikesAvailable = (await connector.Query.GetBikesAsync()).Response;
l_oBikesAtStation.Update(l_oBikesAvailable.GetAtStation(selectedStationId), stations);
return l_oBikesAtStation;
}
[Test]
public void TestBikesAtStation_AccountStoreMock_NoUser_CopriMock_Set2()
{
@ -51,7 +73,7 @@ namespace TestTINKLib.Fixtures.UseCases.SelectStation
merchantId: MERCH_ID,
bluetoothService: Substitute.For<IBluetoothLE>(),
locationPermissionsService: Substitute.For<ILocationPermission>(),
locationServicesContainer: Substitute.For<IServicesContainer<IGeolocation>>(),
locationServicesContainer: Substitute.For<IServicesContainer<IGeolocationService>>(),
locksService: new LocksServiceMock(), // Cipher
device: new DeviceMock(),
specialFolder: new SpecialFolderMock(),
@ -60,25 +82,25 @@ namespace TestTINKLib.Fixtures.UseCases.SelectStation
currentVersion: new Version(3, 2, 0, 115),
lastVersion: new Version(3, 0, 173)); // Current app version. Must be larger or equal 3.0.173 to
Assert.AreEqual(0, TestHelper.GetBikesAtStation(l_oTinkApp.ActiveUser, l_oConnector, l_oTinkApp.Stations, l_oTinkApp.SelectedStation.Id).Result.Count);
Assert.AreEqual(0, GetBikesAtStation(l_oTinkApp.ActiveUser, l_oConnector, l_oTinkApp.Stations, l_oTinkApp.SelectedStation.Id).Result.Count);
l_oTinkApp.SelectedStation = new TINK.Model.Station.Station("5", new List<string>(), null);
Assert.AreEqual(3, TestHelper.GetBikesAtStation(l_oTinkApp.ActiveUser, l_oConnector, l_oTinkApp.Stations, l_oTinkApp.SelectedStation.Id).Result.Count);
Assert.AreEqual("25", TestHelper.GetBikesAtStation(l_oTinkApp.ActiveUser, l_oConnector, l_oTinkApp.Stations, l_oTinkApp.SelectedStation.Id).Result.GetById("25").Id);
Assert.AreEqual("11", TestHelper.GetBikesAtStation(l_oTinkApp.ActiveUser, l_oConnector, l_oTinkApp.Stations, l_oTinkApp.SelectedStation.Id).Result.GetById("11").Id);
Assert.AreEqual("2", TestHelper.GetBikesAtStation(l_oTinkApp.ActiveUser, l_oConnector, l_oTinkApp.Stations, l_oTinkApp.SelectedStation.Id).Result.GetById("2").Id);
Assert.AreEqual(3, GetBikesAtStation(l_oTinkApp.ActiveUser, l_oConnector, l_oTinkApp.Stations, l_oTinkApp.SelectedStation.Id).Result.Count);
Assert.AreEqual("25", GetBikesAtStation(l_oTinkApp.ActiveUser, l_oConnector, l_oTinkApp.Stations, l_oTinkApp.SelectedStation.Id).Result.GetById("25").Id);
Assert.AreEqual("11", GetBikesAtStation(l_oTinkApp.ActiveUser, l_oConnector, l_oTinkApp.Stations, l_oTinkApp.SelectedStation.Id).Result.GetById("11").Id);
Assert.AreEqual("2", GetBikesAtStation(l_oTinkApp.ActiveUser, l_oConnector, l_oTinkApp.Stations, l_oTinkApp.SelectedStation.Id).Result.GetById("2").Id);
l_oTinkApp.SelectedStation = new TINK.Model.Station.Station("10", new List<string>(), null);
Assert.AreEqual(
1,
TestHelper.GetBikesAtStation(l_oTinkApp.ActiveUser, l_oConnector, l_oTinkApp.Stations, l_oTinkApp.SelectedStation.Id).Result.Count);
GetBikesAtStation(l_oTinkApp.ActiveUser, l_oConnector, l_oTinkApp.Stations, l_oTinkApp.SelectedStation.Id).Result.Count);
Assert.AreEqual("18", TestHelper.GetBikesAtStation(l_oTinkApp.ActiveUser, l_oConnector, l_oTinkApp.Stations, l_oTinkApp.SelectedStation.Id).Result.GetById("18").Id);
Assert.AreEqual("18", GetBikesAtStation(l_oTinkApp.ActiveUser, l_oConnector, l_oTinkApp.Stations, l_oTinkApp.SelectedStation.Id).Result.GetById("18").Id);
l_oTinkApp.SelectedStation = new TINK.Model.Station.Station("91345", new List<string>(), null);
Assert.AreEqual(0, TestHelper.GetBikesAtStation(l_oTinkApp.ActiveUser, l_oConnector, l_oTinkApp.Stations, l_oTinkApp.SelectedStation.Id).Result.Count);
Assert.AreEqual(0, GetBikesAtStation(l_oTinkApp.ActiveUser, l_oConnector, l_oTinkApp.Stations, l_oTinkApp.SelectedStation.Id).Result.Count);
}
}
}

View file

@ -1,7 +1,7 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using NSubstitute;
using NUnit.Framework;
using Rhino.Mocks;
using TINK.Model.Connector;
using TINK.Model.User.Account;
@ -14,11 +14,11 @@ namespace TestTINKLib.Fixtures.ObjectTests.User.Account
[Test]
public void TestDoFilter_NoUserLoggedIn()
{
var l_oAccount = MockRepository.GenerateMock<IAccount>();
var l_oAccount = Substitute.For<IAccount>();
l_oAccount.Stub((x) => x.Mail).Return("a@b");
l_oAccount.Stub((x) => x.SessionCookie).Return(""); // User is not logged in
l_oAccount.Stub((x) => x.Group).Return(new List<string> { $"HOM_{FilterHelper.CARGOBIKE}", "HOM_117025" });
l_oAccount.Mail.Returns("a@b");
l_oAccount.SessionCookie.Returns(""); // User is not logged in
l_oAccount.Group.Returns(new List<string> { $"HOM_{FilterHelper.CARGOBIKE}", "HOM_117025" });
var l_oSource = new List<string> { $"HOM_{FilterHelper.CARGOBIKE}", $"HOM_{FilterHelper.CITYBIKE}", "HOM_117025" };
@ -33,11 +33,11 @@ namespace TestTINKLib.Fixtures.ObjectTests.User.Account
[Test]
public void TestDoFilter()
{
var l_oAccount = MockRepository.GenerateMock<IAccount>();
var l_oAccount = Substitute.For<IAccount>();
l_oAccount.Stub((x) => x.Mail).Return("a@b");
l_oAccount.Stub((x) => x.SessionCookie).Return("123");
l_oAccount.Stub((x) => x.Group).Return(new List<string> { $"HOM_{FilterHelper.CARGOBIKE}", "HOM_117025" });
l_oAccount.Mail.Returns("a@b");
l_oAccount.SessionCookie.Returns("123");
l_oAccount.Group.Returns(new List<string> { $"HOM_{FilterHelper.CARGOBIKE}", "HOM_117025" });
var l_oSource = new List<string> { $"HOM_{FilterHelper.CARGOBIKE}", $"HOM_{FilterHelper.CITYBIKE}", "HOM_117025" };

View file

@ -26,11 +26,11 @@ namespace TestTINKLib.Fixtures.Connector.Request
Assert.IsNull(
l_oCopri.GetBikesAvailableAsync().Result.bikes.Values.FirstOrDefault(x => x.state != "available"),
"Bikes available must return bikes which are all of state available.");
"Bikes available must end rentals which are all of state available.");
Assert.IsNull(
l_oCopri.GetBikesOccupiedAsync().Result.bikes_occupied.Values.FirstOrDefault(x => x.state == "available"),
"Bikes occupied must return bikes which are either reserved or booked.");
"Bikes occupied must end rentals which are either reserved or booked.");
}
}
}

View file

@ -1,4 +1,5 @@
using Newtonsoft.Json;
using System.Linq;
using Newtonsoft.Json;
using NUnit.Framework;
using TINK.Repository;
using TINK.Repository.Response;
@ -82,5 +83,158 @@ namespace TestShareeLib.Repository
() => response.DeserializeResponse<ResponseBase>(version => new System.Exception("Ho")).copri_version,
Throws.InstanceOf<System.Exception>());
}
[Test]
public void TestDeserializeObjectBikesAvailableValidResponse()
{
const string VALID_RESPONSE = @"
{
""shareejson"": {
""authcookie"": 0,
""apiserver"": ""https://tinkwwp.copri-bike.de"",
""response"": ""bikes_available"",
""bikes"": {
""3399"": {
""description"": ""Cargo Trike"",
""bike"": ""26"",
""state"": ""available"",
""gps"" : { ""latitude"": ""47.6586936667"", ""longitude"": ""9.16863116667"" },
""station"" : ""4""
},
},
""response_state"": ""OK"",
""copri_version"" : ""4.1.0.0""
}
}
";
// Ensure that answer holds a valid bike.
var l_oBike = CopriCallsStatic.DeserializeResponse<BikesAvailableResponse>(VALID_RESPONSE).bikes.FirstOrDefault().Value;
Assert.NotNull(l_oBike, "Response must contain at leas one bike.");
Assert.Greater(l_oBike.description.Length, 0, "Bike despcription must never be empty.");
Assert.AreEqual(l_oBike.bike, "26");
Assert.That(
l_oBike.station,
Is.EqualTo("4"),
"Station index must never be negative");
Assert.AreEqual("available", l_oBike.state);
Assert.That(l_oBike.gps, Is.Not.Null, "Gps position must never be empty.");
}
[Test]
public void TestDeserializeObjectBikesAvailableValidResponse_NoDescription()
{
const string INVALID_RESPONSE = @"
{
""shareejson"": {
""authcookie"": 0,
""apiserver"": ""https://tinkwwp.copri-bike.de"",
""response"": ""bikes_available"",
""bikes"": {
""3399"": {
""bike"": 26,
""state"": ""available"",
""gps"" : { ""latitude"": ""47.6586936667"", ""longitude"": ""9.16863116667"" },
""station"" : 4
},
},
""response_state"": ""OK"",
""copri_version"" : ""4.1.0.0"",
}
}
";
// Ensure that answer holds a valid bike.
var l_oBike = CopriCallsStatic.DeserializeResponse<BikesAvailableResponse>(INVALID_RESPONSE).bikes.FirstOrDefault().Value;
Assert.NotNull(l_oBike, "Response must contain at leas one bike.");
Assert.IsNull(l_oBike.description);
Assert.That(l_oBike.bike, Is.Not.Null);
Assert.That(l_oBike.station, Is.Not.Null);
Assert.AreEqual("available", l_oBike.state);
Assert.That(l_oBike.gps, Is.Not.Null, "Gps position must never be empty.");
}
[Test]
public void TestDeserializeObjectBikesAvailableValidResponse_NoBikeId()
{
const string VALID_RESPONSE = @"
{
""shareejson"": {
""authcookie"": 0,
""apiserver"": ""https://tinkwwp.copri-bike.de"",
""response"": ""bikes_available"",
""bikes"": {
""3399"": {
""description"": ""Cargo Trike"",
""state"": ""available"",
""gps"" : { ""latitude"": ""47.6586936667"", ""longitude"": ""9.16863116667"" },
""station"" : ""4""
},
},
""response_state"": ""OK"",
""copri_version"" : ""4.1.0.0"",
}
}";
// Ensure that answer holds a valid bike.
var l_oBike = CopriCallsStatic.DeserializeResponse<BikesAvailableResponse>(VALID_RESPONSE).bikes.FirstOrDefault().Value;
Assert.NotNull(l_oBike, "Response must contain at leas one bike.");
Assert.Greater(l_oBike.description.Length, 0, "Bike despcription must never be empty.");
Assert.That(l_oBike.bike, Is.Null);
Assert.That(l_oBike.station, Is.Not.Null);
Assert.AreEqual("available", l_oBike.state);
Assert.That(l_oBike.gps, Is.Not.Null, "Gps position must never be empty.");
}
[Test]
public void TestDeserializeObjectBikesOccupiedValidResponse()
{
const string VALID_RESPONSE = @"
{
""shareejson"": {
""response_state"": ""OK"",
""bikes_occupied"": {
""87781"": {
""timeCode"": ""3630"",
""state"": ""occupied"",
""station"" : ""5"",
""description"": ""Cargo Long"",
""start_time"": ""2017-11-28 11:01:51.637747+01"",
""bike"": ""8""
},
""87782"": {
""timeCode"": ""2931"",
""state"": ""occupied"",
""station"" : ""4"",
""description"": ""Cargo Long"",
""start_time"": ""2017-11-28 13:06:55.147368+01"",
""bike"": ""7""
}
},
""authcookie"": ""b76b97e43a2d76b8499f32e6dd597af8"",
""response"": ""user_bikes_occupied"",
""apiserver"": ""https://tinkwwp.copri-bike.de"",
""copri_version"" : ""4.1.0.0"",
}
}";
// Ensure that answer holds a valid bike.
var l_oBike = CopriCallsStatic.DeserializeResponse<BikesReservedOccupiedResponse>(VALID_RESPONSE).bikes_occupied.FirstOrDefault().Value;
Assert.NotNull(l_oBike, "Response must contain at leas one bike.");
Assert.Greater(l_oBike.description.Length, 0, "Bike despcription must never be empty.");
Assert.That(l_oBike.bike, Is.Not.Null);
Assert.That(l_oBike.station, Is.Not.Null);
Assert.Greater(l_oBike.state.Length, 0, "State info must never be null or empty.");
// Todo: Requested bikes do not have a gps position. What is about booked bikes?
// Assert.Greater(l_oBike.gps.Length, 0, "Gps position must never be empty.");
Assert.Greater(l_oBike.start_time.Length, 0, "Time when request/ booking was performed must never be null or empty.");
Assert.Greater(l_oBike.timeCode.Length, 0, "Booking code must never be null or empty.");
}
}
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using NUnit.Framework;
using TINK.Services;
@ -64,5 +64,35 @@ namespace TestShareeLib.Services
private class MyTypeB { }
private class MyTypeC { }
[Test]
public void TestCtor2()
{
var container = new ServicesContainerMutableT<object>(new List<object> { new MyTypeA(), new MyTypeB() }, typeof(MyTypeB).FullName);
Assert.That(container.Active.GetType().FullName, Is.EqualTo("TestShareeLib.Services.TestServicesContainerMutable+MyTypeB"));
}
[Test]
public void TestCtorExceptionDupes()
{
Assert.That(() => new ServicesContainerMutableT<object>(new List<object> { new MyTypeA(), new MyTypeB(), new MyTypeA() }, typeof(MyTypeB).FullName), Throws.InstanceOf<Exception>());
}
[Test]
public void TestCtorExceptionActiveNotFound()
{
Assert.That(() => new ServicesContainerMutableT<object>(new List<object> { new MyTypeA(), new MyTypeB() }, "MyTypeF"), Throws.InstanceOf<ArgumentException>());
}
[Test]
public void TestSetActive2()
{
var container = new ServicesContainerMutableT<object>(new List<object> { new MyTypeA(), new MyTypeB() }, typeof(MyTypeB).FullName);
container.SetActive(typeof(MyTypeA).FullName);
Assert.That(container.Active.GetType().FullName, Is.EqualTo("TestShareeLib.Services.TestServicesContainerMutable+MyTypeA"));
}
}
}

View file

@ -29,7 +29,7 @@
<ItemGroup>
<PackageReference Include="NSubstitute" Version="5.0.0" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.3.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.4.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="Xamarin.Essentials" Version="1.7.5" />
</ItemGroup>

View file

@ -4,7 +4,6 @@ using System.Threading.Tasks;
using NSubstitute;
using NUnit.Framework;
using Plugin.BLE.Abstractions.Contracts;
using Rhino.Mocks;
using TestFramework.Model.Device;
using TestFramework.Model.Services.Geolocation;
using TestFramework.Model.User.Account;
@ -51,7 +50,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Account
merchantId: MERCH_ID,
bluetoothService: Substitute.For<IBluetoothLE>(),
locationPermissionsService: Substitute.For<ILocationPermission>(),
locationServicesContainer: Substitute.For<IServicesContainer<IGeolocation>>(),
locationServicesContainer: Substitute.For<IServicesContainer<IGeolocationService>>(),
locksService: new LocksServiceMock(), // Cipher
device: new DeviceMock(),
specialFolder: new SpecialFolderMock(),
@ -62,7 +61,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Account
lastVersion: new Version(3, 0, 173), // Current app version. Must be larger or equal 3.0.173 to
whatsNewShownInVersion: null); // Whats new page was never shown.
var viewService = MockRepository.GenerateStub<IViewService>();
var viewService = Substitute.For<IViewService>();
var settingsPageViewModel = new AccountPageViewModel(
tinkApp,
@ -96,7 +95,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Account
merchantId: MERCH_ID,
bluetoothService: Substitute.For<IBluetoothLE>(),
locationPermissionsService: Substitute.For<ILocationPermission>(),
locationServicesContainer: Substitute.For<IServicesContainer<IGeolocation>>(),
locationServicesContainer: Substitute.For<IServicesContainer<IGeolocationService>>(),
locksService: new LocksServiceMock(), // Cipher
device: new DeviceMock(),
specialFolder: new SpecialFolderMock(),
@ -107,7 +106,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Account
lastVersion: new Version(3, 0, 173), // Current app version. Must be larger or equal 3.0.173 to
whatsNewShownInVersion: null); // Whats new page was never shown.
var viewService = MockRepository.GenerateStub<IViewService>();
var viewService = Substitute.For<IViewService>();
var settingsPageViewModel = new AccountPageViewModel(
tinkApp,
@ -140,7 +139,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Account
merchantId: "MyMerchId",
bluetoothService: Substitute.For<IBluetoothLE>(),
locationPermissionsService: Substitute.For<ILocationPermission>(),
locationServicesContainer: Substitute.For<IServicesContainer<IGeolocation>>(),
locationServicesContainer: Substitute.For<IServicesContainer<IGeolocationService>>(),
locksService: new LocksServiceMock(), // Cipher
device: new DeviceMock(),
specialFolder: new SpecialFolderMock(),
@ -151,7 +150,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Account
lastVersion: new Version(3, 0, 173), // Current app version. Must be larger or equal 3.0.173 to
whatsNewShownInVersion: null); // Whats new page was never shown.
var viewService = MockRepository.GenerateStub<IViewService>();
var viewService = Substitute.For<IViewService>();
var settingsPageViewModel = new AccountPageViewModel(
tinkApp,
(uri) => { },
@ -183,7 +182,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Account
merchantId: "MyMerchId",
bluetoothService: Substitute.For<IBluetoothLE>(),
locationPermissionsService: Substitute.For<ILocationPermission>(),
locationServicesContainer: Substitute.For<IServicesContainer<IGeolocation>>(),
locationServicesContainer: Substitute.For<IServicesContainer<IGeolocationService>>(),
locksService: new LocksServiceMock(), // Cipher
device: new DeviceMock(),
specialFolder: new SpecialFolderMock(),
@ -194,7 +193,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Account
lastVersion: new Version(3, 0, 173), // Current app version. Must be larger or equal 3.0.173 to
whatsNewShownInVersion: null); // Whats new page was never shown.
var viewService = MockRepository.GenerateStub<IViewService>();
var viewService = Substitute.For<IViewService>();
var settingsPageViewModel = new AccountPageViewModel(
tinkApp,
(uri) => { },
@ -239,7 +238,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Account
merchantId: "MyMerchId",
bluetoothService: Substitute.For<IBluetoothLE>(),
locationPermissionsService: Substitute.For<ILocationPermission>(),
locationServicesContainer: Substitute.For<IServicesContainer<IGeolocation>>(),
locationServicesContainer: Substitute.For<IServicesContainer<IGeolocationService>>(),
locksService: new LocksServiceMock(), // Cipher
device: new DeviceMock(),
specialFolder: new SpecialFolderMock(),
@ -250,7 +249,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.Account
lastVersion: new Version(3, 0, 173), // Current app version. Must be larger or equal 3.0.173 to
whatsNewShownInVersion: null); // Whats new page was never shown.
var viewService = MockRepository.GenerateStub<IViewService>();
var viewService = Substitute.For<IViewService>();
var settingsPageViewModel = new AccountPageViewModel(
tinkApp,
(uri) => { },

View file

@ -1,6 +1,6 @@
using System;
using System;
using NSubstitute;
using NUnit.Framework;
using Rhino.Mocks;
using TINK.Model.Device;
using TINK.ViewModel;
using TINK.ViewModel.Bikes;
@ -23,12 +23,12 @@ namespace UITest.Fixtures.ViewModel
null,
null,
null,
NSubstitute.Substitute.For<ISmartDevice>(),
Substitute.For<ISmartDevice>(),
null,
bike,
user,
new MyBikeInUseStateInfoProvider(),
MockRepository.GenerateStub<IBikesViewModel>(),
Substitute.For<IBikesViewModel>(),
url => { }));
@ -47,12 +47,12 @@ namespace UITest.Fixtures.ViewModel
null,
null,
null,
NSubstitute.Substitute.For<ISmartDevice>(),
Substitute.For<ISmartDevice>(),
null,
bike,
user,
new MyBikeInUseStateInfoProvider(),
MockRepository.GenerateStub<IBikesViewModel>(),
Substitute.For<IBikesViewModel>(),
url => { }));
Assert.AreEqual("Code 4asdfA, location Station 3, still 7 min. reserved.", l_oViewModel.StateText);
@ -72,12 +72,12 @@ namespace UITest.Fixtures.ViewModel
null,
null,
null,
NSubstitute.Substitute.For<ISmartDevice>(),
Substitute.For<ISmartDevice>(),
null,
bike,
user,
new MyBikeInUseStateInfoProvider(),
MockRepository.GenerateStub<IBikesViewModel>(),
Substitute.For<IBikesViewModel>(),
url => { }));
Assert.AreEqual(

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