mirror of
https://dev.azure.com/TeilRad/sharee.bike%20App/_git/Code
synced 2025-01-21 20:14:27 +01:00
Version 3.0.294
This commit is contained in:
parent
d92fb4a40f
commit
8f40f2c208
133 changed files with 17890 additions and 14246 deletions
|
@ -16,7 +16,7 @@
|
||||||
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
|
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
|
||||||
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
||||||
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
||||||
<TargetFrameworkVersion>v11.0</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v12.0</TargetFrameworkVersion>
|
||||||
<AndroidStoreUncompressedFileExtensions />
|
<AndroidStoreUncompressedFileExtensions />
|
||||||
<MandroidI18n />
|
<MandroidI18n />
|
||||||
<JavaMaximumHeapSize>2G</JavaMaximumHeapSize>
|
<JavaMaximumHeapSize>2G</JavaMaximumHeapSize>
|
||||||
|
@ -47,6 +47,7 @@
|
||||||
<AndroidPackageFormat>aab</AndroidPackageFormat>
|
<AndroidPackageFormat>aab</AndroidPackageFormat>
|
||||||
<AndroidUseAapt2>true</AndroidUseAapt2>
|
<AndroidUseAapt2>true</AndroidUseAapt2>
|
||||||
<AndroidCreatePackagePerAbi>false</AndroidCreatePackagePerAbi>
|
<AndroidCreatePackagePerAbi>false</AndroidCreatePackagePerAbi>
|
||||||
|
<AndroidEnableMultiDex>true</AndroidEnableMultiDex>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
|
@ -66,16 +67,17 @@
|
||||||
<AndroidPackageFormat>aab</AndroidPackageFormat>
|
<AndroidPackageFormat>aab</AndroidPackageFormat>
|
||||||
<AndroidUseAapt2>true</AndroidUseAapt2>
|
<AndroidUseAapt2>true</AndroidUseAapt2>
|
||||||
<AndroidCreatePackagePerAbi>false</AndroidCreatePackagePerAbi>
|
<AndroidCreatePackagePerAbi>false</AndroidCreatePackagePerAbi>
|
||||||
|
<AndroidEnableMultiDex>true</AndroidEnableMultiDex>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||||
<PackageReference Include="Microsoft.NETCore.Platforms" Version="5.0.4" />
|
<PackageReference Include="Microsoft.NETCore.Platforms" Version="6.0.3" />
|
||||||
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
|
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
|
||||||
<PackageReference Include="MonkeyCache">
|
<PackageReference Include="MonkeyCache">
|
||||||
<Version>1.5.2</Version>
|
<Version>1.6.3</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="MonkeyCache.FileStore">
|
<PackageReference Include="MonkeyCache.FileStore">
|
||||||
<Version>1.5.2</Version>
|
<Version>1.6.3</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
|
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
|
@ -142,7 +144,7 @@
|
||||||
<PackageReference Include="System.Xml.ReaderWriter" Version="4.3.1" />
|
<PackageReference Include="System.Xml.ReaderWriter" Version="4.3.1" />
|
||||||
<PackageReference Include="System.Xml.XDocument" Version="4.3.0" />
|
<PackageReference Include="System.Xml.XDocument" Version="4.3.0" />
|
||||||
<PackageReference Include="System.Xml.XmlDocument" Version="4.3.0" />
|
<PackageReference Include="System.Xml.XmlDocument" Version="4.3.0" />
|
||||||
<PackageReference Include="Validation" Version="2.5.42" />
|
<PackageReference Include="Validation" Version="2.5.51" />
|
||||||
<PackageReference Include="Xam.Plugin.Connectivity">
|
<PackageReference Include="Xam.Plugin.Connectivity">
|
||||||
<Version>3.2.0</Version>
|
<Version>3.2.0</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
@ -168,37 +170,37 @@
|
||||||
<PackageReference Include="Xamarin.Android.Support.v7.RecyclerView" Version="28.0.0.3" />
|
<PackageReference Include="Xamarin.Android.Support.v7.RecyclerView" Version="28.0.0.3" />
|
||||||
<PackageReference Include="Xamarin.Android.Support.Vector.Drawable" Version="28.0.0.3" />
|
<PackageReference Include="Xamarin.Android.Support.Vector.Drawable" Version="28.0.0.3" />
|
||||||
<PackageReference Include="Xamarin.AndroidX.Core">
|
<PackageReference Include="Xamarin.AndroidX.Core">
|
||||||
<Version>1.6.0.3</Version>
|
<Version>1.7.0.2</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.AndroidX.MediaRouter">
|
<PackageReference Include="Xamarin.AndroidX.MediaRouter">
|
||||||
<Version>1.2.5.2</Version>
|
<Version>1.2.6.1</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.AndroidX.Palette">
|
<PackageReference Include="Xamarin.AndroidX.Palette">
|
||||||
<Version>1.0.0.10</Version>
|
<Version>1.0.0.13</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.AndroidX.RecyclerView">
|
<PackageReference Include="Xamarin.AndroidX.RecyclerView">
|
||||||
<Version>1.2.1.3</Version>
|
<Version>1.2.1.6</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Auth" Version="1.7.0" />
|
<PackageReference Include="Xamarin.Auth" Version="1.7.0" />
|
||||||
<PackageReference Include="Xamarin.Build.Download" Version="0.10.0" />
|
<PackageReference Include="Xamarin.Build.Download" Version="0.11.0" />
|
||||||
<PackageReference Include="Xamarin.CommunityToolkit">
|
<PackageReference Include="Xamarin.CommunityToolkit">
|
||||||
<Version>1.3.0</Version>
|
<Version>2.0.1</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Essentials">
|
<PackageReference Include="Xamarin.Essentials">
|
||||||
<Version>1.7.0</Version>
|
<Version>1.7.2</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2196" />
|
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2401" />
|
||||||
<PackageReference Include="Xamarin.Forms.AppLinks">
|
<PackageReference Include="Xamarin.Forms.AppLinks">
|
||||||
<Version>5.0.0.2244</Version>
|
<Version>5.0.0.2401</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Forms.GoogleMaps">
|
<PackageReference Include="Xamarin.Forms.GoogleMaps">
|
||||||
<Version>3.3.0</Version>
|
<Version>3.3.0</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Forms.GoogleMaps.Bindings" Version="3.0.0" />
|
<PackageReference Include="Xamarin.Forms.GoogleMaps.Bindings" Version="3.0.0" />
|
||||||
<PackageReference Include="Xamarin.GooglePlayServices.Base" Version="117.6.0.1" />
|
<PackageReference Include="Xamarin.GooglePlayServices.Base" Version="117.6.0.5" />
|
||||||
<PackageReference Include="Xamarin.GooglePlayServices.Basement" Version="117.6.0.2" />
|
<PackageReference Include="Xamarin.GooglePlayServices.Basement" Version="117.6.0.6" />
|
||||||
<PackageReference Include="Xamarin.GooglePlayServices.Maps" Version="117.0.1.1" />
|
<PackageReference Include="Xamarin.GooglePlayServices.Maps" Version="117.0.1.5" />
|
||||||
<PackageReference Include="Xamarin.GooglePlayServices.Tasks" Version="117.2.1.1" />
|
<PackageReference Include="Xamarin.GooglePlayServices.Tasks" Version="117.2.1.5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Mono.Android" />
|
<Reference Include="Mono.Android" />
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?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.290" android:versionCode="290">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="internalOnly" package="com.TeilRad.LastenradBayern" android:versionName="3.0.294" android:versionCode="294">
|
||||||
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="30" />
|
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="31" />
|
||||||
<!-- Google Maps related permissions -->
|
<!-- Google Maps related permissions -->
|
||||||
<!-- Permission to receive remote notifications from Google Play Services -->
|
<!-- Permission to receive remote notifications from Google Play Services -->
|
||||||
<!-- Notice here that we have the package name of our application as a prefix on the permissions. -->
|
<!-- Notice here that we have the package name of our application as a prefix on the permissions. -->
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Android.App;
|
using Android.App;
|
||||||
|
@ -12,7 +12,7 @@ using Xamarin.Forms;
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("")]
|
[assembly: AssemblyCompany("")]
|
||||||
[assembly: AssemblyProduct("LastenradBayern.Android")]
|
[assembly: AssemblyProduct("LastenradBayern.Android")]
|
||||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
[assembly: AssemblyCopyright("Copyright © 2014")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
9185
LastenradBayern/TINK.Android/Resources/Resource.Designer.cs
generated
9185
LastenradBayern/TINK.Android/Resources/Resource.Designer.cs
generated
File diff suppressed because it is too large
Load diff
|
@ -53,8 +53,8 @@
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>LastenradBayern</string>
|
<string>LastenradBayern</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>290</string>
|
<string>294</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>3.0.290</string>
|
<string>3.0.294</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -113,13 +113,13 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Bcl.Build" Version="1.0.21" />
|
<PackageReference Include="Microsoft.Bcl.Build" Version="1.0.21" />
|
||||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||||
<PackageReference Include="Microsoft.NETCore.Platforms" Version="5.0.4" />
|
<PackageReference Include="Microsoft.NETCore.Platforms" Version="6.0.3" />
|
||||||
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
|
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
|
||||||
<PackageReference Include="MonkeyCache">
|
<PackageReference Include="MonkeyCache">
|
||||||
<Version>1.5.2</Version>
|
<Version>1.6.3</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="MonkeyCache.FileStore">
|
<PackageReference Include="MonkeyCache.FileStore">
|
||||||
<Version>1.5.2</Version>
|
<Version>1.6.3</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
|
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
|
@ -182,18 +182,18 @@
|
||||||
<PackageReference Include="System.Xml.ReaderWriter" Version="4.3.1" />
|
<PackageReference Include="System.Xml.ReaderWriter" Version="4.3.1" />
|
||||||
<PackageReference Include="System.Xml.XDocument" Version="4.3.0" />
|
<PackageReference Include="System.Xml.XDocument" Version="4.3.0" />
|
||||||
<PackageReference Include="System.Xml.XmlDocument" Version="4.3.0" />
|
<PackageReference Include="System.Xml.XmlDocument" Version="4.3.0" />
|
||||||
<PackageReference Include="Validation" Version="2.5.42" />
|
<PackageReference Include="Validation" Version="2.5.51" />
|
||||||
<PackageReference Include="Xam.Plugin.Connectivity">
|
<PackageReference Include="Xam.Plugin.Connectivity">
|
||||||
<Version>3.2.0</Version>
|
<Version>3.2.0</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xam.Plugins.Messaging" Version="5.2.0" />
|
<PackageReference Include="Xam.Plugins.Messaging" Version="5.2.0" />
|
||||||
<PackageReference Include="Xamarin.Auth" Version="1.7.0" />
|
<PackageReference Include="Xamarin.Auth" Version="1.7.0" />
|
||||||
<PackageReference Include="Xamarin.Build.Download" Version="0.10.0" />
|
<PackageReference Include="Xamarin.Build.Download" Version="0.11.0" />
|
||||||
<PackageReference Include="Xamarin.CommunityToolkit">
|
<PackageReference Include="Xamarin.CommunityToolkit">
|
||||||
<Version>1.3.0</Version>
|
<Version>2.0.1</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Essentials">
|
<PackageReference Include="Xamarin.Essentials">
|
||||||
<Version>1.7.0</Version>
|
<Version>1.7.2</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Forms.GoogleMaps">
|
<PackageReference Include="Xamarin.Forms.GoogleMaps">
|
||||||
<Version>3.3.0</Version>
|
<Version>3.3.0</Version>
|
||||||
|
@ -213,7 +213,7 @@
|
||||||
<Version>0.7.104</Version>
|
<Version>0.7.104</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Forms">
|
<PackageReference Include="Xamarin.Forms">
|
||||||
<Version>5.0.0.2196</Version>
|
<Version>5.0.0.2401</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
<!-- Add more resources here -->
|
<!-- Add more resources here -->
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<!-- Add more resource dictionaries here -->
|
<!-- Add more resource dictionaries here -->
|
||||||
<themes:ShareeBike/>
|
<themes:LastenradBayern/>
|
||||||
<!-- Add more resource dictionaries here -->
|
<!-- Add more resource dictionaries here -->
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
<!-- Add more resources here -->
|
<!-- Add more resources here -->
|
||||||
|
|
|
@ -17,10 +17,9 @@ namespace TINK.View.Bike
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
|
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
|
||||||
{
|
=> item is TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel ||
|
||||||
return item is TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel
|
item is TINK.ViewModel.Bikes.Bike.CopriLock.BikeViewModel
|
||||||
? iLockIBike
|
? iLockIBike
|
||||||
: bCBike;
|
: bCBike;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,7 @@ namespace TINK.View.BikesAtStation
|
||||||
// No need to create view model, set binding context an items source if already done.
|
// No need to create view model, set binding context an items source if already done.
|
||||||
// If done twice tap events are fired multiple times (when hiding page using home button).
|
// If done twice tap events are fired multiple times (when hiding page using home button).
|
||||||
await m_oViewModel.OnAppearing();
|
await m_oViewModel.OnAppearing();
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,6 +113,7 @@ namespace TINK.View.BikesAtStation
|
||||||
{
|
{
|
||||||
Log.ForContext<BikesAtStationPage>().Error("Displaying bikes at station page failed. {Exception}", exception);
|
Log.ForContext<BikesAtStationPage>().Error("Displaying bikes at station page failed. {Exception}", exception);
|
||||||
await DisplayAlert("Fehler", $"Seite Räder an Station kann nicht angezeigt werden. ${exception.Message}", "OK");
|
await DisplayAlert("Fehler", $"Seite Räder an Station kann nicht angezeigt werden. ${exception.Message}", "OK");
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,6 +128,7 @@ namespace TINK.View.BikesAtStation
|
||||||
BikesAtStationListView.ItemsSource = m_oViewModel;
|
BikesAtStationListView.ItemsSource = m_oViewModel;
|
||||||
|
|
||||||
await m_oViewModel.OnAppearing();
|
await m_oViewModel.OnAppearing();
|
||||||
|
isInitializationStarted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -9,7 +9,6 @@ using Xamarin.Forms.Xaml;
|
||||||
namespace TINK.View.Map
|
namespace TINK.View.Map
|
||||||
{
|
{
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using TINK.Model;
|
|
||||||
using TINK.ViewModel.Map;
|
using TINK.ViewModel.Map;
|
||||||
|
|
||||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||||
|
@ -153,6 +152,7 @@ namespace TINK.View.Map
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
Log.ForContext<MapPage>().Error("Constructing map page view model failed. {Exception}", exception);
|
Log.ForContext<MapPage>().Error("Constructing map page view model failed. {Exception}", exception);
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,6 +167,7 @@ namespace TINK.View.Map
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
Log.ForContext<MapPage>().Error("Setting binding/ navigaton on map page failed. {Exception}", exception);
|
Log.ForContext<MapPage>().Error("Setting binding/ navigaton on map page failed. {Exception}", exception);
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,6 +189,7 @@ namespace TINK.View.Map
|
||||||
{
|
{
|
||||||
// Continue because styling is not essential.
|
// Continue because styling is not essential.
|
||||||
Log.ForContext<MapPage>().Error("Invoking OnAppearing of base failed. {Exception}", exception);
|
Log.ForContext<MapPage>().Error("Invoking OnAppearing of base failed. {Exception}", exception);
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,10 +208,13 @@ namespace TINK.View.Map
|
||||||
{
|
{
|
||||||
Log.ForContext<MapPage>().Verbose("Invoking OnAppearing on map page view model.");
|
Log.ForContext<MapPage>().Verbose("Invoking OnAppearing on map page view model.");
|
||||||
await MapPageViewModel.OnAppearing();
|
await MapPageViewModel.OnAppearing();
|
||||||
|
|
||||||
|
isInitializationStarted = false;
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
Log.ForContext<MapPage>().Error("Invoking OnAppearing on map page view model failed. {Exception}", exception);
|
Log.ForContext<MapPage>().Error("Invoking OnAppearing on map page view model failed. {Exception}", exception);
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,13 +40,14 @@ namespace TINK.View.MyBikes
|
||||||
{
|
{
|
||||||
// Don't repeat the initialization if it has been completed already.
|
// Don't repeat the initialization if it has been completed already.
|
||||||
if (isInitializationStarted) return;
|
if (isInitializationStarted) return;
|
||||||
isInitializationStarted = true;
|
isInitializationStarted = true;
|
||||||
|
|
||||||
if (m_oViewModel != null)
|
if (m_oViewModel != null)
|
||||||
{
|
{
|
||||||
// No need to create view model, set binding context an items source if already done.
|
// No need to create view model, set binding context an items source if already done.
|
||||||
// If done twice tap events are fired multiple times (when hiding page using home button).
|
// If done twice tap events are fired multiple times (when hiding page using home button).
|
||||||
await m_oViewModel.OnAppearing();
|
await m_oViewModel.OnAppearing();
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,8 +81,8 @@ namespace TINK.View.MyBikes
|
||||||
{
|
{
|
||||||
Log.ForContext<MyBikesPage>().Error("Displaying bikes at station page failed. {Exception}", exception);
|
Log.ForContext<MyBikesPage>().Error("Displaying bikes at station page failed. {Exception}", exception);
|
||||||
await DisplayAlert("Fehler", $"Seite Räder an Station kann nicht angezeigt werden. ${exception.Message}", "OK");
|
await DisplayAlert("Fehler", $"Seite Räder an Station kann nicht angezeigt werden. ${exception.Message}", "OK");
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
@ -90,6 +91,7 @@ namespace TINK.View.MyBikes
|
||||||
MyBikesListView.ItemsSource = m_oViewModel;
|
MyBikesListView.ItemsSource = m_oViewModel;
|
||||||
|
|
||||||
await m_oViewModel.OnAppearing();
|
await m_oViewModel.OnAppearing();
|
||||||
|
isInitializationStarted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Plugin.BLE" Version="2.1.2" />
|
<PackageReference Include="Plugin.BLE" Version="2.1.2" />
|
||||||
<PackageReference Include="Polly" Version="7.2.2" />
|
<PackageReference Include="Polly" Version="7.2.3" />
|
||||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||||
<PackageReference Include="Xamarin.Essentials" Version="1.7.0" />
|
<PackageReference Include="Xamarin.Essentials" Version="1.7.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -23,7 +23,6 @@ namespace TINK.Services.BluetoothLock.BLE
|
||||||
/// <summary> Lenght of seed in bytes.</summary>
|
/// <summary> Lenght of seed in bytes.</summary>
|
||||||
private const int SEEDLENGTH = 16;
|
private const int SEEDLENGTH = 16;
|
||||||
|
|
||||||
|
|
||||||
/// <summary> Timeout for open/ close operations.</summary>
|
/// <summary> Timeout for open/ close operations.</summary>
|
||||||
protected const int OPEN_CLOSE_TIMEOUT_MS = 30000;
|
protected const int OPEN_CLOSE_TIMEOUT_MS = 30000;
|
||||||
|
|
||||||
|
|
|
@ -255,7 +255,7 @@ namespace TINK.Services.BluetoothLock.BLE
|
||||||
|
|
||||||
case LockitLockingState.CouldntCloseMoving:
|
case LockitLockingState.CouldntCloseMoving:
|
||||||
// Expected error. ILockIt could not be closed (bike is moving)
|
// Expected error. ILockIt could not be closed (bike is moving)
|
||||||
throw new CounldntCloseMovingException();
|
throw new CouldntCloseMovingException();
|
||||||
|
|
||||||
case LockitLockingState.Closed:
|
case LockitLockingState.Closed:
|
||||||
return lockingState;
|
return lockingState;
|
||||||
|
|
|
@ -200,7 +200,7 @@ namespace TINK.Services.BluetoothLock.BLE
|
||||||
|
|
||||||
case LockitLockingState.CouldntCloseMoving:
|
case LockitLockingState.CouldntCloseMoving:
|
||||||
// Expected error. ILockIt could not be closed (bike is moving)
|
// Expected error. ILockIt could not be closed (bike is moving)
|
||||||
throw new CounldntCloseMovingException();
|
throw new CouldntCloseMovingException();
|
||||||
|
|
||||||
case LockitLockingState.Closed:
|
case LockitLockingState.Closed:
|
||||||
// Everything is ok.
|
// Everything is ok.
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
<Warning Text="$(MSBuildProjectFile) is Multilingual build enabled, but the Multilingual App Toolkit is unavailable during the build. If building with Visual Studio, please check to ensure that toolkit is properly installed." />
|
<Warning Text="$(MSBuildProjectFile) is Multilingual build enabled, but the Multilingual App Toolkit is unavailable during the build. If building with Visual Studio, please check to ensure that toolkit is properly installed." />
|
||||||
</Target>
|
</Target>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Model\Bikes\Bike\BluetoothLock\" />
|
|
||||||
<Folder Include="Model\Bikes\Bike\" />
|
|
||||||
<Folder Include="Model\Device\" />
|
<Folder Include="Model\Device\" />
|
||||||
<Folder Include="Services\BluetoothLock\Crypto\" />
|
<Folder Include="Services\BluetoothLock\Crypto\" />
|
||||||
<Folder Include="Services\BluetoothLock\Tdo\" />
|
<Folder Include="Services\BluetoothLock\Tdo\" />
|
||||||
|
|
8
LockItShared/Model/Bikes/Bike/CopriLock/ILockInfo.cs
Normal file
8
LockItShared/Model/Bikes/Bike/CopriLock/ILockInfo.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace TINK.Model.Bikes.Bike.CopriLock
|
||||||
|
{
|
||||||
|
public interface ILockInfo
|
||||||
|
{
|
||||||
|
/// <summary> Locking state of backend lock. </summary>
|
||||||
|
LockingState State { get; }
|
||||||
|
}
|
||||||
|
}
|
88
LockItShared/Model/Bikes/Bike/CopriLock/LockInfo.cs
Normal file
88
LockItShared/Model/Bikes/Bike/CopriLock/LockInfo.cs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace TINK.Model.Bikes.Bike.CopriLock
|
||||||
|
{
|
||||||
|
/// <summary> Locking states. </summary>
|
||||||
|
public enum LockingState
|
||||||
|
{
|
||||||
|
/// <summary> App is not connected to lock.</summary>
|
||||||
|
UnknownDisconnected,
|
||||||
|
|
||||||
|
/// <summary> Lock is closed. </summary>
|
||||||
|
Closed,
|
||||||
|
|
||||||
|
/// <summary> Lock is closing. </summary>
|
||||||
|
Closing,
|
||||||
|
|
||||||
|
/// <summary> Lock is open. </summary>
|
||||||
|
Open,
|
||||||
|
|
||||||
|
/// <summary> Lock is opening. </summary>
|
||||||
|
Opening
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataContract]
|
||||||
|
public class LockInfo : ILockInfo
|
||||||
|
{
|
||||||
|
/// <summary> Locking state of bluetooth lock. </summary>
|
||||||
|
[DataMember]
|
||||||
|
public LockingState State { get; private set; } = LockingState.UnknownDisconnected;
|
||||||
|
|
||||||
|
public override bool Equals(object obj) => this.Equals(obj as LockInfo);
|
||||||
|
|
||||||
|
public bool Equals(LockInfo other)
|
||||||
|
{
|
||||||
|
if (Object.ReferenceEquals(other, null)) return false;
|
||||||
|
if (Object.ReferenceEquals(this, other)) return true;
|
||||||
|
if (this.GetType() != other.GetType()) return false;
|
||||||
|
|
||||||
|
return ToString() == other.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return ToString().GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return JsonConvert.SerializeObject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(LockInfo lhs, LockInfo rhs)
|
||||||
|
{
|
||||||
|
if (Object.ReferenceEquals(lhs, null))
|
||||||
|
return Object.ReferenceEquals(rhs, null) ? true /*null == null = true*/: false;
|
||||||
|
|
||||||
|
return lhs.Equals(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(LockInfo lhs, LockInfo rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Builder
|
||||||
|
{
|
||||||
|
public Builder(LockInfo lockInfo = null)
|
||||||
|
{
|
||||||
|
if (lockInfo == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LockInfo = JsonConvert.DeserializeObject<LockInfo>(JsonConvert.SerializeObject(lockInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly LockInfo LockInfo = new LockInfo();
|
||||||
|
|
||||||
|
|
||||||
|
public LockingState State { get => LockInfo.State; set => LockInfo.State = value; }
|
||||||
|
|
||||||
|
public LockInfo Build() => LockInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,10 @@
|
||||||
using TINK.Model.Bike.BluetoothLock;
|
using TINK.Model.Bike.BluetoothLock;
|
||||||
using TINK.Services.BluetoothLock.Tdo;
|
|
||||||
|
|
||||||
namespace TINK.Services.BluetoothLock.Exception
|
namespace TINK.Services.BluetoothLock.Exception
|
||||||
{
|
{
|
||||||
public class CounldntCloseMovingException : StateAwareException
|
public class CouldntCloseMovingException : StateAwareException
|
||||||
{
|
{
|
||||||
public CounldntCloseMovingException() : base(
|
public CouldntCloseMovingException() : base(
|
||||||
LockingState.Open, // Locking bold is probable (according to haveltec) still open.
|
LockingState.Open, // Locking bold is probable (according to haveltec) still open.
|
||||||
MultilingualResources.Resources.ErrorCloseLockBikeMoving)
|
MultilingualResources.Resources.ErrorCloseLockBikeMoving)
|
||||||
{
|
{
|
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
namespace TINK.Services.CopriLock.Exception
|
||||||
|
{
|
||||||
|
public class CouldntCloseBoldBlockedException : System.Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
namespace TINK.Services.CopriLock.Exception
|
||||||
|
{
|
||||||
|
public class CouldntOpenBoldIsBlockedException : System.Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
namespace TINK.Services.CopriLock.Exception
|
||||||
|
{
|
||||||
|
public class CouldntOpenBoldWasBlockedException : System.Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
namespace TINK.Services.CopriLock.Exception
|
||||||
|
{
|
||||||
|
public class CounldntCloseMovingException : System.Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
namespace TINK.Services.CopriLock.Exception
|
||||||
|
{
|
||||||
|
public class OutOfReachException : System.Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
using TINK.Model.Bikes.Bike.CopriLock;
|
||||||
|
|
||||||
|
namespace TINK.Services.CopriLock.Exception
|
||||||
|
{
|
||||||
|
public abstract class StateAwareException : System.Exception
|
||||||
|
{
|
||||||
|
public StateAwareException(LockingState state, string description) : base(description)
|
||||||
|
{
|
||||||
|
State = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Holds the state reported by lock.</summary>
|
||||||
|
public LockingState State { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,7 @@
|
||||||
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
|
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
|
||||||
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
||||||
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
||||||
<TargetFrameworkVersion>v11.0</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v12.0</TargetFrameworkVersion>
|
||||||
<AndroidStoreUncompressedFileExtensions />
|
<AndroidStoreUncompressedFileExtensions />
|
||||||
<MandroidI18n />
|
<MandroidI18n />
|
||||||
<JavaMaximumHeapSize>2G</JavaMaximumHeapSize>
|
<JavaMaximumHeapSize>2G</JavaMaximumHeapSize>
|
||||||
|
@ -47,6 +47,7 @@
|
||||||
<AndroidPackageFormat>aab</AndroidPackageFormat>
|
<AndroidPackageFormat>aab</AndroidPackageFormat>
|
||||||
<AndroidUseAapt2>true</AndroidUseAapt2>
|
<AndroidUseAapt2>true</AndroidUseAapt2>
|
||||||
<AndroidCreatePackagePerAbi>false</AndroidCreatePackagePerAbi>
|
<AndroidCreatePackagePerAbi>false</AndroidCreatePackagePerAbi>
|
||||||
|
<AndroidEnableMultiDex>true</AndroidEnableMultiDex>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
|
@ -66,16 +67,17 @@
|
||||||
<AndroidPackageFormat>aab</AndroidPackageFormat>
|
<AndroidPackageFormat>aab</AndroidPackageFormat>
|
||||||
<AndroidUseAapt2>true</AndroidUseAapt2>
|
<AndroidUseAapt2>true</AndroidUseAapt2>
|
||||||
<AndroidCreatePackagePerAbi>false</AndroidCreatePackagePerAbi>
|
<AndroidCreatePackagePerAbi>false</AndroidCreatePackagePerAbi>
|
||||||
|
<AndroidEnableMultiDex>true</AndroidEnableMultiDex>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||||
<PackageReference Include="Microsoft.NETCore.Platforms" Version="5.0.4" />
|
<PackageReference Include="Microsoft.NETCore.Platforms" Version="6.0.3" />
|
||||||
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
|
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
|
||||||
<PackageReference Include="MonkeyCache">
|
<PackageReference Include="MonkeyCache">
|
||||||
<Version>1.5.2</Version>
|
<Version>1.6.3</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="MonkeyCache.FileStore">
|
<PackageReference Include="MonkeyCache.FileStore">
|
||||||
<Version>1.5.2</Version>
|
<Version>1.6.3</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
|
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
|
@ -142,7 +144,7 @@
|
||||||
<PackageReference Include="System.Xml.ReaderWriter" Version="4.3.1" />
|
<PackageReference Include="System.Xml.ReaderWriter" Version="4.3.1" />
|
||||||
<PackageReference Include="System.Xml.XDocument" Version="4.3.0" />
|
<PackageReference Include="System.Xml.XDocument" Version="4.3.0" />
|
||||||
<PackageReference Include="System.Xml.XmlDocument" Version="4.3.0" />
|
<PackageReference Include="System.Xml.XmlDocument" Version="4.3.0" />
|
||||||
<PackageReference Include="Validation" Version="2.5.42" />
|
<PackageReference Include="Validation" Version="2.5.51" />
|
||||||
<PackageReference Include="Xam.Plugin.Connectivity">
|
<PackageReference Include="Xam.Plugin.Connectivity">
|
||||||
<Version>3.2.0</Version>
|
<Version>3.2.0</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
@ -168,37 +170,37 @@
|
||||||
<PackageReference Include="Xamarin.Android.Support.v7.RecyclerView" Version="28.0.0.3" />
|
<PackageReference Include="Xamarin.Android.Support.v7.RecyclerView" Version="28.0.0.3" />
|
||||||
<PackageReference Include="Xamarin.Android.Support.Vector.Drawable" Version="28.0.0.3" />
|
<PackageReference Include="Xamarin.Android.Support.Vector.Drawable" Version="28.0.0.3" />
|
||||||
<PackageReference Include="Xamarin.AndroidX.Core">
|
<PackageReference Include="Xamarin.AndroidX.Core">
|
||||||
<Version>1.6.0.3</Version>
|
<Version>1.7.0.2</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.AndroidX.MediaRouter">
|
<PackageReference Include="Xamarin.AndroidX.MediaRouter">
|
||||||
<Version>1.2.5.2</Version>
|
<Version>1.2.6.1</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.AndroidX.Palette">
|
<PackageReference Include="Xamarin.AndroidX.Palette">
|
||||||
<Version>1.0.0.10</Version>
|
<Version>1.0.0.13</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.AndroidX.RecyclerView">
|
<PackageReference Include="Xamarin.AndroidX.RecyclerView">
|
||||||
<Version>1.2.1.3</Version>
|
<Version>1.2.1.6</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Auth" Version="1.7.0" />
|
<PackageReference Include="Xamarin.Auth" Version="1.7.0" />
|
||||||
<PackageReference Include="Xamarin.Build.Download" Version="0.10.0" />
|
<PackageReference Include="Xamarin.Build.Download" Version="0.11.0" />
|
||||||
<PackageReference Include="Xamarin.CommunityToolkit">
|
<PackageReference Include="Xamarin.CommunityToolkit">
|
||||||
<Version>1.3.0</Version>
|
<Version>2.0.1</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Essentials">
|
<PackageReference Include="Xamarin.Essentials">
|
||||||
<Version>1.7.0</Version>
|
<Version>1.7.2</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2196" />
|
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2401" />
|
||||||
<PackageReference Include="Xamarin.Forms.AppLinks">
|
<PackageReference Include="Xamarin.Forms.AppLinks">
|
||||||
<Version>5.0.0.2244</Version>
|
<Version>5.0.0.2401</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Forms.GoogleMaps">
|
<PackageReference Include="Xamarin.Forms.GoogleMaps">
|
||||||
<Version>3.3.0</Version>
|
<Version>3.3.0</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Forms.GoogleMaps.Bindings" Version="3.0.0" />
|
<PackageReference Include="Xamarin.Forms.GoogleMaps.Bindings" Version="3.0.0" />
|
||||||
<PackageReference Include="Xamarin.GooglePlayServices.Base" Version="117.6.0.1" />
|
<PackageReference Include="Xamarin.GooglePlayServices.Base" Version="117.6.0.5" />
|
||||||
<PackageReference Include="Xamarin.GooglePlayServices.Basement" Version="117.6.0.2" />
|
<PackageReference Include="Xamarin.GooglePlayServices.Basement" Version="117.6.0.6" />
|
||||||
<PackageReference Include="Xamarin.GooglePlayServices.Maps" Version="117.0.1.1" />
|
<PackageReference Include="Xamarin.GooglePlayServices.Maps" Version="117.0.1.5" />
|
||||||
<PackageReference Include="Xamarin.GooglePlayServices.Tasks" Version="117.2.1.1" />
|
<PackageReference Include="Xamarin.GooglePlayServices.Tasks" Version="117.2.1.5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Mono.Android" />
|
<Reference Include="Mono.Android" />
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?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.290" android:versionCode="290">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="internalOnly" package="com.TeilRad.Meinkonrad" android:versionName="3.0.294" android:versionCode="294">
|
||||||
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="30" />
|
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="31" />
|
||||||
<!-- Google Maps related permissions -->
|
<!-- Google Maps related permissions -->
|
||||||
<!-- Permission to receive remote notifications from Google Play Services -->
|
<!-- Permission to receive remote notifications from Google Play Services -->
|
||||||
<!-- Notice here that we have the package name of our application as a prefix on the permissions. -->
|
<!-- Notice here that we have the package name of our application as a prefix on the permissions. -->
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Android.App;
|
using Android.App;
|
||||||
|
@ -12,7 +12,7 @@ using Xamarin.Forms;
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("")]
|
[assembly: AssemblyCompany("")]
|
||||||
[assembly: AssemblyProduct("Meinkonrad.Android")]
|
[assembly: AssemblyProduct("Meinkonrad.Android")]
|
||||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
[assembly: AssemblyCopyright("Copyright © 2014")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
9185
Meinkonrad/TINK.Android/Resources/Resource.Designer.cs
generated
9185
Meinkonrad/TINK.Android/Resources/Resource.Designer.cs
generated
File diff suppressed because it is too large
Load diff
|
@ -53,8 +53,8 @@
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>Mein konrad</string>
|
<string>Mein konrad</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>290</string>
|
<string>294</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>3.0.290</string>
|
<string>3.0.294</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -113,13 +113,13 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Bcl.Build" Version="1.0.21" />
|
<PackageReference Include="Microsoft.Bcl.Build" Version="1.0.21" />
|
||||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||||
<PackageReference Include="Microsoft.NETCore.Platforms" Version="5.0.4" />
|
<PackageReference Include="Microsoft.NETCore.Platforms" Version="6.0.3" />
|
||||||
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
|
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
|
||||||
<PackageReference Include="MonkeyCache">
|
<PackageReference Include="MonkeyCache">
|
||||||
<Version>1.5.2</Version>
|
<Version>1.6.3</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="MonkeyCache.FileStore">
|
<PackageReference Include="MonkeyCache.FileStore">
|
||||||
<Version>1.5.2</Version>
|
<Version>1.6.3</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
|
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
|
@ -182,18 +182,18 @@
|
||||||
<PackageReference Include="System.Xml.ReaderWriter" Version="4.3.1" />
|
<PackageReference Include="System.Xml.ReaderWriter" Version="4.3.1" />
|
||||||
<PackageReference Include="System.Xml.XDocument" Version="4.3.0" />
|
<PackageReference Include="System.Xml.XDocument" Version="4.3.0" />
|
||||||
<PackageReference Include="System.Xml.XmlDocument" Version="4.3.0" />
|
<PackageReference Include="System.Xml.XmlDocument" Version="4.3.0" />
|
||||||
<PackageReference Include="Validation" Version="2.5.42" />
|
<PackageReference Include="Validation" Version="2.5.51" />
|
||||||
<PackageReference Include="Xam.Plugin.Connectivity">
|
<PackageReference Include="Xam.Plugin.Connectivity">
|
||||||
<Version>3.2.0</Version>
|
<Version>3.2.0</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xam.Plugins.Messaging" Version="5.2.0" />
|
<PackageReference Include="Xam.Plugins.Messaging" Version="5.2.0" />
|
||||||
<PackageReference Include="Xamarin.Auth" Version="1.7.0" />
|
<PackageReference Include="Xamarin.Auth" Version="1.7.0" />
|
||||||
<PackageReference Include="Xamarin.Build.Download" Version="0.10.0" />
|
<PackageReference Include="Xamarin.Build.Download" Version="0.11.0" />
|
||||||
<PackageReference Include="Xamarin.CommunityToolkit">
|
<PackageReference Include="Xamarin.CommunityToolkit">
|
||||||
<Version>1.3.0</Version>
|
<Version>2.0.1</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Essentials">
|
<PackageReference Include="Xamarin.Essentials">
|
||||||
<Version>1.7.0</Version>
|
<Version>1.7.2</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Forms.GoogleMaps">
|
<PackageReference Include="Xamarin.Forms.GoogleMaps">
|
||||||
<Version>3.3.0</Version>
|
<Version>3.3.0</Version>
|
||||||
|
@ -213,7 +213,7 @@
|
||||||
<Version>0.7.104</Version>
|
<Version>0.7.104</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Forms">
|
<PackageReference Include="Xamarin.Forms">
|
||||||
<Version>5.0.0.2196</Version>
|
<Version>5.0.0.2401</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1608,12 +1608,12 @@
|
||||||
<Folder Include="Media.xcassets\30_Green.imageset\" />
|
<Folder Include="Media.xcassets\30_Green.imageset\" />
|
||||||
<Folder Include="Media.xcassets\30_LightBlue.imageset\" />
|
<Folder Include="Media.xcassets\30_LightBlue.imageset\" />
|
||||||
<Folder Include="Media.xcassets\30_Red.imageset\" />
|
<Folder Include="Media.xcassets\30_Red.imageset\" />
|
||||||
|
<Folder Include="Media.xcassets\konrad_nobg.imageset\" />
|
||||||
<Folder Include="Media.xcassets\Open_Blue.imageset\" />
|
<Folder Include="Media.xcassets\Open_Blue.imageset\" />
|
||||||
<Folder Include="Media.xcassets\Open_Green.imageset\" />
|
<Folder Include="Media.xcassets\Open_Green.imageset\" />
|
||||||
<Folder Include="Media.xcassets\Open_LightBlue.imageset\" />
|
<Folder Include="Media.xcassets\Open_LightBlue.imageset\" />
|
||||||
<Folder Include="Media.xcassets\Open_Red.imageset\" />
|
<Folder Include="Media.xcassets\Open_Red.imageset\" />
|
||||||
<Folder Include="Media.xcassets\sharee_no_background.imageset\" />
|
<Folder Include="Media.xcassets\sharee_no_background.imageset\" />
|
||||||
<Folder Include="Media.xcassets\konrad_nobg.imageset\" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ITunesArtwork Include="iTunesArtwork" />
|
<ITunesArtwork Include="iTunesArtwork" />
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
<!-- Add more resources here -->
|
<!-- Add more resources here -->
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<!-- Add more resource dictionaries here -->
|
<!-- Add more resource dictionaries here -->
|
||||||
<themes:ShareeBike/>
|
<themes:Konrad/>
|
||||||
<!-- Add more resource dictionaries here -->
|
<!-- Add more resource dictionaries here -->
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
<!-- Add more resources here -->
|
<!-- Add more resources here -->
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace TINK.View.BikesAtStation
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using TINK.Model.Device;
|
using TINK.Model.Device;
|
||||||
#if USEFLYOUT
|
#if USEFLYOUT
|
||||||
using TINK.View.MasterDetail;
|
using TINK.View.MasterDetail;
|
||||||
#endif
|
#endif
|
||||||
using TINK.ViewModel;
|
using TINK.ViewModel;
|
||||||
using TINK.Model;
|
using TINK.Model;
|
||||||
|
@ -33,6 +33,10 @@ using TINK.View.MasterDetail;
|
||||||
{
|
{
|
||||||
|
|
||||||
private BikesAtStationPageViewModel m_oViewModel;
|
private BikesAtStationPageViewModel m_oViewModel;
|
||||||
|
|
||||||
|
/// <summary> Initialization status to ensure initialization logic is not called multiple times. </summary>
|
||||||
|
private bool isInitializationStarted = false;
|
||||||
|
|
||||||
#if TRYNOTBACKSTYLE
|
#if TRYNOTBACKSTYLE
|
||||||
public BikesAtStationPage()
|
public BikesAtStationPage()
|
||||||
{
|
{
|
||||||
|
@ -62,6 +66,10 @@ using TINK.View.MasterDetail;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected async override void OnAppearing()
|
protected async override void OnAppearing()
|
||||||
{
|
{
|
||||||
|
// Don't repeat the initialization if it has been completed already.
|
||||||
|
if (isInitializationStarted) return;
|
||||||
|
isInitializationStarted = true;
|
||||||
|
|
||||||
if (m_oViewModel != null)
|
if (m_oViewModel != null)
|
||||||
{
|
{
|
||||||
#if BACKSTYLE
|
#if BACKSTYLE
|
||||||
|
@ -72,6 +80,7 @@ using TINK.View.MasterDetail;
|
||||||
// No need to create view model, set binding context an items source if already done.
|
// No need to create view model, set binding context an items source if already done.
|
||||||
// If done twice tap events are fired multiple times (when hiding page using home button).
|
// If done twice tap events are fired multiple times (when hiding page using home button).
|
||||||
await m_oViewModel.OnAppearing();
|
await m_oViewModel.OnAppearing();
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,6 +114,7 @@ using TINK.View.MasterDetail;
|
||||||
{
|
{
|
||||||
Log.ForContext<BikesAtStationPage>().Error("Displaying bikes at station page failed. {Exception}", exception);
|
Log.ForContext<BikesAtStationPage>().Error("Displaying bikes at station page failed. {Exception}", exception);
|
||||||
await DisplayAlert("Fehler", $"Seite Räder an Station kann nicht angezeigt werden. ${exception.Message}", "OK");
|
await DisplayAlert("Fehler", $"Seite Räder an Station kann nicht angezeigt werden. ${exception.Message}", "OK");
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,6 +129,7 @@ using TINK.View.MasterDetail;
|
||||||
BikesAtStationListView.ItemsSource = m_oViewModel;
|
BikesAtStationListView.ItemsSource = m_oViewModel;
|
||||||
|
|
||||||
await m_oViewModel.OnAppearing();
|
await m_oViewModel.OnAppearing();
|
||||||
|
isInitializationStarted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -167,7 +178,7 @@ using TINK.View.MasterDetail;
|
||||||
/// <param name="cancel">Text of button.</param>
|
/// <param name="cancel">Text of button.</param>
|
||||||
/// <returns>True if user pressed accept.</returns>
|
/// <returns>True if user pressed accept.</returns>
|
||||||
public new async Task<bool> DisplayAlert(string title, string message, string accept, string cancel)
|
public new async Task<bool> DisplayAlert(string title, string message, string accept, string cancel)
|
||||||
=> await App.Current.MainPage.DisplayAlert(title, message, accept, cancel);
|
=> await App.Current.MainPage.DisplayAlert(title, message, accept, cancel);
|
||||||
|
|
||||||
/// <summary> Displays detailed alert message.</summary>
|
/// <summary> Displays detailed alert message.</summary>
|
||||||
/// <param name="title">Title of message.</param>
|
/// <param name="title">Title of message.</param>
|
||||||
|
@ -233,5 +244,5 @@ using TINK.View.MasterDetail;
|
||||||
/// <returns>User feedback.</returns>
|
/// <returns>User feedback.</returns>
|
||||||
public async Task<IUserFeedback> DisplayUserFeedbackPopup(string co2Saving = null) => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup(co2Saving));
|
public async Task<IUserFeedback> DisplayUserFeedbackPopup(string co2Saving = null) => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup(co2Saving));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -152,6 +152,7 @@ namespace TINK.View.Map
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
Log.ForContext<MapPage>().Error("Constructing map page view model failed. {Exception}", exception);
|
Log.ForContext<MapPage>().Error("Constructing map page view model failed. {Exception}", exception);
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,6 +167,7 @@ namespace TINK.View.Map
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
Log.ForContext<MapPage>().Error("Setting binding/ navigaton on map page failed. {Exception}", exception);
|
Log.ForContext<MapPage>().Error("Setting binding/ navigaton on map page failed. {Exception}", exception);
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,6 +189,7 @@ namespace TINK.View.Map
|
||||||
{
|
{
|
||||||
// Continue because styling is not essential.
|
// Continue because styling is not essential.
|
||||||
Log.ForContext<MapPage>().Error("Invoking OnAppearing of base failed. {Exception}", exception);
|
Log.ForContext<MapPage>().Error("Invoking OnAppearing of base failed. {Exception}", exception);
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,10 +208,13 @@ namespace TINK.View.Map
|
||||||
{
|
{
|
||||||
Log.ForContext<MapPage>().Verbose("Invoking OnAppearing on map page view model.");
|
Log.ForContext<MapPage>().Verbose("Invoking OnAppearing on map page view model.");
|
||||||
await MapPageViewModel.OnAppearing();
|
await MapPageViewModel.OnAppearing();
|
||||||
|
|
||||||
|
isInitializationStarted = false;
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
Log.ForContext<MapPage>().Error("Invoking OnAppearing on map page view model failed. {Exception}", exception);
|
Log.ForContext<MapPage>().Error("Invoking OnAppearing on map page view model failed. {Exception}", exception);
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ using Xamarin.Forms.Xaml;
|
||||||
namespace TINK.View.MyBikes
|
namespace TINK.View.MyBikes
|
||||||
{
|
{
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
using TINK.Model;
|
||||||
using TINK.Model.Device;
|
using TINK.Model.Device;
|
||||||
using TINK.ViewModel.MyBikes;
|
using TINK.ViewModel.MyBikes;
|
||||||
using Xamarin.CommunityToolkit.Extensions;
|
using Xamarin.CommunityToolkit.Extensions;
|
||||||
|
@ -39,13 +40,14 @@ namespace TINK.View.MyBikes
|
||||||
{
|
{
|
||||||
// Don't repeat the initialization if it has been completed already.
|
// Don't repeat the initialization if it has been completed already.
|
||||||
if (isInitializationStarted) return;
|
if (isInitializationStarted) return;
|
||||||
isInitializationStarted = true;
|
isInitializationStarted = true;
|
||||||
|
|
||||||
if (m_oViewModel != null)
|
if (m_oViewModel != null)
|
||||||
{
|
{
|
||||||
// No need to create view model, set binding context an items source if already done.
|
// No need to create view model, set binding context an items source if already done.
|
||||||
// If done twice tap events are fired multiple times (when hiding page using home button).
|
// If done twice tap events are fired multiple times (when hiding page using home button).
|
||||||
await m_oViewModel.OnAppearing();
|
await m_oViewModel.OnAppearing();
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,8 +81,8 @@ namespace TINK.View.MyBikes
|
||||||
{
|
{
|
||||||
Log.ForContext<MyBikesPage>().Error("Displaying bikes at station page failed. {Exception}", exception);
|
Log.ForContext<MyBikesPage>().Error("Displaying bikes at station page failed. {Exception}", exception);
|
||||||
await DisplayAlert("Fehler", $"Seite Räder an Station kann nicht angezeigt werden. ${exception.Message}", "OK");
|
await DisplayAlert("Fehler", $"Seite Räder an Station kann nicht angezeigt werden. ${exception.Message}", "OK");
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
@ -89,6 +91,7 @@ namespace TINK.View.MyBikes
|
||||||
MyBikesListView.ItemsSource = m_oViewModel;
|
MyBikesListView.ItemsSource = m_oViewModel;
|
||||||
|
|
||||||
await m_oViewModel.OnAppearing();
|
await m_oViewModel.OnAppearing();
|
||||||
|
isInitializationStarted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="preferExternal" package="com.hauffware.sharee" android:versionName="3.0.290" android:versionCode="290">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="preferExternal" package="com.hauffware.sharee" android:versionName="3.0.294" android:versionCode="294">
|
||||||
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="30" />
|
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="31" />
|
||||||
<!-- Google Maps related permissions -->
|
<!-- Google Maps related permissions -->
|
||||||
<!-- Permission to receive remote notifications from Google Play Services -->
|
<!-- Permission to receive remote notifications from Google Play Services -->
|
||||||
<!-- Notice here that we have the package name of our application as a prefix on the permissions. -->
|
<!-- Notice here that we have the package name of our application as a prefix on the permissions. -->
|
||||||
|
|
|
@ -12,7 +12,7 @@ using Xamarin.Forms;
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("")]
|
[assembly: AssemblyCompany("")]
|
||||||
[assembly: AssemblyProduct("TINK.Android")]
|
[assembly: AssemblyProduct("TINK.Android")]
|
||||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
[assembly: AssemblyCopyright("Copyright © 2014")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
9185
TINK/TINK.Android/Resources/Resource.Designer.cs
generated
9185
TINK/TINK.Android/Resources/Resource.Designer.cs
generated
File diff suppressed because it is too large
Load diff
|
@ -16,7 +16,7 @@
|
||||||
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
|
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
|
||||||
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
||||||
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
||||||
<TargetFrameworkVersion>v11.0</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v12.0</TargetFrameworkVersion>
|
||||||
<AndroidStoreUncompressedFileExtensions />
|
<AndroidStoreUncompressedFileExtensions />
|
||||||
<MandroidI18n />
|
<MandroidI18n />
|
||||||
<JavaMaximumHeapSize>2G</JavaMaximumHeapSize>
|
<JavaMaximumHeapSize>2G</JavaMaximumHeapSize>
|
||||||
|
@ -44,6 +44,7 @@
|
||||||
<BundleAssemblies>false</BundleAssemblies>
|
<BundleAssemblies>false</BundleAssemblies>
|
||||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
||||||
<AndroidEnableProfiledAot>false</AndroidEnableProfiledAot>
|
<AndroidEnableProfiledAot>false</AndroidEnableProfiledAot>
|
||||||
|
<AndroidEnableMultiDex>true</AndroidEnableMultiDex>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
|
@ -60,16 +61,17 @@
|
||||||
<BundleAssemblies>false</BundleAssemblies>
|
<BundleAssemblies>false</BundleAssemblies>
|
||||||
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64;arm64-v8a</AndroidSupportedAbis>
|
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64;arm64-v8a</AndroidSupportedAbis>
|
||||||
<MandroidI18n />
|
<MandroidI18n />
|
||||||
|
<AndroidEnableMultiDex>true</AndroidEnableMultiDex>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||||
<PackageReference Include="Microsoft.NETCore.Platforms" Version="5.0.4" />
|
<PackageReference Include="Microsoft.NETCore.Platforms" Version="6.0.3" />
|
||||||
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
|
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
|
||||||
<PackageReference Include="MonkeyCache">
|
<PackageReference Include="MonkeyCache">
|
||||||
<Version>1.5.2</Version>
|
<Version>1.6.3</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="MonkeyCache.FileStore">
|
<PackageReference Include="MonkeyCache.FileStore">
|
||||||
<Version>1.5.2</Version>
|
<Version>1.6.3</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
|
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
|
@ -136,7 +138,7 @@
|
||||||
<PackageReference Include="System.Xml.ReaderWriter" Version="4.3.1" />
|
<PackageReference Include="System.Xml.ReaderWriter" Version="4.3.1" />
|
||||||
<PackageReference Include="System.Xml.XDocument" Version="4.3.0" />
|
<PackageReference Include="System.Xml.XDocument" Version="4.3.0" />
|
||||||
<PackageReference Include="System.Xml.XmlDocument" Version="4.3.0" />
|
<PackageReference Include="System.Xml.XmlDocument" Version="4.3.0" />
|
||||||
<PackageReference Include="Validation" Version="2.5.42" />
|
<PackageReference Include="Validation" Version="2.5.51" />
|
||||||
<PackageReference Include="Xam.Plugin.Connectivity">
|
<PackageReference Include="Xam.Plugin.Connectivity">
|
||||||
<Version>3.2.0</Version>
|
<Version>3.2.0</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
@ -162,37 +164,37 @@
|
||||||
<PackageReference Include="Xamarin.Android.Support.v7.RecyclerView" Version="28.0.0.3" />
|
<PackageReference Include="Xamarin.Android.Support.v7.RecyclerView" Version="28.0.0.3" />
|
||||||
<PackageReference Include="Xamarin.Android.Support.Vector.Drawable" Version="28.0.0.3" />
|
<PackageReference Include="Xamarin.Android.Support.Vector.Drawable" Version="28.0.0.3" />
|
||||||
<PackageReference Include="Xamarin.AndroidX.Core">
|
<PackageReference Include="Xamarin.AndroidX.Core">
|
||||||
<Version>1.6.0.3</Version>
|
<Version>1.7.0.2</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.AndroidX.MediaRouter">
|
<PackageReference Include="Xamarin.AndroidX.MediaRouter">
|
||||||
<Version>1.2.5.2</Version>
|
<Version>1.2.6.1</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.AndroidX.Palette">
|
<PackageReference Include="Xamarin.AndroidX.Palette">
|
||||||
<Version>1.0.0.10</Version>
|
<Version>1.0.0.13</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.AndroidX.RecyclerView">
|
<PackageReference Include="Xamarin.AndroidX.RecyclerView">
|
||||||
<Version>1.2.1.3</Version>
|
<Version>1.2.1.6</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Auth" Version="1.7.0" />
|
<PackageReference Include="Xamarin.Auth" Version="1.7.0" />
|
||||||
<PackageReference Include="Xamarin.Build.Download" Version="0.10.0" />
|
<PackageReference Include="Xamarin.Build.Download" Version="0.11.0" />
|
||||||
<PackageReference Include="Xamarin.CommunityToolkit">
|
<PackageReference Include="Xamarin.CommunityToolkit">
|
||||||
<Version>1.3.0</Version>
|
<Version>2.0.1</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Essentials">
|
<PackageReference Include="Xamarin.Essentials">
|
||||||
<Version>1.7.0</Version>
|
<Version>1.7.2</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2196" />
|
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2401" />
|
||||||
<PackageReference Include="Xamarin.Forms.AppLinks">
|
<PackageReference Include="Xamarin.Forms.AppLinks">
|
||||||
<Version>5.0.0.2244</Version>
|
<Version>5.0.0.2401</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Forms.GoogleMaps">
|
<PackageReference Include="Xamarin.Forms.GoogleMaps">
|
||||||
<Version>3.3.0</Version>
|
<Version>3.3.0</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Forms.GoogleMaps.Bindings" Version="3.0.0" />
|
<PackageReference Include="Xamarin.Forms.GoogleMaps.Bindings" Version="3.0.0" />
|
||||||
<PackageReference Include="Xamarin.GooglePlayServices.Base" Version="117.6.0.1" />
|
<PackageReference Include="Xamarin.GooglePlayServices.Base" Version="117.6.0.5" />
|
||||||
<PackageReference Include="Xamarin.GooglePlayServices.Basement" Version="117.6.0.2" />
|
<PackageReference Include="Xamarin.GooglePlayServices.Basement" Version="117.6.0.6" />
|
||||||
<PackageReference Include="Xamarin.GooglePlayServices.Maps" Version="117.0.1.1" />
|
<PackageReference Include="Xamarin.GooglePlayServices.Maps" Version="117.0.1.5" />
|
||||||
<PackageReference Include="Xamarin.GooglePlayServices.Tasks" Version="117.2.1.1" />
|
<PackageReference Include="Xamarin.GooglePlayServices.Tasks" Version="117.2.1.5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Mono.Android" />
|
<Reference Include="Mono.Android" />
|
||||||
|
|
|
@ -53,8 +53,8 @@
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>sharee.bike</string>
|
<string>sharee.bike</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>290</string>
|
<string>294</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>3.0.290</string>
|
<string>3.0.294</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -113,13 +113,13 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Bcl.Build" Version="1.0.21" />
|
<PackageReference Include="Microsoft.Bcl.Build" Version="1.0.21" />
|
||||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||||
<PackageReference Include="Microsoft.NETCore.Platforms" Version="5.0.4" />
|
<PackageReference Include="Microsoft.NETCore.Platforms" Version="6.0.3" />
|
||||||
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
|
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
|
||||||
<PackageReference Include="MonkeyCache">
|
<PackageReference Include="MonkeyCache">
|
||||||
<Version>1.5.2</Version>
|
<Version>1.6.3</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="MonkeyCache.FileStore">
|
<PackageReference Include="MonkeyCache.FileStore">
|
||||||
<Version>1.5.2</Version>
|
<Version>1.6.3</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
|
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
|
@ -182,18 +182,18 @@
|
||||||
<PackageReference Include="System.Xml.ReaderWriter" Version="4.3.1" />
|
<PackageReference Include="System.Xml.ReaderWriter" Version="4.3.1" />
|
||||||
<PackageReference Include="System.Xml.XDocument" Version="4.3.0" />
|
<PackageReference Include="System.Xml.XDocument" Version="4.3.0" />
|
||||||
<PackageReference Include="System.Xml.XmlDocument" Version="4.3.0" />
|
<PackageReference Include="System.Xml.XmlDocument" Version="4.3.0" />
|
||||||
<PackageReference Include="Validation" Version="2.5.42" />
|
<PackageReference Include="Validation" Version="2.5.51" />
|
||||||
<PackageReference Include="Xam.Plugin.Connectivity">
|
<PackageReference Include="Xam.Plugin.Connectivity">
|
||||||
<Version>3.2.0</Version>
|
<Version>3.2.0</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xam.Plugins.Messaging" Version="5.2.0" />
|
<PackageReference Include="Xam.Plugins.Messaging" Version="5.2.0" />
|
||||||
<PackageReference Include="Xamarin.Auth" Version="1.7.0" />
|
<PackageReference Include="Xamarin.Auth" Version="1.7.0" />
|
||||||
<PackageReference Include="Xamarin.Build.Download" Version="0.10.0" />
|
<PackageReference Include="Xamarin.Build.Download" Version="0.11.0" />
|
||||||
<PackageReference Include="Xamarin.CommunityToolkit">
|
<PackageReference Include="Xamarin.CommunityToolkit">
|
||||||
<Version>1.3.0</Version>
|
<Version>2.0.1</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Essentials">
|
<PackageReference Include="Xamarin.Essentials">
|
||||||
<Version>1.7.0</Version>
|
<Version>1.7.2</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Forms.GoogleMaps">
|
<PackageReference Include="Xamarin.Forms.GoogleMaps">
|
||||||
<Version>3.3.0</Version>
|
<Version>3.3.0</Version>
|
||||||
|
@ -213,7 +213,7 @@
|
||||||
<Version>0.7.104</Version>
|
<Version>0.7.104</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Forms">
|
<PackageReference Include="Xamarin.Forms">
|
||||||
<Version>5.0.0.2196</Version>
|
<Version>5.0.0.2401</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace TINK.View.Bike
|
||||||
|
|
||||||
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
|
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
|
||||||
{
|
{
|
||||||
return item is TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel
|
return item is ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel
|
||||||
? iLockIBike
|
? iLockIBike
|
||||||
: bCBike;
|
: bCBike;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace TINK.View.BikesAtStation
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using TINK.Model.Device;
|
using TINK.Model.Device;
|
||||||
#if USEFLYOUT
|
#if USEFLYOUT
|
||||||
using TINK.View.MasterDetail;
|
using TINK.View.MasterDetail;
|
||||||
#endif
|
#endif
|
||||||
using TINK.ViewModel;
|
using TINK.ViewModel;
|
||||||
using TINK.Model;
|
using TINK.Model;
|
||||||
|
@ -33,6 +33,10 @@ using TINK.View.MasterDetail;
|
||||||
{
|
{
|
||||||
|
|
||||||
private BikesAtStationPageViewModel m_oViewModel;
|
private BikesAtStationPageViewModel m_oViewModel;
|
||||||
|
|
||||||
|
/// <summary> Initialization status to ensure initialization logic is not called multiple times. </summary>
|
||||||
|
private bool isInitializationStarted = false;
|
||||||
|
|
||||||
#if TRYNOTBACKSTYLE
|
#if TRYNOTBACKSTYLE
|
||||||
public BikesAtStationPage()
|
public BikesAtStationPage()
|
||||||
{
|
{
|
||||||
|
@ -62,6 +66,10 @@ using TINK.View.MasterDetail;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected async override void OnAppearing()
|
protected async override void OnAppearing()
|
||||||
{
|
{
|
||||||
|
// Don't repeat the initialization if it has been completed already.
|
||||||
|
if (isInitializationStarted) return;
|
||||||
|
isInitializationStarted = true;
|
||||||
|
|
||||||
if (m_oViewModel != null)
|
if (m_oViewModel != null)
|
||||||
{
|
{
|
||||||
#if BACKSTYLE
|
#if BACKSTYLE
|
||||||
|
@ -72,6 +80,7 @@ using TINK.View.MasterDetail;
|
||||||
// No need to create view model, set binding context an items source if already done.
|
// No need to create view model, set binding context an items source if already done.
|
||||||
// If done twice tap events are fired multiple times (when hiding page using home button).
|
// If done twice tap events are fired multiple times (when hiding page using home button).
|
||||||
await m_oViewModel.OnAppearing();
|
await m_oViewModel.OnAppearing();
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,6 +114,7 @@ using TINK.View.MasterDetail;
|
||||||
{
|
{
|
||||||
Log.ForContext<BikesAtStationPage>().Error("Displaying bikes at station page failed. {Exception}", exception);
|
Log.ForContext<BikesAtStationPage>().Error("Displaying bikes at station page failed. {Exception}", exception);
|
||||||
await DisplayAlert("Fehler", $"Seite Räder an Station kann nicht angezeigt werden. ${exception.Message}", "OK");
|
await DisplayAlert("Fehler", $"Seite Räder an Station kann nicht angezeigt werden. ${exception.Message}", "OK");
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,6 +129,7 @@ using TINK.View.MasterDetail;
|
||||||
BikesAtStationListView.ItemsSource = m_oViewModel;
|
BikesAtStationListView.ItemsSource = m_oViewModel;
|
||||||
|
|
||||||
await m_oViewModel.OnAppearing();
|
await m_oViewModel.OnAppearing();
|
||||||
|
isInitializationStarted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -167,7 +178,7 @@ using TINK.View.MasterDetail;
|
||||||
/// <param name="cancel">Text of button.</param>
|
/// <param name="cancel">Text of button.</param>
|
||||||
/// <returns>True if user pressed accept.</returns>
|
/// <returns>True if user pressed accept.</returns>
|
||||||
public new async Task<bool> DisplayAlert(string title, string message, string accept, string cancel)
|
public new async Task<bool> DisplayAlert(string title, string message, string accept, string cancel)
|
||||||
=> await App.Current.MainPage.DisplayAlert(title, message, accept, cancel);
|
=> await App.Current.MainPage.DisplayAlert(title, message, accept, cancel);
|
||||||
|
|
||||||
/// <summary> Displays detailed alert message.</summary>
|
/// <summary> Displays detailed alert message.</summary>
|
||||||
/// <param name="title">Title of message.</param>
|
/// <param name="title">Title of message.</param>
|
||||||
|
@ -233,5 +244,5 @@ using TINK.View.MasterDetail;
|
||||||
/// <returns>User feedback.</returns>
|
/// <returns>User feedback.</returns>
|
||||||
public async Task<IUserFeedback> DisplayUserFeedbackPopup(string co2Saving = null) => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup(co2Saving));
|
public async Task<IUserFeedback> DisplayUserFeedbackPopup(string co2Saving = null) => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup(co2Saving));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -152,6 +152,7 @@ namespace TINK.View.Map
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
Log.ForContext<MapPage>().Error("Constructing map page view model failed. {Exception}", exception);
|
Log.ForContext<MapPage>().Error("Constructing map page view model failed. {Exception}", exception);
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,6 +167,7 @@ namespace TINK.View.Map
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
Log.ForContext<MapPage>().Error("Setting binding/ navigaton on map page failed. {Exception}", exception);
|
Log.ForContext<MapPage>().Error("Setting binding/ navigaton on map page failed. {Exception}", exception);
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,6 +189,7 @@ namespace TINK.View.Map
|
||||||
{
|
{
|
||||||
// Continue because styling is not essential.
|
// Continue because styling is not essential.
|
||||||
Log.ForContext<MapPage>().Error("Invoking OnAppearing of base failed. {Exception}", exception);
|
Log.ForContext<MapPage>().Error("Invoking OnAppearing of base failed. {Exception}", exception);
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,10 +208,13 @@ namespace TINK.View.Map
|
||||||
{
|
{
|
||||||
Log.ForContext<MapPage>().Verbose("Invoking OnAppearing on map page view model.");
|
Log.ForContext<MapPage>().Verbose("Invoking OnAppearing on map page view model.");
|
||||||
await MapPageViewModel.OnAppearing();
|
await MapPageViewModel.OnAppearing();
|
||||||
|
|
||||||
|
isInitializationStarted = false;
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
Log.ForContext<MapPage>().Error("Invoking OnAppearing on map page view model failed. {Exception}", exception);
|
Log.ForContext<MapPage>().Error("Invoking OnAppearing on map page view model failed. {Exception}", exception);
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ using Xamarin.Forms.Xaml;
|
||||||
namespace TINK.View.MyBikes
|
namespace TINK.View.MyBikes
|
||||||
{
|
{
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
using TINK.Model;
|
||||||
using TINK.Model.Device;
|
using TINK.Model.Device;
|
||||||
using TINK.ViewModel.MyBikes;
|
using TINK.ViewModel.MyBikes;
|
||||||
using Xamarin.CommunityToolkit.Extensions;
|
using Xamarin.CommunityToolkit.Extensions;
|
||||||
|
@ -39,13 +40,14 @@ namespace TINK.View.MyBikes
|
||||||
{
|
{
|
||||||
// Don't repeat the initialization if it has been completed already.
|
// Don't repeat the initialization if it has been completed already.
|
||||||
if (isInitializationStarted) return;
|
if (isInitializationStarted) return;
|
||||||
isInitializationStarted = true;
|
isInitializationStarted = true;
|
||||||
|
|
||||||
if (m_oViewModel != null)
|
if (m_oViewModel != null)
|
||||||
{
|
{
|
||||||
// No need to create view model, set binding context an items source if already done.
|
// No need to create view model, set binding context an items source if already done.
|
||||||
// If done twice tap events are fired multiple times (when hiding page using home button).
|
// If done twice tap events are fired multiple times (when hiding page using home button).
|
||||||
await m_oViewModel.OnAppearing();
|
await m_oViewModel.OnAppearing();
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,8 +81,8 @@ namespace TINK.View.MyBikes
|
||||||
{
|
{
|
||||||
Log.ForContext<MyBikesPage>().Error("Displaying bikes at station page failed. {Exception}", exception);
|
Log.ForContext<MyBikesPage>().Error("Displaying bikes at station page failed. {Exception}", exception);
|
||||||
await DisplayAlert("Fehler", $"Seite Räder an Station kann nicht angezeigt werden. ${exception.Message}", "OK");
|
await DisplayAlert("Fehler", $"Seite Räder an Station kann nicht angezeigt werden. ${exception.Message}", "OK");
|
||||||
|
isInitializationStarted = false;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
@ -89,6 +91,7 @@ namespace TINK.View.MyBikes
|
||||||
MyBikesListView.ItemsSource = m_oViewModel;
|
MyBikesListView.ItemsSource = m_oViewModel;
|
||||||
|
|
||||||
await m_oViewModel.OnAppearing();
|
await m_oViewModel.OnAppearing();
|
||||||
|
isInitializationStarted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -22,6 +22,7 @@ namespace TINK.Model.Bike.BC
|
||||||
protected BikeInfo(
|
protected BikeInfo(
|
||||||
IStateInfo stateInfo,
|
IStateInfo stateInfo,
|
||||||
string id,
|
string id,
|
||||||
|
LockModel lockModel,
|
||||||
bool? isDemo = DEFAULTVALUEISDEMO,
|
bool? isDemo = DEFAULTVALUEISDEMO,
|
||||||
IEnumerable<string> group = null,
|
IEnumerable<string> group = null,
|
||||||
WheelType? wheelType = null,
|
WheelType? wheelType = null,
|
||||||
|
@ -31,7 +32,7 @@ namespace TINK.Model.Bike.BC
|
||||||
Uri operatorUri = null,
|
Uri operatorUri = null,
|
||||||
TariffDescription tariffDescription = null)
|
TariffDescription tariffDescription = null)
|
||||||
{
|
{
|
||||||
Bike = new Bike(id, wheelType, typeOfBike, description);
|
Bike = new Bike(id, lockModel, wheelType, typeOfBike, description);
|
||||||
|
|
||||||
m_oStateInfo = stateInfo;
|
m_oStateInfo = stateInfo;
|
||||||
|
|
||||||
|
@ -45,6 +46,7 @@ namespace TINK.Model.Bike.BC
|
||||||
public BikeInfo(BikeInfo bikeInfo) : this(
|
public BikeInfo(BikeInfo bikeInfo) : this(
|
||||||
bikeInfo?.State,
|
bikeInfo?.State,
|
||||||
bikeInfo?.Id ?? throw new ArgumentException($"Can not copy-construct {typeof(BikeInfo).Name}-object. Source must not be null."),
|
bikeInfo?.Id ?? throw new ArgumentException($"Can not copy-construct {typeof(BikeInfo).Name}-object. Source must not be null."),
|
||||||
|
bikeInfo.LockModel,
|
||||||
bikeInfo.IsDemo,
|
bikeInfo.IsDemo,
|
||||||
bikeInfo.Group,
|
bikeInfo.Group,
|
||||||
bikeInfo.WheelType,
|
bikeInfo.WheelType,
|
||||||
|
@ -64,6 +66,7 @@ namespace TINK.Model.Bike.BC
|
||||||
/// <param name="wheelType"></param>
|
/// <param name="wheelType"></param>
|
||||||
public BikeInfo(
|
public BikeInfo(
|
||||||
string id,
|
string id,
|
||||||
|
LockModel lockModel,
|
||||||
string stationId,
|
string stationId,
|
||||||
Uri operatorUri = null,
|
Uri operatorUri = null,
|
||||||
TariffDescription tariffDescription = null,
|
TariffDescription tariffDescription = null,
|
||||||
|
@ -73,7 +76,8 @@ namespace TINK.Model.Bike.BC
|
||||||
TypeOfBike? typeOfBike = null,
|
TypeOfBike? typeOfBike = null,
|
||||||
string description = null) : this(
|
string description = null) : this(
|
||||||
new StateInfo(),
|
new StateInfo(),
|
||||||
id,
|
id,
|
||||||
|
lockModel,
|
||||||
isDemo,
|
isDemo,
|
||||||
group,
|
group,
|
||||||
wheelType,
|
wheelType,
|
||||||
|
@ -88,7 +92,6 @@ namespace TINK.Model.Bike.BC
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a bike info object for a requested bike.
|
/// Constructs a bike info object for a requested bike.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dateTimeProvider">Provider for current date time to calculate remainig time on demand for state of type reserved.</param>
|
|
||||||
/// <param name="wheelType"></param>
|
/// <param name="wheelType"></param>
|
||||||
/// <param name="id">Unique id of bike.</param>
|
/// <param name="id">Unique id of bike.</param>
|
||||||
/// <param name="stationId">Name of station where bike is located, null if bike is on the road.</param>
|
/// <param name="stationId">Name of station where bike is located, null if bike is on the road.</param>
|
||||||
|
@ -97,9 +100,10 @@ namespace TINK.Model.Bike.BC
|
||||||
/// <param name="requestedAt">Date time when bike was requested</param>
|
/// <param name="requestedAt">Date time when bike was requested</param>
|
||||||
/// <param name="mailAddress">Mail address of user which requested bike.</param>
|
/// <param name="mailAddress">Mail address of user which requested bike.</param>
|
||||||
/// <param name="code">Booking code.</param>
|
/// <param name="code">Booking code.</param>
|
||||||
/// <param name="p_oDateTimeNowProvider">Date time provider to calculate reaining time.</param>
|
/// <param name="dateTimeProvider">Date time provider to calculate reaining time.</param>
|
||||||
public BikeInfo(
|
public BikeInfo(
|
||||||
string id,
|
string id,
|
||||||
|
LockModel lockModel,
|
||||||
bool? isDemo,
|
bool? isDemo,
|
||||||
IEnumerable<string> group,
|
IEnumerable<string> group,
|
||||||
WheelType? wheelType,
|
WheelType? wheelType,
|
||||||
|
@ -117,7 +121,8 @@ namespace TINK.Model.Bike.BC
|
||||||
requestedAt,
|
requestedAt,
|
||||||
mailAddress,
|
mailAddress,
|
||||||
code),
|
code),
|
||||||
id,
|
id,
|
||||||
|
lockModel,
|
||||||
isDemo,
|
isDemo,
|
||||||
group,
|
group,
|
||||||
wheelType,
|
wheelType,
|
||||||
|
@ -134,6 +139,7 @@ namespace TINK.Model.Bike.BC
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dateTimeProvider">Provider for current date time to calculate remainig time on demand for state of type reserved.</param>
|
/// <param name="dateTimeProvider">Provider for current date time to calculate remainig time on demand for state of type reserved.</param>
|
||||||
/// <param name="wheelType"></param>
|
/// <param name="wheelType"></param>
|
||||||
|
/// <param name="lockModel">Specifies the lock model.</param>
|
||||||
/// <param name="id">Unique id of bike.</param>
|
/// <param name="id">Unique id of bike.</param>
|
||||||
/// <param name="currentStationId">Name of station where bike is located, null if bike is on the road.</param>
|
/// <param name="currentStationId">Name of station where bike is located, null if bike is on the road.</param>
|
||||||
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||||
|
@ -143,6 +149,7 @@ namespace TINK.Model.Bike.BC
|
||||||
/// <param name="code">Booking code.</param>
|
/// <param name="code">Booking code.</param>
|
||||||
public BikeInfo(
|
public BikeInfo(
|
||||||
string id,
|
string id,
|
||||||
|
LockModel lockModel,
|
||||||
bool? isDemo,
|
bool? isDemo,
|
||||||
IEnumerable<string> group,
|
IEnumerable<string> group,
|
||||||
WheelType? wheelType,
|
WheelType? wheelType,
|
||||||
|
@ -158,7 +165,8 @@ namespace TINK.Model.Bike.BC
|
||||||
bookedAt,
|
bookedAt,
|
||||||
mailAddress,
|
mailAddress,
|
||||||
code),
|
code),
|
||||||
id,
|
id,
|
||||||
|
lockModel,
|
||||||
isDemo,
|
isDemo,
|
||||||
group,
|
group,
|
||||||
wheelType,
|
wheelType,
|
||||||
|
@ -198,6 +206,9 @@ namespace TINK.Model.Bike.BC
|
||||||
|
|
||||||
public TypeOfBike? TypeOfBike => Bike.TypeOfBike;
|
public TypeOfBike? TypeOfBike => Bike.TypeOfBike;
|
||||||
|
|
||||||
|
/// <summary> Gets the model of the lock. </summary>
|
||||||
|
public LockModel LockModel => Bike.LockModel;
|
||||||
|
|
||||||
public string Description => Bike.Description;
|
public string Description => Bike.Description;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -30,6 +30,7 @@ namespace TINK.Model.Bike.BC
|
||||||
/// <param name="stateInfo">Bike state info.</param>
|
/// <param name="stateInfo">Bike state info.</param>
|
||||||
protected BikeInfoMutable(
|
protected BikeInfoMutable(
|
||||||
string id,
|
string id,
|
||||||
|
LockModel lockModel,
|
||||||
bool isDemo = BikeInfo.DEFAULTVALUEISDEMO,
|
bool isDemo = BikeInfo.DEFAULTVALUEISDEMO,
|
||||||
IEnumerable<string> group = null,
|
IEnumerable<string> group = null,
|
||||||
WheelType? wheelType = null,
|
WheelType? wheelType = null,
|
||||||
|
@ -44,7 +45,7 @@ namespace TINK.Model.Bike.BC
|
||||||
{
|
{
|
||||||
IsDemo = isDemo;
|
IsDemo = isDemo;
|
||||||
Group = group;
|
Group = group;
|
||||||
m_oBike = new Bike(id, wheelType, typeOfBike, description);
|
m_oBike = new Bike(id, lockModel, wheelType, typeOfBike, description);
|
||||||
m_oStateInfo = new StateInfoMutable(dateTimeProvider, stateInfo);
|
m_oStateInfo = new StateInfoMutable(dateTimeProvider, stateInfo);
|
||||||
m_oStateInfo.PropertyChanged += (sender, eventargs) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(eventargs.PropertyName));
|
m_oStateInfo.PropertyChanged += (sender, eventargs) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(eventargs.PropertyName));
|
||||||
StationId = stationId;
|
StationId = stationId;
|
||||||
|
@ -56,6 +57,7 @@ namespace TINK.Model.Bike.BC
|
||||||
/// <summary> Constructs a bike object from source. </summary>
|
/// <summary> Constructs a bike object from source. </summary>
|
||||||
public BikeInfoMutable(IBikeInfo bike, string stationName) : this(
|
public BikeInfoMutable(IBikeInfo bike, string stationName) : this(
|
||||||
bike.Id,
|
bike.Id,
|
||||||
|
bike.LockModel,
|
||||||
bike.IsDemo,
|
bike.IsDemo,
|
||||||
bike.Group,
|
bike.Group,
|
||||||
bike.WheelType,
|
bike.WheelType,
|
||||||
|
@ -110,6 +112,8 @@ namespace TINK.Model.Bike.BC
|
||||||
|
|
||||||
public TypeOfBike? TypeOfBike => m_oBike.TypeOfBike;
|
public TypeOfBike? TypeOfBike => m_oBike.TypeOfBike;
|
||||||
|
|
||||||
|
public LockModel LockModel => m_oBike.LockModel;
|
||||||
|
|
||||||
public string Description => m_oBike.Description;
|
public string Description => m_oBike.Description;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -31,6 +31,9 @@ namespace TINK.Model.Bike.BC
|
||||||
/// </summary>
|
/// </summary>
|
||||||
TypeOfBike? TypeOfBike { get; }
|
TypeOfBike? TypeOfBike { get; }
|
||||||
|
|
||||||
|
/// <summary> Gets the model of the lock. </summary>
|
||||||
|
LockModel LockModel { get; }
|
||||||
|
|
||||||
/// <summary> Holds the description of the bike. </summary>
|
/// <summary> Holds the description of the bike. </summary>
|
||||||
string Description { get; }
|
string Description { get; }
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,9 @@ namespace TINK.Model.Bikes.Bike.BC
|
||||||
/// </summary>
|
/// </summary>
|
||||||
TypeOfBike? TypeOfBike { get; }
|
TypeOfBike? TypeOfBike { get; }
|
||||||
|
|
||||||
|
/// <summary> Gets the model of the lock. </summary>
|
||||||
|
LockModel LockModel { get; }
|
||||||
|
|
||||||
/// <summary> Holds the description of the bike. </summary>
|
/// <summary> Holds the description of the bike. </summary>
|
||||||
string Description { get; }
|
string Description { get; }
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace TINK.Model.Bike
|
namespace TINK.Model.Bike
|
||||||
{
|
{
|
||||||
/// <summary> Count of wheels. </summary>
|
/// <summary> Count of wheels. </summary>
|
||||||
public enum WheelType
|
public enum WheelType
|
||||||
{
|
{
|
||||||
|
@ -19,23 +19,36 @@ namespace TINK.Model.Bike
|
||||||
Citybike = 2,
|
Citybike = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Holds the model of lock. </summary>
|
||||||
|
public enum LockModel
|
||||||
|
{
|
||||||
|
ILockIt, // haveltec GbmH Brandenburg, Germany bluetooth lock
|
||||||
|
BordComputer, // Teilrad BC
|
||||||
|
Sigo, // Sigo Gmbh Darmstadt, Germany bike lock
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Holds the type of lock. </summary>
|
||||||
|
public enum LockType
|
||||||
|
{
|
||||||
|
Backend, // Backend, i.e. COPRI controls lock (open, close, ...)
|
||||||
|
Bluethooth, // Lock is controlled.
|
||||||
|
}
|
||||||
|
|
||||||
public class Bike : IEquatable<Bike>
|
public class Bike : IEquatable<Bike>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a bike.
|
/// Constructs a bike.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dateTimeProvider">Provider for current date time to calculate remainig time on demand for state of type reserved.</param>
|
|
||||||
/// <param name="wheelType"></param>
|
|
||||||
/// <param name="p_iId">Unique id of bike.</param>
|
|
||||||
/// <param name="p_strCurrentStationName">Name of station where bike is located, null if bike is on the road.</param>
|
|
||||||
public Bike(
|
public Bike(
|
||||||
string p_iId,
|
string p_iId,
|
||||||
|
LockModel lockModel,
|
||||||
WheelType? wheelType = null,
|
WheelType? wheelType = null,
|
||||||
TypeOfBike? typeOfBike = null,
|
TypeOfBike? typeOfBike = null,
|
||||||
string description = null)
|
string description = null)
|
||||||
{
|
{
|
||||||
WheelType = wheelType;
|
WheelType = wheelType;
|
||||||
TypeOfBike = typeOfBike;
|
TypeOfBike = typeOfBike;
|
||||||
|
LockModel = lockModel;
|
||||||
Id = p_iId;
|
Id = p_iId;
|
||||||
Description = description;
|
Description = description;
|
||||||
}
|
}
|
||||||
|
@ -55,6 +68,9 @@ namespace TINK.Model.Bike
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TypeOfBike? TypeOfBike { get; }
|
public TypeOfBike? TypeOfBike { get; }
|
||||||
|
|
||||||
|
/// <summary> Gets the model of the lock. </summary>
|
||||||
|
public LockModel LockModel { get; private set; }
|
||||||
|
|
||||||
/// <summary> Holds the description of the bike. </summary>
|
/// <summary> Holds the description of the bike. </summary>
|
||||||
public string Description { get; }
|
public string Description { get; }
|
||||||
|
|
||||||
|
|
23
TINKLib/Model/Bikes/Bike/BikeExtension.cs
Normal file
23
TINKLib/Model/Bikes/Bike/BikeExtension.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using TINK.Model.Bike;
|
||||||
|
|
||||||
|
namespace TINK.Model.Bikes.Bike
|
||||||
|
{
|
||||||
|
public static class BikeExtension
|
||||||
|
{
|
||||||
|
public static LockType GetLockType(this LockModel model)
|
||||||
|
{
|
||||||
|
switch (model)
|
||||||
|
{
|
||||||
|
case LockModel.ILockIt:
|
||||||
|
return LockType.Bluethooth;
|
||||||
|
|
||||||
|
case LockModel.Sigo:
|
||||||
|
return LockType.Backend;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentException($"Unsupported lock model {model} detected.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,7 @@ namespace TINK.Model.Bike.BluetoothLock
|
||||||
string description = null) : base(
|
string description = null) : base(
|
||||||
new StateInfo(),
|
new StateInfo(),
|
||||||
bikeId,
|
bikeId,
|
||||||
|
LockModel.ILockIt,
|
||||||
isDemo,
|
isDemo,
|
||||||
group,
|
group,
|
||||||
wheelType,
|
wheelType,
|
||||||
|
@ -81,6 +82,7 @@ namespace TINK.Model.Bike.BluetoothLock
|
||||||
mailAddress,
|
mailAddress,
|
||||||
""),
|
""),
|
||||||
id,
|
id,
|
||||||
|
LockModel.ILockIt,
|
||||||
isDemo,
|
isDemo,
|
||||||
group,
|
group,
|
||||||
wheelType,
|
wheelType,
|
||||||
|
@ -127,6 +129,7 @@ namespace TINK.Model.Bike.BluetoothLock
|
||||||
mailAddress,
|
mailAddress,
|
||||||
""),
|
""),
|
||||||
id,
|
id,
|
||||||
|
LockModel.ILockIt,
|
||||||
isDemo,
|
isDemo,
|
||||||
group,
|
group,
|
||||||
wheelType,
|
wheelType,
|
||||||
|
|
|
@ -7,7 +7,8 @@ namespace TINK.Model.Bike.BluetoothLock
|
||||||
{
|
{
|
||||||
/// <summary> Constructs a bike object from source. </summary>
|
/// <summary> Constructs a bike object from source. </summary>
|
||||||
public BikeInfoMutable(BikeInfo bike, string stationName) : base(
|
public BikeInfoMutable(BikeInfo bike, string stationName) : base(
|
||||||
bike.Id,
|
bike.Id,
|
||||||
|
bike.LockModel,
|
||||||
bike.IsDemo,
|
bike.IsDemo,
|
||||||
bike.Group,
|
bike.Group,
|
||||||
bike.WheelType,
|
bike.WheelType,
|
||||||
|
|
141
TINKLib/Model/Bikes/Bike/CopriLock/BikeInfo.cs
Normal file
141
TINKLib/Model/Bikes/Bike/CopriLock/BikeInfo.cs
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using TINK.Model.Bikes.Bike;
|
||||||
|
using TINK.Model.Bikes.Bike.CopriLock;
|
||||||
|
using TINK.Model.State;
|
||||||
|
|
||||||
|
namespace TINK.Model.Bike.CopriLock
|
||||||
|
{
|
||||||
|
public class BikeInfo : BC.BikeInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a bike info object for a available bike.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bikeId">Unique id of bike.</param>
|
||||||
|
/// <param name="currentStationId">Id of station where bike is located.</param>
|
||||||
|
/// <param name="lockInfo">Lock info.</param>
|
||||||
|
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||||
|
/// <param name="tariffDescription">Hold tariff description of bike.</param>
|
||||||
|
/// <param name="wheelType">Trike, two wheels, mono, ....</param>
|
||||||
|
public BikeInfo(
|
||||||
|
string bikeId,
|
||||||
|
string currentStationId,
|
||||||
|
LockInfo lockInfo,
|
||||||
|
Uri operatorUri = null,
|
||||||
|
TariffDescription tariffDescription = null,
|
||||||
|
bool? isDemo = DEFAULTVALUEISDEMO,
|
||||||
|
IEnumerable<string> group = null,
|
||||||
|
WheelType? wheelType = null,
|
||||||
|
TypeOfBike? typeOfBike = null,
|
||||||
|
string description = null) : base(
|
||||||
|
new StateInfo(),
|
||||||
|
bikeId,
|
||||||
|
LockModel.Sigo,
|
||||||
|
isDemo,
|
||||||
|
group,
|
||||||
|
wheelType,
|
||||||
|
typeOfBike,
|
||||||
|
description,
|
||||||
|
currentStationId,
|
||||||
|
operatorUri,
|
||||||
|
tariffDescription)
|
||||||
|
{
|
||||||
|
LockInfo = lockInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a bike info object for a requested bike.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">Unique id of bike.</param>
|
||||||
|
/// <param name="requestedAt">Date time when bike was requested</param>
|
||||||
|
/// <param name="mailAddress">Mail address of user which requested bike.</param>
|
||||||
|
/// <param name="currentStationId">Name of station where bike is located, null if bike is on the road.</param>
|
||||||
|
/// <param name="lockInfo">Lock info.</param>
|
||||||
|
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||||
|
/// <param name="tariffDescription">Hold tariff description of bike.</param>
|
||||||
|
/// <param name="dateTimeProvider">Provider for current date time to calculate remainig time on demand for state of type reserved.</param>
|
||||||
|
/// <param name="wheelType"></param>
|
||||||
|
public BikeInfo(
|
||||||
|
string id,
|
||||||
|
DateTime requestedAt,
|
||||||
|
string mailAddress,
|
||||||
|
string currentStationId,
|
||||||
|
LockInfo lockInfo,
|
||||||
|
Uri operatorUri,
|
||||||
|
TariffDescription tariffDescription,
|
||||||
|
Func<DateTime> dateTimeProvider,
|
||||||
|
bool? isDemo = DEFAULTVALUEISDEMO,
|
||||||
|
IEnumerable<string> group = null,
|
||||||
|
WheelType? wheelType = null,
|
||||||
|
TypeOfBike? typeOfBike = null,
|
||||||
|
string description = null) : base(
|
||||||
|
new StateInfo(
|
||||||
|
dateTimeProvider,
|
||||||
|
requestedAt,
|
||||||
|
mailAddress,
|
||||||
|
""),
|
||||||
|
id,
|
||||||
|
LockModel.ILockIt,
|
||||||
|
isDemo,
|
||||||
|
group,
|
||||||
|
wheelType,
|
||||||
|
typeOfBike,
|
||||||
|
description,
|
||||||
|
currentStationId,
|
||||||
|
operatorUri,
|
||||||
|
tariffDescription)
|
||||||
|
{
|
||||||
|
LockInfo = lockInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a bike info object for a booked bike.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bookedAt">Date time when bike was booked</param>
|
||||||
|
/// <param name="mailAddress">Mail address of user which booked bike.</param>
|
||||||
|
/// <param name="currentStationId">Name of station where bike is located, null if bike is on the road.</param>
|
||||||
|
/// <param name="lockInfo">Lock info.</param>
|
||||||
|
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||||
|
/// <param name="tariffDescription">Hold tariff description of bike.</param>
|
||||||
|
/// <param name="wheelType"></param>
|
||||||
|
public BikeInfo(
|
||||||
|
string id,
|
||||||
|
DateTime bookedAt,
|
||||||
|
string mailAddress,
|
||||||
|
string currentStationId,
|
||||||
|
LockInfo lockInfo,
|
||||||
|
Uri operatorUri,
|
||||||
|
TariffDescription tariffDescription = null,
|
||||||
|
bool? isDemo = DEFAULTVALUEISDEMO,
|
||||||
|
IEnumerable<string> group = null,
|
||||||
|
WheelType? wheelType = null,
|
||||||
|
TypeOfBike? typeOfBike = null,
|
||||||
|
string description = null) : base(
|
||||||
|
new StateInfo(
|
||||||
|
bookedAt,
|
||||||
|
mailAddress,
|
||||||
|
""),
|
||||||
|
id,
|
||||||
|
LockModel.ILockIt,
|
||||||
|
isDemo,
|
||||||
|
group,
|
||||||
|
wheelType,
|
||||||
|
typeOfBike,
|
||||||
|
description,
|
||||||
|
currentStationId,
|
||||||
|
operatorUri,
|
||||||
|
tariffDescription)
|
||||||
|
{
|
||||||
|
LockInfo = lockInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BikeInfo(BC.BikeInfo bikeInfo, LockInfo lockInfo) : base(
|
||||||
|
bikeInfo ?? throw new ArgumentException($"Can not copy-construct {typeof(BikeInfo).Name}-object. Source bike info must not be null."))
|
||||||
|
{
|
||||||
|
LockInfo = lockInfo
|
||||||
|
?? throw new ArgumentException($"Can not copy-construct {typeof(BikeInfo).Name}-object. Source lock object must not be null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public LockInfo LockInfo { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
31
TINKLib/Model/Bikes/Bike/CopriLock/BikeInfoMutable.cs
Normal file
31
TINKLib/Model/Bikes/Bike/CopriLock/BikeInfoMutable.cs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
using System;
|
||||||
|
using TINK.Model.Bikes.Bike.CopriLock;
|
||||||
|
|
||||||
|
namespace TINK.Model.Bike.CopriLock
|
||||||
|
{
|
||||||
|
public class BikeInfoMutable : BC.BikeInfoMutable, IBikeInfoMutable
|
||||||
|
{
|
||||||
|
/// <summary> Constructs a bike object from source. </summary>
|
||||||
|
public BikeInfoMutable(BikeInfo bike, string stationName) : base(
|
||||||
|
bike?.Id ?? throw new ArgumentException(nameof(bike)),
|
||||||
|
bike.LockModel,
|
||||||
|
bike.IsDemo,
|
||||||
|
bike.Group,
|
||||||
|
bike.WheelType,
|
||||||
|
bike.TypeOfBike,
|
||||||
|
bike.Description,
|
||||||
|
bike.StationId,
|
||||||
|
stationName,
|
||||||
|
bike.OperatorUri,
|
||||||
|
bike.TariffDescription,
|
||||||
|
() => DateTime.Now,
|
||||||
|
bike.State)
|
||||||
|
{
|
||||||
|
LockInfo = new LockInfoMutable(bike.LockInfo.State);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LockInfoMutable LockInfo { get; }
|
||||||
|
|
||||||
|
ILockInfoMutable IBikeInfoMutable.LockInfo => LockInfo;
|
||||||
|
}
|
||||||
|
}
|
7
TINKLib/Model/Bikes/Bike/CopriLock/IBikeInfoMutable.cs
Normal file
7
TINKLib/Model/Bikes/Bike/CopriLock/IBikeInfoMutable.cs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
namespace TINK.Model.Bikes.Bike.CopriLock
|
||||||
|
{
|
||||||
|
public interface IBikeInfoMutable : BC.IBikeInfoMutable
|
||||||
|
{
|
||||||
|
ILockInfoMutable LockInfo { get; }
|
||||||
|
}
|
||||||
|
}
|
8
TINKLib/Model/Bikes/Bike/CopriLock/ILockInfoMutable.cs
Normal file
8
TINKLib/Model/Bikes/Bike/CopriLock/ILockInfoMutable.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
namespace TINK.Model.Bikes.Bike.CopriLock
|
||||||
|
{
|
||||||
|
public interface ILockInfoMutable
|
||||||
|
{
|
||||||
|
LockingState State { get; set; }
|
||||||
|
}
|
||||||
|
}
|
33
TINKLib/Model/Bikes/Bike/CopriLock/LockInfoMutable.cs
Normal file
33
TINKLib/Model/Bikes/Bike/CopriLock/LockInfoMutable.cs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
using System;
|
||||||
|
using TINK.Model.Bikes.Bike.CopriLock;
|
||||||
|
|
||||||
|
namespace TINK.Model.Bike.CopriLock
|
||||||
|
{
|
||||||
|
public class LockInfoMutable : ILockInfoMutable
|
||||||
|
{
|
||||||
|
/// <summary> Lock info object. </summary>
|
||||||
|
private LockInfo LockInfo { get; set; }
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
public LockInfoMutable(LockingState state)
|
||||||
|
{
|
||||||
|
LockInfo = new LockInfo.Builder() { State = state }.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public LockingState State
|
||||||
|
{
|
||||||
|
get => LockInfo.State;
|
||||||
|
set => LockInfo = new LockInfo.Builder(LockInfo) { State = value }.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Holds the percentage of lock battery.</summary>
|
||||||
|
public double BatteryPercentage { get; set; } = double.NaN;
|
||||||
|
|
||||||
|
/// <summary> Loads lock info object from values. </summary>
|
||||||
|
public void Load()
|
||||||
|
{
|
||||||
|
LockInfo = new LockInfo.Builder(LockInfo) { }.Build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,8 +43,13 @@ namespace TINK.Model.Bike
|
||||||
// Check if bike has to be added to list of existing station.
|
// Check if bike has to be added to list of existing station.
|
||||||
if (ContainsKey(bikeInfo.Id) == false)
|
if (ContainsKey(bikeInfo.Id) == false)
|
||||||
{
|
{
|
||||||
// Bike does not yet exist in list of bikes.
|
var bikeInfoMutable = BikeInfoMutableFactory.Create(bikeInfo, stationName);
|
||||||
Add(BikeInfoMutableFactory.Create(bikeInfo, stationName));
|
if (bikeInfoMutable != null)
|
||||||
|
{
|
||||||
|
// Bike does not yet exist in list of bikes.
|
||||||
|
Add(bikeInfoMutable);
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,13 +144,24 @@ namespace TINK.Model.Bike
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create mutable objects from immutable objects.
|
/// Create mutable objects from immutable objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static class BikeInfoMutableFactory
|
public static class BikeInfoMutableFactory
|
||||||
{
|
{
|
||||||
public static BikeInfoMutable Create(BikeInfo bikeInfo, string stationName)
|
public static BikeInfoMutable Create(
|
||||||
|
BikeInfo bikeInfo,
|
||||||
|
string stationName)
|
||||||
{
|
{
|
||||||
return (bikeInfo is BluetoothLock.BikeInfo bluetoothLockBikeInfo)
|
if (bikeInfo is BluetoothLock.BikeInfo btBikeInfo)
|
||||||
? new BluetoothLock.BikeInfoMutable(bluetoothLockBikeInfo, stationName)
|
{
|
||||||
: new BikeInfoMutable(bikeInfo, stationName);
|
return new BluetoothLock.BikeInfoMutable(btBikeInfo, stationName);
|
||||||
|
}
|
||||||
|
else if (bikeInfo is CopriLock.BikeInfo copriBikeInfo)
|
||||||
|
{
|
||||||
|
return new CopriLock.BikeInfoMutable(copriBikeInfo, stationName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unsupported type detected.
|
||||||
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ using TINK.Repository.Response;
|
||||||
using TINK.Model.User.Account;
|
using TINK.Model.User.Account;
|
||||||
using TINK.Model.Device;
|
using TINK.Model.Device;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using TINK.Model.MiniSurvey;
|
|
||||||
|
|
||||||
namespace TINK.Model.Connector
|
namespace TINK.Model.Connector
|
||||||
{
|
{
|
||||||
|
@ -111,7 +110,7 @@ namespace TINK.Model.Connector
|
||||||
/// <param name="bike">Bike to update locking state for.</param>
|
/// <param name="bike">Bike to update locking state for.</param>
|
||||||
/// <param name="location">Location where lock was opened/ changed.</param>
|
/// <param name="location">Location where lock was opened/ changed.</param>
|
||||||
/// <returns>Response on updating locking state.</returns>
|
/// <returns>Response on updating locking state.</returns>
|
||||||
public async Task StartReturningBike(Bikes.Bike.BluetoothLock.IBikeInfoMutable bike)
|
public async Task StartReturningBike(Bikes.Bike.BC.IBikeInfoMutable bike)
|
||||||
{
|
{
|
||||||
Log.ForContext<Command>().Error("Unexpected request to notify about start of returning bike. No user logged in.");
|
Log.ForContext<Command>().Error("Unexpected request to notify about start of returning bike. No user logged in.");
|
||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
|
@ -127,13 +126,20 @@ namespace TINK.Model.Connector
|
||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DoBook(Bikes.Bike.BluetoothLock.IBikeInfoMutable bike)
|
public async Task DoBook(Bikes.Bike.BC.IBikeInfoMutable bike)
|
||||||
{
|
{
|
||||||
Log.ForContext<Command>().Error("Unexpected booking request detected. No user logged in.");
|
Log.ForContext<Command>().Error("Unexpected booking request detected. No user logged in.");
|
||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task BookAndOpenAync(Bikes.Bike.CopriLock.IBikeInfoMutable bike)
|
||||||
|
{
|
||||||
|
Log.ForContext<Command>().Error("Unexpected request to book and open bike detected. No user logged in.");
|
||||||
|
await Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<BookingFinishedModel> DoReturn(
|
public async Task<BookingFinishedModel> DoReturn(
|
||||||
Bikes.Bike.BluetoothLock.IBikeInfoMutable bike,
|
Bikes.Bike.BC.IBikeInfoMutable bike,
|
||||||
LocationDto location,
|
LocationDto location,
|
||||||
ISmartDevice smartDevice)
|
ISmartDevice smartDevice)
|
||||||
{
|
{
|
||||||
|
@ -141,6 +147,14 @@ namespace TINK.Model.Connector
|
||||||
return await Task.FromResult(new BookingFinishedModel());
|
return await Task.FromResult(new BookingFinishedModel());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<BookingFinishedModel> ReturnAndCloseAsync(
|
||||||
|
Bikes.Bike.CopriLock.IBikeInfoMutable bike,
|
||||||
|
ISmartDevice smartDevice)
|
||||||
|
{
|
||||||
|
Log.ForContext<Command>().Error("Unexpected close lock and return request detected. No user logged in.");
|
||||||
|
return await Task.FromResult(new BookingFinishedModel());
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Submits feedback to copri server.
|
/// Submits feedback to copri server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -162,5 +176,11 @@ namespace TINK.Model.Connector
|
||||||
Log.ForContext<Command>().Error("Unexpected submit mini survey request detected. No user logged in.");
|
Log.ForContext<Command>().Error("Unexpected submit mini survey request detected. No user logged in.");
|
||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task OpenLockAsync(Bikes.Bike.CopriLock.IBikeInfoMutable bike)
|
||||||
|
=> throw new NotImplementedException();
|
||||||
|
|
||||||
|
public Task CloseLockAsync(Bikes.Bike.CopriLock.IBikeInfoMutable bike)
|
||||||
|
=> throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,7 +8,7 @@ using TINK.Repository.Response;
|
||||||
using TINK.Model.User.Account;
|
using TINK.Model.User.Account;
|
||||||
using TINK.Model.Device;
|
using TINK.Model.Device;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using TINK.Model.MiniSurvey;
|
using TINK.Services.CopriApi;
|
||||||
|
|
||||||
namespace TINK.Model.Connector
|
namespace TINK.Model.Connector
|
||||||
{
|
{
|
||||||
|
@ -93,7 +93,7 @@ namespace TINK.Model.Connector
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
bike.Load(response, Mail, DateTimeProvider, Bikes.Bike.BC.NotifyPropertyChangedLevel.None);
|
bike.Load(response, Mail, Bikes.Bike.BC.NotifyPropertyChangedLevel.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Request to cancel a reservation.</summary>
|
/// <summary> Request to cancel a reservation.</summary>
|
||||||
|
@ -155,7 +155,6 @@ namespace TINK.Model.Connector
|
||||||
bike,
|
bike,
|
||||||
response,
|
response,
|
||||||
Mail,
|
Mail,
|
||||||
DateTimeProvider,
|
|
||||||
Bikes.Bike.BC.NotifyPropertyChangedLevel.None);
|
Bikes.Bike.BC.NotifyPropertyChangedLevel.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,7 +162,7 @@ namespace TINK.Model.Connector
|
||||||
/// <remarks> Operator specific call.</remarks>
|
/// <remarks> Operator specific call.</remarks>
|
||||||
/// <param name="bike">Bike to return.</param>
|
/// <param name="bike">Bike to return.</param>
|
||||||
/// <returns>Response on notification about start of returning sequence.</returns>
|
/// <returns>Response on notification about start of returning sequence.</returns>
|
||||||
public async Task StartReturningBike(Bikes.Bike.BluetoothLock.IBikeInfoMutable bike)
|
public async Task StartReturningBike(Bikes.Bike.BC.IBikeInfoMutable bike)
|
||||||
{
|
{
|
||||||
if (bike == null)
|
if (bike == null)
|
||||||
{
|
{
|
||||||
|
@ -223,10 +222,10 @@ namespace TINK.Model.Connector
|
||||||
{
|
{
|
||||||
(await CopriServer.UpdateLockingStateAsync(
|
(await CopriServer.UpdateLockingStateAsync(
|
||||||
bike.Id,
|
bike.Id,
|
||||||
|
state.Value,
|
||||||
|
bike.OperatorUri,
|
||||||
location,
|
location,
|
||||||
state.Value,
|
bike.LockInfo.BatteryPercentage)).GetIsBookingResponseOk(bike.Id);
|
||||||
bike.LockInfo.BatteryPercentage,
|
|
||||||
bike.OperatorUri)).GetIsBookingResponseOk(bike.Id);
|
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
|
@ -235,11 +234,9 @@ namespace TINK.Model.Connector
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary> Request to book a bike. </summary>
|
/// <summary> Request to book a bike. </summary>
|
||||||
/// <param name="bike">Bike to book.</param>
|
/// <param name="bike">Bike to book.</param>
|
||||||
public async Task DoBook(
|
public async Task DoBook(Bikes.Bike.BC.IBikeInfoMutable bike)
|
||||||
Bikes.Bike.BluetoothLock.IBikeInfoMutable bike)
|
|
||||||
{
|
{
|
||||||
if (bike == null)
|
if (bike == null)
|
||||||
{
|
{
|
||||||
|
@ -250,56 +247,53 @@ namespace TINK.Model.Connector
|
||||||
var btBike = bike as BikeInfoMutable;
|
var btBike = bike as BikeInfoMutable;
|
||||||
Guid guid = btBike != null ? btBike.LockInfo.Guid : new Guid();
|
Guid guid = btBike != null ? btBike.LockInfo.Guid : new Guid();
|
||||||
double batteryPercentage = btBike != null ? btBike.LockInfo.BatteryPercentage : double.NaN;
|
double batteryPercentage = btBike != null ? btBike.LockInfo.BatteryPercentage : double.NaN;
|
||||||
try
|
|
||||||
{
|
response = (await CopriServer.DoBookAsync(
|
||||||
response = (await CopriServer.DoBookAsync(
|
bike.Id,
|
||||||
bike.Id,
|
guid,
|
||||||
guid,
|
batteryPercentage,
|
||||||
batteryPercentage,
|
bike.OperatorUri)).GetIsBookingResponseOk(bike.Id);
|
||||||
bike.OperatorUri)).GetIsBookingResponseOk(bike.Id);
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
// Exception was not expected or too many subsequent excepitons detected.
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
bike.Load(
|
bike.Load(
|
||||||
response,
|
response,
|
||||||
Mail,
|
Mail,
|
||||||
DateTimeProvider,
|
|
||||||
Bikes.Bike.BC.NotifyPropertyChangedLevel.None);
|
Bikes.Bike.BC.NotifyPropertyChangedLevel.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Books a bike and opens the lock.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bike">Bike to book and open.</param>
|
||||||
|
public async Task BookAndOpenAync(Bikes.Bike.CopriLock.IBikeInfoMutable bike)
|
||||||
|
=> await Polling.BookAndOpenAync(CopriServer, bike, Mail);
|
||||||
|
|
||||||
/// <summary> Request to return a bike.</summary>
|
/// <summary> Request to return a bike.</summary>
|
||||||
/// <param name="bike">Bike to return.</param>
|
/// <param name="bike">Bike to return.</param>
|
||||||
/// <param name="locaton">Position of the bike.</param>
|
/// <param name="locaton">Position of the bike for bluetooth locks.</param>
|
||||||
/// <param name="smartDevice">Provides info about hard and software.</param>
|
/// <param name="smartDevice">Provides info about hard and software.</param>
|
||||||
public async Task<BookingFinishedModel> DoReturn(
|
public async Task<BookingFinishedModel> DoReturn(
|
||||||
Bikes.Bike.BluetoothLock.IBikeInfoMutable bike,
|
Bikes.Bike.BC.IBikeInfoMutable bike,
|
||||||
LocationDto location,
|
LocationDto location = null,
|
||||||
ISmartDevice smartDevice)
|
ISmartDevice smartDevice = null)
|
||||||
{
|
{
|
||||||
if (bike == null)
|
if (bike == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("Can not return bike. No bike object available.");
|
throw new ArgumentNullException("Can not return bike. No bike object available.");
|
||||||
}
|
}
|
||||||
|
|
||||||
DoReturnResponse response;
|
DoReturnResponse response
|
||||||
try
|
= (await CopriServer.DoReturn(bike.Id, location, smartDevice, bike.OperatorUri)).GetIsReturnBikeResponseOk(bike.Id);
|
||||||
{
|
|
||||||
response = (await CopriServer.DoReturn(bike.Id, location, smartDevice, bike.OperatorUri)).GetIsReturnBikeResponseOk(bike.Id);
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
// Exception was not expected or too many subsequent exceptions detected.
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
bike.Load(Bikes.Bike.BC.NotifyPropertyChangedLevel.None);
|
bike.Load(Bikes.Bike.BC.NotifyPropertyChangedLevel.None);
|
||||||
return response?.Create() ?? new BookingFinishedModel();
|
return response?.Create() ?? new BookingFinishedModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Request to return bike and close the lock.</summary>
|
||||||
|
/// <param name="bike">Bike to return.</param>
|
||||||
|
/// <param name="smartDevice">Provides info about hard and software.</param>
|
||||||
|
public async Task<BookingFinishedModel> ReturnAndCloseAsync(Bikes.Bike.CopriLock.IBikeInfoMutable bike, ISmartDevice smartDevice = null)
|
||||||
|
=> await Polling.ReturnAndCloseAync(CopriServer, smartDevice, bike);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Submits feedback to copri server.
|
/// Submits feedback to copri server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -316,5 +310,10 @@ namespace TINK.Model.Connector
|
||||||
/// <param name="answers">Collection of answers.</param>
|
/// <param name="answers">Collection of answers.</param>
|
||||||
public async Task DoSubmitMiniSurvey(IDictionary<string, string> answers)
|
public async Task DoSubmitMiniSurvey(IDictionary<string, string> answers)
|
||||||
=> await CopriServer.DoSubmitMiniSurvey(answers);
|
=> await CopriServer.DoSubmitMiniSurvey(answers);
|
||||||
|
|
||||||
|
public async Task OpenLockAsync(Bikes.Bike.CopriLock.IBikeInfoMutable bike)
|
||||||
|
=> await CopriServer.OpenAync(bike);
|
||||||
|
public async Task CloseLockAsync(Bikes.Bike.CopriLock.IBikeInfoMutable bike)
|
||||||
|
=> await CopriServer.CloseAync(bike);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,7 +4,6 @@ using TINK.Repository.Request;
|
||||||
using TINK.Model.User.Account;
|
using TINK.Model.User.Account;
|
||||||
using TINK.Model.Device;
|
using TINK.Model.Device;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using TINK.Model.MiniSurvey;
|
|
||||||
|
|
||||||
namespace TINK.Model.Connector
|
namespace TINK.Model.Connector
|
||||||
{
|
{
|
||||||
|
@ -40,7 +39,7 @@ namespace TINK.Model.Connector
|
||||||
/// <remarks> Operator specific call.</remarks>
|
/// <remarks> Operator specific call.</remarks>
|
||||||
/// <param name="bike">Bike to return.</param>
|
/// <param name="bike">Bike to return.</param>
|
||||||
/// <returns>Response on notification about start of returning sequence.</returns>
|
/// <returns>Response on notification about start of returning sequence.</returns>
|
||||||
Task StartReturningBike(Bikes.Bike.BluetoothLock.IBikeInfoMutable bike);
|
Task StartReturningBike(Bikes.Bike.BC.IBikeInfoMutable bike);
|
||||||
|
|
||||||
/// <summary> Updates COPRI lock state for a booked bike. </summary>
|
/// <summary> Updates COPRI lock state for a booked bike. </summary>
|
||||||
/// <param name="bike">Bike to update locking state for.</param>
|
/// <param name="bike">Bike to update locking state for.</param>
|
||||||
|
@ -50,13 +49,30 @@ namespace TINK.Model.Connector
|
||||||
|
|
||||||
/// <summary> Request to book a bike.</summary>
|
/// <summary> Request to book a bike.</summary>
|
||||||
/// <param name="bike">Bike to book.</param>
|
/// <param name="bike">Bike to book.</param>
|
||||||
Task DoBook(Bikes.Bike.BluetoothLock.IBikeInfoMutable bike);
|
Task DoBook(Bikes.Bike.BC.IBikeInfoMutable bike);
|
||||||
|
|
||||||
|
/// <summary> Request to book a bike and open its lock.</summary>
|
||||||
|
/// <param name="bike">Bike to book and to open lock for.</param>
|
||||||
|
Task BookAndOpenAync(Bikes.Bike.CopriLock.IBikeInfoMutable bike);
|
||||||
|
|
||||||
|
/// <summary> Request to open lock.</summary>
|
||||||
|
/// <param name="bike">Bike for which lock has to be opened.</param>
|
||||||
|
Task OpenLockAsync(Bikes.Bike.CopriLock.IBikeInfoMutable bike);
|
||||||
|
|
||||||
|
/// <summary> Request to close lock.</summary>
|
||||||
|
/// <param name="bike">Bike for which lock has to be closed.</param>
|
||||||
|
Task CloseLockAsync(Bikes.Bike.CopriLock.IBikeInfoMutable bike);
|
||||||
|
|
||||||
/// <summary> Request to return a bike.</summary>
|
/// <summary> Request to return a bike.</summary>
|
||||||
/// <param name="bike">Bike to return.</param>
|
/// <param name="bike">Bike to return.</param>
|
||||||
/// <param name="location">Geolocation of lock when returning bike.</param>
|
/// <param name="location">Geolocation of lock when returning bike.</param>
|
||||||
/// <param name="smartDevice">Provides info about hard and software.</param>
|
/// <param name="smartDevice">Provides info about hard and software.</param>
|
||||||
Task<BookingFinishedModel> DoReturn(Bikes.Bike.BluetoothLock.IBikeInfoMutable bike, LocationDto geolocation = null, ISmartDevice smartDevice = null);
|
Task<BookingFinishedModel> DoReturn(Bikes.Bike.BC.IBikeInfoMutable bike, LocationDto geolocation = null, ISmartDevice smartDevice = null);
|
||||||
|
|
||||||
|
/// <summary> Request to return bike and close the lock.</summary>
|
||||||
|
/// <param name="bike">Bike to return.</param>
|
||||||
|
/// <param name="smartDevice">Provides info about hard and software.</param>
|
||||||
|
Task<BookingFinishedModel> ReturnAndCloseAsync(Bikes.Bike.CopriLock.IBikeInfoMutable bike, ISmartDevice smartDevice = null);
|
||||||
|
|
||||||
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
|
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
|
||||||
bool IsConnected { get; }
|
bool IsConnected { get; }
|
||||||
|
|
|
@ -182,6 +182,29 @@ namespace TINK.Model.Connector
|
||||||
&& bikeInfo.system.ToUpper().StartsWith("ILOCKIT");
|
&& bikeInfo.system.ToUpper().StartsWith("ILOCKIT");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets whether the bike Is a Sigo bike or not. </summary>
|
||||||
|
/// <param name="bikeInfo">JSON to get information from..</param>
|
||||||
|
/// <returns>True if bike is a Sigo.</returns>
|
||||||
|
public static bool GetIsSigoBike(this BikeInfoBase bikeInfo)
|
||||||
|
{
|
||||||
|
return !string.IsNullOrEmpty(bikeInfo.system)
|
||||||
|
&& bikeInfo.system.ToUpper().StartsWith("SIGO");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LockModel? GetLockModel(this BikeInfoBase bikeInfo)
|
||||||
|
{
|
||||||
|
if (GetIsBluetoothLockBike(bikeInfo))
|
||||||
|
return LockModel.ILockIt;
|
||||||
|
|
||||||
|
if (GetIsManualLockBike(bikeInfo))
|
||||||
|
return LockModel.BordComputer;
|
||||||
|
|
||||||
|
if (GetIsSigoBike(bikeInfo))
|
||||||
|
return LockModel.Sigo;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Gets whether the bike has a bord computer or not. </summary>
|
/// <summary> Gets whether the bike has a bord computer or not. </summary>
|
||||||
/// <param name="bikeInfo">JSON to get information from..</param>
|
/// <param name="bikeInfo">JSON to get information from..</param>
|
||||||
/// <returns>From information.</returns>
|
/// <returns>From information.</returns>
|
||||||
|
@ -334,6 +357,36 @@ namespace TINK.Model.Connector
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the locking state from response.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bikeInfo"> Response locking state from.</param>
|
||||||
|
/// <returns>Locking state</returns>
|
||||||
|
public static Bikes.Bike.CopriLock.LockingState GetCopriLockingState(this BikeInfoBase bikeInfo)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(bikeInfo?.lock_state))
|
||||||
|
return Bikes.Bike.CopriLock.LockingState.UnknownDisconnected;
|
||||||
|
|
||||||
|
if (bikeInfo.lock_state.ToUpper().Trim() == "locked".ToUpper())
|
||||||
|
return Bikes.Bike.CopriLock.LockingState.Closed;
|
||||||
|
|
||||||
|
if (bikeInfo.lock_state.ToUpper().Trim() == "locking".ToUpper())
|
||||||
|
return Bikes.Bike.CopriLock.LockingState.Closing;
|
||||||
|
|
||||||
|
if (bikeInfo.lock_state.ToUpper().Trim() == "unlocked".ToUpper())
|
||||||
|
return Bikes.Bike.CopriLock.LockingState.Open;
|
||||||
|
|
||||||
|
if (bikeInfo.lock_state.ToUpper().Trim() == "unlocking".ToUpper())
|
||||||
|
return Bikes.Bike.CopriLock.LockingState.Opening;
|
||||||
|
|
||||||
|
return Bikes.Bike.CopriLock.LockingState.UnknownDisconnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the operator Uri from response.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bikeInfo"> Response to get uri from.</param>
|
||||||
|
/// <returns>Operatore Uri</returns>
|
||||||
public static Uri GetOperatorUri(this BikeInfoBase bikeInfo)
|
public static Uri GetOperatorUri(this BikeInfoBase bikeInfo)
|
||||||
{
|
{
|
||||||
return bikeInfo?.uri_operator != null && !string.IsNullOrEmpty(bikeInfo?.uri_operator)
|
return bikeInfo?.uri_operator != null && !string.IsNullOrEmpty(bikeInfo?.uri_operator)
|
||||||
|
|
|
@ -10,6 +10,8 @@ using Serilog;
|
||||||
|
|
||||||
using BikeInfo = TINK.Model.Bike.BC.BikeInfo;
|
using BikeInfo = TINK.Model.Bike.BC.BikeInfo;
|
||||||
using IBikeInfoMutable = TINK.Model.Bikes.Bike.BC.IBikeInfoMutable;
|
using IBikeInfoMutable = TINK.Model.Bikes.Bike.BC.IBikeInfoMutable;
|
||||||
|
using BikeExtension = TINK.Model.Bikes.Bike.BikeExtension;
|
||||||
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using TINK.Model.Station.Operator;
|
using TINK.Model.Station.Operator;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
|
@ -71,7 +73,7 @@ namespace TINK.Model.Connector
|
||||||
station.Value.operator_data?.operator_phone,
|
station.Value.operator_data?.operator_phone,
|
||||||
station.Value.operator_data?.operator_hours,
|
station.Value.operator_data?.operator_hours,
|
||||||
station.Value.operator_data?.operator_email,
|
station.Value.operator_data?.operator_email,
|
||||||
!string.IsNullOrEmpty(station.Value.operator_data?.operator_color)
|
!string.IsNullOrEmpty(station.Value.operator_data?.operator_color)
|
||||||
? Color.FromHex(station.Value.operator_data?.operator_color)
|
? Color.FromHex(station.Value.operator_data?.operator_color)
|
||||||
: (Color?)null)));
|
: (Color?)null)));
|
||||||
}
|
}
|
||||||
|
@ -86,10 +88,10 @@ namespace TINK.Model.Connector
|
||||||
/// <returns>General data object initialized form COPRI response.</returns>
|
/// <returns>General data object initialized form COPRI response.</returns>
|
||||||
public static GeneralData GetGeneralData(this ResponseBase response)
|
public static GeneralData GetGeneralData(this ResponseBase response)
|
||||||
=> new GeneralData(
|
=> new GeneralData(
|
||||||
response.init_map.GetMapSpan(),
|
response.init_map.GetMapSpan(),
|
||||||
response.merchant_message,
|
response.merchant_message,
|
||||||
response.TryGetCopriVersion(out Version copriVersion)
|
response.TryGetCopriVersion(out Version copriVersion)
|
||||||
? new Version(0,0)
|
? new Version(0, 0)
|
||||||
: copriVersion,
|
: copriVersion,
|
||||||
new ResourceUrls(response.tariff_info_html, response.bike_info_html, response.agb_html, response.privacy_html, response.impress_html));
|
new ResourceUrls(response.tariff_info_html, response.bike_info_html, response.agb_html, response.privacy_html, response.impress_html));
|
||||||
|
|
||||||
|
@ -116,28 +118,21 @@ namespace TINK.Model.Connector
|
||||||
loginResponse.authcookie?.Replace(merchantId, ""),
|
loginResponse.authcookie?.Replace(merchantId, ""),
|
||||||
loginResponse.GetGroup(),
|
loginResponse.GetGroup(),
|
||||||
loginResponse.debuglevel == 1
|
loginResponse.debuglevel == 1
|
||||||
? Permissions.All :
|
? Permissions.All :
|
||||||
(Permissions)loginResponse.debuglevel) ;
|
(Permissions)loginResponse.debuglevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Load bike object from booking response. </summary>
|
/// <summary> Load bike object from booking response. </summary>
|
||||||
/// <param name="bike">Bike object to load from response.</param>
|
/// <param name="bike">Bike object to load from response.</param>
|
||||||
/// <param name="bikeInfo">Booking response.</param>
|
/// <param name="bikeInfo">Booking response.</param>
|
||||||
/// <param name="mailAddress">Mail address of user which books bike.</param>
|
/// <param name="mailAddress">Mail address of user which books bike.</param>
|
||||||
/// <param name="p_strSessionCookie">Session cookie of user which books bike.</param>
|
|
||||||
/// <param name="notifyLevel">Controls whether notify property changed events are fired or not.</param>
|
/// <param name="notifyLevel">Controls whether notify property changed events are fired or not.</param>
|
||||||
public static void Load(
|
public static void Load(
|
||||||
this IBikeInfoMutable bike,
|
this IBikeInfoMutable bike,
|
||||||
BikeInfoReservedOrBooked bikeInfo,
|
BikeInfoReservedOrBooked bikeInfo,
|
||||||
string mailAddress,
|
string mailAddress,
|
||||||
Func<DateTime> dateTimeProvider,
|
|
||||||
Bikes.Bike.BC.NotifyPropertyChangedLevel notifyLevel = Bikes.Bike.BC.NotifyPropertyChangedLevel.All)
|
Bikes.Bike.BC.NotifyPropertyChangedLevel notifyLevel = Bikes.Bike.BC.NotifyPropertyChangedLevel.All)
|
||||||
{
|
{
|
||||||
|
|
||||||
var l_oDateTimeProvider = dateTimeProvider != null
|
|
||||||
? dateTimeProvider
|
|
||||||
: () => DateTime.Now;
|
|
||||||
|
|
||||||
if (bike is Bike.BluetoothLock.BikeInfoMutable btBikeInfo)
|
if (bike is Bike.BluetoothLock.BikeInfoMutable btBikeInfo)
|
||||||
{
|
{
|
||||||
btBikeInfo.LockInfo.Load(
|
btBikeInfo.LockInfo.Load(
|
||||||
|
@ -171,7 +166,7 @@ namespace TINK.Model.Connector
|
||||||
InUseStateEnum.Booked,
|
InUseStateEnum.Booked,
|
||||||
bikeInfo.GetFrom(),
|
bikeInfo.GetFrom(),
|
||||||
mailAddress,
|
mailAddress,
|
||||||
bikeInfo.timeCode,
|
bikeInfo.timeCode,
|
||||||
notifyLevel);
|
notifyLevel);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -293,15 +288,22 @@ namespace TINK.Model.Connector
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs bike info instances/ bike info derived instances.
|
/// Constructs bike info instances/ bike info derived instances.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class BikeInfoFactory
|
public static class BikeInfoFactory
|
||||||
{
|
{
|
||||||
|
/// <summary> Set default lock type to . </summary>
|
||||||
|
public static LockModel DEFAULTLOCKMODEL = LockModel.Sigo;
|
||||||
|
|
||||||
|
/// <summary> Creates a bike info object from copri response. </summary>
|
||||||
|
/// <param name="bikeInfo">Copri response for a disposable bike. </param>
|
||||||
public static BikeInfo Create(BikeInfoAvailable bikeInfo)
|
public static BikeInfo Create(BikeInfoAvailable bikeInfo)
|
||||||
{
|
{
|
||||||
if (bikeInfo.GetIsManualLockBike())
|
var lockModel = bikeInfo.GetLockModel();
|
||||||
|
|
||||||
|
if (lockModel.HasValue
|
||||||
|
&& lockModel.Value == LockModel.BordComputer)
|
||||||
{
|
{
|
||||||
// Manual lock bikes are no more supported.
|
// Manual lock bikes are no more supported.
|
||||||
Log.Error(
|
Log.Error(
|
||||||
|
@ -309,6 +311,7 @@ namespace TINK.Model.Connector
|
||||||
"Manual lock bikes are no more supported." +
|
"Manual lock bikes are no more supported." +
|
||||||
$"Bike number: {bikeInfo.bike}{(bikeInfo.station != null ? $"station number {bikeInfo.station}" : string.Empty)}."
|
$"Bike number: {bikeInfo.bike}{(bikeInfo.station != null ? $"station number {bikeInfo.station}" : string.Empty)}."
|
||||||
);
|
);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,40 +332,52 @@ namespace TINK.Model.Connector
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var lockType = lockModel.HasValue
|
||||||
|
? BikeExtension.GetLockType(lockModel.Value)
|
||||||
|
: BikeExtension.GetLockType(DEFAULTLOCKMODEL); // Map bikes without "system"- entry in response to backend- locks.
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return !bikeInfo.GetIsBluetoothLockBike()
|
switch (lockType)
|
||||||
? new BikeInfo(
|
{
|
||||||
bikeInfo.bike,
|
case LockType.Backend:
|
||||||
bikeInfo.station,
|
return new Bike.CopriLock.BikeInfo(
|
||||||
bikeInfo.GetOperatorUri(),
|
bikeInfo.bike,
|
||||||
|
bikeInfo.station,
|
||||||
|
new Bikes.Bike.CopriLock.LockInfo.Builder { State = bikeInfo.GetCopriLockingState()}.Build(),
|
||||||
|
bikeInfo.GetOperatorUri(),
|
||||||
#if !NOTARIFFDESCRIPTION
|
#if !NOTARIFFDESCRIPTION
|
||||||
Create(bikeInfo.tariff_description),
|
Create(bikeInfo.tariff_description),
|
||||||
#else
|
#else
|
||||||
Create((TINK.Repository.Response.TariffDescription) null),
|
Create((TINK.Repository.Response.TariffDescription) null),
|
||||||
#endif
|
#endif
|
||||||
bikeInfo.GetIsDemo(),
|
bikeInfo.GetIsDemo(),
|
||||||
bikeInfo.GetGroup(),
|
bikeInfo.GetGroup(),
|
||||||
bikeInfo.GetWheelType(),
|
bikeInfo.GetWheelType(),
|
||||||
bikeInfo.GetTypeOfBike(),
|
bikeInfo.GetTypeOfBike(),
|
||||||
bikeInfo.description)
|
bikeInfo.description);
|
||||||
: new Bike.BluetoothLock.BikeInfo(
|
|
||||||
bikeInfo.bike,
|
case LockType.Bluethooth:
|
||||||
bikeInfo.GetBluetoothLockId(),
|
return new Bike.BluetoothLock.BikeInfo(
|
||||||
bikeInfo.GetBluetoothLockGuid(),
|
bikeInfo.bike,
|
||||||
bikeInfo.station,
|
bikeInfo.GetBluetoothLockId(),
|
||||||
bikeInfo.GetOperatorUri(),
|
bikeInfo.GetBluetoothLockGuid(),
|
||||||
|
bikeInfo.station,
|
||||||
|
bikeInfo.GetOperatorUri(),
|
||||||
#if !NOTARIFFDESCRIPTION
|
#if !NOTARIFFDESCRIPTION
|
||||||
Create(bikeInfo.tariff_description),
|
Create(bikeInfo.tariff_description),
|
||||||
#else
|
#else
|
||||||
Create((TINK.Repository.Response.TariffDescription)null),
|
Create((TINK.Repository.Response.TariffDescription)null),
|
||||||
#endif
|
#endif
|
||||||
bikeInfo.GetIsDemo(),
|
bikeInfo.GetIsDemo(),
|
||||||
bikeInfo.GetGroup(),
|
bikeInfo.GetGroup(),
|
||||||
bikeInfo.GetWheelType(),
|
bikeInfo.GetWheelType(),
|
||||||
bikeInfo.GetTypeOfBike(),
|
bikeInfo.GetTypeOfBike(),
|
||||||
bikeInfo.description);
|
bikeInfo.description);
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentException($"Unsupported lock type {lockType} detected.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (ArgumentException ex)
|
catch (ArgumentException ex)
|
||||||
{
|
{
|
||||||
|
@ -376,13 +391,15 @@ namespace TINK.Model.Connector
|
||||||
/// <param name="bikeInfo">Copri response. </param>
|
/// <param name="bikeInfo">Copri response. </param>
|
||||||
/// <param name="mailAddress">Mail address of user.</param>
|
/// <param name="mailAddress">Mail address of user.</param>
|
||||||
/// <param name="dateTimeProvider">Date and time provider function.</param>
|
/// <param name="dateTimeProvider">Date and time provider function.</param>
|
||||||
/// <returns></returns>
|
|
||||||
public static BikeInfo Create(
|
public static BikeInfo Create(
|
||||||
BikeInfoReservedOrBooked bikeInfo,
|
BikeInfoReservedOrBooked bikeInfo,
|
||||||
string mailAddress,
|
string mailAddress,
|
||||||
Func<DateTime> dateTimeProvider)
|
Func<DateTime> dateTimeProvider)
|
||||||
{
|
{
|
||||||
if (bikeInfo.GetIsManualLockBike())
|
var lockModel = bikeInfo.GetLockModel();
|
||||||
|
|
||||||
|
if (lockModel.HasValue
|
||||||
|
&& lockModel.Value == LockModel.BordComputer)
|
||||||
{
|
{
|
||||||
// Manual lock bikes are no more supported.
|
// Manual lock bikes are no more supported.
|
||||||
Log.Error(
|
Log.Error(
|
||||||
|
@ -393,8 +410,11 @@ namespace TINK.Model.Connector
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var lockType = lockModel.HasValue
|
||||||
|
? BikeExtension.GetLockType(lockModel.Value)
|
||||||
|
: BikeExtension.GetLockType(DEFAULTLOCKMODEL); // Map bikes without "system"- entry in response to backend- locks.
|
||||||
|
|
||||||
// Check if bike is a bluetooth lock bike.
|
// Check if bike is a bluetooth lock bike.
|
||||||
var isBluetoothBike = bikeInfo.GetIsBluetoothLockBike();
|
|
||||||
int lockSerial = bikeInfo.GetBluetoothLockId();
|
int lockSerial = bikeInfo.GetBluetoothLockId();
|
||||||
Guid lockGuid = bikeInfo.GetBluetoothLockGuid();
|
Guid lockGuid = bikeInfo.GetBluetoothLockGuid();
|
||||||
|
|
||||||
|
@ -403,48 +423,54 @@ namespace TINK.Model.Connector
|
||||||
case InUseStateEnum.Reserved:
|
case InUseStateEnum.Reserved:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return !isBluetoothBike
|
switch (lockType)
|
||||||
? new BikeInfo(
|
{
|
||||||
bikeInfo.bike,
|
case LockType.Bluethooth:
|
||||||
bikeInfo.GetIsDemo(),
|
return new Bike.BluetoothLock.BikeInfo(
|
||||||
bikeInfo.GetGroup(),
|
bikeInfo.bike,
|
||||||
bikeInfo.GetWheelType(),
|
lockSerial,
|
||||||
bikeInfo.GetTypeOfBike(),
|
lockGuid,
|
||||||
bikeInfo.description,
|
bikeInfo.GetUserKey(),
|
||||||
bikeInfo.station,
|
bikeInfo.GetAdminKey(),
|
||||||
bikeInfo.GetOperatorUri(),
|
bikeInfo.GetSeed(),
|
||||||
|
bikeInfo.GetFrom(),
|
||||||
|
mailAddress,
|
||||||
|
bikeInfo.station,
|
||||||
|
bikeInfo.GetOperatorUri(),
|
||||||
|
#if !NOTARIFFDESCRIPTION
|
||||||
|
Create(bikeInfo.tariff_description),
|
||||||
|
#else
|
||||||
|
Create((TINK.Repository.Response.TariffDescription)null),
|
||||||
|
#endif
|
||||||
|
dateTimeProvider,
|
||||||
|
bikeInfo.GetIsDemo(),
|
||||||
|
bikeInfo.GetGroup(),
|
||||||
|
bikeInfo.GetWheelType(),
|
||||||
|
bikeInfo.GetTypeOfBike(),
|
||||||
|
bikeInfo.description);
|
||||||
|
|
||||||
|
case LockType.Backend:
|
||||||
|
return new Bike.CopriLock.BikeInfo(
|
||||||
|
bikeInfo.bike,
|
||||||
|
bikeInfo.GetFrom(),
|
||||||
|
mailAddress,
|
||||||
|
bikeInfo.station,
|
||||||
|
new Bikes.Bike.CopriLock.LockInfo.Builder { State = bikeInfo.GetCopriLockingState() }.Build(),
|
||||||
|
bikeInfo.GetOperatorUri(),
|
||||||
#if !NOTARIFFDESCRIPTION
|
#if !NOTARIFFDESCRIPTION
|
||||||
Create(bikeInfo.tariff_description),
|
Create(bikeInfo.tariff_description),
|
||||||
#else
|
#else
|
||||||
Create((TINK.Repository.Response.TariffDescription)null),
|
Create((TINK.Repository.Response.TariffDescription)null),
|
||||||
#endif
|
#endif
|
||||||
bikeInfo.GetFrom(),
|
dateTimeProvider,
|
||||||
mailAddress,
|
bikeInfo.GetIsDemo(),
|
||||||
bikeInfo.timeCode,
|
bikeInfo.GetGroup(),
|
||||||
dateTimeProvider)
|
bikeInfo.GetWheelType(),
|
||||||
: new Bike.BluetoothLock.BikeInfo(
|
bikeInfo.GetTypeOfBike(),
|
||||||
bikeInfo.bike,
|
bikeInfo.description);
|
||||||
lockSerial,
|
default:
|
||||||
lockGuid,
|
throw new ArgumentException($"Unsupported lock type {lockType} detected.");
|
||||||
bikeInfo.GetUserKey(),
|
}
|
||||||
bikeInfo.GetAdminKey(),
|
|
||||||
bikeInfo.GetSeed(),
|
|
||||||
bikeInfo.GetFrom(),
|
|
||||||
mailAddress,
|
|
||||||
bikeInfo.station,
|
|
||||||
bikeInfo.GetOperatorUri(),
|
|
||||||
#if !NOTARIFFDESCRIPTION
|
|
||||||
Create(bikeInfo.tariff_description),
|
|
||||||
#else
|
|
||||||
Create((TINK.Repository.Response.TariffDescription)null),
|
|
||||||
#endif
|
|
||||||
dateTimeProvider,
|
|
||||||
bikeInfo.GetIsDemo(),
|
|
||||||
bikeInfo.GetGroup(),
|
|
||||||
bikeInfo.GetWheelType(),
|
|
||||||
bikeInfo.GetTypeOfBike(),
|
|
||||||
bikeInfo.description);
|
|
||||||
}
|
}
|
||||||
catch (ArgumentException ex)
|
catch (ArgumentException ex)
|
||||||
{
|
{
|
||||||
|
@ -456,45 +482,69 @@ namespace TINK.Model.Connector
|
||||||
case InUseStateEnum.Booked:
|
case InUseStateEnum.Booked:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return !isBluetoothBike
|
switch (lockModel)
|
||||||
? new BikeInfo(
|
{
|
||||||
bikeInfo.bike,
|
case LockModel.ILockIt:
|
||||||
bikeInfo.GetIsDemo(),
|
return new Bike.BluetoothLock.BikeInfo(
|
||||||
bikeInfo.GetGroup(),
|
bikeInfo.bike,
|
||||||
bikeInfo.GetWheelType(),
|
lockSerial,
|
||||||
bikeInfo.GetTypeOfBike(),
|
bikeInfo.GetBluetoothLockGuid(),
|
||||||
bikeInfo.description,
|
bikeInfo.GetUserKey(),
|
||||||
bikeInfo.station,
|
bikeInfo.GetAdminKey(),
|
||||||
bikeInfo.GetOperatorUri(),
|
bikeInfo.GetSeed(),
|
||||||
|
bikeInfo.GetFrom(),
|
||||||
|
mailAddress,
|
||||||
|
bikeInfo.station,
|
||||||
|
bikeInfo.GetOperatorUri(),
|
||||||
#if !NOTARIFFDESCRIPTION
|
#if !NOTARIFFDESCRIPTION
|
||||||
Create(bikeInfo.tariff_description),
|
Create(bikeInfo.tariff_description),
|
||||||
#else
|
#else
|
||||||
Create((TINK.Repository.Response.TariffDescription)null),
|
Create((TINK.Repository.Response.TariffDescription)null),
|
||||||
#endif
|
#endif
|
||||||
bikeInfo.GetFrom(),
|
bikeInfo.GetIsDemo(),
|
||||||
mailAddress,
|
bikeInfo.GetGroup(),
|
||||||
bikeInfo.timeCode)
|
bikeInfo.GetWheelType(),
|
||||||
: new Bike.BluetoothLock.BikeInfo(
|
bikeInfo.GetTypeOfBike(),
|
||||||
bikeInfo.bike,
|
bikeInfo.description);
|
||||||
lockSerial,
|
|
||||||
bikeInfo.GetBluetoothLockGuid(),
|
case LockModel.BordComputer:
|
||||||
bikeInfo.GetUserKey(),
|
return new BikeInfo(
|
||||||
bikeInfo.GetAdminKey(),
|
bikeInfo.bike,
|
||||||
bikeInfo.GetSeed(),
|
LockModel.BordComputer,
|
||||||
bikeInfo.GetFrom(),
|
bikeInfo.GetIsDemo(),
|
||||||
mailAddress,
|
bikeInfo.GetGroup(),
|
||||||
bikeInfo.station,
|
bikeInfo.GetWheelType(),
|
||||||
bikeInfo.GetOperatorUri(),
|
bikeInfo.GetTypeOfBike(),
|
||||||
|
bikeInfo.description,
|
||||||
|
bikeInfo.station,
|
||||||
|
bikeInfo.GetOperatorUri(),
|
||||||
#if !NOTARIFFDESCRIPTION
|
#if !NOTARIFFDESCRIPTION
|
||||||
Create(bikeInfo.tariff_description),
|
Create(bikeInfo.tariff_description),
|
||||||
#else
|
#else
|
||||||
Create((TINK.Repository.Response.TariffDescription)null),
|
Create((TINK.Repository.Response.TariffDescription)null),
|
||||||
#endif
|
#endif
|
||||||
bikeInfo.GetIsDemo(),
|
bikeInfo.GetFrom(),
|
||||||
bikeInfo.GetGroup(),
|
mailAddress,
|
||||||
bikeInfo.GetWheelType(),
|
bikeInfo.timeCode);
|
||||||
bikeInfo.GetTypeOfBike(),
|
default:
|
||||||
bikeInfo.description);
|
return new Bike.CopriLock.BikeInfo(
|
||||||
|
bikeInfo.bike,
|
||||||
|
bikeInfo.GetFrom(),
|
||||||
|
mailAddress,
|
||||||
|
bikeInfo.station,
|
||||||
|
new Bikes.Bike.CopriLock.LockInfo.Builder { State = bikeInfo.GetCopriLockingState() }.Build(),
|
||||||
|
bikeInfo.GetOperatorUri(),
|
||||||
|
#if !NOTARIFFDESCRIPTION
|
||||||
|
Create(bikeInfo.tariff_description),
|
||||||
|
#else
|
||||||
|
Create((TINK.Repository.Response.TariffDescription)null),
|
||||||
|
#endif
|
||||||
|
bikeInfo.GetIsDemo(),
|
||||||
|
bikeInfo.GetGroup(),
|
||||||
|
bikeInfo.GetWheelType(),
|
||||||
|
bikeInfo.GetTypeOfBike(),
|
||||||
|
bikeInfo.description);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (ArgumentException ex)
|
catch (ArgumentException ex)
|
||||||
{
|
{
|
||||||
|
@ -517,7 +567,7 @@ namespace TINK.Model.Connector
|
||||||
#if USCSHARP9
|
#if USCSHARP9
|
||||||
Number = int.TryParse(tariffDesciption?.number, out int number) ? number : null,
|
Number = int.TryParse(tariffDesciption?.number, out int number) ? number : null,
|
||||||
#else
|
#else
|
||||||
Number = int.TryParse(tariffDesciption?.number, out int number) ? number : (int?) null,
|
Number = int.TryParse(tariffDesciption?.number, out int number) ? number : (int?)null,
|
||||||
#endif
|
#endif
|
||||||
FreeTimePerSession = double.TryParse(tariffDesciption?.free_hours, NumberStyles.Any, CultureInfo.InvariantCulture, out double freeHours) ? TimeSpan.FromHours(freeHours) : TimeSpan.Zero,
|
FreeTimePerSession = double.TryParse(tariffDesciption?.free_hours, NumberStyles.Any, CultureInfo.InvariantCulture, out double freeHours) ? TimeSpan.FromHours(freeHours) : TimeSpan.Zero,
|
||||||
FeeEuroPerHour = double.TryParse(tariffDesciption?.eur_per_hour, NumberStyles.Any, CultureInfo.InvariantCulture, out double euroPerHour) ? euroPerHour : double.NaN,
|
FeeEuroPerHour = double.TryParse(tariffDesciption?.eur_per_hour, NumberStyles.Any, CultureInfo.InvariantCulture, out double euroPerHour) ? euroPerHour : double.NaN,
|
||||||
|
@ -545,11 +595,11 @@ namespace TINK.Model.Connector
|
||||||
|
|
||||||
var miniquery = response.user_miniquery;
|
var miniquery = response.user_miniquery;
|
||||||
bookingFinished.MiniSurvey = new MiniSurveyModel
|
bookingFinished.MiniSurvey = new MiniSurveyModel
|
||||||
{
|
{
|
||||||
Title = miniquery.title,
|
Title = miniquery.title,
|
||||||
Subtitle = miniquery.subtitle,
|
Subtitle = miniquery.subtitle,
|
||||||
Footer = miniquery.footer
|
Footer = miniquery.footer
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var question in miniquery?.questions?.OrderBy(x => x.Key) ?? new Dictionary<string, MiniSurveyResponse.Question>().OrderBy(x => x.Key))
|
foreach (var question in miniquery?.questions?.OrderBy(x => x.Key) ?? new Dictionary<string, MiniSurveyResponse.Question>().OrderBy(x => x.Key))
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,17 +7,16 @@ namespace TINK.Model.State
|
||||||
InUseStateEnum Value { get; }
|
InUseStateEnum Value { get; }
|
||||||
|
|
||||||
/// <summary> Updates state from webserver. </summary>
|
/// <summary> Updates state from webserver. </summary>
|
||||||
/// <param name="p_oState">State of the bike.</param>
|
/// <param name="state">State of the bike.</param>
|
||||||
/// <param name="p_oFrom">Date time when bike was reserved/ booked.</param>
|
/// <param name="from">Date time when bike was reserved/ booked.</param>
|
||||||
/// <param name="p_oDuration">Lenght of time span for which bike remains booked.</param>
|
/// <param name="mailAddress">Mailaddress of the one which reserved/ booked.</param>
|
||||||
/// <param name="p_strMailAddress">Mailaddress of the one which reserved/ booked.</param>
|
/// <param name="code">Booking code if bike is booked or reserved.</param>
|
||||||
/// <param name="p_strCode">Booking code if bike is booked or reserved.</param>
|
|
||||||
/// <param name="notifyLevel">Controls whether notify property changed events are fired or not.</param>
|
/// <param name="notifyLevel">Controls whether notify property changed events are fired or not.</param>
|
||||||
void Load(
|
void Load(
|
||||||
InUseStateEnum p_oState,
|
InUseStateEnum state,
|
||||||
DateTime? p_oFrom = null,
|
DateTime? from = null,
|
||||||
string p_strMailAddress = null,
|
string mailAddress = null,
|
||||||
string p_strCode = null,
|
string code = null,
|
||||||
Bikes.Bike.BC.NotifyPropertyChangedLevel notifyLevel = Bikes.Bike.BC.NotifyPropertyChangedLevel.All);
|
Bikes.Bike.BC.NotifyPropertyChangedLevel notifyLevel = Bikes.Bike.BC.NotifyPropertyChangedLevel.All);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ namespace TINK.Model
|
||||||
public void SetWhatsNewWasShown() => WhatsNew = WhatsNew.SetWasShown();
|
public void SetWhatsNewWasShown() => WhatsNew = WhatsNew.SetWasShown();
|
||||||
|
|
||||||
/// <summary>Holds uris of copri servers. </summary>
|
/// <summary>Holds uris of copri servers. </summary>
|
||||||
public CopriServerUriList Uris { get; }
|
public CopriServerUriList Uris { get; private set; }
|
||||||
|
|
||||||
/// <summary> Holds the filters loaded from settings. </summary>
|
/// <summary> Holds the filters loaded from settings. </summary>
|
||||||
public IGroupFilterSettings FilterGroupSetting { get; set; }
|
public IGroupFilterSettings FilterGroupSetting { get; set; }
|
||||||
|
@ -298,7 +298,8 @@ namespace TINK.Model
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set active app theme
|
// Set active app theme from settings.
|
||||||
|
// Value might differ from default scheme value defined in ResourceDictionary.MergedDictionaries (App.xaml)
|
||||||
ICollection<ResourceDictionary> mergedDictionaries = Application.Current.Resources.MergedDictionaries;
|
ICollection<ResourceDictionary> mergedDictionaries = Application.Current.Resources.MergedDictionaries;
|
||||||
if (mergedDictionaries == null)
|
if (mergedDictionaries == null)
|
||||||
{
|
{
|
||||||
|
@ -399,7 +400,7 @@ namespace TINK.Model
|
||||||
public IServicesContainer<IGeolocation> GeolocationServices { get; }
|
public IServicesContainer<IGeolocation> GeolocationServices { get; }
|
||||||
|
|
||||||
/// <summary> Manages the different types of LocksService objects.</summary>
|
/// <summary> Manages the different types of LocksService objects.</summary>
|
||||||
public ServicesContainerMutable<object> Themes { get; }
|
public ServicesContainerMutable<object> Themes { get; private set; }
|
||||||
|
|
||||||
/// <summary> Object to switch logging level. </summary>
|
/// <summary> Object to switch logging level. </summary>
|
||||||
private LoggingLevelSwitch m_oLoggingLevelSwitch;
|
private LoggingLevelSwitch m_oLoggingLevelSwitch;
|
||||||
|
|
|
@ -514,6 +514,10 @@ namespace TINK.Model
|
||||||
{
|
{
|
||||||
new Version(3, 0, 290),
|
new Version(3, 0, 290),
|
||||||
AppResources.ChangeLog3_0_290
|
AppResources.ChangeLog3_0_290
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new Version(3, 0, 294),
|
||||||
|
AppResources.ChangeLog3_0_293
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1033,6 +1033,17 @@ namespace TINK.MultilingualResources {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Target Android framework set from 11.0 to 12.0 (Level 31 S).
|
||||||
|
///NuGet packages updated.
|
||||||
|
///Started adding support for new lock type..
|
||||||
|
/// </summary>
|
||||||
|
public static string ChangeLog3_0_293 {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ChangeLog3_0_293", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Lock of rented bike cannot be be connected right now..
|
/// Looks up a localized string similar to Lock of rented bike cannot be be connected right now..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1356,6 +1367,24 @@ namespace TINK.MultilingualResources {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Error returning bike!.
|
||||||
|
/// </summary>
|
||||||
|
public static string ErrorReturnBikeTitle {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ErrorReturnBikeTitle", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Connection error when returning the bike!.
|
||||||
|
/// </summary>
|
||||||
|
public static string ErrorReturnBikeNoWebTitle {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ErrorReturnBikeNoWebTitle", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Error returning bike!.
|
/// Looks up a localized string similar to Error returning bike!.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -869,4 +869,10 @@ Activity Indicator zu Konto-Verwaltungsseiten hinzugefügt und Logging erweitert
|
||||||
<data name="ChangeLog3_0_290" xml:space="preserve">
|
<data name="ChangeLog3_0_290" xml:space="preserve">
|
||||||
<value>Der aktuelle Standort wird mit höherer Genauigkeit abgefragt.</value>
|
<value>Der aktuelle Standort wird mit höherer Genauigkeit abgefragt.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ChangeLog3_0_293" xml:space="preserve">
|
||||||
|
<value>Target Android framework von 11.0 auf 12.0 (Level 31 S) gesetzt.
|
||||||
|
NuGet packages aktualisiert.
|
||||||
|
Entwurf Untertützung eines neuen Schlosstyps hinzugefügt.
|
||||||
|
</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -962,4 +962,9 @@ Activity indicator added account management pages and logging extended.</value>
|
||||||
<data name="ChangeLog3_0_290" xml:space="preserve">
|
<data name="ChangeLog3_0_290" xml:space="preserve">
|
||||||
<value>Geolocation is queried with higher accuracy.</value>
|
<value>Geolocation is queried with higher accuracy.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ChangeLog3_0_293" xml:space="preserve">
|
||||||
|
<value>Target Android framework set from 11.0 to 12.0 (Level 31 S).
|
||||||
|
NuGet packages updated.
|
||||||
|
Started adding support for new lock type.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1182,6 +1182,15 @@ Activity Indicator zu Konto-Verwaltungsseiten hinzugefügt und Logging erweitert
|
||||||
<source>Geolocation is queried with higher accuracy.</source>
|
<source>Geolocation is queried with higher accuracy.</source>
|
||||||
<target state="translated">Der aktuelle Standort wird mit höherer Genauigkeit abgefragt.</target>
|
<target state="translated">Der aktuelle Standort wird mit höherer Genauigkeit abgefragt.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="ChangeLog3_0_293" translate="yes" xml:space="preserve">
|
||||||
|
<source>Target Android framework set from 11.0 to 12.0 (Level 31 S).
|
||||||
|
NuGet packages updated.
|
||||||
|
Started adding support for new lock type.</source>
|
||||||
|
<target state="translated">Target Android framework von 11.0 auf 12.0 (Level 31 S) gesetzt.
|
||||||
|
NuGet packages aktualisiert.
|
||||||
|
Entwurf Untertützung eines neuen Schlosstyps hinzugefügt.
|
||||||
|
</target>
|
||||||
|
</trans-unit>
|
||||||
</group>
|
</group>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|
|
@ -180,13 +180,13 @@ namespace TINK.Repository
|
||||||
/// <returns>Response on updating locking state.</returns>
|
/// <returns>Response on updating locking state.</returns>
|
||||||
public async Task<ReservationBookingResponse> UpdateLockingStateAsync(
|
public async Task<ReservationBookingResponse> UpdateLockingStateAsync(
|
||||||
string bikeId,
|
string bikeId,
|
||||||
LocationDto location,
|
|
||||||
lock_state state,
|
lock_state state,
|
||||||
double batteryLevel,
|
Uri operatorUri,
|
||||||
Uri operatorUri)=>
|
LocationDto location,
|
||||||
|
double batteryLevel) =>
|
||||||
await DoUpdateLockingStateAsync(
|
await DoUpdateLockingStateAsync(
|
||||||
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
|
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
|
||||||
requestBuilder.UpateLockingState(bikeId, location, state, batteryLevel),
|
requestBuilder.UpateLockingState(bikeId, state, location, batteryLevel),
|
||||||
UserAgent);
|
UserAgent);
|
||||||
|
|
||||||
/// <summary> Gets booking request request. </summary>
|
/// <summary> Gets booking request request. </summary>
|
||||||
|
@ -200,12 +200,22 @@ namespace TINK.Repository
|
||||||
Guid guid,
|
Guid guid,
|
||||||
double batteryPercentage,
|
double batteryPercentage,
|
||||||
Uri operatorUri)
|
Uri operatorUri)
|
||||||
{
|
=> await DoBookAsync(
|
||||||
return await DoBookAsync(
|
|
||||||
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
|
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
|
||||||
requestBuilder.DoBook(bikeId, guid, batteryPercentage),
|
requestBuilder.DoBook(bikeId, guid, batteryPercentage),
|
||||||
UserAgent);
|
UserAgent);
|
||||||
}
|
|
||||||
|
/// <summary> Books a bike and starts opening bike. </summary>
|
||||||
|
/// <param name="bikeId">Id of the bike to book.</param>
|
||||||
|
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||||
|
/// <returns>Response on booking request.</returns>
|
||||||
|
public async Task<ReservationBookingResponse> BookAndStartOpeningAsync(
|
||||||
|
string bikeId,
|
||||||
|
Uri operatorUri)
|
||||||
|
=> await DoBookAsync(
|
||||||
|
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
|
||||||
|
requestBuilder.BookAndStartOpening(bikeId),
|
||||||
|
UserAgent);
|
||||||
|
|
||||||
/// <summary> Returns a bike. </summary>
|
/// <summary> Returns a bike. </summary>
|
||||||
/// <param name="bikeId">Id of the bike to return.</param>
|
/// <param name="bikeId">Id of the bike to return.</param>
|
||||||
|
@ -218,12 +228,24 @@ namespace TINK.Repository
|
||||||
LocationDto location,
|
LocationDto location,
|
||||||
ISmartDevice smartDevice,
|
ISmartDevice smartDevice,
|
||||||
Uri operatorUri)
|
Uri operatorUri)
|
||||||
{
|
=> await DoReturn(
|
||||||
return await DoReturn(
|
|
||||||
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
|
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
|
||||||
requestBuilder.DoReturn(bikeId, location, smartDevice),
|
requestBuilder.DoReturn(bikeId, location, smartDevice),
|
||||||
UserAgent);
|
UserAgent);
|
||||||
}
|
|
||||||
|
/// <summary> Returns a bike and starts closing. </summary>
|
||||||
|
/// <param name="bikeId">Id of the bike to return.</param>
|
||||||
|
/// <param name="smartDevice">Provides info about hard and software.</param>
|
||||||
|
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||||
|
/// <returns>Response on returning request.</returns>
|
||||||
|
public async Task<DoReturnResponse> ReturnAndStartClosingAsync(
|
||||||
|
string bikeId,
|
||||||
|
ISmartDevice smartDevice,
|
||||||
|
Uri operatorUri)
|
||||||
|
=> await DoReturn(
|
||||||
|
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
|
||||||
|
requestBuilder.ReturnAndStartClosing(bikeId, smartDevice),
|
||||||
|
UserAgent);
|
||||||
|
|
||||||
/// <summary> Submits feedback to copri server. </summary>
|
/// <summary> Submits feedback to copri server. </summary>
|
||||||
/// <param name="bikeId">Id of the bike to which the feedback is related to.</param>
|
/// <param name="bikeId">Id of the bike to which the feedback is related to.</param>
|
||||||
|
@ -630,10 +652,10 @@ namespace TINK.Repository
|
||||||
string agent = null)
|
string agent = null)
|
||||||
{
|
{
|
||||||
#if !WINDOWS_UWP
|
#if !WINDOWS_UWP
|
||||||
string l_oBikesAvaialbeResponse;
|
string bikesAvaialbeResponse;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
l_oBikesAvaialbeResponse = await PostAsync(copriHost, command, agent);
|
bikesAvaialbeResponse = await PostAsync(copriHost, command, agent);
|
||||||
}
|
}
|
||||||
catch (System.Exception exception)
|
catch (System.Exception exception)
|
||||||
{
|
{
|
||||||
|
@ -651,7 +673,7 @@ namespace TINK.Repository
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract bikes from response.
|
// Extract bikes from response.
|
||||||
return JsonConvertRethrow.DeserializeObject<ResponseContainer<ReservationBookingResponse>>(l_oBikesAvaialbeResponse)?.shareejson;
|
return JsonConvertRethrow.DeserializeObject<ResponseContainer<ReservationBookingResponse>>(bikesAvaialbeResponse)?.shareejson;
|
||||||
#else
|
#else
|
||||||
return null;
|
return null;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1380,7 +1380,7 @@ namespace TINK.Repository
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var l_iCount = 1;
|
var l_iCount = 1;
|
||||||
while (GetBikesAvailable(CopriDevelHostUri, MerchantId, p_eSampleSet: ActiveSampleSet, p_lStageIndex: l_iCount) != null)
|
while (GetBikesAvailable(CopriDevelHostUri, MerchantId, sampleSet: ActiveSampleSet, stageIndex: l_iCount) != null)
|
||||||
{
|
{
|
||||||
l_iCount++;
|
l_iCount++;
|
||||||
}
|
}
|
||||||
|
@ -1474,21 +1474,21 @@ namespace TINK.Repository
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets list of bikes from memory.
|
/// Gets list of bikes from memory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="p_strMerchantId">Id of the merchant.</param>
|
/// <param name="merchantId">Id of the merchant.</param>
|
||||||
/// <param name="p_strSessionCookie">Auto cookie of user if user is logged in.</param>
|
/// <param name="sessionCookie">Auto cookie of user if user is logged in.</param>
|
||||||
/// <param name="p_eSampleSet">Set of samples.</param>
|
/// <param name="sampleSet">Set of samples.</param>
|
||||||
/// <param name="p_lStageIndex">Index of the stage.</param>
|
/// <param name="stageIndex">Index of the stage.</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static BikesAvailableResponse GetBikesAvailable(
|
public static BikesAvailableResponse GetBikesAvailable(
|
||||||
string p_strMerchantId,
|
string merchantId,
|
||||||
string p_strSessionCookie = null,
|
string sessionCookie = null,
|
||||||
SampleSets p_eSampleSet = DEFAULT_SAMPLE_SET,
|
SampleSets sampleSet = DEFAULT_SAMPLE_SET,
|
||||||
long p_lStageIndex = DEFAULT_STAGE_INDEX)
|
long stageIndex = DEFAULT_STAGE_INDEX)
|
||||||
{
|
{
|
||||||
switch (p_eSampleSet)
|
switch (sampleSet)
|
||||||
{
|
{
|
||||||
case SampleSets.Set1:
|
case SampleSets.Set1:
|
||||||
switch (p_lStageIndex)
|
switch (stageIndex)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
return CopriCallsStatic.DeserializeResponse<BikesAvailableResponse>(BIKES_AVAILABLE_SET01_001_FILE);
|
return CopriCallsStatic.DeserializeResponse<BikesAvailableResponse>(BIKES_AVAILABLE_SET01_001_FILE);
|
||||||
|
@ -1497,7 +1497,7 @@ namespace TINK.Repository
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
case SampleSets.Set2:
|
case SampleSets.Set2:
|
||||||
switch (p_lStageIndex)
|
switch (stageIndex)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
return CopriCallsStatic.DeserializeResponse<BikesAvailableResponse>(BIKES_AVAILABLE_SET02_001_FILE);
|
return CopriCallsStatic.DeserializeResponse<BikesAvailableResponse>(BIKES_AVAILABLE_SET02_001_FILE);
|
||||||
|
@ -1513,7 +1513,7 @@ namespace TINK.Repository
|
||||||
}
|
}
|
||||||
|
|
||||||
case SampleSets.ShareeFr01_Set1:
|
case SampleSets.ShareeFr01_Set1:
|
||||||
switch (p_lStageIndex)
|
switch (stageIndex)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
return CopriCallsStatic.DeserializeResponse<BikesAvailableResponse>(BIKES_AVAILABLE_REQUEST_SHAREEFR01_SET1_FILE);
|
return CopriCallsStatic.DeserializeResponse<BikesAvailableResponse>(BIKES_AVAILABLE_REQUEST_SHAREEFR01_SET1_FILE);
|
||||||
|
@ -1619,15 +1619,18 @@ namespace TINK.Repository
|
||||||
|
|
||||||
public Task<ReservationBookingResponse> UpdateLockingStateAsync(
|
public Task<ReservationBookingResponse> UpdateLockingStateAsync(
|
||||||
string bikeId,
|
string bikeId,
|
||||||
LocationDto geolocation,
|
|
||||||
lock_state state,
|
lock_state state,
|
||||||
double batteryLevel,
|
Uri operatorUri,
|
||||||
Uri operatorUri) => null;
|
LocationDto geolocation,
|
||||||
|
double batteryLevel) => null;
|
||||||
|
|
||||||
public Task<ReservationBookingResponse> DoBookAsync(string bikeId, Guid guid, double batteryPercentage, Uri operatorUri)
|
public Task<ReservationBookingResponse> DoBookAsync(string bikeId, Guid guid, double batteryPercentage, Uri operatorUri)
|
||||||
{
|
=> null;
|
||||||
return null;
|
|
||||||
}
|
public Task<ReservationBookingResponse> BookAndStartOpeningAsync(
|
||||||
|
string bikeId,
|
||||||
|
Uri operatorUri)
|
||||||
|
=> null;
|
||||||
|
|
||||||
public Task<DoReturnResponse> DoReturn(
|
public Task<DoReturnResponse> DoReturn(
|
||||||
string bikeId,
|
string bikeId,
|
||||||
|
@ -1636,6 +1639,12 @@ namespace TINK.Repository
|
||||||
Uri operatorUri)
|
Uri operatorUri)
|
||||||
=> null;
|
=> null;
|
||||||
|
|
||||||
|
public Task<DoReturnResponse> ReturnAndStartClosingAsync(
|
||||||
|
string bikeId,
|
||||||
|
ISmartDevice smartDevice,
|
||||||
|
Uri operatorUri)
|
||||||
|
=> throw new NotImplementedException();
|
||||||
|
|
||||||
public Task<SubmitFeedbackResponse> DoSubmitFeedback(string bikeId, string message, bool isBikeBroken, Uri operatorUri)
|
public Task<SubmitFeedbackResponse> DoSubmitFeedback(string bikeId, string message, bool isBikeBroken, Uri operatorUri)
|
||||||
=> null;
|
=> null;
|
||||||
|
|
||||||
|
|
|
@ -166,16 +166,23 @@ namespace TINK.Repository
|
||||||
|
|
||||||
public Task<ReservationBookingResponse> UpdateLockingStateAsync(
|
public Task<ReservationBookingResponse> UpdateLockingStateAsync(
|
||||||
string bikeId,
|
string bikeId,
|
||||||
LocationDto geolocation,
|
|
||||||
lock_state state,
|
lock_state state,
|
||||||
double batteryLevel,
|
Uri operatorUri,
|
||||||
Uri operatorUri)
|
LocationDto geolocation,
|
||||||
|
double batteryLevel)
|
||||||
=> throw new System.Exception("Aktualisierung des Schlossstatuses im Offlinemodus nicht möglich!");
|
=> throw new System.Exception("Aktualisierung des Schlossstatuses im Offlinemodus nicht möglich!");
|
||||||
|
|
||||||
public Task<ReservationBookingResponse> DoBookAsync(string bikeId, Guid guid, double batteryPercentage, Uri operatorUri)
|
public Task<ReservationBookingResponse> DoBookAsync(string bikeId, Guid guid, double batteryPercentage, Uri operatorUri)
|
||||||
{
|
=> throw new System.Exception("Buchung im Offlinemodus nicht möglich!");
|
||||||
throw new System.Exception("Buchung im Offlinemodus nicht möglich!");
|
|
||||||
}
|
/// <summary> Books a bike and starts opening bike. </summary>
|
||||||
|
/// <param name="bikeId">Id of the bike to book.</param>
|
||||||
|
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||||
|
/// <returns>Response on booking request.</returns>
|
||||||
|
public Task<ReservationBookingResponse> BookAndStartOpeningAsync(
|
||||||
|
string bikeId,
|
||||||
|
Uri operatorUri)
|
||||||
|
=> throw new System.Exception("Buchung mit Start von Schlossöffnen ist im Offlinemodus nicht möglich!");
|
||||||
|
|
||||||
public Task<DoReturnResponse> DoReturn(
|
public Task<DoReturnResponse> DoReturn(
|
||||||
string bikeId,
|
string bikeId,
|
||||||
|
@ -184,6 +191,17 @@ namespace TINK.Repository
|
||||||
Uri operatorUri)
|
Uri operatorUri)
|
||||||
=> throw new System.Exception("Rückgabe im Offlinemodus nicht möglich!");
|
=> throw new System.Exception("Rückgabe im Offlinemodus nicht möglich!");
|
||||||
|
|
||||||
|
/// <summary> Returns a bike and starts closing. </summary>
|
||||||
|
/// <param name="bikeId">Id of the bike to return.</param>
|
||||||
|
/// <param name="smartDevice">Provides info about hard and software.</param>
|
||||||
|
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||||
|
/// <returns>Response on returning request.</returns>
|
||||||
|
public Task<DoReturnResponse> ReturnAndStartClosingAsync(
|
||||||
|
string bikeId,
|
||||||
|
ISmartDevice smartDevice,
|
||||||
|
Uri operatorUri)
|
||||||
|
=> throw new System.Exception("Rückgabe mit Schloss schließen Befehl im Offlinemodus nicht möglich!");
|
||||||
|
|
||||||
public Task<SubmitFeedbackResponse> DoSubmitFeedback(string bikeId, string message, bool isBikeBroken, Uri operatorUri) =>
|
public Task<SubmitFeedbackResponse> DoSubmitFeedback(string bikeId, string message, bool isBikeBroken, Uri operatorUri) =>
|
||||||
throw new System.Exception("Übermittlung von Feedback im Offlinemodus nicht möglich!");
|
throw new System.Exception("Übermittlung von Feedback im Offlinemodus nicht möglich!");
|
||||||
|
|
||||||
|
|
|
@ -66,12 +66,12 @@ namespace TINK.Repository
|
||||||
/// <returns>Response on updating locking state.</returns>
|
/// <returns>Response on updating locking state.</returns>
|
||||||
Task<ReservationBookingResponse> UpdateLockingStateAsync(
|
Task<ReservationBookingResponse> UpdateLockingStateAsync(
|
||||||
string bikeId,
|
string bikeId,
|
||||||
LocationDto location,
|
|
||||||
lock_state state,
|
lock_state state,
|
||||||
double batteryPercentage,
|
Uri operatorUri,
|
||||||
Uri operatorUri);
|
LocationDto location = null,
|
||||||
|
double batteryPercentage = double.NaN);
|
||||||
|
|
||||||
/// <summary> Books a bike. </summary>
|
/// <summary> Books a bluetooth bike. </summary>
|
||||||
/// <param name="bikeId">Id of the bike to book.</param>
|
/// <param name="bikeId">Id of the bike to book.</param>
|
||||||
/// <param name="guid">Used to publish GUID from app to copri. Used for initial setup of bike in copri.</param>
|
/// <param name="guid">Used to publish GUID from app to copri. Used for initial setup of bike in copri.</param>
|
||||||
/// <param name="batteryPercentage">Holds the filling level percentage of the battery.</param>
|
/// <param name="batteryPercentage">Holds the filling level percentage of the battery.</param>
|
||||||
|
@ -83,6 +83,14 @@ namespace TINK.Repository
|
||||||
double batteryPercentage,
|
double batteryPercentage,
|
||||||
Uri operatorUri);
|
Uri operatorUri);
|
||||||
|
|
||||||
|
/// <summary> Books a bike and starts opening bike. </summary>
|
||||||
|
/// <param name="bikeId">Id of the bike to book.</param>
|
||||||
|
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||||
|
/// <returns>Response on booking request.</returns>
|
||||||
|
Task<ReservationBookingResponse> BookAndStartOpeningAsync(
|
||||||
|
string bikeId,
|
||||||
|
Uri operatorUri);
|
||||||
|
|
||||||
/// <summary> Returns a bike. </summary>
|
/// <summary> Returns a bike. </summary>
|
||||||
/// <param name="bikeId">Id of the bike to return.</param>
|
/// <param name="bikeId">Id of the bike to return.</param>
|
||||||
/// <param name="location">Geolocation of lock.</param>
|
/// <param name="location">Geolocation of lock.</param>
|
||||||
|
@ -95,6 +103,16 @@ namespace TINK.Repository
|
||||||
ISmartDevice smartDevice,
|
ISmartDevice smartDevice,
|
||||||
Uri operatorUri);
|
Uri operatorUri);
|
||||||
|
|
||||||
|
/// <summary> Returns a bike and starts closing. </summary>
|
||||||
|
/// <param name="bikeId">Id of the bike to return.</param>
|
||||||
|
/// <param name="smartDevice">Provides info about hard and software.</param>
|
||||||
|
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||||
|
/// <returns>Response on returning request.</returns>
|
||||||
|
Task<DoReturnResponse> ReturnAndStartClosingAsync(
|
||||||
|
string bikeId,
|
||||||
|
ISmartDevice smartDevice,
|
||||||
|
Uri operatorUri);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Submits feedback to copri server.
|
/// Submits feedback to copri server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -68,23 +68,34 @@ namespace TINK.Repository.Request
|
||||||
/// <returns>Request to update locking state.</returns>
|
/// <returns>Request to update locking state.</returns>
|
||||||
string UpateLockingState(
|
string UpateLockingState(
|
||||||
string bikeId,
|
string bikeId,
|
||||||
LocationDto location,
|
|
||||||
lock_state state,
|
lock_state state,
|
||||||
double batteryPercentage);
|
LocationDto location = null,
|
||||||
|
double batteryPercentage = double.NaN);
|
||||||
|
|
||||||
/// <summary> Gets booking request request (synonym: booking == renting == mieten). </summary>
|
/// <summary> Gets the booking request (synonym: booking == renting == mieten). </summary>
|
||||||
/// <param name="bikeId">Id of the bike to book.</param>
|
/// <param name="bikeId">Id of the bike to book.</param>
|
||||||
/// <param name="guid">Used to publish GUID from app to copri. Used for initial setup of bike in copri.</param>
|
/// <param name="guid">Used to publish GUID from app to copri. Used for initial setup of bike in copri.</param>
|
||||||
/// <param name="batteryPercentage">Holds the filling level percentage of the battery.</param>
|
/// <param name="batteryPercentage">Holds the filling level percentage of the battery.</param>
|
||||||
/// <returns>Request to booking bike.</returns>
|
/// <returns>Request to booking bike.</returns>
|
||||||
string DoBook(string bikeId, Guid guid, double batteryPercentage);
|
string DoBook(string bikeId, Guid guid, double batteryPercentage);
|
||||||
|
|
||||||
|
/// <summary> Gets the request to book and start opening the bike (synonym: booking == renting == mieten). </summary>
|
||||||
|
/// <param name="bikeId">Id of the bike to book.</param>
|
||||||
|
/// <returns>Request to booking bike.</returns>
|
||||||
|
string BookAndStartOpening(string bikeId);
|
||||||
|
|
||||||
/// <summary> Gets request for returning the bike. </summary>
|
/// <summary> Gets request for returning the bike. </summary>
|
||||||
/// <param name="bikeId">Id of the bike to return.</param>
|
/// <param name="bikeId">Id of the bike to return.</param>
|
||||||
/// <param name="location">Geolocation of lock when returning bike.</param>
|
/// <param name="location">Geolocation of lock when returning bike.</param>
|
||||||
/// <returns>Requst on returning request.</returns>
|
/// <returns>Requst on returning request.</returns>
|
||||||
string DoReturn(string bikeId, LocationDto location, ISmartDevice smartDevice);
|
string DoReturn(string bikeId, LocationDto location, ISmartDevice smartDevice);
|
||||||
|
|
||||||
|
/// <summary> Returns a bike and starts closing. </summary>
|
||||||
|
/// <param name="bikeId">Id of the bike to return.</param>
|
||||||
|
/// <param name="smartDevice">Provides info about hard and software.</param>
|
||||||
|
/// <returns>Response to send to corpi.</returns>
|
||||||
|
string ReturnAndStartClosing(string bikeId, ISmartDevice smartDevice);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets request for submiting feedback to copri server.
|
/// Gets request for submiting feedback to copri server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -103,8 +114,10 @@ namespace TINK.Repository.Request
|
||||||
/// <summary> Copri locking states</summary>
|
/// <summary> Copri locking states</summary>
|
||||||
public enum lock_state
|
public enum lock_state
|
||||||
{
|
{
|
||||||
|
locking,
|
||||||
locked,
|
locked,
|
||||||
unlocked
|
unlocking,
|
||||||
|
unlocked,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Holds lockation info.</summary>
|
/// <summary> Holds lockation info.</summary>
|
||||||
|
|
|
@ -103,13 +103,24 @@ namespace TINK.Repository.Request
|
||||||
public string StartReturningBike(string bikeId)
|
public string StartReturningBike(string bikeId)
|
||||||
=> throw new NotSupportedException();
|
=> throw new NotSupportedException();
|
||||||
|
|
||||||
public string UpateLockingState(string bikeId, LocationDto geolocation, lock_state state, double batteryPercentage)
|
public string UpateLockingState(string bikeId, lock_state state, LocationDto geolocation, double batteryPercentage)
|
||||||
=> throw new NotSupportedException();
|
=> throw new NotSupportedException();
|
||||||
|
|
||||||
public string DoBook(string bikeId, Guid guid, double batteryPercentage) => throw new NotSupportedException();
|
public string DoBook(string bikeId, Guid guid, double batteryPercentage) => throw new NotSupportedException();
|
||||||
|
|
||||||
|
/// <summary> Gets the request to book and start opening the bike (synonym: booking == renting == mieten). </summary>
|
||||||
|
/// <param name="bikeId">Id of the bike to book.</param>
|
||||||
|
/// <returns>Request to booking bike.</returns>
|
||||||
|
public string BookAndStartOpening(string bikeId) => throw new NotSupportedException();
|
||||||
|
|
||||||
public string DoReturn(string bikeId, LocationDto geolocation, ISmartDevice smartDevice) => throw new NotSupportedException();
|
public string DoReturn(string bikeId, LocationDto geolocation, ISmartDevice smartDevice) => throw new NotSupportedException();
|
||||||
|
|
||||||
|
/// <summary> Returns a bike and starts closing. </summary>
|
||||||
|
/// <param name="bikeId">Id of the bike to return.</param>
|
||||||
|
/// <param name="smartDevice">Provides info about hard and software.</param>
|
||||||
|
/// <returns>Response to send to corpi.</returns>
|
||||||
|
public string ReturnAndStartClosing(string bikeId, ISmartDevice smartDevice) => throw new NotSupportedException();
|
||||||
|
|
||||||
/// <summary> Gets submit feedback request. </summary>
|
/// <summary> Gets submit feedback request. </summary>
|
||||||
/// <param name="bikeId">Id of the bike to which the feedback is related to.</param>
|
/// <param name="bikeId">Id of the bike to which the feedback is related to.</param>
|
||||||
/// <param name="message">General purpose message or error description.</param>
|
/// <param name="message">General purpose message or error description.</param>
|
||||||
|
|
|
@ -107,7 +107,11 @@ namespace TINK.Repository.Request
|
||||||
/// <param name="bikeId">Id of the bike to update locking state for.</param>
|
/// <param name="bikeId">Id of the bike to update locking state for.</param>
|
||||||
/// <param name="state">New locking state.</param>
|
/// <param name="state">New locking state.</param>
|
||||||
/// <returns>Request to update locking state.</returns>
|
/// <returns>Request to update locking state.</returns>
|
||||||
public string UpateLockingState(string bikeId, LocationDto geolocation, lock_state state, double batteryPercentage)
|
public string UpateLockingState(
|
||||||
|
string bikeId,
|
||||||
|
lock_state state,
|
||||||
|
LocationDto geolocation,
|
||||||
|
double batteryPercentage)
|
||||||
=> $"request=booking_update&bike={bikeId}{GetLocationParameters(geolocation)}&lock_state={state}{GetBatteryPercentageParameters(batteryPercentage)}&authcookie={SessionCookie}{MerchantId}";
|
=> $"request=booking_update&bike={bikeId}{GetLocationParameters(geolocation)}&lock_state={state}{GetBatteryPercentageParameters(batteryPercentage)}&authcookie={SessionCookie}{MerchantId}";
|
||||||
|
|
||||||
/// <summary> Gets booking request request (synonym: booking == renting == mieten). </summary>
|
/// <summary> Gets booking request request (synonym: booking == renting == mieten). </summary>
|
||||||
|
@ -119,21 +123,37 @@ namespace TINK.Repository.Request
|
||||||
public string DoBook(string bikeId, Guid guid, double batteryPercentage)
|
public string DoBook(string bikeId, Guid guid, double batteryPercentage)
|
||||||
=> $"request=booking_update&bike={bikeId}&authcookie={SessionCookie}{MerchantId}&Ilockit_GUID={guid}&state=occupied&lock_state=unlocked{GetBatteryPercentageParameters(batteryPercentage)}";
|
=> $"request=booking_update&bike={bikeId}&authcookie={SessionCookie}{MerchantId}&Ilockit_GUID={guid}&state=occupied&lock_state=unlocked{GetBatteryPercentageParameters(batteryPercentage)}";
|
||||||
|
|
||||||
|
/// <summary> Gets the request to book and start opening the bike (synonym: booking == renting == mieten). </summary>
|
||||||
|
/// <param name="bikeId">Id of the bike to book.</param>
|
||||||
|
/// <returns>Request to booking bike.</returns>
|
||||||
|
public string BookAndStartOpening(string bikeId)
|
||||||
|
=> $"request=booking_request&bike={bikeId}&authcookie={SessionCookie}{MerchantId}&state=occupied&lock_state={lock_state.unlocking}";
|
||||||
|
|
||||||
/// <summary> Gets request for returning the bike. </summary>
|
/// <summary> Gets request for returning the bike. </summary>
|
||||||
/// <remarks> Operator specific call.</remarks>
|
/// <remarks> Operator specific call.</remarks>
|
||||||
/// <param name="bikeId">Id of bike to return.</param>
|
/// <param name="bikeId">Id of bike to return.</param>
|
||||||
/// <param name="geolocation">Geolocation of lock when returning bike.</param>
|
/// <param name="geolocation">Geolocation of lock when returning bike.</param>
|
||||||
/// <returns>Requst on returning request.</returns>
|
/// <returns>Requst on returning request.</returns>
|
||||||
public string DoReturn(string bikeId, LocationDto geolocation, ISmartDevice smartDevice)
|
public string DoReturn(string bikeId, LocationDto geolocation, ISmartDevice smartDevice)
|
||||||
{
|
=> $"request=booking_update" +
|
||||||
return $"request=booking_update" +
|
|
||||||
$"&bike={bikeId}" +
|
$"&bike={bikeId}" +
|
||||||
$"&authcookie={SessionCookie}{MerchantId}" +
|
$"&authcookie={SessionCookie}{MerchantId}" +
|
||||||
$"&state=available" +
|
$"&state=available" +
|
||||||
$"{GetLocationParameters(geolocation)}" +
|
$"{GetLocationParameters(geolocation)}" +
|
||||||
$"&lock_state=locked" +
|
$"&lock_state=locked" +
|
||||||
$"{GetSmartDeviceParameters(smartDevice)}";
|
$"{GetSmartDeviceParameters(smartDevice)}";
|
||||||
}
|
|
||||||
|
/// <summary> Returns a bike and starts closing. </summary>
|
||||||
|
/// <param name="bikeId">Id of the bike to return.</param>
|
||||||
|
/// <param name="smartDevice">Provides info about hard and software.</param>
|
||||||
|
/// <returns>Response to send to corpi.</returns>
|
||||||
|
public string ReturnAndStartClosing(string bikeId, ISmartDevice smartDevice)
|
||||||
|
=> $"request=booking_update" +
|
||||||
|
$"&bike={bikeId}" +
|
||||||
|
$"&authcookie={SessionCookie}{MerchantId}" +
|
||||||
|
$"&state=available" +
|
||||||
|
$"&lock_state={lock_state.locking}" +
|
||||||
|
$"{GetSmartDeviceParameters(smartDevice)}";
|
||||||
|
|
||||||
/// <summary> Gets submit feedback request. </summary>
|
/// <summary> Gets submit feedback request. </summary>
|
||||||
/// <param name="bikeId">Id of the bike to return.</param>
|
/// <param name="bikeId">Id of the bike to return.</param>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
namespace TINK.Repository.Response
|
namespace TINK.Repository.Response
|
||||||
{
|
{
|
||||||
|
@ -50,8 +50,9 @@ namespace TINK.Repository.Response
|
||||||
/// <table>
|
/// <table>
|
||||||
/// <tr><th>Value </th><th>Type of bike </th><th>Member to extract info.</th></tr>
|
/// <tr><th>Value </th><th>Type of bike </th><th>Member to extract info.</th></tr>
|
||||||
/// <tr><td>LOCK </td><td>Bike with manual lock. </td><td>TextToTypeHelper.GetIsNonBikeComputerBike</td></tr>
|
/// <tr><td>LOCK </td><td>Bike with manual lock. </td><td>TextToTypeHelper.GetIsNonBikeComputerBike</td></tr>
|
||||||
/// <tr><td> </td><td>Bike with a bord computer. </td><td></td></tr>
|
/// <tr><td>BC </td><td>Bike with a bord computer. </td><td></td></tr>
|
||||||
/// <tr><td>? </td><td>Bike with a bluetooth lock.</td><td></td></tr>
|
/// <tr><td>Ilockit </td><td>Bike with a bluetooth lock.</td><td></td></tr>
|
||||||
|
/// <tr><td>sigo </td><td>Sigo bike.</td><td></td></tr>
|
||||||
/// </table>
|
/// </table>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[DataMember]
|
[DataMember]
|
||||||
|
@ -66,6 +67,10 @@ namespace TINK.Repository.Response
|
||||||
[DataMember]
|
[DataMember]
|
||||||
public string bike_charge { get; private set; }
|
public string bike_charge { get; private set; }
|
||||||
|
|
||||||
|
/// <summary> Locking state of the bike. </summary>
|
||||||
|
[DataMember]
|
||||||
|
public string lock_state { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Textual description of response.
|
/// Textual description of response.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -234,11 +234,16 @@ namespace TINK.Model.Services.CopriApi
|
||||||
|
|
||||||
public async Task<ReservationBookingResponse> UpdateLockingStateAsync(
|
public async Task<ReservationBookingResponse> UpdateLockingStateAsync(
|
||||||
string bikeId,
|
string bikeId,
|
||||||
LocationDto location,
|
|
||||||
lock_state state,
|
lock_state state,
|
||||||
double batteryLevel,
|
Uri operatorUri,
|
||||||
Uri operatorUri)
|
LocationDto location,
|
||||||
=> await HttpsServer.UpdateLockingStateAsync(bikeId, location, state, batteryLevel, operatorUri);
|
double batteryLevel)
|
||||||
|
=> await HttpsServer.UpdateLockingStateAsync(
|
||||||
|
bikeId,
|
||||||
|
state,
|
||||||
|
operatorUri,
|
||||||
|
location,
|
||||||
|
batteryLevel);
|
||||||
|
|
||||||
/// <summary> Books a bike. </summary>
|
/// <summary> Books a bike. </summary>
|
||||||
/// <param name="bikeId">Id of the bike to book.</param>
|
/// <param name="bikeId">Id of the bike to book.</param>
|
||||||
|
@ -246,9 +251,17 @@ namespace TINK.Model.Services.CopriApi
|
||||||
/// <param name="batteryPercentage">Holds the filling level percentage of the battery.</param>
|
/// <param name="batteryPercentage">Holds the filling level percentage of the battery.</param>
|
||||||
/// <returns>Response on booking request.</returns>
|
/// <returns>Response on booking request.</returns>
|
||||||
public async Task<ReservationBookingResponse> DoBookAsync(string bikeId, Guid guid, double batteryPercentage, Uri operatorUri)
|
public async Task<ReservationBookingResponse> DoBookAsync(string bikeId, Guid guid, double batteryPercentage, Uri operatorUri)
|
||||||
{
|
=> await HttpsServer.DoBookAsync(bikeId, guid, batteryPercentage, operatorUri);
|
||||||
return await HttpsServer.DoBookAsync(bikeId, guid, batteryPercentage, operatorUri);
|
|
||||||
}
|
/// <summary> Books a bike and starts opening bike. </summary>
|
||||||
|
/// <param name="bikeId">Id of the bike to book.</param>
|
||||||
|
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||||
|
/// <returns>Response on booking request.</returns>
|
||||||
|
public async Task<ReservationBookingResponse> BookAndStartOpeningAsync(
|
||||||
|
string bikeId,
|
||||||
|
Uri operatorUri)
|
||||||
|
=> await HttpsServer.BookAndStartOpeningAsync(bikeId, operatorUri);
|
||||||
|
|
||||||
|
|
||||||
public async Task<DoReturnResponse> DoReturn(
|
public async Task<DoReturnResponse> DoReturn(
|
||||||
string bikeId,
|
string bikeId,
|
||||||
|
@ -257,6 +270,17 @@ namespace TINK.Model.Services.CopriApi
|
||||||
Uri operatorUri)
|
Uri operatorUri)
|
||||||
=> await HttpsServer.DoReturn(bikeId, location, smartDevice, operatorUri);
|
=> await HttpsServer.DoReturn(bikeId, location, smartDevice, operatorUri);
|
||||||
|
|
||||||
|
/// <summary> Returns a bike and starts closing. </summary>
|
||||||
|
/// <param name="bikeId">Id of the bike to return.</param>
|
||||||
|
/// <param name="smartDevice">Provides info about hard and software.</param>
|
||||||
|
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
|
||||||
|
/// <returns>Response on returning request.</returns>
|
||||||
|
public async Task<DoReturnResponse> ReturnAndStartClosingAsync(
|
||||||
|
string bikeId,
|
||||||
|
ISmartDevice smartDevice,
|
||||||
|
Uri operatorUri)
|
||||||
|
=> await HttpsServer.ReturnAndStartClosingAsync(bikeId, smartDevice, operatorUri);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Submits feedback to copri server.
|
/// Submits feedback to copri server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -48,17 +48,27 @@ namespace TINK.Model.Services.CopriApi
|
||||||
|
|
||||||
public async Task<ReservationBookingResponse> UpdateLockingStateAsync(
|
public async Task<ReservationBookingResponse> UpdateLockingStateAsync(
|
||||||
string bikeId,
|
string bikeId,
|
||||||
LocationDto geolocation,
|
|
||||||
lock_state state,
|
lock_state state,
|
||||||
double batteryLevel,
|
Uri operatorUri,
|
||||||
Uri operatorUri)
|
LocationDto geolocation,
|
||||||
=> await monkeyStore.UpdateLockingStateAsync(bikeId, geolocation, state, batteryLevel, operatorUri);
|
double batteryLevel)
|
||||||
|
=> await monkeyStore.UpdateLockingStateAsync(
|
||||||
|
bikeId,
|
||||||
|
state,
|
||||||
|
operatorUri,
|
||||||
|
geolocation,
|
||||||
|
batteryLevel);
|
||||||
|
|
||||||
public async Task<ReservationBookingResponse> DoBookAsync(string bikeId, Guid guid, double batteryPercentage, Uri operatorUri)
|
public async Task<ReservationBookingResponse> DoBookAsync(string bikeId, Guid guid, double batteryPercentage, Uri operatorUri)
|
||||||
{
|
{
|
||||||
return await monkeyStore.DoBookAsync(bikeId, guid, batteryPercentage, operatorUri);
|
return await monkeyStore.DoBookAsync(bikeId, guid, batteryPercentage, operatorUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ReservationBookingResponse> BookAndStartOpeningAsync(
|
||||||
|
string bikeId,
|
||||||
|
Uri operatorUri)
|
||||||
|
=> await monkeyStore.BookAndStartOpeningAsync(bikeId, operatorUri);
|
||||||
|
|
||||||
public async Task<DoReturnResponse> DoReturn(
|
public async Task<DoReturnResponse> DoReturn(
|
||||||
string bikeId,
|
string bikeId,
|
||||||
LocationDto geolocation,
|
LocationDto geolocation,
|
||||||
|
@ -66,6 +76,12 @@ namespace TINK.Model.Services.CopriApi
|
||||||
Uri operatorUri)
|
Uri operatorUri)
|
||||||
=> await monkeyStore.DoReturn(bikeId, geolocation, smartDevice, operatorUri);
|
=> await monkeyStore.DoReturn(bikeId, geolocation, smartDevice, operatorUri);
|
||||||
|
|
||||||
|
public async Task<DoReturnResponse> ReturnAndStartClosingAsync(
|
||||||
|
string bikeId,
|
||||||
|
ISmartDevice smartDevice,
|
||||||
|
Uri operatorUri)
|
||||||
|
=> await monkeyStore.ReturnAndStartClosingAsync(bikeId, smartDevice, operatorUri);
|
||||||
|
|
||||||
public Task<SubmitFeedbackResponse> DoSubmitFeedback(string bikeId, string messge, bool bIsBikeBroke, Uri operatorUri)
|
public Task<SubmitFeedbackResponse> DoSubmitFeedback(string bikeId, string messge, bool bIsBikeBroke, Uri operatorUri)
|
||||||
=> throw new NotImplementedException();
|
=> throw new NotImplementedException();
|
||||||
|
|
||||||
|
|
209
TINKLib/Services/CopriApi/Polling.cs
Normal file
209
TINKLib/Services/CopriApi/Polling.cs
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
using Serilog;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using TINK.Model;
|
||||||
|
using TINK.Model.Bikes.Bike.CopriLock;
|
||||||
|
using TINK.Model.Connector;
|
||||||
|
using TINK.Model.Device;
|
||||||
|
using TINK.Model.Services.CopriApi;
|
||||||
|
using TINK.Repository;
|
||||||
|
using TINK.Repository.Response;
|
||||||
|
|
||||||
|
namespace TINK.Services.CopriApi
|
||||||
|
{
|
||||||
|
public static class Polling
|
||||||
|
{
|
||||||
|
/// <summary> Timeout for open/ close operations.</summary>
|
||||||
|
private const int OPEN_CLOSE_TIMEOUT_MS = 50000;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a bike and closes the lock.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="corpiServer"> Instance to communicate with backend.</param>
|
||||||
|
/// <param name="bike">Bike to open.</param>
|
||||||
|
public static async Task OpenAync(
|
||||||
|
this ICopriServerBase corpiServer,
|
||||||
|
IBikeInfoMutable bike)
|
||||||
|
{
|
||||||
|
if (!(corpiServer is ICachedCopriServer cachedServer))
|
||||||
|
throw new ArgumentNullException(nameof(corpiServer));
|
||||||
|
|
||||||
|
// Send command to close lock
|
||||||
|
await corpiServer.UpdateLockingStateAsync(
|
||||||
|
bike.Id,
|
||||||
|
Repository.Request.lock_state.unlocking,
|
||||||
|
bike.OperatorUri);
|
||||||
|
|
||||||
|
var lockingState = await cachedServer.GetLockStateAsync(bike.Id);
|
||||||
|
|
||||||
|
var watch = new Stopwatch();
|
||||||
|
watch.Start();
|
||||||
|
|
||||||
|
while (lockingState != LockingState.Open
|
||||||
|
&& lockingState != LockingState.UnknownDisconnected
|
||||||
|
&& watch.Elapsed < TimeSpan.FromMilliseconds(OPEN_CLOSE_TIMEOUT_MS))
|
||||||
|
{
|
||||||
|
// Delay a litte to reduce load on backend.
|
||||||
|
await Task.Delay(3000);
|
||||||
|
|
||||||
|
lockingState = await cachedServer.GetLockStateAsync(bike.Id);
|
||||||
|
Log.Information($"Current lock state is {lockingState}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update locking state.
|
||||||
|
bike.LockInfo.State = lockingState;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Books a bike and opens the lock.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="corpiServer"> Instance to communicate with backend.</param>
|
||||||
|
/// <param name="bike">Bike to book and open.</param>
|
||||||
|
/// <param name="mailAddress">Mail address of user which books bike.</param>
|
||||||
|
public static async Task BookAndOpenAync(
|
||||||
|
this ICopriServerBase corpiServer,
|
||||||
|
IBikeInfoMutable bike,
|
||||||
|
string mailAddress)
|
||||||
|
{
|
||||||
|
if (bike == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(bike), "Can not book bike and open lock. No bike object available.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(corpiServer is ICachedCopriServer cachedServer))
|
||||||
|
throw new ArgumentNullException(nameof(corpiServer));
|
||||||
|
|
||||||
|
// Send command to open lock
|
||||||
|
var response = (await corpiServer.BookAndStartOpeningAsync(bike.Id, bike.OperatorUri)).GetIsBookingResponseOk(bike.Id);
|
||||||
|
|
||||||
|
// Upate booking state
|
||||||
|
bike.Load(
|
||||||
|
response,
|
||||||
|
mailAddress,
|
||||||
|
Model.Bikes.Bike.BC.NotifyPropertyChangedLevel.None);
|
||||||
|
|
||||||
|
// Upated locking state.
|
||||||
|
var lockingState = await cachedServer.GetLockStateAsync(bike.Id);
|
||||||
|
|
||||||
|
var watch = new Stopwatch();
|
||||||
|
watch.Start();
|
||||||
|
|
||||||
|
|
||||||
|
while (lockingState!= LockingState.Open
|
||||||
|
&& lockingState != LockingState.UnknownDisconnected
|
||||||
|
&& watch.Elapsed < TimeSpan.FromMilliseconds(OPEN_CLOSE_TIMEOUT_MS))
|
||||||
|
{
|
||||||
|
// Delay a litte to reduce load on backend.
|
||||||
|
await Task.Delay(3000);
|
||||||
|
|
||||||
|
lockingState = await cachedServer.GetLockStateAsync(bike.Id);
|
||||||
|
Log.Information($"Current lock state is {lockingState}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update locking state.
|
||||||
|
bike.LockInfo.State = lockingState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a bike and closes the lock.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="corpiServer"> Instance to communicate with backend.</param>
|
||||||
|
/// <param name="bike">Bike to close.</param>
|
||||||
|
public static async Task CloseAync(
|
||||||
|
this ICopriServerBase corpiServer,
|
||||||
|
IBikeInfoMutable bike)
|
||||||
|
{
|
||||||
|
if (!(corpiServer is ICachedCopriServer cachedServer))
|
||||||
|
throw new ArgumentNullException(nameof(corpiServer));
|
||||||
|
|
||||||
|
// Send command to close lock
|
||||||
|
await corpiServer.UpdateLockingStateAsync(
|
||||||
|
bike.Id,
|
||||||
|
Repository.Request.lock_state.locking,
|
||||||
|
bike.OperatorUri);
|
||||||
|
|
||||||
|
var lockingState = await cachedServer.GetLockStateAsync(bike.Id);
|
||||||
|
|
||||||
|
var watch = new Stopwatch();
|
||||||
|
watch.Start();
|
||||||
|
|
||||||
|
while (lockingState != LockingState.Closed
|
||||||
|
&& lockingState != LockingState.UnknownDisconnected
|
||||||
|
&& watch.Elapsed < TimeSpan.FromMilliseconds(OPEN_CLOSE_TIMEOUT_MS))
|
||||||
|
{
|
||||||
|
// Delay a litte to reduce load on backend.
|
||||||
|
await Task.Delay(3000);
|
||||||
|
|
||||||
|
lockingState = await cachedServer.GetLockStateAsync(bike.Id);
|
||||||
|
Log.Information($"Current lock state is {lockingState}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update locking state.
|
||||||
|
bike.LockInfo.State = lockingState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a bike and closes the lock.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="corpiServer"> Instance to communicate with backend.</param>
|
||||||
|
/// <param name="smartDevice">Smart device on which app runs on.</param>
|
||||||
|
/// <param name="mailAddress">Mail address of user which books bike.</param>
|
||||||
|
public static async Task<BookingFinishedModel> ReturnAndCloseAync(
|
||||||
|
this ICopriServerBase corpiServer,
|
||||||
|
ISmartDevice smartDevice,
|
||||||
|
IBikeInfoMutable bike)
|
||||||
|
{
|
||||||
|
if (!(corpiServer is ICachedCopriServer cachedServer))
|
||||||
|
throw new ArgumentNullException(nameof(corpiServer));
|
||||||
|
|
||||||
|
// Send command to open lock
|
||||||
|
DoReturnResponse response =
|
||||||
|
await corpiServer.ReturnAndStartClosingAsync(bike.Id, smartDevice, bike.OperatorUri);
|
||||||
|
|
||||||
|
// Upate booking state
|
||||||
|
bike.Load(Model.Bikes.Bike.BC.NotifyPropertyChangedLevel.None);
|
||||||
|
|
||||||
|
var lockingState = await cachedServer.GetLockStateAsync(bike.Id);
|
||||||
|
|
||||||
|
var watch = new Stopwatch();
|
||||||
|
watch.Start();
|
||||||
|
|
||||||
|
while (lockingState != LockingState.Closed
|
||||||
|
&& lockingState != LockingState.UnknownDisconnected
|
||||||
|
&& watch.Elapsed < TimeSpan.FromMilliseconds(OPEN_CLOSE_TIMEOUT_MS))
|
||||||
|
{
|
||||||
|
// Delay a litte to reduce load on backend.
|
||||||
|
await Task.Delay(3000);
|
||||||
|
|
||||||
|
lockingState = await cachedServer.GetLockStateAsync(bike.Id);
|
||||||
|
Log.Information($"Current lock state is {lockingState}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update locking state.
|
||||||
|
bike.LockInfo.State = lockingState;
|
||||||
|
|
||||||
|
return response?.Create() ?? new BookingFinishedModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queries the locking state from copri.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="corpiServer">Service to use.</param>
|
||||||
|
/// <param name="bikeId">Bike id to query lock state for.</param>
|
||||||
|
/// <returns>Locking state</returns>
|
||||||
|
private static async Task<LockingState> GetLockStateAsync(
|
||||||
|
this ICachedCopriServer corpiServer,
|
||||||
|
string bikeId)
|
||||||
|
{
|
||||||
|
var bike = (await corpiServer.GetBikesOccupied(false))?.Response.bikes_occupied?.Values?.FirstOrDefault(x => x.bike == bikeId);
|
||||||
|
|
||||||
|
if (bike == null)
|
||||||
|
return LockingState.UnknownDisconnected;
|
||||||
|
|
||||||
|
return bike.GetCopriLockingState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,8 +24,8 @@
|
||||||
<Warning Text="$(MSBuildProjectFile) is Multilingual build enabled, but the Multilingual App Toolkit is unavailable during the build. If building with Visual Studio, please check to ensure that toolkit is properly installed." />
|
<Warning Text="$(MSBuildProjectFile) is Multilingual build enabled, but the Multilingual App Toolkit is unavailable during the build. If building with Visual Studio, please check to ensure that toolkit is properly installed." />
|
||||||
</Target>
|
</Target>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MonkeyCache" Version="1.5.2" />
|
<PackageReference Include="MonkeyCache" Version="1.6.3" />
|
||||||
<PackageReference Include="MonkeyCache.FileStore" Version="1.5.2" />
|
<PackageReference Include="MonkeyCache.FileStore" Version="1.6.3" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="Plugin.BLE" Version="2.1.2" />
|
<PackageReference Include="Plugin.BLE" Version="2.1.2" />
|
||||||
<PackageReference Include="Plugin.BluetoothLE" Version="6.3.0.19" />
|
<PackageReference Include="Plugin.BluetoothLE" Version="6.3.0.19" />
|
||||||
|
@ -43,8 +43,8 @@
|
||||||
<PackageReference Include="System.Xml.XDocument" Version="4.3.0" />
|
<PackageReference Include="System.Xml.XDocument" Version="4.3.0" />
|
||||||
<PackageReference Include="Xam.Plugin.Connectivity" Version="3.2.0" />
|
<PackageReference Include="Xam.Plugin.Connectivity" Version="3.2.0" />
|
||||||
<PackageReference Include="Xam.Plugins.Messaging" Version="5.2.0" />
|
<PackageReference Include="Xam.Plugins.Messaging" Version="5.2.0" />
|
||||||
<PackageReference Include="Xamarin.Essentials" Version="1.7.0" />
|
<PackageReference Include="Xamarin.Essentials" Version="1.7.2" />
|
||||||
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2196" />
|
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2401" />
|
||||||
<PackageReference Include="Xamarin.Forms.GoogleMaps" Version="3.3.0" />
|
<PackageReference Include="Xamarin.Forms.GoogleMaps" Version="3.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -55,6 +55,9 @@
|
||||||
<Folder Include="Services\Permissions\Plugin\" />
|
<Folder Include="Services\Permissions\Plugin\" />
|
||||||
<Folder Include="ViewModel\Info\BikeInfo\" />
|
<Folder Include="ViewModel\Info\BikeInfo\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Page Include="Model\Bikes\Bike\CopriLock\ILockInfoMutable.cs" />
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\LockItBLE\LockItBLE.csproj" />
|
<ProjectReference Include="..\LockItBLE\LockItBLE.csproj" />
|
||||||
<ProjectReference Include="..\LockItShared\LockItShared.csproj" />
|
<ProjectReference Include="..\LockItShared\LockItShared.csproj" />
|
||||||
|
|
|
@ -76,7 +76,7 @@ namespace TINK.ViewModel.Bikes.Bike.BC
|
||||||
public override void OnSelectedBikeStateChanged ()
|
public override void OnSelectedBikeStateChanged ()
|
||||||
{
|
{
|
||||||
RequestHandler = RequestHandlerFactory.Create(
|
RequestHandler = RequestHandlerFactory.Create(
|
||||||
bike,
|
Bike,
|
||||||
IsConnectedDelegate,
|
IsConnectedDelegate,
|
||||||
ConnectorFactory,
|
ConnectorFactory,
|
||||||
ViewUpdateManager,
|
ViewUpdateManager,
|
||||||
|
|
|
@ -54,7 +54,7 @@ namespace TINK.ViewModel.Bikes.Bike
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Holds the bike to display.
|
/// Holds the bike to display.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected BikeInfoMutable bike;
|
protected BikeInfoMutable Bike;
|
||||||
|
|
||||||
/// <summary> Reference on the user </summary>
|
/// <summary> Reference on the user </summary>
|
||||||
protected IUser ActiveUser { get; }
|
protected IUser ActiveUser { get; }
|
||||||
|
@ -117,7 +117,7 @@ namespace TINK.ViewModel.Bikes.Bike
|
||||||
|
|
||||||
ViewService = viewService;
|
ViewService = viewService;
|
||||||
|
|
||||||
bike = selectedBike
|
Bike = selectedBike
|
||||||
?? throw new ArgumentException(string.Format("Can not construct {0}- object, bike object is null.", typeof(BikeViewModelBase)));
|
?? throw new ArgumentException(string.Format("Can not construct {0}- object, bike object is null.", typeof(BikeViewModelBase)));
|
||||||
|
|
||||||
ActiveUser = activeUser
|
ActiveUser = activeUser
|
||||||
|
@ -172,18 +172,18 @@ namespace TINK.ViewModel.Bikes.Bike
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the display name of the bike containing of bike id and type of bike..
|
/// Gets the display name of the bike containing of bike id and type of bike..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Name => bike.GetDisplayName();
|
public string Name => Bike.GetDisplayName();
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the unique Id of bike or an empty string, if no name is defined to avoid duplicate display of id.
|
/// Gets the unique Id of bike or an empty string, if no name is defined to avoid duplicate display of id.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string DisplayId => bike.GetDisplayId();
|
public string DisplayId => Bike.GetDisplayId();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the unique Id of bike used by derived model to determine which bike to remove.
|
/// Gets the unique Id of bike used by derived model to determine which bike to remove.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Id=> bike.Id;
|
public string Id=> Bike.Id;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns status of a bike as text.
|
/// Returns status of a bike as text.
|
||||||
|
@ -193,7 +193,7 @@ namespace TINK.ViewModel.Bikes.Bike
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
switch (bike.State.Value)
|
switch (Bike.State.Value)
|
||||||
{
|
{
|
||||||
case InUseStateEnum.Disposable:
|
case InUseStateEnum.Disposable:
|
||||||
return AppResources.StatusTextAvailable;
|
return AppResources.StatusTextAvailable;
|
||||||
|
@ -202,45 +202,45 @@ namespace TINK.ViewModel.Bikes.Bike
|
||||||
if (!ActiveUser.IsLoggedIn)
|
if (!ActiveUser.IsLoggedIn)
|
||||||
{
|
{
|
||||||
// Nobody is logged in.
|
// Nobody is logged in.
|
||||||
switch (bike.State.Value)
|
switch (Bike.State.Value)
|
||||||
{
|
{
|
||||||
case InUseStateEnum.Reserved:
|
case InUseStateEnum.Reserved:
|
||||||
return GetReservedInfo(
|
return GetReservedInfo(
|
||||||
bike.State.RemainingTime,
|
Bike.State.RemainingTime,
|
||||||
bike.StationId,
|
Bike.StationId,
|
||||||
null); // Hide reservation code because no one but active user should see code
|
null); // Hide reservation code because no one but active user should see code
|
||||||
|
|
||||||
case InUseStateEnum.Booked:
|
case InUseStateEnum.Booked:
|
||||||
return GetBookedInfo(
|
return GetBookedInfo(
|
||||||
bike.State.From,
|
Bike.State.From,
|
||||||
bike.StationId,
|
Bike.StationId,
|
||||||
null); // Hide reservation code because no one but active user should see code
|
null); // Hide reservation code because no one but active user should see code
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return string.Format("Unbekannter status {0}.", bike.State.Value);
|
return string.Format("Unbekannter status {0}.", Bike.State.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (bike.State.Value)
|
switch (Bike.State.Value)
|
||||||
{
|
{
|
||||||
case InUseStateEnum.Reserved:
|
case InUseStateEnum.Reserved:
|
||||||
return bike.State.MailAddress == ActiveUser.Mail
|
return Bike.State.MailAddress == ActiveUser.Mail
|
||||||
? GetReservedInfo(
|
? GetReservedInfo(
|
||||||
bike.State.RemainingTime,
|
Bike.State.RemainingTime,
|
||||||
bike.StationId,
|
Bike.StationId,
|
||||||
bike.State.Code)
|
Bike.State.Code)
|
||||||
: "Fahrrad bereits reserviert durch anderen Nutzer.";
|
: "Fahrrad bereits reserviert durch anderen Nutzer.";
|
||||||
|
|
||||||
case InUseStateEnum.Booked:
|
case InUseStateEnum.Booked:
|
||||||
return bike.State.MailAddress == ActiveUser.Mail
|
return Bike.State.MailAddress == ActiveUser.Mail
|
||||||
? GetBookedInfo(
|
? GetBookedInfo(
|
||||||
bike.State.From,
|
Bike.State.From,
|
||||||
bike.StationId,
|
Bike.StationId,
|
||||||
bike.State.Code)
|
Bike.State.Code)
|
||||||
: "Fahrrad bereits gebucht durch anderen Nutzer.";
|
: "Fahrrad bereits gebucht durch anderen Nutzer.";
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return string.Format("Unbekannter status {0}.", bike.State.Value);
|
return string.Format("Unbekannter status {0}.", Bike.State.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,7 +279,7 @@ namespace TINK.ViewModel.Bikes.Bike
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Exposes the bike state.
|
/// Exposes the bike state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public InUseStateEnum State => bike.State.Value;
|
public InUseStateEnum State => Bike.State.Value;
|
||||||
|
|
||||||
/// <summary> Gets the value of property <see cref="State"/> when PropertyChanged was fired. </summary>
|
/// <summary> Gets the value of property <see cref="State"/> when PropertyChanged was fired. </summary>
|
||||||
public InUseStateEnum LastState { get; set; }
|
public InUseStateEnum LastState { get; set; }
|
||||||
|
@ -296,7 +296,7 @@ namespace TINK.ViewModel.Bikes.Bike
|
||||||
return Color.Default;
|
return Color.Default;
|
||||||
}
|
}
|
||||||
|
|
||||||
var l_oSelectedBikeState = bike.State;
|
var l_oSelectedBikeState = Bike.State;
|
||||||
switch (l_oSelectedBikeState.Value)
|
switch (l_oSelectedBikeState.Value)
|
||||||
{
|
{
|
||||||
case InUseStateEnum.Reserved:
|
case InUseStateEnum.Reserved:
|
||||||
|
@ -316,7 +316,7 @@ namespace TINK.ViewModel.Bikes.Bike
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Holds description about the tarif. </summary>
|
/// <summary> Holds description about the tarif. </summary>
|
||||||
public TariffDescriptionViewModel TariffDescription => new TariffDescriptionViewModel(bike.TariffDescription);
|
public TariffDescriptionViewModel TariffDescription => new TariffDescriptionViewModel(Bike.TariffDescription);
|
||||||
|
|
||||||
/// <summary> Gets the value of property <see cref="StateColor"/> when PropertyChanged was fired. </summary>
|
/// <summary> Gets the value of property <see cref="StateColor"/> when PropertyChanged was fired. </summary>
|
||||||
public Color LastStateColor { get; set; }
|
public Color LastStateColor { get; set; }
|
||||||
|
|
|
@ -29,8 +29,9 @@ namespace TINK.ViewModel.Bikes.Bike
|
||||||
IBikesViewModel bikesViewModel,
|
IBikesViewModel bikesViewModel,
|
||||||
Action<string> openUrlInBrowser)
|
Action<string> openUrlInBrowser)
|
||||||
{
|
{
|
||||||
return bikeInfo as Model.Bikes.Bike.BluetoothLock.IBikeInfoMutable != null
|
if (bikeInfo is Model.Bike.BluetoothLock.BikeInfoMutable)
|
||||||
? new BluetoothLock.BikeViewModel(
|
{
|
||||||
|
return new BluetoothLock.BikeViewModel(
|
||||||
isConnectedDelegate,
|
isConnectedDelegate,
|
||||||
connectorFactory,
|
connectorFactory,
|
||||||
geolocation,
|
geolocation,
|
||||||
|
@ -43,10 +44,14 @@ namespace TINK.ViewModel.Bikes.Bike
|
||||||
activeUser,
|
activeUser,
|
||||||
stateInfoProvider,
|
stateInfoProvider,
|
||||||
bikesViewModel,
|
bikesViewModel,
|
||||||
openUrlInBrowser) as BikeViewModelBase
|
openUrlInBrowser);
|
||||||
: new BC.BikeViewModel(
|
}
|
||||||
|
if (bikeInfo is Model.Bike.CopriLock.BikeInfoMutable)
|
||||||
|
{
|
||||||
|
return new CopriLock.BikeViewModel(
|
||||||
isConnectedDelegate,
|
isConnectedDelegate,
|
||||||
connectorFactory,
|
connectorFactory,
|
||||||
|
geolocation,
|
||||||
bikeRemoveDelegate,
|
bikeRemoveDelegate,
|
||||||
viewUpdateManager,
|
viewUpdateManager,
|
||||||
smartDevice,
|
smartDevice,
|
||||||
|
@ -56,6 +61,9 @@ namespace TINK.ViewModel.Bikes.Bike
|
||||||
stateInfoProvider,
|
stateInfoProvider,
|
||||||
bikesViewModel,
|
bikesViewModel,
|
||||||
openUrlInBrowser);
|
openUrlInBrowser);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,7 +132,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
|
||||||
{
|
{
|
||||||
var lastHandler = RequestHandler;
|
var lastHandler = RequestHandler;
|
||||||
RequestHandler = RequestHandlerFactory.Create(
|
RequestHandler = RequestHandlerFactory.Create(
|
||||||
bike,
|
Bike,
|
||||||
IsConnectedDelegate,
|
IsConnectedDelegate,
|
||||||
ConnectorFactory,
|
ConnectorFactory,
|
||||||
Geolocation,
|
Geolocation,
|
||||||
|
|
|
@ -209,7 +209,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||||
AppResources.ErrorCloseLockOutOfReachMessage,
|
AppResources.ErrorCloseLockOutOfReachMessage,
|
||||||
AppResources.MessageAnswerOk);
|
AppResources.MessageAnswerOk);
|
||||||
}
|
}
|
||||||
else if (exception is CounldntCloseMovingException)
|
else if (exception is CouldntCloseMovingException)
|
||||||
{
|
{
|
||||||
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||||
|
|
||||||
|
@ -533,7 +533,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||||
AppResources.ErrorCloseLockOutOfReachMessage,
|
AppResources.ErrorCloseLockOutOfReachMessage,
|
||||||
AppResources.MessageAnswerOk);
|
AppResources.MessageAnswerOk);
|
||||||
}
|
}
|
||||||
else if (exception is CounldntCloseMovingException)
|
else if (exception is CouldntCloseMovingException)
|
||||||
{
|
{
|
||||||
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||||
|
|
||||||
|
|
|
@ -253,7 +253,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||||
AppResources.ErrorCloseLockOutOfReachMessage,
|
AppResources.ErrorCloseLockOutOfReachMessage,
|
||||||
AppResources.MessageAnswerOk);
|
AppResources.MessageAnswerOk);
|
||||||
}
|
}
|
||||||
else if (exception is CounldntCloseMovingException)
|
else if (exception is CouldntCloseMovingException)
|
||||||
{
|
{
|
||||||
Log.ForContext<BookedUnknown>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
Log.ForContext<BookedUnknown>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||||
|
|
||||||
|
|
|
@ -53,12 +53,12 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||||
public override InUseStateEnum State => InUseStateEnum.Disposable;
|
public override InUseStateEnum State => InUseStateEnum.Disposable;
|
||||||
|
|
||||||
/// <summary>Reserve bike and connect to lock.</summary>
|
/// <summary>Reserve bike and connect to lock.</summary>
|
||||||
public async Task<IRequestHandler> HandleRequestOption1() => await ReserverBookAndOpen();
|
public async Task<IRequestHandler> HandleRequestOption1() => await ReserveBookAndOpen();
|
||||||
|
|
||||||
public async Task<IRequestHandler> HandleRequestOption2() => await UnsupportedRequest();
|
public async Task<IRequestHandler> HandleRequestOption2() => await UnsupportedRequest();
|
||||||
|
|
||||||
/// <summary>Reserve bike and connect to lock.</summary>
|
/// <summary>Reserve bike and connect to lock.</summary>
|
||||||
public async Task<IRequestHandler> ReserverBookAndOpen()
|
public async Task<IRequestHandler> ReserveBookAndOpen()
|
||||||
{
|
{
|
||||||
BikesViewModel.IsIdle = false;
|
BikesViewModel.IsIdle = false;
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||||
AppResources.ErrorCloseLockOutOfReachMessage,
|
AppResources.ErrorCloseLockOutOfReachMessage,
|
||||||
AppResources.MessageAnswerOk);
|
AppResources.MessageAnswerOk);
|
||||||
}
|
}
|
||||||
else if (exception is CounldntCloseMovingException)
|
else if (exception is CouldntCloseMovingException)
|
||||||
{
|
{
|
||||||
Log.ForContext<DisposableOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
Log.ForContext<DisposableOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||||
public async Task<IRequestHandler> HandleRequestOption1() => await CancelReservation();
|
public async Task<IRequestHandler> HandleRequestOption1() => await CancelReservation();
|
||||||
|
|
||||||
/// <summary> Open lock and book bike. </summary>
|
/// <summary> Open lock and book bike. </summary>
|
||||||
public async Task<IRequestHandler> HandleRequestOption2() => await OpenLockAndDooBook();
|
public async Task<IRequestHandler> HandleRequestOption2() => await OpenLockAndDoBook();
|
||||||
|
|
||||||
/// <summary> Cancel reservation. </summary>
|
/// <summary> Cancel reservation. </summary>
|
||||||
public async Task<IRequestHandler> CancelReservation()
|
public async Task<IRequestHandler> CancelReservation()
|
||||||
|
@ -160,18 +160,18 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Open lock and book bike. </summary>
|
/// <summary> Open lock and book bike. </summary>
|
||||||
public async Task<IRequestHandler> OpenLockAndDooBook()
|
public async Task<IRequestHandler> OpenLockAndDoBook()
|
||||||
{
|
{
|
||||||
BikesViewModel.IsIdle = false;
|
BikesViewModel.IsIdle = false;
|
||||||
|
|
||||||
// Ask whether to really book bike?
|
// Ask whether to really book bike?
|
||||||
var l_oResult = await ViewService.DisplayAlert(
|
var alertResult = await ViewService.DisplayAlert(
|
||||||
string.Empty,
|
string.Empty,
|
||||||
string.Format(AppResources.QuestionOpenLockAndBookBike, SelectedBike.GetFullDisplayName()),
|
string.Format(AppResources.QuestionOpenLockAndBookBike, SelectedBike.GetFullDisplayName()),
|
||||||
AppResources.MessageAnswerYes,
|
AppResources.MessageAnswerYes,
|
||||||
AppResources.MessageAnswerNo);
|
AppResources.MessageAnswerNo);
|
||||||
|
|
||||||
if (l_oResult == false)
|
if (alertResult == false)
|
||||||
{
|
{
|
||||||
// User aborted booking process
|
// User aborted booking process
|
||||||
Log.ForContext<ReservedClosed>().Information("User selected requested bike {bike} in order to book but action was canceled.", SelectedBike);
|
Log.ForContext<ReservedClosed>().Information("User selected requested bike {bike} in order to book but action was canceled.", SelectedBike);
|
||||||
|
|
|
@ -188,7 +188,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||||
AppResources.ErrorCloseLockOutOfReachStateReservedMessage,
|
AppResources.ErrorCloseLockOutOfReachStateReservedMessage,
|
||||||
"OK");
|
"OK");
|
||||||
}
|
}
|
||||||
else if (exception is CounldntCloseMovingException)
|
else if (exception is CouldntCloseMovingException)
|
||||||
{
|
{
|
||||||
Log.ForContext<ReservedOpen>().Debug("Lock can not be closed. Lock bike is moving. {Exception}", exception);
|
Log.ForContext<ReservedOpen>().Debug("Lock can not be closed. Lock bike is moving. {Exception}", exception);
|
||||||
|
|
||||||
|
|
|
@ -253,7 +253,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||||
AppResources.ErrorCloseLockOutOfReachMessage,
|
AppResources.ErrorCloseLockOutOfReachMessage,
|
||||||
AppResources.MessageAnswerOk);
|
AppResources.MessageAnswerOk);
|
||||||
}
|
}
|
||||||
else if (exception is CounldntCloseMovingException)
|
else if (exception is CouldntCloseMovingException)
|
||||||
{
|
{
|
||||||
Log.ForContext<ReservedUnknown>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
Log.ForContext<ReservedUnknown>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||||
|
|
||||||
|
|
189
TINKLib/ViewModel/Bikes/Bike/CopriLock/BikeViewModel.cs
Normal file
189
TINKLib/ViewModel/Bikes/Bike/CopriLock/BikeViewModel.cs
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using TINK.Model.Connector;
|
||||||
|
using TINK.Services.BluetoothLock;
|
||||||
|
using TINK.Services.Geolocation;
|
||||||
|
using TINK.Model.User;
|
||||||
|
using TINK.View;
|
||||||
|
using BikeInfoMutable = TINK.Model.Bike.BC.BikeInfoMutable;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using TINK.Model.Device;
|
||||||
|
|
||||||
|
namespace TINK.ViewModel.Bikes.Bike.CopriLock
|
||||||
|
{
|
||||||
|
using IRequestHandler = BluetoothLock.IRequestHandler;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// View model for a ILockIt bike.
|
||||||
|
/// Provides functionality for views
|
||||||
|
/// - MyBikes
|
||||||
|
/// - BikesAtStation
|
||||||
|
/// </summary>
|
||||||
|
public class BikeViewModel : BikeViewModelBase, INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
/// <summary> Notifies GUI about changes. </summary>
|
||||||
|
public override event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
private IGeolocation Geolocation { get; }
|
||||||
|
|
||||||
|
/// <summary> Holds object which manages requests. </summary>
|
||||||
|
private IRequestHandler RequestHandler { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Raises events in order to update GUI.</summary>
|
||||||
|
public override void RaisePropertyChanged(object sender, PropertyChangedEventArgs eventArgs) => PropertyChanged?.Invoke(sender, eventArgs);
|
||||||
|
|
||||||
|
/// <summary> Raises events if property values changed in order to update GUI.</summary>
|
||||||
|
private void RaisePropertyChangedEvent(
|
||||||
|
IRequestHandler lastHandler,
|
||||||
|
string lastStateText = null,
|
||||||
|
Xamarin.Forms.Color? lastStateColor = null)
|
||||||
|
{
|
||||||
|
if (lastHandler.ButtonText != ButtonText)
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonText)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastHandler.IsButtonVisible != IsButtonVisible)
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsButtonVisible)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastHandler.LockitButtonText != LockitButtonText)
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(LockitButtonText)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastHandler.IsLockitButtonVisible != IsLockitButtonVisible)
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsLockitButtonVisible)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RequestHandler.ErrorText != lastHandler.ErrorText)
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ErrorText)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(lastStateText) && lastStateText != StateText)
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(StateText)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastStateColor != null && lastStateColor != StateColor)
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(StateColor)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a bike view model object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...)</param>
|
||||||
|
/// <param name="selectedBike">Bike to be displayed.</param>
|
||||||
|
/// <param name="user">Object holding logged in user or an empty user object.</param>
|
||||||
|
/// <param name="stateInfoProvider">Provides in use state information.</param>
|
||||||
|
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||||
|
/// <param name="openUrlInBrowser">Delegate to open browser.</param>
|
||||||
|
public BikeViewModel(
|
||||||
|
Func<bool> isConnectedDelegate,
|
||||||
|
Func<bool, IConnector> connectorFactory,
|
||||||
|
IGeolocation geolocation,
|
||||||
|
Action<string> bikeRemoveDelegate,
|
||||||
|
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||||
|
ISmartDevice smartDevice,
|
||||||
|
IViewService viewService,
|
||||||
|
BikeInfoMutable selectedBike,
|
||||||
|
IUser user,
|
||||||
|
IInUseStateInfoProvider stateInfoProvider,
|
||||||
|
IBikesViewModel bikesViewModel,
|
||||||
|
Action<string> openUrlInBrowser) : base(isConnectedDelegate, connectorFactory, bikeRemoveDelegate, viewUpdateManager, smartDevice, viewService, selectedBike, user, stateInfoProvider, bikesViewModel, openUrlInBrowser)
|
||||||
|
{
|
||||||
|
RequestHandler = user.IsLoggedIn
|
||||||
|
? RequestHandlerFactory.Create(
|
||||||
|
selectedBike,
|
||||||
|
isConnectedDelegate,
|
||||||
|
connectorFactory,
|
||||||
|
geolocation,
|
||||||
|
viewUpdateManager,
|
||||||
|
smartDevice,
|
||||||
|
viewService,
|
||||||
|
bikesViewModel,
|
||||||
|
user)
|
||||||
|
: new BluetoothLock.NotLoggedIn(
|
||||||
|
selectedBike.State.Value,
|
||||||
|
viewService,
|
||||||
|
bikesViewModel);
|
||||||
|
|
||||||
|
Geolocation = geolocation
|
||||||
|
?? throw new ArgumentException($"Can not instantiate {this.GetType().Name}-object. Parameter {nameof(geolocation)} can not be null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles BikeInfoMutable events.
|
||||||
|
/// Helper member to raise events. Maps model event change notification to view model events.
|
||||||
|
/// Todo: Check which events are received here and filter, to avoid event storm.
|
||||||
|
/// </summary>
|
||||||
|
public override void OnSelectedBikeStateChanged()
|
||||||
|
{
|
||||||
|
var lastHandler = RequestHandler;
|
||||||
|
RequestHandler = RequestHandlerFactory.Create(
|
||||||
|
Bike,
|
||||||
|
IsConnectedDelegate,
|
||||||
|
ConnectorFactory,
|
||||||
|
Geolocation,
|
||||||
|
ViewUpdateManager,
|
||||||
|
SmartDevice,
|
||||||
|
ViewService,
|
||||||
|
BikesViewModel,
|
||||||
|
ActiveUser);
|
||||||
|
|
||||||
|
RaisePropertyChangedEvent(lastHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets visiblity of the copri command button. </summary>
|
||||||
|
public bool IsButtonVisible => RequestHandler.IsButtonVisible;
|
||||||
|
|
||||||
|
/// <summary> Gets the text of the copri command button. </summary>
|
||||||
|
public string ButtonText => RequestHandler.ButtonText;
|
||||||
|
|
||||||
|
/// <summary> Gets visiblity of the ILockIt command button. </summary>
|
||||||
|
public bool IsLockitButtonVisible => RequestHandler.IsLockitButtonVisible;
|
||||||
|
|
||||||
|
/// <summary> Gets the text of the ILockIt command button. </summary>
|
||||||
|
public string LockitButtonText => RequestHandler.LockitButtonText;
|
||||||
|
|
||||||
|
/// <summary> Processes request to perform a copri action (reserve bike and cancel reservation). </summary>
|
||||||
|
public System.Windows.Input.ICommand OnButtonClicked => new Xamarin.Forms.Command(async () => await ClickButton(RequestHandler.HandleRequestOption1()));
|
||||||
|
|
||||||
|
/// <summary> Processes request to perform a ILockIt action (unlock bike and lock bike). </summary>
|
||||||
|
public System.Windows.Input.ICommand OnLockitButtonClicked => new Xamarin.Forms.Command(async () => await ClickButton(RequestHandler.HandleRequestOption2()));
|
||||||
|
|
||||||
|
/// <summary> Processes request to perform a copri action (reserve bike and cancel reservation). </summary>
|
||||||
|
private async Task ClickButton(Task<IRequestHandler> handleRequest)
|
||||||
|
{
|
||||||
|
var lastHandler = RequestHandler;
|
||||||
|
var lastStateText = StateText;
|
||||||
|
var lastStateColor = StateColor;
|
||||||
|
|
||||||
|
RequestHandler = await handleRequest;
|
||||||
|
|
||||||
|
if (lastHandler.IsRemoveBikeRequired)
|
||||||
|
{
|
||||||
|
BikeRemoveDelegate(Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RuntimeHelpers.Equals(lastHandler, RequestHandler))
|
||||||
|
{
|
||||||
|
// No state change occurred (same instance is returned).
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RaisePropertyChangedEvent(
|
||||||
|
lastHandler,
|
||||||
|
lastStateText,
|
||||||
|
lastStateColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ErrorText => RequestHandler.ErrorText;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
using System;
|
||||||
|
using TINK.Model.Connector;
|
||||||
|
using TINK.Services.Geolocation;
|
||||||
|
using TINK.Model.State;
|
||||||
|
using TINK.View;
|
||||||
|
using TINK.Model.User;
|
||||||
|
using TINK.Model.Device;
|
||||||
|
|
||||||
|
namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
||||||
|
{
|
||||||
|
public abstract class Base : BC.RequestHandler.Base<Model.Bikes.Bike.CopriLock.IBikeInfoMutable>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs the reqest handler base.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="selectedBike">Bike which is reserved or for which reservation is canceled.</param>
|
||||||
|
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...)</param>
|
||||||
|
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||||
|
public Base(
|
||||||
|
Model.Bikes.Bike.CopriLock.IBikeInfoMutable selectedBike,
|
||||||
|
string buttonText,
|
||||||
|
bool isCopriButtonVisible,
|
||||||
|
Func<bool> isConnectedDelegate,
|
||||||
|
Func<bool, IConnector> connectorFactory,
|
||||||
|
IGeolocation geolocation,
|
||||||
|
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||||
|
ISmartDevice smartDevice,
|
||||||
|
IViewService viewService,
|
||||||
|
IBikesViewModel bikesViewModel,
|
||||||
|
IUser activeUser) : base(selectedBike, buttonText, isCopriButtonVisible, isConnectedDelegate, connectorFactory, viewUpdateManager, smartDevice, viewService, bikesViewModel, activeUser)
|
||||||
|
{
|
||||||
|
Geolocation = geolocation
|
||||||
|
?? throw new ArgumentException($"Can not construct {GetType().Name}-object. Parameter {nameof(geolocation)} must not be null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IGeolocation Geolocation { get; }
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary> Gets the bike state. </summary>
|
||||||
|
public abstract override InUseStateEnum State { get; }
|
||||||
|
|
||||||
|
public string LockitButtonText { get; protected set; }
|
||||||
|
|
||||||
|
public bool IsLockitButtonVisible { get; protected set; }
|
||||||
|
|
||||||
|
public string ErrorText => string.Empty;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,294 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using TINK.Model.Connector;
|
||||||
|
using TINK.Model.State;
|
||||||
|
using TINK.View;
|
||||||
|
using TINK.Services.Geolocation;
|
||||||
|
using Serilog;
|
||||||
|
using TINK.Repository.Exception;
|
||||||
|
using TINK.MultilingualResources;
|
||||||
|
using TINK.Model.User;
|
||||||
|
using TINK.Model.Device;
|
||||||
|
using TINK.Model;
|
||||||
|
using TINK.Model.Bikes.Bike.CopriLock;
|
||||||
|
using TINK.Services.CopriLock.Exception;
|
||||||
|
|
||||||
|
namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
||||||
|
{
|
||||||
|
using IRequestHandler = BluetoothLock.IRequestHandler;
|
||||||
|
|
||||||
|
public class BookedClosed : Base, IRequestHandler
|
||||||
|
{
|
||||||
|
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...)</param>
|
||||||
|
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||||
|
public BookedClosed(
|
||||||
|
IBikeInfoMutable selectedBike,
|
||||||
|
Func<bool> isConnectedDelegate,
|
||||||
|
Func<bool, IConnector> connectorFactory,
|
||||||
|
IGeolocation geolocation,
|
||||||
|
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||||
|
ISmartDevice smartDevice,
|
||||||
|
IViewService viewService,
|
||||||
|
IBikesViewModel bikesViewModel,
|
||||||
|
IUser activeUser) : base(
|
||||||
|
selectedBike,
|
||||||
|
AppResources.ActionReturn, // Copri button text "Miete beenden"
|
||||||
|
true, // Show button to enabled returning of bike.
|
||||||
|
isConnectedDelegate,
|
||||||
|
connectorFactory,
|
||||||
|
geolocation,
|
||||||
|
viewUpdateManager,
|
||||||
|
smartDevice,
|
||||||
|
viewService,
|
||||||
|
bikesViewModel,
|
||||||
|
activeUser)
|
||||||
|
{
|
||||||
|
LockitButtonText = AppResources.ActionOpenAndPause;
|
||||||
|
IsLockitButtonVisible = true; // Show button to enable opening lock in case user took a pause and does not want to return the bike.
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets the bike state. </summary>
|
||||||
|
public override InUseStateEnum State => InUseStateEnum.Booked;
|
||||||
|
|
||||||
|
/// <summary> Return bike. </summary>
|
||||||
|
public async Task<IRequestHandler> HandleRequestOption1() => await ReturnBike();
|
||||||
|
|
||||||
|
/// <summary> Open bike and update COPRI lock state. </summary>
|
||||||
|
public async Task<IRequestHandler> HandleRequestOption2() => await OpenLock();
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary> Return bike. </summary>
|
||||||
|
public async Task<IRequestHandler> ReturnBike()
|
||||||
|
{
|
||||||
|
BikesViewModel.IsIdle = false;
|
||||||
|
|
||||||
|
// Ask whether to really return bike?
|
||||||
|
var l_oResult = await ViewService.DisplayAlert(
|
||||||
|
string.Empty,
|
||||||
|
string.Format(AppResources.QuestionReturnBike, SelectedBike.GetFullDisplayName()),
|
||||||
|
AppResources.MessageAnswerYes,
|
||||||
|
AppResources.MessageAnswerNo);
|
||||||
|
|
||||||
|
if (l_oResult == false)
|
||||||
|
{
|
||||||
|
// User aborted returning bike process
|
||||||
|
Log.ForContext<BookedClosed>().Information("User selected booked bike {l_oId} in order to return but action was canceled.", SelectedBike.Id);
|
||||||
|
|
||||||
|
BikesViewModel.IsIdle = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock list to avoid multiple taps while copri action is pending.
|
||||||
|
Log.ForContext<BookedClosed>().Information("Request to return bike {bike} detected.", SelectedBike);
|
||||||
|
|
||||||
|
// Stop polling before returning bike.
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||||
|
await ViewUpdateManager().StopUpdatePeridically();
|
||||||
|
|
||||||
|
BikesViewModel.ActionText = "Returning bike...";
|
||||||
|
IsConnected = IsConnectedDelegate();
|
||||||
|
|
||||||
|
var feedBackUri = SelectedBike?.OperatorUri;
|
||||||
|
BookingFinishedModel bookingFinished;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bookingFinished = await ConnectorFactory(IsConnected).Command.DoReturn(SelectedBike);
|
||||||
|
|
||||||
|
// If canceling bike succedes remove bike because it is not ready to be booked again
|
||||||
|
IsRemoveBikeRequired = true;
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
|
||||||
|
if (exception is WebConnectFailureException)
|
||||||
|
{
|
||||||
|
// Copri server is not reachable.
|
||||||
|
Log.ForContext<BookedClosed>().Information("User selected booked bike {bike} but returing failed (Copri server not reachable).", SelectedBike);
|
||||||
|
|
||||||
|
await ViewService.DisplayAdvancedAlert(
|
||||||
|
AppResources.ErrorReturnBikeNoWebTitle,
|
||||||
|
string.Format("{0}\r\n{1}", AppResources.ErrorReturnBikeNoWebMessage, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
|
||||||
|
exception.Message,
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
}
|
||||||
|
else if (exception is NotAtStationException notAtStationException)
|
||||||
|
{
|
||||||
|
// COPRI returned an error.
|
||||||
|
Log.ForContext<BookedClosed>().Information("User selected booked bike {bike} but returning failed. COPRI returned an not at station error.", SelectedBike);
|
||||||
|
|
||||||
|
await ViewService.DisplayAlert(
|
||||||
|
AppResources.ErrorReturnBikeTitle,
|
||||||
|
string.Format(AppResources.ErrorReturnBikeNotAtStationMessage, notAtStationException.StationNr, notAtStationException.Distance),
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
}
|
||||||
|
else if (exception is NoGPSDataException)
|
||||||
|
{
|
||||||
|
// COPRI returned an error.
|
||||||
|
Log.ForContext<BookedClosed>().Information("User selected booked bike {bike} but returing failed. COPRI returned an no GPS- data error.", SelectedBike);
|
||||||
|
|
||||||
|
await ViewService.DisplayAlert(
|
||||||
|
AppResources.ErrorReturnBikeTitle,
|
||||||
|
string.Format(AppResources.ErrorReturnBikeLockClosedNoGPSMessage),
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
}
|
||||||
|
else if (exception is ResponseException copriException)
|
||||||
|
{
|
||||||
|
// COPRI returned an error.
|
||||||
|
Log.ForContext<BookedClosed>().Information("User selected booked bike {bike} but returing failed. COPRI returned an error.", SelectedBike);
|
||||||
|
|
||||||
|
await ViewService.DisplayAdvancedAlert(
|
||||||
|
"Statusfehler beim Zurückgeben des Rads!",
|
||||||
|
copriException.Message,
|
||||||
|
copriException.Response,
|
||||||
|
"OK");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.ForContext<BookedClosed>().Error("User selected booked bike {bike} but returning failed. {@l_oException}", SelectedBike.Id, exception);
|
||||||
|
|
||||||
|
await ViewService.DisplayAlert(
|
||||||
|
AppResources.ErrorReturnBikeTitle,
|
||||||
|
exception.Message,
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
}
|
||||||
|
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||||
|
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||||
|
BikesViewModel.ActionText = "";
|
||||||
|
BikesViewModel.IsIdle = true;
|
||||||
|
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.ForContext<BookedClosed>().Information("User returned bike {bike} successfully.", SelectedBike);
|
||||||
|
|
||||||
|
#if !USERFEEDBACKDLG_OFF
|
||||||
|
// Do get Feedback
|
||||||
|
var feedback = await ViewService.DisplayUserFeedbackPopup(bookingFinished?.Co2Saving);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await ConnectorFactory(IsConnected).Command.DoSubmitFeedback(
|
||||||
|
new UserFeedbackDto { BikeId = SelectedBike.Id, IsBikeBroken = feedback.IsBikeBroken, Message = feedback.Message },
|
||||||
|
feedBackUri);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
|
||||||
|
if (exception is ResponseException copriException)
|
||||||
|
{
|
||||||
|
// Copri server is not reachable.
|
||||||
|
Log.ForContext<BookedClosed>().Information("Submitting feedback for bike {bike} failed. COPRI returned an error.", SelectedBike);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.ForContext<BookedClosed>().Error("Submitting feedback for bike {bike} failed. {@l_oException}", SelectedBike.Id, exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
await ViewService.DisplayAlert(
|
||||||
|
AppResources.ErrorReturnSubmitFeedbackTitle,
|
||||||
|
AppResources.ErrorReturnSubmitFeedbackMessage,
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
|
||||||
|
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||||
|
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||||
|
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
BikesViewModel.IsIdle = true;
|
||||||
|
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (bookingFinished != null && bookingFinished.MiniSurvey.Questions.Count > 0)
|
||||||
|
{
|
||||||
|
await ViewService.PushModalAsync(ViewTypes.MiniSurvey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restart polling again.
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||||
|
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
BikesViewModel.IsIdle = true;
|
||||||
|
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Open bike and update COPRI lock state. </summary>
|
||||||
|
public async Task<IRequestHandler> OpenLock()
|
||||||
|
{
|
||||||
|
// Unlock bike.
|
||||||
|
Log.ForContext<BookedClosed>().Information("User request to unlock bike {bike}.", SelectedBike);
|
||||||
|
|
||||||
|
// Stop polling before returning bike.
|
||||||
|
BikesViewModel.IsIdle = false;
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||||
|
await ViewUpdateManager().StopUpdatePeridically();
|
||||||
|
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextOpeningLock;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await ConnectorFactory(IsConnected).Command.OpenLockAsync(SelectedBike);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
|
||||||
|
if (exception is OutOfReachException)
|
||||||
|
{
|
||||||
|
Log.ForContext<BookedClosed>().Debug("Lock can not be opened. {Exception}", exception);
|
||||||
|
|
||||||
|
await ViewService.DisplayAlert(
|
||||||
|
AppResources.ErrorOpenLockTitle,
|
||||||
|
AppResources.ErrorOpenLockOutOfReachMessage,
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
}
|
||||||
|
else if (exception is CouldntOpenBoldIsBlockedException)
|
||||||
|
{
|
||||||
|
Log.ForContext<BookedClosed>().Debug("Lock can not be opened. Bold is blocked. {Exception}", exception);
|
||||||
|
|
||||||
|
await ViewService.DisplayAlert(
|
||||||
|
AppResources.ErrorOpenLockTitle,
|
||||||
|
AppResources.ErrorOpenLockBoldBlockedMessage,
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
}
|
||||||
|
else if (exception is CouldntOpenBoldWasBlockedException)
|
||||||
|
{
|
||||||
|
Log.ForContext<BookedClosed>().Debug("Lock can not be opened. Bold was or is blocked. {Exception}", exception);
|
||||||
|
|
||||||
|
await ViewService.DisplayAlert(
|
||||||
|
AppResources.ErrorOpenLockStillOpenTitle,
|
||||||
|
AppResources.ErrorOpenLockBoldWasBlockedMessage,
|
||||||
|
"OK");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.ForContext<BookedClosed>().Error("Lock can not be opened. {Exception}", exception);
|
||||||
|
|
||||||
|
await ViewService.DisplayAlert(
|
||||||
|
AppResources.ErrorOpenLockTitle,
|
||||||
|
exception.Message,
|
||||||
|
"OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
// When bold is blocked lock is still closed even if exception occurres.
|
||||||
|
// In all other cases state is supposed to be unknown. Example: Lock is out of reach and no more bluetooth connected.
|
||||||
|
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||||
|
? stateAwareException.State
|
||||||
|
: LockingState.UnknownDisconnected;
|
||||||
|
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||||
|
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
BikesViewModel.IsIdle = true;
|
||||||
|
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.ForContext<BookedClosed>().Information("User paused ride using {bike} successfully.", SelectedBike);
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||||
|
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
BikesViewModel.IsIdle = true;
|
||||||
|
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
using Serilog;
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using TINK.Model.Bike.CopriLock;
|
||||||
|
using TINK.Model.Bikes.Bike.CopriLock;
|
||||||
|
using TINK.Model.Connector;
|
||||||
|
using TINK.Services.Geolocation;
|
||||||
|
using TINK.Model.State;
|
||||||
|
using TINK.MultilingualResources;
|
||||||
|
using TINK.View;
|
||||||
|
using TINK.Model.User;
|
||||||
|
using TINK.Model.Device;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
||||||
|
{
|
||||||
|
using IRequestHandler = BluetoothLock.IRequestHandler;
|
||||||
|
|
||||||
|
public class BookedDefault : Base, IRequestHandler
|
||||||
|
{
|
||||||
|
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...)</param>
|
||||||
|
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||||
|
public BookedDefault(
|
||||||
|
IBikeInfoMutable selectedBike,
|
||||||
|
Func<bool> isConnectedDelegate,
|
||||||
|
Func<bool, IConnector> connectorFactory,
|
||||||
|
IGeolocation geolocation,
|
||||||
|
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||||
|
ISmartDevice smartDevice,
|
||||||
|
IViewService viewService,
|
||||||
|
IBikesViewModel bikesViewModel,
|
||||||
|
IUser activeUser) :
|
||||||
|
base(
|
||||||
|
selectedBike,
|
||||||
|
nameof(BookedDefault),
|
||||||
|
false,
|
||||||
|
isConnectedDelegate,
|
||||||
|
connectorFactory,
|
||||||
|
geolocation,
|
||||||
|
viewUpdateManager,
|
||||||
|
smartDevice,
|
||||||
|
viewService,
|
||||||
|
bikesViewModel,
|
||||||
|
activeUser)
|
||||||
|
{
|
||||||
|
LockitButtonText = AppResources.ActionSearchLock;
|
||||||
|
IsLockitButtonVisible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets the bike state. </summary>
|
||||||
|
public override InUseStateEnum State => InUseStateEnum.Booked;
|
||||||
|
|
||||||
|
public async Task<IRequestHandler> HandleRequestOption1() => await UnsupportedRequest();
|
||||||
|
|
||||||
|
/// <summary> Scan for lock.</summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<IRequestHandler> HandleRequestOption2() => await ConnectLock();
|
||||||
|
|
||||||
|
/// <summary> Requst is not supported, button should be disabled. </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<IRequestHandler> UnsupportedRequest()
|
||||||
|
{
|
||||||
|
Log.ForContext<BookedDefault>().Error("Click of unsupported button click detected.");
|
||||||
|
return await Task.FromResult<IRequestHandler>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Scan for lock.</summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<IRequestHandler> ConnectLock()
|
||||||
|
{
|
||||||
|
// Lock list to avoid multiple taps while copri action is pending.
|
||||||
|
BikesViewModel.IsIdle = false;
|
||||||
|
Log.ForContext<BookedDefault>().Information("Request to search {bike} detected.", SelectedBike);
|
||||||
|
|
||||||
|
// Stop polling before getting new auth-values.
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||||
|
await ViewUpdateManager().StopUpdatePeridically();
|
||||||
|
|
||||||
|
var bikesInfo = (await ConnectorFactory(IsConnected).Query.GetBikesOccupiedAsync())?.Response?.Where(bike => bike.Id == SelectedBike.Id).ToArray();
|
||||||
|
|
||||||
|
var bikeInfo = bikesInfo.Length > 0 ? bikesInfo[0] as BikeInfo : null;
|
||||||
|
SelectedBike.LockInfo.State = bikeInfo != null ? bikeInfo.LockInfo.State: SelectedBike.LockInfo.State;
|
||||||
|
|
||||||
|
Log.ForContext<BookedDefault>().Information($"State for bike {SelectedBike.Id} updated successfully. Value is {SelectedBike.LockInfo.State}.");
|
||||||
|
|
||||||
|
// Restart polling again.
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||||
|
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
BikesViewModel.IsIdle = true;
|
||||||
|
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,382 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using TINK.Model.Connector;
|
||||||
|
using TINK.Model.State;
|
||||||
|
using TINK.View;
|
||||||
|
using Serilog;
|
||||||
|
using TINK.Repository.Exception;
|
||||||
|
using TINK.MultilingualResources;
|
||||||
|
using TINK.Model.User;
|
||||||
|
using TINK.Model.Device;
|
||||||
|
using TINK.Model;
|
||||||
|
using TINK.Model.Bikes.Bike.CopriLock;
|
||||||
|
using TINK.Services.CopriLock.Exception;
|
||||||
|
|
||||||
|
namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
||||||
|
{
|
||||||
|
using IRequestHandler = BluetoothLock.IRequestHandler;
|
||||||
|
|
||||||
|
public class BookedOpen : Base, IRequestHandler
|
||||||
|
|
||||||
|
{
|
||||||
|
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...)</param>
|
||||||
|
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||||
|
public BookedOpen(
|
||||||
|
IBikeInfoMutable selectedBike,
|
||||||
|
Func<bool> isConnectedDelegate,
|
||||||
|
Func<bool, IConnector> connectorFactory,
|
||||||
|
Services.Geolocation.IGeolocation geolocation,
|
||||||
|
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||||
|
ISmartDevice smartDevice,
|
||||||
|
IViewService viewService,
|
||||||
|
IBikesViewModel bikesViewModel,
|
||||||
|
IUser activeUser) : base(
|
||||||
|
selectedBike,
|
||||||
|
AppResources.ActionCloseAndReturn, // Copri button text: "Schloss schließen & Miete beenden"
|
||||||
|
true, // Show button to allow user to return bike.
|
||||||
|
isConnectedDelegate,
|
||||||
|
connectorFactory,
|
||||||
|
geolocation,
|
||||||
|
viewUpdateManager,
|
||||||
|
smartDevice,
|
||||||
|
viewService,
|
||||||
|
bikesViewModel,
|
||||||
|
activeUser)
|
||||||
|
{
|
||||||
|
LockitButtonText = AppResources.ActionClose; // BT button text "Schließen".
|
||||||
|
IsLockitButtonVisible = true; // Show button to allow user to lock bike.
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets the bike state. </summary>
|
||||||
|
public override InUseStateEnum State => InUseStateEnum.Disposable;
|
||||||
|
|
||||||
|
/// <summary> Close lock and return bike.</summary>
|
||||||
|
public async Task<IRequestHandler> HandleRequestOption1() => await CloseLockAndReturnBike();
|
||||||
|
|
||||||
|
/// <summary> Close lock in order to pause ride and update COPRI lock state.</summary>
|
||||||
|
public async Task<IRequestHandler> HandleRequestOption2() => await CloseLock();
|
||||||
|
|
||||||
|
/// <summary> Close lock and return bike.</summary>
|
||||||
|
public async Task<IRequestHandler> CloseLockAndReturnBike()
|
||||||
|
{
|
||||||
|
// Prevent concurrent interaction
|
||||||
|
BikesViewModel.IsIdle = false;
|
||||||
|
|
||||||
|
// Ask whether to really return bike?
|
||||||
|
var l_oResult = await ViewService.DisplayAlert(
|
||||||
|
string.Empty,
|
||||||
|
string.Format(AppResources.QuestionCloseLockAndReturnBike, SelectedBike.GetFullDisplayName()),
|
||||||
|
AppResources.MessageAnswerYes,
|
||||||
|
AppResources.MessageAnswerNo);
|
||||||
|
|
||||||
|
if (l_oResult == false)
|
||||||
|
{
|
||||||
|
// User aborted closing and returning bike process
|
||||||
|
Log.ForContext<BookedOpen>().Information("User selected booked bike {l_oId} in order to close and return but action was canceled.", SelectedBike.Id);
|
||||||
|
|
||||||
|
BikesViewModel.IsIdle = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlock bike.
|
||||||
|
Log.ForContext<BookedOpen>().Information("Request to return bike {bike} detected.", SelectedBike);
|
||||||
|
|
||||||
|
// Stop polling before returning bike.
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||||
|
await ViewUpdateManager().StopUpdatePeridically();
|
||||||
|
|
||||||
|
// Close lock
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextClosingLock;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await ConnectorFactory(IsConnected).Command.ReturnAndCloseAsync(SelectedBike);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
|
||||||
|
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||||
|
? stateAwareException.State
|
||||||
|
: LockingState.UnknownDisconnected;
|
||||||
|
|
||||||
|
if (exception is OutOfReachException)
|
||||||
|
{
|
||||||
|
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||||
|
|
||||||
|
await ViewService.DisplayAlert(
|
||||||
|
AppResources.ErrorCloseLockTitle,
|
||||||
|
AppResources.ErrorCloseLockOutOfReachMessage,
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
}
|
||||||
|
else if (exception is CounldntCloseMovingException)
|
||||||
|
{
|
||||||
|
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||||
|
|
||||||
|
await ViewService.DisplayAlert(
|
||||||
|
AppResources.ErrorCloseLockTitle,
|
||||||
|
AppResources.ErrorCloseLockMovingMessage,
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
}
|
||||||
|
else if (exception is CouldntCloseBoldBlockedException)
|
||||||
|
{
|
||||||
|
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||||
|
|
||||||
|
await ViewService.DisplayAlert(
|
||||||
|
AppResources.ErrorCloseLockTitle,
|
||||||
|
AppResources.ErrorCloseLockBoldBlockedMessage,
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.ForContext<BookedOpen>().Error("Lock can not be closed. {Exception}", exception);
|
||||||
|
|
||||||
|
await ViewService.DisplayAlert(
|
||||||
|
AppResources.ErrorCloseLockTitle,
|
||||||
|
exception.Message,
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
}
|
||||||
|
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||||
|
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||||
|
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||||
|
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SelectedBike.LockInfo.State != LockingState.Closed)
|
||||||
|
{
|
||||||
|
Log.ForContext<BookedOpen>().Error($"Lock can not be closed. Invalid locking state state {SelectedBike.LockInfo.State} detected.");
|
||||||
|
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
|
||||||
|
await ViewService.DisplayAlert(
|
||||||
|
AppResources.ErrorCloseLockTitle,
|
||||||
|
SelectedBike.LockInfo.State == LockingState.Open
|
||||||
|
? AppResources.ErrorCloseLockStillOpenMessage
|
||||||
|
: string.Format(AppResources.ErrorCloseLockUnexpectedStateMessage, SelectedBike.LockInfo.State),
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||||
|
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||||
|
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||||
|
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock list to avoid multiple taps while copri action is pending.
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextReturningBike;
|
||||||
|
|
||||||
|
IsConnected = IsConnectedDelegate();
|
||||||
|
|
||||||
|
var feedBackUri = SelectedBike?.OperatorUri;
|
||||||
|
BookingFinishedModel bookingFinished;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bookingFinished = await ConnectorFactory(IsConnected).Command.DoReturn(
|
||||||
|
SelectedBike,
|
||||||
|
smartDevice: SmartDevice);
|
||||||
|
// If canceling bike succedes remove bike because it is not ready to be booked again
|
||||||
|
IsRemoveBikeRequired = true;
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
if (exception is WebConnectFailureException)
|
||||||
|
{
|
||||||
|
// Copri server is not reachable.
|
||||||
|
Log.ForContext<BookedOpen>().Information("User selected booked bike {bike} but returing failed (Copri server not reachable).", SelectedBike);
|
||||||
|
|
||||||
|
await ViewService.DisplayAdvancedAlert(
|
||||||
|
AppResources.ErrorReturnBikeNoWebTitle,
|
||||||
|
string.Format("{0}\r\n{1}", AppResources.ErrorReturnBikeNoWebMessage, WebConnectFailureException.GetHintToPossibleExceptionsReasons),
|
||||||
|
exception.Message,
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
}
|
||||||
|
else if (exception is NotAtStationException notAtStationException)
|
||||||
|
{
|
||||||
|
// COPRI returned an error.
|
||||||
|
Log.ForContext<BookedOpen>().Information("User selected booked bike {bike} but returing failed. COPRI returned an error.", SelectedBike);
|
||||||
|
|
||||||
|
await ViewService.DisplayAlert(
|
||||||
|
AppResources.ErrorReturnBikeTitle,
|
||||||
|
string.Format(AppResources.ErrorReturnBikeNotAtStationMessage, notAtStationException.StationNr, notAtStationException.Distance),
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
}
|
||||||
|
else if (exception is NoGPSDataException)
|
||||||
|
{
|
||||||
|
// COPRI returned an error.
|
||||||
|
Log.ForContext<BookedOpen>().Information("User selected booked bike {bike} but returing failed. COPRI returned an no GPS- data error.", SelectedBike);
|
||||||
|
|
||||||
|
await ViewService.DisplayAlert(
|
||||||
|
AppResources.ErrorReturnBikeTitle,
|
||||||
|
string.Format(AppResources.ErrorReturnBikeLockOpenNoGPSMessage),
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
}
|
||||||
|
else if (exception is ResponseException copriException)
|
||||||
|
{
|
||||||
|
// Copri server is not reachable.
|
||||||
|
Log.ForContext<BookedOpen>().Information("User selected booked bike {bike} but returing failed. COPRI returned an error.", SelectedBike);
|
||||||
|
|
||||||
|
await ViewService.DisplayAdvancedAlert(
|
||||||
|
"Statusfehler beim Zurückgeben des Rads!",
|
||||||
|
copriException.Message,
|
||||||
|
copriException.Response,
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.ForContext<BookedOpen>().Error("User selected booked bike {bike} but returning failed. {@l_oException}", SelectedBike.Id, exception);
|
||||||
|
|
||||||
|
await ViewService.DisplayAlert(
|
||||||
|
AppResources.ErrorReturnBikeTitle,
|
||||||
|
exception.Message,
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
}
|
||||||
|
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||||
|
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||||
|
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
BikesViewModel.IsIdle = true;
|
||||||
|
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.ForContext<BookedOpen>().Information("User returned bike {bike} successfully.", SelectedBike);
|
||||||
|
|
||||||
|
// Disconnect lock.
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextDisconnectingLock;
|
||||||
|
|
||||||
|
#if !USERFEEDBACKDLG_OFF
|
||||||
|
// Do get Feedback
|
||||||
|
var feedback = await ViewService.DisplayUserFeedbackPopup(bookingFinished?.Co2Saving);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await ConnectorFactory(IsConnected).Command.DoSubmitFeedback(
|
||||||
|
new UserFeedbackDto { BikeId = SelectedBike.Id, IsBikeBroken = feedback.IsBikeBroken, Message = feedback.Message },
|
||||||
|
feedBackUri);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
|
||||||
|
if (exception is ResponseException copriException)
|
||||||
|
{
|
||||||
|
// Copri server is not reachable.
|
||||||
|
Log.ForContext<BookedOpen>().Information("Submitting feedback for bike {bike} failed. COPRI returned an error.", SelectedBike);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.ForContext<BookedOpen>().Error("Submitting feedback for bike {bike} failed. {@l_oException}", SelectedBike.Id, exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
await ViewService.DisplayAlert(
|
||||||
|
AppResources.ErrorReturnSubmitFeedbackTitle,
|
||||||
|
AppResources.ErrorReturnSubmitFeedbackMessage,
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||||
|
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||||
|
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
BikesViewModel.IsIdle = true;
|
||||||
|
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (bookingFinished != null && bookingFinished.MiniSurvey.Questions.Count > 0)
|
||||||
|
{
|
||||||
|
await ViewService.PushModalAsync(ViewTypes.MiniSurvey);
|
||||||
|
}
|
||||||
|
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||||
|
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
BikesViewModel.IsIdle = true;
|
||||||
|
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Close lock in order to pause ride and update COPRI lock state.</summary>
|
||||||
|
public async Task<IRequestHandler> CloseLock()
|
||||||
|
{
|
||||||
|
// Unlock bike.
|
||||||
|
BikesViewModel.IsIdle = false;
|
||||||
|
Log.ForContext<BookedOpen>().Information("User request to lock bike {bike} in order to pause ride.", SelectedBike);
|
||||||
|
|
||||||
|
// Stop polling before returning bike.
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
|
||||||
|
await ViewUpdateManager().StopUpdatePeridically();
|
||||||
|
|
||||||
|
// Close lock
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextClosingLock;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await ConnectorFactory(IsConnected).Command.CloseLockAsync(SelectedBike);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
|
||||||
|
if (exception is OutOfReachException)
|
||||||
|
{
|
||||||
|
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. {Exception}", exception);
|
||||||
|
await ViewService.DisplayAlert(
|
||||||
|
AppResources.ErrorCloseLockTitle,
|
||||||
|
AppResources.ErrorCloseLockOutOfReachMessage,
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
}
|
||||||
|
else if (exception is CounldntCloseMovingException)
|
||||||
|
{
|
||||||
|
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||||
|
|
||||||
|
await ViewService.DisplayAlert(
|
||||||
|
AppResources.ErrorCloseLockTitle,
|
||||||
|
AppResources.ErrorCloseLockMovingMessage,
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
}
|
||||||
|
else if (exception is CouldntCloseBoldBlockedException)
|
||||||
|
{
|
||||||
|
Log.ForContext<BookedOpen>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||||
|
|
||||||
|
await ViewService.DisplayAlert(
|
||||||
|
AppResources.ErrorCloseLockTitle,
|
||||||
|
AppResources.ErrorCloseLockBoldBlockedMessage,
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.ForContext<BookedOpen>().Error("Lock can not be closed. {Exception}", exception);
|
||||||
|
await ViewService.DisplayAlert(
|
||||||
|
AppResources.ErrorCloseLockTitle,
|
||||||
|
exception.Message,
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedBike.LockInfo.State = exception is StateAwareException stateAwareException
|
||||||
|
? stateAwareException.State
|
||||||
|
: LockingState.UnknownDisconnected;
|
||||||
|
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||||
|
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||||
|
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
BikesViewModel.IsIdle = true;
|
||||||
|
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock list to avoid multiple taps while copri action is pending.
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdatingLockingState;
|
||||||
|
|
||||||
|
IsConnected = IsConnectedDelegate();
|
||||||
|
|
||||||
|
Log.ForContext<BookedOpen>().Information("User paused ride using {bike} successfully.", SelectedBike);
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||||
|
await ViewUpdateManager().StartUpdateAyncPeridically();
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
BikesViewModel.IsIdle = true;
|
||||||
|
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,135 @@
|
||||||
|
using System;
|
||||||
|
using Serilog;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using TINK.Model.Connector;
|
||||||
|
using TINK.Model.State;
|
||||||
|
using TINK.View;
|
||||||
|
using TINK.Repository.Exception;
|
||||||
|
using TINK.Services.Geolocation;
|
||||||
|
using TINK.MultilingualResources;
|
||||||
|
using TINK.Model.Bikes.Bike.CopriLock;
|
||||||
|
using TINK.Model.User;
|
||||||
|
using TINK.Model.Device;
|
||||||
|
|
||||||
|
namespace TINK.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
||||||
|
{
|
||||||
|
using IRequestHandler = BluetoothLock.IRequestHandler;
|
||||||
|
|
||||||
|
public class DisposableClosed : Base, IRequestHandler
|
||||||
|
{
|
||||||
|
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...).</param>
|
||||||
|
/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
|
||||||
|
public DisposableClosed(
|
||||||
|
IBikeInfoMutable selectedBike,
|
||||||
|
Func<bool> isConnectedDelegate,
|
||||||
|
Func<bool, IConnector> connectorFactory,
|
||||||
|
IGeolocation geolocation,
|
||||||
|
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
||||||
|
ISmartDevice smartDevice,
|
||||||
|
IViewService viewService,
|
||||||
|
IBikesViewModel bikesViewModel,
|
||||||
|
IUser activeUser) : base(
|
||||||
|
selectedBike,
|
||||||
|
AppResources.ActionOpenAndBook, // Button text: "Schloss öffnen & Rad mieten"
|
||||||
|
true, // Show copri button to enable reserving and opening
|
||||||
|
isConnectedDelegate,
|
||||||
|
connectorFactory,
|
||||||
|
geolocation,
|
||||||
|
viewUpdateManager,
|
||||||
|
smartDevice,
|
||||||
|
viewService,
|
||||||
|
bikesViewModel,
|
||||||
|
activeUser)
|
||||||
|
{
|
||||||
|
LockitButtonText = GetType().Name;
|
||||||
|
IsLockitButtonVisible = false; // If bike is not reserved/ booked app can not connect to lock
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets the bike state. </summary>
|
||||||
|
public override InUseStateEnum State => InUseStateEnum.Disposable;
|
||||||
|
|
||||||
|
/// <summary>Reserve bike and connect to lock.</summary>
|
||||||
|
public async Task<IRequestHandler> HandleRequestOption1() => await BookAndOpen();
|
||||||
|
|
||||||
|
public async Task<IRequestHandler> HandleRequestOption2() => await UnsupportedRequest();
|
||||||
|
|
||||||
|
/// <summary>Reserve bike and connect to lock.</summary>
|
||||||
|
public async Task<IRequestHandler> BookAndOpen()
|
||||||
|
{
|
||||||
|
BikesViewModel.IsIdle = false;
|
||||||
|
|
||||||
|
// Ask whether to really book bike?
|
||||||
|
var alertResult = await ViewService.DisplayAlert(
|
||||||
|
string.Empty,
|
||||||
|
string.Format(AppResources.QuestionOpenLockAndBookBike, SelectedBike.GetFullDisplayName()),
|
||||||
|
AppResources.MessageAnswerYes,
|
||||||
|
AppResources.MessageAnswerNo);
|
||||||
|
|
||||||
|
if (alertResult == false)
|
||||||
|
{
|
||||||
|
// User aborted booking process
|
||||||
|
Log.ForContext<DisposableClosed>().Information("User selected recently requested bike {bike} in order to reserve but did deny to book bike.", SelectedBike);
|
||||||
|
|
||||||
|
// Restart polling again.
|
||||||
|
BikesViewModel.IsIdle = true;
|
||||||
|
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.ForContext<DisposableClosed>().Information("User selected recently requested bike {bike} in order to book.", SelectedBike);
|
||||||
|
|
||||||
|
// Book bike prior to opening lock.
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextRentingBike;
|
||||||
|
IsConnected = IsConnectedDelegate();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await ConnectorFactory(IsConnected).Command.BookAndOpenAync(SelectedBike);
|
||||||
|
}
|
||||||
|
catch (Exception l_oException)
|
||||||
|
{
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
|
||||||
|
if (l_oException is WebConnectFailureException)
|
||||||
|
{
|
||||||
|
// Copri server is not reachable.
|
||||||
|
Log.ForContext<DisposableClosed>().Information("User selected recently requested bike {l_oId} but booking failed (Copri server not reachable).", SelectedBike.Id);
|
||||||
|
|
||||||
|
await ViewService.DisplayAdvancedAlert(
|
||||||
|
AppResources.MessageRentingBikeErrorConnectionTitle,
|
||||||
|
WebConnectFailureException.GetHintToPossibleExceptionsReasons,
|
||||||
|
l_oException.Message,
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.ForContext<DisposableClosed>().Error("User selected recently requested bike {l_oId} but reserving failed. {@l_oException}", SelectedBike.Id, l_oException);
|
||||||
|
|
||||||
|
await ViewService.DisplayAdvancedAlert(
|
||||||
|
AppResources.MessageRentingBikeErrorGeneralTitle,
|
||||||
|
string.Empty,
|
||||||
|
l_oException.Message,
|
||||||
|
AppResources.MessageAnswerOk);
|
||||||
|
}
|
||||||
|
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||||
|
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||||
|
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||||
|
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.ForContext<DisposableClosed>().Information("User reserved bike {bike} successfully.", SelectedBike);
|
||||||
|
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
|
||||||
|
await ViewUpdateManager().StartUpdateAyncPeridically(); // Restart polling again.
|
||||||
|
BikesViewModel.ActionText = string.Empty;
|
||||||
|
BikesViewModel.IsIdle = true; // Unlock GUI
|
||||||
|
return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, Geolocation, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Requst is not supported, button should be disabled. </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<IRequestHandler> UnsupportedRequest()
|
||||||
|
{
|
||||||
|
Log.ForContext<DisposableClosed>().Error("Click of unsupported button click detected.");
|
||||||
|
return await Task.FromResult<IRequestHandler>(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue