This commit is contained in:
Oliver Hauff 2022-01-22 18:30:23 +01:00
parent 578fcee611
commit 6ed1579494
34 changed files with 357 additions and 89 deletions

View file

@ -1,5 +1,5 @@
<?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.275" android:versionCode="275"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="internalOnly" package="com.TeilRad.LastenradBayern" android:versionName="3.0.276" android:versionCode="276">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="30" /> <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="30" />
<!-- 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 -->
@ -18,5 +18,19 @@
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" /> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
<application android:icon="@drawable/sharee" android:label="LastenradBayern" android:allowBackup="false"></application> <application android:icon="@drawable/sharee" android:label="LastenradBayern" android:allowBackup="false"></application>
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="http"/>
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https"/>
</intent>
<intent>
<action android:name="android.intent.action.SENDTO" />
<data android:scheme="mailto" />
</intent>
</queries>
<meta-data android:name="com.google.android.geo.API_KEY" android:value="000000000000000000000000000000000000000" /> <meta-data android:name="com.google.android.geo.API_KEY" android:value="000000000000000000000000000000000000000" />
</manifest> </manifest>

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
@ -24,6 +24,10 @@
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>mailto</string>
</array>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
<string>LaunchScreen</string> <string>LaunchScreen</string>
<key>XSLaunchImageAssets</key> <key>XSLaunchImageAssets</key>
@ -49,8 +53,8 @@
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>
<string>LastenradBayern</string> <string>LastenradBayern</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>275</string> <string>276</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>3.0.275</string> <string>3.0.276</string>
</dict> </dict>
</plist> </plist>

View file

@ -102,7 +102,11 @@
Text="{Binding TariffDescription.OperatorAgb}" Text="{Binding TariffDescription.OperatorAgb}"
IsVisible="{Binding TariffDescription.OperatorAgb, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.OperatorAgb, Converter={StaticResource Label_Converter}}"
Grid.Row="5" Grid.Row="5"
Grid.ColumnSpan="3"/> Grid.ColumnSpan="3">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding ShowAgbTappedCommand}"/>
</Label.GestureRecognizers>
</Label>
</Grid> </Grid>
</StackLayout> </StackLayout>
</ContentView> </ContentView>

View file

@ -2,6 +2,7 @@
using System; using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using TINK.Model.Device;
using TINK.ViewModel.FindBike; using TINK.ViewModel.FindBike;
using Xamarin.CommunityToolkit.Extensions; using Xamarin.CommunityToolkit.Extensions;
using Xamarin.Forms; using Xamarin.Forms;
@ -51,7 +52,8 @@ namespace TINK.View.FindBike
model.Polling, model.Polling,
(d, obj) => synchronizationContext.Post(d, obj), (d, obj) => synchronizationContext.Post(d, obj),
model.SmartDevice, model.SmartDevice,
this) this,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url))
{ {
IsReportLevelVerbose = model.IsReportLevelVerbose IsReportLevelVerbose = model.IsReportLevelVerbose
}; };

View file

@ -11,6 +11,7 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.MyBikes namespace TINK.View.MyBikes
{ {
using Serilog; using Serilog;
using TINK.Model.Device;
using TINK.ViewModel.MyBikes; using TINK.ViewModel.MyBikes;
using Xamarin.CommunityToolkit.Extensions; using Xamarin.CommunityToolkit.Extensions;
@ -68,7 +69,8 @@ namespace TINK.View.MyBikes
model.Polling, model.Polling,
(d, obj) => synchronizationContext.Post(d, obj), (d, obj) => synchronizationContext.Post(d, obj),
model.SmartDevice, model.SmartDevice,
this) this,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url))
{ {
IsReportLevelVerbose = model.IsReportLevelVerbose IsReportLevelVerbose = model.IsReportLevelVerbose
}; };

View file

@ -1,5 +1,5 @@
<?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.275" android:versionCode="275"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="internalOnly" package="com.TeilRad.Meinkonrad" android:versionName="3.0.276" android:versionCode="276">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="30" /> <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="30" />
<!-- 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 -->
@ -18,5 +18,19 @@
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" /> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
<application android:icon="@drawable/sharee" android:label="Meinkonrad" android:allowBackup="false"></application> <application android:icon="@drawable/sharee" android:label="Meinkonrad" android:allowBackup="false"></application>
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="http"/>
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https"/>
</intent>
<intent>
<action android:name="android.intent.action.SENDTO" />
<data android:scheme="mailto" />
</intent>
</queries>
<meta-data android:name="com.google.android.geo.API_KEY" android:value="000000000000000000000000000000000000000" /> <meta-data android:name="com.google.android.geo.API_KEY" android:value="000000000000000000000000000000000000000" />
</manifest> </manifest>

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
@ -24,6 +24,10 @@
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>mailto</string>
</array>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
<string>LaunchScreen</string> <string>LaunchScreen</string>
<key>XSLaunchImageAssets</key> <key>XSLaunchImageAssets</key>
@ -49,8 +53,8 @@
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>
<string>Mein konrad</string> <string>Mein konrad</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>275</string> <string>276</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>3.0.275</string> <string>3.0.276</string>
</dict> </dict>
</plist> </plist>

View file

@ -102,7 +102,11 @@
Text="{Binding TariffDescription.OperatorAgb}" Text="{Binding TariffDescription.OperatorAgb}"
IsVisible="{Binding TariffDescription.OperatorAgb, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.OperatorAgb, Converter={StaticResource Label_Converter}}"
Grid.Row="5" Grid.Row="5"
Grid.ColumnSpan="3"/> Grid.ColumnSpan="3">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding ShowAgbTappedCommand}"/>
</Label.GestureRecognizers>
</Label>
</Grid> </Grid>
</StackLayout> </StackLayout>
</ContentView> </ContentView>

View file

@ -2,6 +2,7 @@
using System; using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using TINK.Model.Device;
using TINK.ViewModel.FindBike; using TINK.ViewModel.FindBike;
using Xamarin.CommunityToolkit.Extensions; using Xamarin.CommunityToolkit.Extensions;
using Xamarin.Forms; using Xamarin.Forms;
@ -51,7 +52,8 @@ namespace TINK.View.FindBike
model.Polling, model.Polling,
(d, obj) => synchronizationContext.Post(d, obj), (d, obj) => synchronizationContext.Post(d, obj),
model.SmartDevice, model.SmartDevice,
this) this,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url))
{ {
IsReportLevelVerbose = model.IsReportLevelVerbose IsReportLevelVerbose = model.IsReportLevelVerbose
}; };

View file

@ -11,6 +11,7 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.MyBikes namespace TINK.View.MyBikes
{ {
using Serilog; using Serilog;
using TINK.Model.Device;
using TINK.ViewModel.MyBikes; using TINK.ViewModel.MyBikes;
using Xamarin.CommunityToolkit.Extensions; using Xamarin.CommunityToolkit.Extensions;
@ -68,7 +69,8 @@ namespace TINK.View.MyBikes
model.Polling, model.Polling,
(d, obj) => synchronizationContext.Post(d, obj), (d, obj) => synchronizationContext.Post(d, obj),
model.SmartDevice, model.SmartDevice,
this) this,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url))
{ {
IsReportLevelVerbose = model.IsReportLevelVerbose IsReportLevelVerbose = model.IsReportLevelVerbose
}; };

View file

@ -1,5 +1,5 @@
<?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.275" android:versionCode="275"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="preferExternal" package="com.hauffware.sharee" android:versionName="3.0.276" android:versionCode="276">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="30" /> <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="30" />
<!-- 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 -->
@ -18,5 +18,19 @@
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" /> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
<application android:icon="@drawable/sharee" android:label="sharee.bike" android:allowBackup="false"></application> <application android:icon="@drawable/sharee" android:label="sharee.bike" android:allowBackup="false"></application>
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="http"/>
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https"/>
</intent>
<intent>
<action android:name="android.intent.action.SENDTO" />
<data android:scheme="mailto" />
</intent>
</queries>
<meta-data android:name="com.google.android.geo.API_KEY" android:value="000000000000000000000000000000000000000" /> <meta-data android:name="com.google.android.geo.API_KEY" android:value="000000000000000000000000000000000000000" />
</manifest> </manifest>

View file

@ -24,6 +24,10 @@
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>mailto</string>
</array>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
<string>LaunchScreen</string> <string>LaunchScreen</string>
<key>XSLaunchImageAssets</key> <key>XSLaunchImageAssets</key>
@ -49,8 +53,8 @@
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>
<string>sharee.bike</string> <string>sharee.bike</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>275</string> <string>276</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>3.0.275</string> <string>3.0.276</string>
</dict> </dict>
</plist> </plist>

View file

@ -102,7 +102,11 @@
Text="{Binding TariffDescription.OperatorAgb}" Text="{Binding TariffDescription.OperatorAgb}"
IsVisible="{Binding TariffDescription.OperatorAgb, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.OperatorAgb, Converter={StaticResource Label_Converter}}"
Grid.Row="5" Grid.Row="5"
Grid.ColumnSpan="3"/> Grid.ColumnSpan="3">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding ShowAgbTappedCommand}"/>
</Label.GestureRecognizers>
</Label>
</Grid> </Grid>
</StackLayout> </StackLayout>
</ContentView> </ContentView>

View file

@ -2,6 +2,7 @@
using System; using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using TINK.Model.Device;
using TINK.ViewModel.FindBike; using TINK.ViewModel.FindBike;
using Xamarin.CommunityToolkit.Extensions; using Xamarin.CommunityToolkit.Extensions;
using Xamarin.Forms; using Xamarin.Forms;
@ -51,7 +52,8 @@ namespace TINK.View.FindBike
model.Polling, model.Polling,
(d, obj) => synchronizationContext.Post(d, obj), (d, obj) => synchronizationContext.Post(d, obj),
model.SmartDevice, model.SmartDevice,
this) this,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url))
{ {
IsReportLevelVerbose = model.IsReportLevelVerbose IsReportLevelVerbose = model.IsReportLevelVerbose
}; };

View file

@ -11,6 +11,7 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.MyBikes namespace TINK.View.MyBikes
{ {
using Serilog; using Serilog;
using TINK.Model.Device;
using TINK.ViewModel.MyBikes; using TINK.ViewModel.MyBikes;
using Xamarin.CommunityToolkit.Extensions; using Xamarin.CommunityToolkit.Extensions;
@ -68,7 +69,8 @@ namespace TINK.View.MyBikes
model.Polling, model.Polling,
(d, obj) => synchronizationContext.Post(d, obj), (d, obj) => synchronizationContext.Post(d, obj),
model.SmartDevice, model.SmartDevice,
this) this,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url))
{ {
IsReportLevelVerbose = model.IsReportLevelVerbose IsReportLevelVerbose = model.IsReportLevelVerbose
}; };

View file

@ -476,8 +476,8 @@ namespace TINK.Model
AppResources.ChangeLog3_0_266 AppResources.ChangeLog3_0_266
}, },
{ {
new Version(3, 0, 274), new Version(3, 0, 276),
AppResources.ChangeLog3_0_231 // Minor improvements. AppResources.ChangeLog3_0_276
} }
}; };

View file

@ -909,6 +909,17 @@ namespace TINK.MultilingualResources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Link to operator AGB is displayed if required.
///Display of status information extended.
///Bugfix: Sending support mails works again. .
/// </summary>
public static string ChangeLog3_0_276 {
get {
return ResourceManager.GetString("ChangeLog3_0_276", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Lock of rented bike can not be found.. /// Looks up a localized string similar to Lock of rented bike can not be found..
/// </summary> /// </summary>
@ -1818,6 +1829,16 @@ namespace TINK.MultilingualResources {
} }
} }
/// <summary>
/// Looks up a localized string similar to An error occurred switching from cargo bikes/ city bikes.
///{0}.
/// </summary>
public static string MessageMapPageErrorSwitch {
get {
return ResourceManager.GetString("MessageMapPageErrorSwitch", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Urgent questions?. /// Looks up a localized string similar to Urgent questions?.
/// </summary> /// </summary>

View file

@ -733,4 +733,13 @@ Deep linking wird unterstützt.</value>
<data name="ChangeLog3_0_266" xml:space="preserve"> <data name="ChangeLog3_0_266" xml:space="preserve">
<value>Abfrage Erlaubnis für Zugriff azf Standort verbessert.</value> <value>Abfrage Erlaubnis für Zugriff azf Standort verbessert.</value>
</data> </data>
<data name="ChangeLog3_0_276" xml:space="preserve">
<value>Link auf Betreiber-AGB wird bei Bedarf angezeigt.
Anzeige von Statusinformationen erweitert.
Fehlerbehebung: Supportmails können wieder verschickt werden.</value>
</data>
<data name="MessageMapPageErrorSwitch" xml:space="preserve">
<value>Beim Umschalten zwischen Lasten-/ Stadträdern ist ein Fehler aufgetreten.
{0}</value>
</data>
</root> </root>

View file

@ -828,4 +828,13 @@ App supports deep linking.</value>
<data name="ChangeLog3_0_266" xml:space="preserve"> <data name="ChangeLog3_0_266" xml:space="preserve">
<value>Location permissions handling improved.</value> <value>Location permissions handling improved.</value>
</data> </data>
<data name="ChangeLog3_0_276" xml:space="preserve">
<value>Link to operator AGB is displayed if required.
Display of status information extended.
Bugfix: Sending support mails works again. </value>
</data>
<data name="MessageMapPageErrorSwitch" xml:space="preserve">
<value>An error occurred switching from cargo bikes/ city bikes.
{0}</value>
</data>
</root> </root>

View file

@ -984,6 +984,20 @@ Deep linking wird unterstützt.</target>
<source>Location permissions handling improved.</source> <source>Location permissions handling improved.</source>
<target state="translated">Abfrage Erlaubnis für Zugriff azf Standort verbessert.</target> <target state="translated">Abfrage Erlaubnis für Zugriff azf Standort verbessert.</target>
</trans-unit> </trans-unit>
<trans-unit id="ChangeLog3_0_276" translate="yes" xml:space="preserve">
<source>Link to operator AGB is displayed if required.
Display of status information extended.
Bugfix: Sending support mails works again. </source>
<target state="translated">Link auf Betreiber-AGB wird bei Bedarf angezeigt.
Anzeige von Statusinformationen erweitert.
Fehlerbehebung: Supportmails können wieder verschickt werden.</target>
</trans-unit>
<trans-unit id="MessageMapPageErrorSwitch" translate="yes" xml:space="preserve">
<source>An error occurred switching from cargo bikes/ city bikes.
{0}</source>
<target state="translated">Beim Umschalten zwischen Lasten-/ Stadträdern ist ein Fehler aufgetreten.
{0}</target>
</trans-unit>
</group> </group>
</body> </body>
</file> </file>

View file

@ -36,6 +36,7 @@ namespace TINK.ViewModel.Bikes.Bike.BC
/// <param name="activeUser">Object holding logged in user or an empty user object.</param> /// <param name="activeUser">Object holding logged in user or an empty user object.</param>
/// <param name="stateInfoProvider">Provides in use state information.</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="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
/// <param name="openUrlInBrowser">Delegate to open browser.</param>
public BikeViewModel( public BikeViewModel(
Func<bool> isConnectedDelegate, Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory, Func<bool, IConnector> connectorFactory,
@ -46,7 +47,8 @@ namespace TINK.ViewModel.Bikes.Bike.BC
BikeInfoMutable selectedBike, BikeInfoMutable selectedBike,
IUser activeUser, IUser activeUser,
IInUseStateInfoProvider stateInfoProvider, IInUseStateInfoProvider stateInfoProvider,
IBikesViewModel bikesViewModel) : base(isConnectedDelegate, connectorFactory, bikeRemoveDelegate, viewUpdateManager, smartDevice, viewService, selectedBike, activeUser, stateInfoProvider, bikesViewModel) IBikesViewModel bikesViewModel,
Action<string> openUrlInBrowser) : base(isConnectedDelegate, connectorFactory, bikeRemoveDelegate, viewUpdateManager, smartDevice, viewService, selectedBike, activeUser, stateInfoProvider, bikesViewModel, openUrlInBrowser)
{ {
RequestHandler = activeUser.IsLoggedIn RequestHandler = activeUser.IsLoggedIn
? RequestHandlerFactory.Create( ? RequestHandlerFactory.Create(

View file

@ -1,5 +1,7 @@
using System; using Serilog;
using System;
using System.ComponentModel; using System.ComponentModel;
using System.Text.RegularExpressions;
using TINK.Model.Connector; using TINK.Model.Connector;
using TINK.Model.Device; using TINK.Model.Device;
using TINK.Model.State; using TINK.Model.State;
@ -62,6 +64,9 @@ namespace TINK.ViewModel.Bikes.Bike
/// <summary>View model to be used for progress report and unlocking/ locking view.</summary> /// <summary>View model to be used for progress report and unlocking/ locking view.</summary>
protected IBikesViewModel BikesViewModel { get; } protected IBikesViewModel BikesViewModel { get; }
/// <summary> Delegate to open browser. </summary>
private Action<string> OpenUrlInBrowser;
/// <summary> /// <summary>
/// Notifies GUI about changes. /// Notifies GUI about changes.
/// </summary> /// </summary>
@ -83,6 +88,7 @@ namespace TINK.ViewModel.Bikes.Bike
/// <param name="activeUser">Object holding logged in user or an empty user object.</param> /// <param name="activeUser">Object holding logged in user or an empty user object.</param>
/// <param name="stateInfoProvider">Provides in use state information.</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="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
/// <param name="openUrlInBrowser">Delegate to open browser.</param>
public BikeViewModelBase( public BikeViewModelBase(
Func<bool> isConnectedDelegate, Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory, Func<bool, IConnector> connectorFactory,
@ -93,7 +99,8 @@ namespace TINK.ViewModel.Bikes.Bike
BikeInfoMutable selectedBike, BikeInfoMutable selectedBike,
IUser activeUser, IUser activeUser,
IInUseStateInfoProvider stateInfoProvider, IInUseStateInfoProvider stateInfoProvider,
IBikesViewModel bikesViewModel) IBikesViewModel bikesViewModel,
Action<string> openUrlInBrowser)
{ {
IsConnectedDelegate = isConnectedDelegate; IsConnectedDelegate = isConnectedDelegate;
@ -121,6 +128,8 @@ namespace TINK.ViewModel.Bikes.Bike
BikesViewModel = bikesViewModel BikesViewModel = bikesViewModel
?? throw new ArgumentException($"Can not construct {GetType().Name}-object. {nameof(bikesViewModel)} must not be null."); ?? throw new ArgumentException($"Can not construct {GetType().Name}-object. {nameof(bikesViewModel)} must not be null.");
OpenUrlInBrowser = openUrlInBrowser ?? (url => { Log.ForContext<BikeViewModelBase>().Error($"No browse service avialble to upen {url}."); });
} }
/// <summary> /// <summary>
@ -309,5 +318,63 @@ namespace TINK.ViewModel.Bikes.Bike
/// <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; }
/// <summary> Command object to bind login page redirect link to view model.</summary>
public System.Windows.Input.ICommand ShowAgbTappedCommand
#if USEFLYOUT
=> new Xamarin.Forms.Command(() => ShowAgbPageAsync());
#else
=> new Xamarin.Forms.Command(async () => await OpenLoginPageAsync());
#endif
/// <summary> Opens login page. </summary>
#if USEFLYOUT
public void ShowAgbPageAsync()
#else
public async Task ShowAgbPageAsync()
#endif
{
try
{
// Switch to map page
#if USEFLYOUT
var url = GetUrlFirstOrDefault(TariffDescription.OperatorAgb);
if (string.IsNullOrEmpty(url))
{
// No url contained in string.
return;
}
OpenUrlInBrowser(url);
#endif
}
catch (Exception p_oException)
{
Log.Error("An unexpected error occurred opening broser. {@Exception}", p_oException);
return;
}
}
/// <summary> Gets first url from text.</summary>
/// <param name="htmlSource">url to extract text from.</param>
/// <returns>Gets first url or an empty string if on url is contained in text.</returns>
public static string GetUrlFirstOrDefault(string htmlSource)
{
if (string.IsNullOrEmpty(htmlSource))
return string.Empty;
try
{
var matches = new Regex(@"https://[-a-zA-Z0-9+&@#/%?=~_|!:, .;]*[-a-zA-Z0-9+&@#/%=~_|]").Matches(htmlSource);
return matches.Count > 0
? matches[0].Value
: string.Empty;
} catch (Exception e)
{
Log.ForContext<BikeViewModelBase>().Error("Extracting URL failed. {Exception}", e);
return string.Empty;
}
}
} }
} }

View file

@ -13,6 +13,7 @@ namespace TINK.ViewModel.Bikes.Bike
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...).</param> /// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...).</param>
/// <param name="stateInfoProvider">Provides in use state information.</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="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
/// <param name="openUrlInBrowser">Delegate to open browser.</param>
public static BikeViewModelBase Create( public static BikeViewModelBase Create(
Func<bool> isConnectedDelegate, Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory, Func<bool, IConnector> connectorFactory,
@ -25,7 +26,8 @@ namespace TINK.ViewModel.Bikes.Bike
Model.Bike.BC.BikeInfoMutable bikeInfo, Model.Bike.BC.BikeInfoMutable bikeInfo,
IUser activeUser, IUser activeUser,
IInUseStateInfoProvider stateInfoProvider, IInUseStateInfoProvider stateInfoProvider,
IBikesViewModel bikesViewModel) IBikesViewModel bikesViewModel,
Action<string> openUrlInBrowser)
{ {
return bikeInfo as Model.Bikes.Bike.BluetoothLock.IBikeInfoMutable != null return bikeInfo as Model.Bikes.Bike.BluetoothLock.IBikeInfoMutable != null
? new BluetoothLock.BikeViewModel( ? new BluetoothLock.BikeViewModel(
@ -40,7 +42,8 @@ namespace TINK.ViewModel.Bikes.Bike
bikeInfo as Model.Bike.BluetoothLock.BikeInfoMutable, bikeInfo as Model.Bike.BluetoothLock.BikeInfoMutable,
activeUser, activeUser,
stateInfoProvider, stateInfoProvider,
bikesViewModel) as BikeViewModelBase bikesViewModel,
openUrlInBrowser) as BikeViewModelBase
: new BC.BikeViewModel( : new BC.BikeViewModel(
isConnectedDelegate, isConnectedDelegate,
connectorFactory, connectorFactory,
@ -51,7 +54,8 @@ namespace TINK.ViewModel.Bikes.Bike
bikeInfo, bikeInfo,
activeUser, activeUser,
stateInfoProvider, stateInfoProvider,
bikesViewModel); bikesViewModel,
openUrlInBrowser);
} }
} }
} }

View file

@ -83,6 +83,7 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
/// <param name="user">Object holding logged in user or an empty user object.</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="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="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
/// <param name="openUrlInBrowser">Delegate to open browser.</param>
public BikeViewModel( public BikeViewModel(
Func<bool> isConnectedDelegate, Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory, Func<bool, IConnector> connectorFactory,
@ -95,7 +96,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
BikeInfoMutable selectedBike, BikeInfoMutable selectedBike,
IUser user, IUser user,
IInUseStateInfoProvider stateInfoProvider, IInUseStateInfoProvider stateInfoProvider,
IBikesViewModel bikesViewModel) : base(isConnectedDelegate, connectorFactory, bikeRemoveDelegate, viewUpdateManager, smartDevice, viewService, selectedBike, user, stateInfoProvider, bikesViewModel) IBikesViewModel bikesViewModel,
Action<string> openUrlInBrowser) : base(isConnectedDelegate, connectorFactory, bikeRemoveDelegate, viewUpdateManager, smartDevice, viewService, selectedBike, user, stateInfoProvider, bikesViewModel, openUrlInBrowser)
{ {
RequestHandler = user.IsLoggedIn RequestHandler = user.IsLoggedIn
? RequestHandlerFactory.Create( ? RequestHandlerFactory.Create(

View file

@ -54,6 +54,9 @@ namespace TINK.ViewModel.Bikes
/// <summary> Action to post to GUI thread.</summary> /// <summary> Action to post to GUI thread.</summary>
public Action<SendOrPostCallback, object> PostAction { get; } public Action<SendOrPostCallback, object> PostAction { get; }
/// <summary> Delegate to open browser. </summary>
private Action<string> OpenUrlInBrowser { get; }
/// <summary>Enables derived class to fire property changed event. </summary> /// <summary>Enables derived class to fire property changed event. </summary>
/// <param name="p_oEventArgs"></param> /// <param name="p_oEventArgs"></param>
protected override void OnPropertyChanged(PropertyChangedEventArgs p_oEventArgs) => base.OnPropertyChanged(p_oEventArgs); protected override void OnPropertyChanged(PropertyChangedEventArgs p_oEventArgs) => base.OnPropertyChanged(p_oEventArgs);
@ -89,6 +92,7 @@ namespace TINK.ViewModel.Bikes
/// <param name="postAction">Executes actions on GUI thread.</param> /// <param name="postAction">Executes actions on GUI thread.</param>
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...)</param> /// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...)</param>
/// <param name="viewService">Interface to actuate methodes on GUI.</param> /// <param name="viewService">Interface to actuate methodes on GUI.</param>
/// <param name="openUrlInBrowser">Delegate to open browser.</param>
public BikesViewModel( public BikesViewModel(
User user, User user,
ILocationPermission permissions, ILocationPermission permissions,
@ -102,6 +106,7 @@ namespace TINK.ViewModel.Bikes
Action<SendOrPostCallback, object> postAction, Action<SendOrPostCallback, object> postAction,
ISmartDevice smartDevice, ISmartDevice smartDevice,
IViewService viewService, IViewService viewService,
Action<string> openUrlInBrowser,
Func<IInUseStateInfoProvider> itemFactory) Func<IInUseStateInfoProvider> itemFactory)
{ {
User = user User = user
@ -150,6 +155,8 @@ namespace TINK.ViewModel.Bikes
isConnected = IsConnectedDelegate(); isConnected = IsConnectedDelegate();
OpenUrlInBrowser = openUrlInBrowser;
CollectionChanged += (sender, eventargs) => CollectionChanged += (sender, eventargs) =>
{ {
// Notify about bikes occuring/ vanishing from list. // Notify about bikes occuring/ vanishing from list.
@ -186,7 +193,8 @@ namespace TINK.ViewModel.Bikes
l_oBike, l_oBike,
User, User,
m_oItemFactory(), m_oItemFactory(),
this); this,
OpenUrlInBrowser);
bikeViewModel.PropertyChanged += OnBikeRequestHandlerPropertyChanged; bikeViewModel.PropertyChanged += OnBikeRequestHandlerPropertyChanged;

View file

@ -36,9 +36,6 @@ namespace TINK.ViewModel.BikesAtStation
/// </summary> /// </summary>
private readonly IStation m_oStation; private readonly IStation m_oStation;
/// <summary> Holds a reference to the external trigger service. </summary>
private Action<string> OpenUrlInExternalBrowser { get; }
/// <summary> /// <summary>
/// Constructs bike collection view model. /// Constructs bike collection view model.
/// </summary> /// </summary>
@ -70,11 +67,8 @@ namespace TINK.ViewModel.BikesAtStation
Action<string> openUrlInExternalBrowser, Action<string> openUrlInExternalBrowser,
Action<SendOrPostCallback, object> postAction, Action<SendOrPostCallback, object> postAction,
ISmartDevice smartDevice, ISmartDevice smartDevice,
IViewService viewService) : base(user, permissions, bluetoothLE, runtimPlatform, isConnectedDelegate, connectorFactory, geolocation, lockService, polling, postAction, smartDevice, viewService, () => new BikeAtStationInUseStateInfoProvider()) IViewService viewService) : base(user, permissions, bluetoothLE, runtimPlatform, isConnectedDelegate, connectorFactory, geolocation, lockService, polling, postAction, smartDevice, viewService, openUrlInExternalBrowser, () => new BikeAtStationInUseStateInfoProvider())
{ {
OpenUrlInExternalBrowser = openUrlInExternalBrowser
?? throw new ArgumentException("Can not instantiate login page view model- object. No user external browse service available.");
m_oStation = selectedStation; m_oStation = selectedStation;
Title = string.Format(m_oStation?.StationName != null Title = string.Format(m_oStation?.StationName != null
@ -387,20 +381,5 @@ namespace TINK.ViewModel.BikesAtStation
base.OnPropertyChanged(new PropertyChangedEventArgs(nameof(NoBikesAtStationText))); base.OnPropertyChanged(new PropertyChangedEventArgs(nameof(NoBikesAtStationText)));
} }
} }
/// <summary> Opens login page.</summary>
/// <param name="url">Url to open.</param>
private void RegisterRequest(string url)
{
try
{
OpenUrlInExternalBrowser(url);
}
catch (Exception p_oException)
{
Log.Error("Ein unerwarteter Fehler ist auf der Login Seite beim Öffnen eines Browsers, Seite {url}, aufgetreten. {@Exception}", url, p_oException);
return;
}
}
} }
} }

View file

@ -75,6 +75,7 @@ namespace TINK.ViewModel.FindBike
/// <param name="postAction">Executes actions on GUI thread.</param> /// <param name="postAction">Executes actions on GUI thread.</param>
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...).</param> /// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...).</param>
/// <param name="viewService">Interface to actuate methodes on GUI.</param> /// <param name="viewService">Interface to actuate methodes on GUI.</param>
/// <param name="openUrlInBrowser">Delegate to open browser.</param>
public FindBikePageViewModel( public FindBikePageViewModel(
User p_oUser, User p_oUser,
ILocationPermission permissions, ILocationPermission permissions,
@ -88,7 +89,8 @@ namespace TINK.ViewModel.FindBike
PollingParameters polling, PollingParameters polling,
Action<SendOrPostCallback, object> postAction, Action<SendOrPostCallback, object> postAction,
ISmartDevice smartDevice, ISmartDevice smartDevice,
IViewService viewService) : base(p_oUser, permissions, bluetoothLE, runtimPlatform, isConnectedDelegate, connectorFactory, geolocation, lockService, polling, postAction, smartDevice, viewService, () => new MyBikeInUseStateInfoProvider()) IViewService viewService,
Action<string> openUrlInBrowser) : base(p_oUser, permissions, bluetoothLE, runtimPlatform, isConnectedDelegate, connectorFactory, geolocation, lockService, polling, postAction, smartDevice, viewService, openUrlInBrowser, () => new MyBikeInUseStateInfoProvider())
{ {
CollectionChanged += (sender, eventargs) => CollectionChanged += (sender, eventargs) =>
{ {

View file

@ -333,7 +333,7 @@ namespace TINK.ViewModel.Map
await ViewService.DisplayAlert( await ViewService.DisplayAlert(
"Information", "Information",
resultStationsAndBikes.GeneralData.MerchantMessage, resultStationsAndBikes.GeneralData.MerchantMessage,
"OK"); AppResources.MessageAnswerOk);
WasMerchantMessageAlreadyShown = true; WasMerchantMessageAlreadyShown = true;
} }
@ -876,9 +876,13 @@ namespace TINK.ViewModel.Map
{ {
try try
{ {
IsMapPageEnabled = false;
IsRunning = true;
Log.ForContext<MapPageViewModel>().Information($"Request to toggle to \"{p_strSelectedFilter}\"."); Log.ForContext<MapPageViewModel>().Information($"Request to toggle to \"{p_strSelectedFilter}\".");
// Stop polling. // Stop polling.
ActionText = AppResources.ActivityTextOneMomentPlease;
await m_oViewUpdateManager.StopUpdatePeridically(); await m_oViewUpdateManager.StopUpdatePeridically();
// Clear error info. // Clear error info.
@ -896,27 +900,29 @@ namespace TINK.ViewModel.Map
Pins.Clear(); Pins.Clear();
// Check location permission // Check location permission
ActionText = AppResources.ActivityTextRequestingLocationPermissions;
var status = await PermissionsService.CheckStatusAsync(); var status = await PermissionsService.CheckStatusAsync();
if (TinkApp.CenterMapToCurrentLocation if (TinkApp.CenterMapToCurrentLocation
&& !GeolocationService.IsSimulation && !GeolocationService.IsSimulation
&& status != Status.Granted) && status != Status.Granted)
{ {
var permissionResult = await PermissionsService.RequestAsync(); status = await PermissionsService.RequestAsync();
if (permissionResult != Status.Granted) if (status != Status.Granted)
{ {
var dialogResult = await ViewService.DisplayAlert( var dialogResult = await ViewService.DisplayAlert(
AppResources.MessageTitleHint, AppResources.MessageTitleHint,
AppResources.MessageBikesManagementLocationPermission, AppResources.MessageCenterMapLocationPermissionOpenDialog,
"Ja", AppResources.MessageAnswerYes,
"Nein"); AppResources.MessageAnswerNo);
if (dialogResult) if (dialogResult)
{ {
// User decided to give access to locations permissions. // User decided to give access to locations permissions.
PermissionsService.OpenAppSettings(); PermissionsService.OpenAppSettings();
IsMapPageEnabled = true;
ActionText = ""; ActionText = "";
IsRunning = false;
IsMapPageEnabled = true;
return; return;
} }
} }
@ -930,13 +936,16 @@ namespace TINK.ViewModel.Map
AppResources.MessageTitleHint, AppResources.MessageTitleHint,
AppResources.MessageBikesManagementBluetoothActivation, AppResources.MessageBikesManagementBluetoothActivation,
AppResources.MessageAnswerOk); AppResources.MessageAnswerOk);
IsMapPageEnabled = true;
ActionText = ""; ActionText = "";
IsRunning = false;
IsMapPageEnabled = true;
return; return;
} }
} }
// Move and scale before getting stations and bikes which takes some time. // Move and scale before getting stations and bikes which takes some time.
ActionText = AppResources.ActivityTextCenterMap;
if (TinkApp.CenterMapToCurrentLocation) if (TinkApp.CenterMapToCurrentLocation)
{ {
Location currentLocation = null; Location currentLocation = null;
@ -962,6 +971,7 @@ namespace TINK.ViewModel.Map
// Update stations // Update stations
MoveAndScale(m_oMoveToRegionDelegate, TinkApp.ActiveMapSpan); MoveAndScale(m_oMoveToRegionDelegate, TinkApp.ActiveMapSpan);
ActionText = AppResources.ActivityTextMapLoadingStationsAndBikes;
IsConnected = TinkApp.GetIsConnected(); IsConnected = TinkApp.GetIsConnected();
var resultStationsAndBikes = await TinkApp.GetConnector(IsConnected).Query.GetBikesAndStationsAsync(); var resultStationsAndBikes = await TinkApp.GetConnector(IsConnected).Query.GetBikesAndStationsAsync();
@ -990,16 +1000,24 @@ namespace TINK.ViewModel.Map
// Excpetions are handled insde update task; // Excpetions are handled insde update task;
} }
ActionText = "";
IsRunning = false;
IsMapPageEnabled = true;
Log.ForContext<MapPageViewModel>().Information($"Toggle to \"{p_strSelectedFilter}\" done."); Log.ForContext<MapPageViewModel>().Information($"Toggle to \"{p_strSelectedFilter}\" done.");
} }
catch (Exception l_oException) catch (Exception l_oException)
{ {
Log.ForContext<MapPageViewModel>().Error("An error occurred switching view Cargobike/ Citybike.{}"); Log.ForContext<MapPageViewModel>().Error("An error occurred switching view Cargobike/ Citybike.{}");
ActionText = "";
IsRunning = false;
await ViewService.DisplayAlert( await ViewService.DisplayAlert(
"Fehler", "Fehler",
$"Beim Umschalten TINK/ Konrad ist ein Fehler aufgetreten.\r\n{l_oException.Message}", AppResources.MessageMapPageErrorSwitch,
"OK"); String.Format(AppResources.MessageMapPageErrorSwitch, l_oException.Message),
AppResources.MessageAnswerOk);
IsMapPageEnabled = true;
} }
} }

View file

@ -47,6 +47,7 @@ namespace TINK.ViewModel.MyBikes
/// <param name="postAction">Executes actions on GUI thread.</param> /// <param name="postAction">Executes actions on GUI thread.</param>
/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...).</param> /// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...).</param>
/// <param name="viewService">Interface to actuate methodes on GUI.</param> /// <param name="viewService">Interface to actuate methodes on GUI.</param>
/// <param name="openUrlInBrowser">Delegate to open browser.</param>
public MyBikesPageViewModel( public MyBikesPageViewModel(
User p_oUser, User p_oUser,
ILocationPermission permissions, ILocationPermission permissions,
@ -60,7 +61,8 @@ namespace TINK.ViewModel.MyBikes
PollingParameters p_oPolling, PollingParameters p_oPolling,
Action<SendOrPostCallback, object> postAction, Action<SendOrPostCallback, object> postAction,
ISmartDevice smartDevice, ISmartDevice smartDevice,
IViewService viewService) : base(p_oUser, permissions, bluetoothLE, runtimPlatform, isConnectedDelegate, connectorFactory, geolocation, lockService, p_oPolling, postAction, smartDevice, viewService, () => new MyBikeInUseStateInfoProvider()) IViewService viewService,
Action<string> openUrlInBrowser) : base(p_oUser, permissions, bluetoothLE, runtimPlatform, isConnectedDelegate, connectorFactory, geolocation, lockService, p_oPolling, postAction, smartDevice, viewService, openUrlInBrowser, () => new MyBikeInUseStateInfoProvider())
{ {
CollectionChanged += (sender, eventargs) => CollectionChanged += (sender, eventargs) =>
{ {

View file

@ -0,0 +1,33 @@
using NUnit.Framework;
using TINK.ViewModel.Bikes.Bike;
namespace TestShareeLib.ViewModel.Bikes.Bike
{
[TestFixture]
public class TestBikeViewModelBase
{
[Test]
public void TestGetUrl()
{
Assert.That(
BikeViewModelBase.GetUrlFirstOrDefault(@"Mit der Mietrad Anmietung wird folgender Betreiber <a href='https://shareeapp-fr01.copri.eu/site/agb.html' target='_blank'>AGB</a> zugestimmt (als Demo sharee AGB)."),
Is.EqualTo(@"https://shareeapp-fr01.copri.eu/site/agb.html"));
}
[Test]
public void TestGetUrlNoProtocol()
{
Assert.That(
BikeViewModelBase.GetUrlFirstOrDefault(@"Mit der Mietrad Anmietung wird folgender Betreiber <a href='shareeapp-fr01.copri.eu/site/agb.html' target='_blank'>AGB</a> zugestimmt (als Demo sharee AGB)."),
Is.EqualTo(""));
}
[Test]
public void TestGetUrlNull()
{
Assert.That(
BikeViewModelBase.GetUrlFirstOrDefault(null),
Is.EqualTo(""));
}
}
}

View file

@ -68,7 +68,8 @@ namespace UITest.Fixtures.ViewModel
l_oBike, l_oBike,
l_oUser, l_oUser,
new MyBikeInUseStateInfoProvider(), new MyBikeInUseStateInfoProvider(),
MockRepository.GenerateStub<IBikesViewModel>()); MockRepository.GenerateStub<IBikesViewModel>(),
url => { });
Assert.AreEqual("2", l_oViewModel.Name); Assert.AreEqual("2", l_oViewModel.Name);
Assert.AreEqual("", l_oViewModel.DisplayId); Assert.AreEqual("", l_oViewModel.DisplayId);
@ -94,7 +95,8 @@ namespace UITest.Fixtures.ViewModel
bike, bike,
user, user,
new BikeAtStationInUseStateInfoProvider(), new BikeAtStationInUseStateInfoProvider(),
MockRepository.GenerateStub<IBikesViewModel>())); MockRepository.GenerateStub<IBikesViewModel>(),
url => { }));
Assert.AreEqual("Still 15 minutes reserved.", l_oViewModel.StateText); Assert.AreEqual("Still 15 minutes reserved.", l_oViewModel.StateText);
} }
@ -116,7 +118,8 @@ namespace UITest.Fixtures.ViewModel
bike, bike,
user, user,
new BikeAtStationInUseStateInfoProvider(), new BikeAtStationInUseStateInfoProvider(),
MockRepository.GenerateStub<IBikesViewModel>())); MockRepository.GenerateStub<IBikesViewModel>(),
url => { }));
Assert.AreEqual("Code 4asdfA, still 7 minutes reserved.", l_oViewModel.StateText); Assert.AreEqual("Code 4asdfA, still 7 minutes reserved.", l_oViewModel.StateText);
} }
@ -138,7 +141,8 @@ namespace UITest.Fixtures.ViewModel
bike, bike,
user, user,
new BikeAtStationInUseStateInfoProvider(), new BikeAtStationInUseStateInfoProvider(),
MockRepository.GenerateStub<IBikesViewModel>())); MockRepository.GenerateStub<IBikesViewModel>(),
url => { }));
Assert.AreEqual( Assert.AreEqual(
$"Code 4asdfA, rented since {new DateTime(2018, 10, 24, 21, 49, 00).ToString("dd. MMMM HH:mm")}.", $"Code 4asdfA, rented since {new DateTime(2018, 10, 24, 21, 49, 00).ToString("dd. MMMM HH:mm")}.",
@ -174,7 +178,8 @@ namespace UITest.Fixtures.ViewModel
l_oStoreMock.Load().Result, l_oStoreMock.Load().Result,
"123456789"), // Device id "123456789"), // Device id
new BikeAtStationInUseStateInfoProvider(), new BikeAtStationInUseStateInfoProvider(),
MockRepository.GenerateStub<IBikesViewModel>()); MockRepository.GenerateStub<IBikesViewModel>(),
url => { });
Assert.AreEqual("Test description", l_oViewModel.Name); Assert.AreEqual("Test description", l_oViewModel.Name);
Assert.AreEqual("2", l_oViewModel.DisplayId); Assert.AreEqual("2", l_oViewModel.DisplayId);
@ -212,7 +217,8 @@ namespace UITest.Fixtures.ViewModel
l_oStoreMock.Load().Result, l_oStoreMock.Load().Result,
"123456789"), "123456789"),
new BikeAtStationInUseStateInfoProvider(), new BikeAtStationInUseStateInfoProvider(),
MockRepository.GenerateStub<IBikesViewModel>()); MockRepository.GenerateStub<IBikesViewModel>(),
url => { });
Assert.AreEqual("Test description", l_oViewModel.Name); Assert.AreEqual("Test description", l_oViewModel.Name);
Assert.AreEqual("2", l_oViewModel.DisplayId); Assert.AreEqual("2", l_oViewModel.DisplayId);

View file

@ -31,7 +31,8 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel
new TINK.Model.Bike.BC.BikeInfoMutable(new TINK.Model.Bike.BluetoothLock.BikeInfo("42", 5200544, new Guid("00000000-0000-0000-0000-000000000001"), "42"), "My Station Name"), new TINK.Model.Bike.BC.BikeInfoMutable(new TINK.Model.Bike.BluetoothLock.BikeInfo("42", 5200544, new Guid("00000000-0000-0000-0000-000000000001"), "42"), "My Station Name"),
MockRepository.GenerateStub<IUser>(), // user MockRepository.GenerateStub<IUser>(), // user
MockRepository.GenerateStub<IInUseStateInfoProvider>(), MockRepository.GenerateStub<IInUseStateInfoProvider>(),
MockRepository.GenerateStub<IBikesViewModel>()).GetType()); // stateInfoProvider MockRepository.GenerateStub<IBikesViewModel>(),
url => { }).GetType()); // stateInfoProvider
Assert.AreEqual( Assert.AreEqual(
typeof(TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel), typeof(TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel),
@ -47,7 +48,8 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel
new TINK.Model.Bike.BluetoothLock.BikeInfoMutable(new TINK.Model.Bike.BluetoothLock.BikeInfo("42", 5200544, new Guid("00000000-0000-0000-0000-000000000001"), "42"), "My Station Name"), new TINK.Model.Bike.BluetoothLock.BikeInfoMutable(new TINK.Model.Bike.BluetoothLock.BikeInfo("42", 5200544, new Guid("00000000-0000-0000-0000-000000000001"), "42"), "My Station Name"),
MockRepository.GenerateStub<IUser>(), // user MockRepository.GenerateStub<IUser>(), // user
MockRepository.GenerateStub<IInUseStateInfoProvider>(), MockRepository.GenerateStub<IInUseStateInfoProvider>(),
MockRepository.GenerateStub<IBikesViewModel>()).GetType()); // stateInfoProvider MockRepository.GenerateStub<IBikesViewModel>(),
url => { }).GetType()); // stateInfoProvider
} }
} }
} }

View file

@ -28,7 +28,8 @@ namespace UITest.Fixtures.ViewModel
bike, bike,
user, user,
new MyBikeInUseStateInfoProvider(), new MyBikeInUseStateInfoProvider(),
MockRepository.GenerateStub<IBikesViewModel>())); MockRepository.GenerateStub<IBikesViewModel>(),
url => { }));
Assert.AreEqual("Location Station 3, still 15 minutes reserved.", l_oViewModel.StateText); Assert.AreEqual("Location Station 3, still 15 minutes reserved.", l_oViewModel.StateText);
@ -51,7 +52,8 @@ namespace UITest.Fixtures.ViewModel
bike, bike,
user, user,
new MyBikeInUseStateInfoProvider(), new MyBikeInUseStateInfoProvider(),
MockRepository.GenerateStub<IBikesViewModel>())); MockRepository.GenerateStub<IBikesViewModel>(),
url => { }));
Assert.AreEqual("Code 4asdfA, location Station 3, still 7 minutes reserved.", l_oViewModel.StateText); Assert.AreEqual("Code 4asdfA, location Station 3, still 7 minutes reserved.", l_oViewModel.StateText);
} }
@ -75,7 +77,8 @@ namespace UITest.Fixtures.ViewModel
bike, bike,
user, user,
new MyBikeInUseStateInfoProvider(), new MyBikeInUseStateInfoProvider(),
MockRepository.GenerateStub<IBikesViewModel>())); MockRepository.GenerateStub<IBikesViewModel>(),
url => { }));
Assert.AreEqual( Assert.AreEqual(
$"Code 4asdfA, location Station 3, rented since {new DateTime(2018, 10, 24, 21, 49, 00).ToString("dd. MMMM HH:mm")}.", $"Code 4asdfA, location Station 3, rented since {new DateTime(2018, 10, 24, 21, 49, 00).ToString("dd. MMMM HH:mm")}.",

View file

@ -98,7 +98,8 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel
tinkApp.Polling, tinkApp.Polling,
(d, obj) => d(obj), (d, obj) => d(obj),
Substitute.For<ISmartDevice>(), Substitute.For<ISmartDevice>(),
viewService); viewService,
url => { });
await myBikes.OnAppearing(); await myBikes.OnAppearing();
@ -191,7 +192,8 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel
tinkApp.Polling, tinkApp.Polling,
(d, obj) => d(obj), (d, obj) => d(obj),
Substitute.For<ISmartDevice>(), Substitute.For<ISmartDevice>(),
viewService); viewService,
url => { });
await myBikes.OnAppearing(); await myBikes.OnAppearing();
@ -292,7 +294,8 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel
tinkApp.Polling, tinkApp.Polling,
(d, obj) => d(obj), (d, obj) => d(obj),
Substitute.For<ISmartDevice>(), Substitute.For<ISmartDevice>(),
viewService); viewService,
url => { });
await myBikes.OnAppearing(); await myBikes.OnAppearing();
@ -388,7 +391,8 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel
tinkApp.Polling, tinkApp.Polling,
(d, obj) => d(obj), (d, obj) => d(obj),
Substitute.For<ISmartDevice>(), Substitute.For<ISmartDevice>(),
viewService); viewService,
url => { });
await myBikes.OnAppearing(); await myBikes.OnAppearing();
@ -482,7 +486,8 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel
tinkApp.Polling, tinkApp.Polling,
(d, obj) => d(obj), (d, obj) => d(obj),
Substitute.For<ISmartDevice>(), Substitute.For<ISmartDevice>(),
viewService); viewService,
url => { });
await myBikes.OnAppearing(); await myBikes.OnAppearing();
@ -570,7 +575,8 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel
tinkApp.Polling, tinkApp.Polling,
(d, obj) => d(obj), (d, obj) => d(obj),
Substitute.For<ISmartDevice>(), Substitute.For<ISmartDevice>(),
viewService); viewService,
url => { });
await myBikes.OnAppearing(); await myBikes.OnAppearing();
@ -633,7 +639,8 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel
tinkApp.Polling, tinkApp.Polling,
(d, obj) => d(obj), (d, obj) => d(obj),
Substitute.For<ISmartDevice>(), Substitute.For<ISmartDevice>(),
viewService); viewService,
url => { });
await myBikes.OnAppearing(); await myBikes.OnAppearing();
@ -710,7 +717,8 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel
tinkApp.Polling, tinkApp.Polling,
(d, obj) => d(obj), (d, obj) => d(obj),
Substitute.For<ISmartDevice>(), Substitute.For<ISmartDevice>(),
viewService) viewService,
url => { })
{ {
IsReportLevelVerbose = true IsReportLevelVerbose = true
}; };
@ -790,7 +798,8 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel
tinkApp.Polling, tinkApp.Polling,
(d, obj) => d(obj), (d, obj) => d(obj),
Substitute.For<ISmartDevice>(), Substitute.For<ISmartDevice>(),
viewService) viewService,
url => { })
{ {
IsReportLevelVerbose = true IsReportLevelVerbose = true
}; };