Version 3.0.338

This commit is contained in:
Anja Müller-Meißner 2022-09-06 16:08:19 +02:00 committed by Anja
parent 573fe77e12
commit 0468955d49
751 changed files with 62747 additions and 60672 deletions

View file

@ -4,21 +4,13 @@
root = true
# All files
[*]
indent_style = space
# XML project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
indent_size = 2
# XML config files
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
indent_size = 2
# Code files
[*.{cs,csx,vb,vbx}]
indent_size = 4
indent_style = tab
tab_width = 4
insert_final_newline = true
charset = utf-8-bom
trim_trailing_whitespace = true
charset = utf-8
end_of_line = crlf
###############################
# .NET Coding Conventions #
###############################
@ -139,4 +131,4 @@ csharp_style_expression_bodied_local_functions = false:silent
###############################
[*.vb]
# Modifier preferences
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion

View file

@ -13,96 +13,96 @@ using Xamarin.Forms.Platform.Android.AppLinks;
namespace TINK.Droid
{
[Activity(Label = "LastenradBayern", Icon = "@drawable/sharee", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
[Activity(Label = "LastenradBayern", Icon = "@drawable/sharee", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
[IntentFilter(new[] { Intent.ActionView },
Categories = new[] { Intent.ActionView, Intent.CategoryBrowsable, Intent.CategoryDefault },
DataScheme = "https",
DataHost = "sharee.bike",
DataPathPrefix = "/lastenrad",
AutoVerify = true)]
[IntentFilter(new[] { Intent.ActionView },
Categories = new[] { Intent.ActionView, Intent.CategoryBrowsable, Intent.CategoryDefault },
DataScheme = "https",
DataHost = "sharee.bike",
DataPathPrefix = "/lastenrad",
AutoVerify = true)]
[IntentFilter(new[] { Intent.ActionView },
Categories = new[] { Intent.ActionView, Intent.CategoryBrowsable, Intent.CategoryDefault },
DataScheme = "http",
DataHost = "sharee.bike",
DataPathPrefix = "/lastenrad",
AutoVerify = true)]
[IntentFilter(new[] { Intent.ActionView },
Categories = new[] { Intent.ActionView, Intent.CategoryBrowsable, Intent.CategoryDefault },
DataScheme = "http",
DataHost = "sharee.bike",
DataPathPrefix = "/lastenrad",
AutoVerify = true)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
private void initFontScale()
{
Configuration configuration = Resources.Configuration;
configuration.FontScale = (float)1;
//0.85 small, 1 standard, 1.15 big1.3 more bigger 1.45 supper big
DisplayMetrics metrics = new DisplayMetrics();
WindowManager.DefaultDisplay.GetMetrics(metrics);
metrics.ScaledDensity = configuration.FontScale * metrics.Density;
BaseContext.Resources.UpdateConfiguration(configuration, metrics);
}
protected override void OnCreate(Bundle bundle)
{
initFontScale();
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
private void initFontScale()
{
Configuration configuration = Resources.Configuration;
configuration.FontScale = (float)1;
//0.85 small, 1 standard, 1.15 big1.3 more bigger 1.45 supper big
DisplayMetrics metrics = new DisplayMetrics();
WindowManager.DefaultDisplay.GetMetrics(metrics);
metrics.ScaledDensity = configuration.FontScale * metrics.Density;
BaseContext.Resources.UpdateConfiguration(configuration, metrics);
}
protected override void OnCreate(Bundle bundle)
{
initFontScale();
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
FirebaseApp.InitializeApp(this);
AndroidAppLinks.Init(this);
FirebaseApp.InitializeApp(this);
AndroidAppLinks.Init(this);
// Initialize xamarin.essentials, see https://docs.microsoft.com/en-us/xamarin/essentials/get-started?tabs=macos%2Candroid.
Xamarin.Essentials.Platform.Init(this, bundle);
// Initialize xamarin.essentials, see https://docs.microsoft.com/en-us/xamarin/essentials/get-started?tabs=macos%2Candroid.
Xamarin.Essentials.Platform.Init(this, bundle);
// Required for initialization of Maps, see https://developer.xamarin.com/guides/xamarin-forms/user-interface/map/
Xamarin.FormsGoogleMaps.Init(this, bundle);
// Required for initialization of Maps, see https://developer.xamarin.com/guides/xamarin-forms/user-interface/map/
Xamarin.FormsGoogleMaps.Init(this, bundle);
// Required for initialization of binding package, see https://github.com/nuitsjp/Xamarin.Forms.GoogleMaps.Bindings.
Xamarin.FormsGoogleMapsBindings.Init();
// Required for initialization of binding package, see https://github.com/nuitsjp/Xamarin.Forms.GoogleMaps.Bindings.
Xamarin.FormsGoogleMapsBindings.Init();
// Get version name of app.
Context context = ApplicationContext;
new Model.Device.AppInfo(context.PackageManager.GetPackageInfo(context.PackageName, 0).VersionName);
// Get version name of app.
Context context = ApplicationContext;
new Model.Device.AppInfo(context.PackageManager.GetPackageInfo(context.PackageName, 0).VersionName);
Xamarin.Forms.Forms.ViewInitialized += (object sender, Xamarin.Forms.ViewInitializedEventArgs e) =>
{
if (!string.IsNullOrWhiteSpace(e.View.AutomationId))
{
e.NativeView.ContentDescription = e.View.AutomationId;
}
};
Xamarin.Forms.Forms.ViewInitialized += (object sender, Xamarin.Forms.ViewInitializedEventArgs e) =>
{
if (!string.IsNullOrWhiteSpace(e.View.AutomationId))
{
e.NativeView.ContentDescription = e.View.AutomationId;
}
};
LoadApplication(new App());
}
LoadApplication(new App());
}
/// <summary>
/// Handles opening the dialog to request for permissions.
/// </summary>
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Android.Content.PM.Permission[] grantResults)
{
if (App.PermissionsService.GetType() == typeof(TINK.Services.Permissions.Essentials.Permissions))
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
else if (App.PermissionsService.GetType() == typeof(TINK.Services.Permissions.Plugin.Permissions))
{
// Bug in 3.0.244 and earlier versions of sharee.bike app: Call of PermissionsImplementation.Current.OnRequestedPermission result was missing.
// see https://dev.azure.com/TeilRad/sharee.bike%20Buchungsplattform/_workitems/edit/136 for further details.
PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
/// <summary>
/// Handles opening the dialog to request for permissions.
/// </summary>
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Android.Content.PM.Permission[] grantResults)
{
if (App.PermissionsService.GetType() == typeof(TINK.Services.Permissions.Essentials.Permissions))
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
else if (App.PermissionsService.GetType() == typeof(TINK.Services.Permissions.Plugin.Permissions))
{
// Bug in 3.0.244 and earlier versions of sharee.bike app: Call of PermissionsImplementation.Current.OnRequestedPermission result was missing.
// see https://dev.azure.com/TeilRad/sharee.bike%20Buchungsplattform/_workitems/edit/136 for further details.
PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
[Export("TapStation")]
public void TapStation(string stationNr)
{
BackdoorMethodHelpers.DoTapPage(stationNr);
}
}
[Export("TapStation")]
public void TapStation(string stationNr)
{
BackdoorMethodHelpers.DoTapPage(stationNr);
}
}
}

View file

@ -6,40 +6,40 @@ using Xamarin.Forms;
[assembly: Dependency(typeof(AppInfo))]
namespace TINK.Droid.Model.Device
{
/// <summary> Holds information about the TINK- app. </summary>
public class AppInfo : IAppInfo
{
/// <summary> Holds the the version of the app.</summary>
private static Version m_oVersion = null;
/// <summary> Holds information about the TINK- app. </summary>
public class AppInfo : IAppInfo
{
/// <summary> Holds the the version of the app.</summary>
private static Version m_oVersion = null;
/// <summary> Constructs a app info object. </summary>
public AppInfo()
{
}
/// <summary> Constructs a app info object. </summary>
public AppInfo()
{
}
/// <summary> Constructs a app info object for initialization. </summary>
/// <param name="p_strVersionText"> Version to initializ object with.</param>
internal AppInfo(string p_strVersionText)
{
if (m_oVersion != null)
{
// Set version only once.
return;
}
/// <summary> Constructs a app info object for initialization. </summary>
/// <param name="p_strVersionText"> Version to initializ object with.</param>
internal AppInfo(string p_strVersionText)
{
if (m_oVersion != null)
{
// Set version only once.
return;
}
if (!Version.TryParse(p_strVersionText, out Version l_oVersion))
{
m_oVersion = new Version(0, 8);
}
if (!Version.TryParse(p_strVersionText, out Version l_oVersion))
{
m_oVersion = new Version(0, 8);
}
m_oVersion = l_oVersion;
}
m_oVersion = l_oVersion;
}
/// <summary> Get the version of the app. </summary>
public Version Version => m_oVersion ?? new Version(0, 9);
/// <summary> Get the version of the app. </summary>
public Version Version => m_oVersion ?? new Version(0, 9);
/// <summary> Gets the URL to the app store. </summary>
/// <value>The store URL.</value>
public string StoreUrl => $"https://play.google.com/store/apps/details?id={Android.App.Application.Context.PackageName}";
}
/// <summary> Gets the URL to the app store. </summary>
/// <value>The store URL.</value>
public string StoreUrl => $"https://play.google.com/store/apps/details?id={Android.App.Application.Context.PackageName}";
}
}

View file

@ -5,19 +5,19 @@ using Xamarin.Forms;
[assembly: Dependency(typeof(TINK.Droid.Model.Device.Device))]
namespace TINK.Droid.Model.Device
{
public class Device : ISmartDevice
{
public string Manufacturer => DeviceInfo.Manufacturer;
public class Device : ISmartDevice
{
public string Manufacturer => DeviceInfo.Manufacturer;
public string Model => DeviceInfo.Model;
public string Model => DeviceInfo.Model;
public DevicePlatform Platform => DeviceInfo.Platform;
public DevicePlatform Platform => DeviceInfo.Platform;
public string VersionText => DeviceInfo.VersionString;
public string VersionText => DeviceInfo.VersionString;
/// <summary> Gets unitque device identifier. </summary>
/// <returns>Gets the identifies specifying device.</returns>
public string Identifier
=> Android.Provider.Settings.Secure.GetString(Android.App.Application.Context.ContentResolver, Android.Provider.Settings.Secure.AndroidId);
}
/// <summary> Gets unitque device identifier. </summary>
/// <returns>Gets the identifies specifying device.</returns>
public string Identifier
=> Android.Provider.Settings.Secure.GetString(Android.App.Application.Context.ContentResolver, Android.Provider.Settings.Secure.AndroidId);
}
}

View file

@ -6,18 +6,18 @@ using Xamarin.Forms;
[assembly: Dependency(typeof(ExternalBrowseService))]
namespace TINK.Droid.Model.Device
{
public class ExternalBrowseService : IExternalBrowserService
{
/// <summary> Opens an external browser. </summary>
/// <param name="p_strUrl">Url to open.</param>
public void OpenUrl(string p_strUrl)
{
var uri = Android.Net.Uri.Parse(p_strUrl);
var intent = new Intent(Intent.ActionView, uri);
public class ExternalBrowseService : IExternalBrowserService
{
/// <summary> Opens an external browser. </summary>
/// <param name="p_strUrl">Url to open.</param>
public void OpenUrl(string p_strUrl)
{
var uri = Android.Net.Uri.Parse(p_strUrl);
var intent = new Intent(Intent.ActionView, uri);
intent.AddFlags(ActivityFlags.NewTask);
intent.AddFlags(ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity(intent);
}
}
Android.App.Application.Context.StartActivity(intent);
}
}
}

View file

@ -16,15 +16,15 @@ using Xamarin.Forms;
[assembly: Dependency(typeof(TINK.Droid.Model.Device.Gps))]
namespace TINK.Droid.Model.Device
{
public class Gps : IGeolodationDependent
{
public bool IsGeolcationEnabled
{
get
{
LocationManager locationManager = (LocationManager)Android.App.Application.Context.GetSystemService(Context.LocationService);
return locationManager.IsProviderEnabled(LocationManager.GpsProvider);
}
}
}
public class Gps : IGeolodationDependent
{
public bool IsGeolcationEnabled
{
get
{
LocationManager locationManager = (LocationManager)Android.App.Application.Context.GetSystemService(Context.LocationService);
return locationManager.IsProviderEnabled(LocationManager.GpsProvider);
}
}
}
}

View file

@ -6,44 +6,44 @@ using Xamarin.Forms;
[assembly: Dependency(typeof(TINK.Droid.Model.Device.SpecialFolder))]
namespace TINK.Droid.Model.Device
{
public class SpecialFolder : ISpecialFolder
{
/// <summary> Get the folder name of external folder to write to. </summary>
/// <returns> Name of the external folder. </returns>
public string GetExternalFilesDir()
{
string baseFolderPath = string.Empty;
try
{
var context = Android.App.Application.Context;
Java.IO.File[] dirs = context.GetExternalFilesDirs(null);
public class SpecialFolder : ISpecialFolder
{
/// <summary> Get the folder name of external folder to write to. </summary>
/// <returns> Name of the external folder. </returns>
public string GetExternalFilesDir()
{
string baseFolderPath = string.Empty;
try
{
var context = Android.App.Application.Context;
Java.IO.File[] dirs = context.GetExternalFilesDirs(null);
foreach (Java.IO.File folder in dirs)
{
bool IsRemovable = Android.OS.Environment.InvokeIsExternalStorageRemovable(folder);
bool IsEmulated = Android.OS.Environment.InvokeIsExternalStorageEmulated(folder);
foreach (Java.IO.File folder in dirs)
{
bool IsRemovable = Android.OS.Environment.InvokeIsExternalStorageRemovable(folder);
bool IsEmulated = Android.OS.Environment.InvokeIsExternalStorageEmulated(folder);
if (IsRemovable
&& !IsEmulated)
{
baseFolderPath = folder.Path;
}
}
}
if (IsRemovable
&& !IsEmulated)
{
baseFolderPath = folder.Path;
}
}
}
catch (Exception l_oException)
{
Log.Error("Getting external files directory failed. {@l_oException}", l_oException);
}
catch (Exception l_oException)
{
Log.Error("Getting external files directory failed. {@l_oException}", l_oException);
}
return baseFolderPath;
}
return baseFolderPath;
}
/// <summary> Gets the folder name of the personal data folder dir on internal storage. </summary>
/// <returns>Directory name.</returns>
public string GetInternalPersonalDir()
{
return Environment.GetFolderPath(Environment.SpecialFolder.Personal);
}
}
/// <summary> Gets the folder name of the personal data folder dir on internal storage. </summary>
/// <returns>Directory name.</returns>
public string GetInternalPersonalDir()
{
return Environment.GetFolderPath(Environment.SpecialFolder.Personal);
}
}
}

View file

@ -4,13 +4,13 @@ using TINK.Model.Device;
[assembly: Xamarin.Forms.Dependency(typeof(TINK.Droid.Model.Device.WebView))]
namespace TINK.Droid.Model.Device
{
public class WebView : IWebView
{
/// <summary> Clears the cookie cache for all web views. </summary>
public void ClearCookies()
{
var cookieManager = CookieManager.Instance;
cookieManager.RemoveAllCookie();
}
}
public class WebView : IWebView
{
/// <summary> Clears the cookie cache for all web views. </summary>
public void ClearCookies()
{
var cookieManager = CookieManager.Instance;
cookieManager.RemoveAllCookie();
}
}
}

View file

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

View file

@ -4,45 +4,45 @@ using Xamarin.Forms;
namespace TINK.iOS
{
// The UIApplicationDelegate for the application. This class is responsible for launching the
// User Interface of the application, as well as listening (and optionally responding) to
// application events from iOS.
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
//
// This method is invoked when the application has loaded and is ready to run. In this
// method you should instantiate the window, load the UI into it and then make the window
// visible.
//
// You have 17 seconds to return from this method, or iOS will terminate your application.
//
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
// The UIApplicationDelegate for the application. This class is responsible for launching the
// User Interface of the application, as well as listening (and optionally responding) to
// application events from iOS.
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
//
// This method is invoked when the application has loaded and is ready to run. In this
// method you should instantiate the window, load the UI into it and then make the window
// visible.
//
// You have 17 seconds to return from this method, or iOS will terminate your application.
//
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
//Color of Icons in Navigation bar (e.g. burger menu and back arrow)
//UINavigationBar.Appearance.TintColor = Color.White.ToUIColor();
//Color of Icons in Navigation bar (e.g. burger menu and back arrow)
//UINavigationBar.Appearance.TintColor = Color.White.ToUIColor();
new iOS.Device.AppInfo(NSBundle.MainBundle.InfoDictionary[new NSString("CFBundleShortVersionString")]?.ToString() ?? string.Empty);
new iOS.Device.AppInfo(NSBundle.MainBundle.InfoDictionary[new NSString("CFBundleShortVersionString")]?.ToString() ?? string.Empty);
Forms.ViewInitialized += (object sender, ViewInitializedEventArgs e) =>
{
// http://developer.xamarin.com/recipes/testcloud/set-accessibilityidentifier-ios/
if (null != e.View.AutomationId)
{
e.NativeView.AccessibilityIdentifier = e.View.AutomationId;
}
};
LoadApplication(new TINK.App());
Forms.ViewInitialized += (object sender, ViewInitializedEventArgs e) =>
{
// http://developer.xamarin.com/recipes/testcloud/set-accessibilityidentifier-ios/
if (null != e.View.AutomationId)
{
e.NativeView.AccessibilityIdentifier = e.View.AutomationId;
}
};
LoadApplication(new TINK.App());
// Required for initialization of Maps, see https://developer.xamarin.com/guides/xamarin-forms/user-interface/map/
Xamarin.FormsGoogleMaps.Init("000000000000000000000000000000000000000");
// Required for initialization of Maps, see https://developer.xamarin.com/guides/xamarin-forms/user-interface/map/
Xamarin.FormsGoogleMaps.Init("000000000000000000000000000000000000000");
// Required for initialization of binding package, see https://github.com/nuitsjp/Xamarin.Forms.GoogleMaps.Bindings.
Xamarin.FormsGoogleMapsBindings.Init();
// Required for initialization of binding package, see https://github.com/nuitsjp/Xamarin.Forms.GoogleMaps.Bindings.
Xamarin.FormsGoogleMapsBindings.Init();
return base.FinishedLaunching(app, options);
}
}
return base.FinishedLaunching(app, options);
}
}
}

View file

@ -7,41 +7,41 @@ using Xamarin.Forms;
[assembly: Dependency(typeof(AppInfo))]
namespace TINK.iOS.Device
{
/// <summary> Holds information about the TINK- app. </summary>
public class AppInfo : IAppInfo
{
/// <summary> Holds the the version of the app.</summary>
private static Version m_oVersion = null;
/// <summary> Holds information about the TINK- app. </summary>
public class AppInfo : IAppInfo
{
/// <summary> Holds the the version of the app.</summary>
private static Version m_oVersion = null;
/// <summary> Constructs a app info object. </summary>
public AppInfo()
{
}
/// <summary> Constructs a app info object. </summary>
public AppInfo()
{
}
/// <summary> Constructs a app info object for initialization. </summary>
/// <param name="p_strVersionText"> Version to initializ object with.</param>
internal AppInfo(string p_strVersionText)
{
if (m_oVersion != null)
{
// Set version only once.
return;
}
/// <summary> Constructs a app info object for initialization. </summary>
/// <param name="p_strVersionText"> Version to initializ object with.</param>
internal AppInfo(string p_strVersionText)
{
if (m_oVersion != null)
{
// Set version only once.
return;
}
if (!Version.TryParse(p_strVersionText, out Version l_oVersion))
{
m_oVersion = new Version(0, 8);
}
if (!Version.TryParse(p_strVersionText, out Version l_oVersion))
{
m_oVersion = new Version(0, 8);
}
m_oVersion = l_oVersion;
}
m_oVersion = l_oVersion;
}
/// <summary> Get the version of the app. </summary>
public Version Version => m_oVersion ?? new Version(0, 9);
/// <summary> Get the version of the app. </summary>
public Version Version => m_oVersion ?? new Version(0, 9);
/// <summary> Gets the URL to the app store. </summary>
/// <remarks> TINK Url was @"http://itunes.apple.com/de/app/tink-konstanz/id1181519270?mt=8"</remarks>
/// <value>The store URL.</value>
public string StoreUrl => $"https://itunes.apple.com/de/app/apple-store/{NSBundle.MainBundle.BundleIdentifier}?mt=8";
}
/// <summary> Gets the URL to the app store. </summary>
/// <remarks> TINK Url was @"http://itunes.apple.com/de/app/tink-konstanz/id1181519270?mt=8"</remarks>
/// <value>The store URL.</value>
public string StoreUrl => $"https://itunes.apple.com/de/app/apple-store/{NSBundle.MainBundle.BundleIdentifier}?mt=8";
}
}

View file

@ -6,30 +6,30 @@ using Xamarin.Essentials;
[assembly: Xamarin.Forms.Dependency(typeof(TINK.iOS.Device.Device))]
namespace TINK.iOS.Device
{
public class Device : ISmartDevice
{
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern uint IOServiceGetMatchingService(uint masterPort, IntPtr matching);
public class Device : ISmartDevice
{
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern uint IOServiceGetMatchingService(uint masterPort, IntPtr matching);
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern IntPtr IOServiceMatching(string s);
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern IntPtr IOServiceMatching(string s);
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern IntPtr IORegistryEntryCreateCFProperty(uint entry, IntPtr key, IntPtr allocator, uint options);
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern IntPtr IORegistryEntryCreateCFProperty(uint entry, IntPtr key, IntPtr allocator, uint options);
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern int IOObjectRelease(uint o);
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern int IOObjectRelease(uint o);
public string Manufacturer => DeviceInfo.Manufacturer;
public string Manufacturer => DeviceInfo.Manufacturer;
public string Model => DeviceInfo.Model;
public string Model => DeviceInfo.Model;
public DevicePlatform Platform => DeviceInfo.Platform;
public DevicePlatform Platform => DeviceInfo.Platform;
public string VersionText => DeviceInfo.VersionString;
/// <summary> Gets unitque device identifier. </summary>
/// <returns>Gets the identifies specifying device.</returns>
public string Identifier
=> UIKit.UIDevice.CurrentDevice?.IdentifierForVendor?.AsString() ?? string.Empty;
}
public string VersionText => DeviceInfo.VersionString;
/// <summary> Gets unitque device identifier. </summary>
/// <returns>Gets the identifies specifying device.</returns>
public string Identifier
=> UIKit.UIDevice.CurrentDevice?.IdentifierForVendor?.AsString() ?? string.Empty;
}
}

View file

@ -7,17 +7,17 @@ using Xamarin.Forms;
[assembly: Dependency(typeof(ExternalBrowseService))]
namespace TINK.iOS.Device
{
public class ExternalBrowseService : IExternalBrowserService
{
/// <summary> Opens an external browser. </summary>
/// <param name="p_strUrl">Url to open.</param>
public void OpenUrl(string p_strUrl)
{
var l_oUrl = NSUrl.FromString(p_strUrl);
if (l_oUrl == null)
return;
public class ExternalBrowseService : IExternalBrowserService
{
/// <summary> Opens an external browser. </summary>
/// <param name="p_strUrl">Url to open.</param>
public void OpenUrl(string p_strUrl)
{
var l_oUrl = NSUrl.FromString(p_strUrl);
if (l_oUrl == null)
return;
UIApplication.SharedApplication.OpenUrl(l_oUrl);
}
}
UIApplication.SharedApplication.OpenUrl(l_oUrl);
}
}
}

View file

@ -3,8 +3,8 @@
[assembly: Xamarin.Forms.Dependency(typeof(TINK.iOS.Device.Gps))]
namespace TINK.iOS.Device
{
public class Gps : IGeolodationDependent
{
public bool IsGeolcationEnabled => true;
}
public class Gps : IGeolodationDependent
{
public bool IsGeolcationEnabled => true;
}
}

View file

@ -5,23 +5,23 @@ using Xamarin.Forms;
[assembly: Dependency(typeof(TINK.iOS.Device.SpecialFolder))]
namespace TINK.iOS.Device
{
public class SpecialFolder : ISpecialFolder
{
/// <summary>
/// Get the folder name of external folder to write to.
/// </summary>
/// <returns></returns>
public string GetExternalFilesDir()
{
return Environment.GetFolderPath(Environment.SpecialFolder.Personal);
}
public class SpecialFolder : ISpecialFolder
{
/// <summary>
/// Get the folder name of external folder to write to.
/// </summary>
/// <returns></returns>
public string GetExternalFilesDir()
{
return Environment.GetFolderPath(Environment.SpecialFolder.Personal);
}
/// <summary> Gets the folder name of the personal data folder dir on internal storage. </summary>
/// <returns>Directory name.</returns>
public string GetInternalPersonalDir()
{
return Environment.GetFolderPath(Environment.SpecialFolder.Personal);
}
/// <summary> Gets the folder name of the personal data folder dir on internal storage. </summary>
/// <returns>Directory name.</returns>
public string GetInternalPersonalDir()
{
return Environment.GetFolderPath(Environment.SpecialFolder.Personal);
}
}
}
}

View file

@ -5,14 +5,14 @@ using TINK.Model.Device;
[assembly: Xamarin.Forms.Dependency(typeof(TINK.iOS.Device.WebView))]
namespace TINK.iOS.Device
{
public class WebView : IWebView
{
/// <summary> Clears the cookie cache for all web views. </summary>
public void ClearCookies()
{
NSHttpCookieStorage CookieStorage = NSHttpCookieStorage.SharedStorage;
foreach (var cookie in CookieStorage.Cookies)
CookieStorage.DeleteCookie(cookie);
}
}
public class WebView : IWebView
{
/// <summary> Clears the cookie cache for all web views. </summary>
public void ClearCookies()
{
NSHttpCookieStorage CookieStorage = NSHttpCookieStorage.SharedStorage;
foreach (var cookie in CookieStorage.Cookies)
CookieStorage.DeleteCookie(cookie);
}
}
}

View file

@ -5,24 +5,24 @@ using Xamarin.Forms;
[assembly: Dependency(typeof(TINK.iOS.Device.IOSCipher))]
namespace TINK.iOS.Device
{
public class IOSCipher : ICipher
{
/// <summary> Encrypt data.</summary>
/// <param name="key">Key to encrypt data.</param>
/// <param name="clear">Data to entrycpt.</param>
/// <returns></returns>
public byte[] Encrypt(byte[] key, byte[] clear)
{
throw new NotSupportedException();
}
public class IOSCipher : ICipher
{
/// <summary> Encrypt data.</summary>
/// <param name="key">Key to encrypt data.</param>
/// <param name="clear">Data to entrycpt.</param>
/// <returns></returns>
public byte[] Encrypt(byte[] key, byte[] clear)
{
throw new NotSupportedException();
}
/// <summary> Decrypt data. </summary>
/// <param name="key">Key to decrypt data with.</param>
/// <param name="encrypted">Encrpyted data to decrypt.</param>
/// <returns>Decrypted data.</returns>
public byte[] Decrypt(byte[] key, byte[] encrypted)
{
throw new NotSupportedException();
}
}
/// <summary> Decrypt data. </summary>
/// <param name="key">Key to decrypt data with.</param>
/// <param name="encrypted">Encrpyted data to decrypt.</param>
/// <returns>Decrypted data.</returns>
public byte[] Decrypt(byte[] key, byte[] encrypted)
{
throw new NotSupportedException();
}
}
}

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">
<plist version="1.0">
<dict>
@ -6,8 +6,8 @@
<array>
<string>bluetooth-peripheral</string>
</array>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
@ -47,7 +47,7 @@
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Location access is needed to show map at current position and pass position to server when returning bikes.</string>
<key>MinimumOSVersion</key>
<string>9.0</string>
<string>13.0</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Location access is needed to show map at current position and pass position to server when returning bikes.</string>
<key>CFBundleIdentifier</key>
@ -55,8 +55,8 @@
<key>CFBundleDisplayName</key>
<string>LastenradBayern</string>
<key>CFBundleVersion</key>
<string>337</string>
<string>338</string>
<key>CFBundleShortVersionString</key>
<string>3.0.337</string>
<string>3.0.338</string>
</dict>
</plist>

View file

@ -24,7 +24,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<MtouchArch>i386, x86_64</MtouchArch>
<MtouchArch>x86_64</MtouchArch>
<MtouchLink>None</MtouchLink>
<MtouchDebug>true</MtouchDebug>
<CodesignProvision>VS: com.TeilRad.LastenradBayern Development</CodesignProvision>
@ -37,8 +37,8 @@
<DefineConstants>__IOS__;__MOBILE__;__UNIFIED__</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<MtouchLink>None</MtouchLink>
<MtouchArch>i386, x86_64</MtouchArch>
<MtouchLink>SdkOnly</MtouchLink>
<MtouchArch>x86_64</MtouchArch>
<ConsolePause>false</ConsolePause>
<CodesignProvision>VS: com.TeilRad.LastenradBayern Development</CodesignProvision>
<CodesignKey>Apple Development: Oliver Hauff (8SZ7J9P24J)</CodesignKey>
@ -52,11 +52,11 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<MtouchArch>ARMv7, ARM64</MtouchArch>
<MtouchArch>ARM64</MtouchArch>
<CodesignKey>Apple Development: Oliver Hauff (8SZ7J9P24J)</CodesignKey>
<MtouchDebug>true</MtouchDebug>
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
<MtouchLink>None</MtouchLink>
<MtouchLink>SdkOnly</MtouchLink>
<MtouchInterpreter>-all</MtouchInterpreter>
<CodesignProvision>VS: com.TeilRad.LastenradBayern Development</CodesignProvision>
</PropertyGroup>
@ -67,7 +67,7 @@
<DefineConstants>__IOS__;__MOBILE__;__UNIFIED__</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<MtouchArch>ARMv7, ARM64</MtouchArch>
<MtouchArch>ARM64</MtouchArch>
<ConsolePause>false</ConsolePause>
<CodesignKey>Apple Development: Oliver Hauff (8SZ7J9P24J)</CodesignKey>
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
@ -77,6 +77,7 @@
<CrashReportingApiKey>
</CrashReportingApiKey>
<MtouchLink>SdkOnly</MtouchLink>
<MtouchSdkVersion>15.5</MtouchSdkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Ad-Hoc|iPhone' ">
<DebugType>none</DebugType>
@ -202,10 +203,10 @@
<Version>1.7.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Forms.GoogleMaps">
<Version>3.3.0</Version>
<Version>5.0.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.Forms.GoogleMaps.Bindings" Version="3.0.0" />
<PackageReference Include="Xamarin.Google.iOS.Maps" Version="3.9.0" />
<PackageReference Include="Xamarin.Google.iOS.Maps" Version="6.0.1.1" />
<PackageReference Include="PInvoke.BCrypt">
<Version>0.7.124</Version>
</PackageReference>

View file

@ -2,14 +2,14 @@
namespace TINK.iOS
{
public class Application
{
// This is the main entry point of the application.
static void Main(string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main(args, null, "AppDelegate");
}
}
public class Application
{
// This is the main entry point of the application.
static void Main(string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main(args, null, "AppDelegate");
}
}
}

View file

@ -30,166 +30,166 @@ using Arendi.BleLibrary.Local;
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
namespace TINK
{
public partial class App : Application
{
/// <summary>Title of the attachment file.</summary>
private const string ATTACHMENTTITLE = "Diagnostics.txt";
public partial class App : Application
{
/// <summary>Title of the attachment file.</summary>
private const string ATTACHMENTTITLE = "Diagnostics.txt";
/// <summary> Model root. </summary>
private static TinkApp m_oModelRoot;
/// <summary> Model root. </summary>
private static TinkApp m_oModelRoot;
/// <summary>
/// Gets the model root.
/// </summary>
public static TinkApp ModelRoot
{
get
{
if (m_oModelRoot != null)
{
// Root model already exists, nothing to do.
return m_oModelRoot;
}
/// <summary>
/// Gets the model root.
/// </summary>
public static TinkApp ModelRoot
{
get
{
if (m_oModelRoot != null)
{
// Root model already exists, nothing to do.
return m_oModelRoot;
}
// Get folder where to read settings from
var specialFolders = DependencyService.Get<ISpecialFolder>();
var internalPersonalDir = specialFolders.GetInternalPersonalDir();
// Get folder where to read settings from
var specialFolders = DependencyService.Get<ISpecialFolder>();
var internalPersonalDir = specialFolders.GetInternalPersonalDir();
// Delete attachtment from previous session.
DeleteAttachment(internalPersonalDir);
// Delete attachtment from previous session.
DeleteAttachment(internalPersonalDir);
// Setup logger using default settings.
TinkApp.SetupLogging(
new LoggingLevelSwitch(Model.Settings.Settings.DEFAULTLOGGINLEVEL),
internalPersonalDir);
// Setup logger using default settings.
TinkApp.SetupLogging(
new LoggingLevelSwitch(Model.Settings.Settings.DEFAULTLOGGINLEVEL),
internalPersonalDir);
// Subscribe to any unhandled/ unobserved exceptions.
AppDomain.CurrentDomain.UnhandledException += (sender, unobservedTaskExceptionEventArgs) => { Log.Fatal("Unobserved task exception: {Exception}", unobservedTaskExceptionEventArgs.ExceptionObject); };
TaskScheduler.UnobservedTaskException += (sender, unhandledExceptionEventArgs) => { Log.Fatal("Unhandled exception: {Exception}", unhandledExceptionEventArgs.Exception); };
// Subscribe to any unhandled/ unobserved exceptions.
AppDomain.CurrentDomain.UnhandledException += (sender, unobservedTaskExceptionEventArgs) => { Log.Fatal("Unobserved task exception: {Exception}", unobservedTaskExceptionEventArgs.ExceptionObject); };
TaskScheduler.UnobservedTaskException += (sender, unhandledExceptionEventArgs) => { Log.Fatal("Unhandled exception: {Exception}", unhandledExceptionEventArgs.Exception); };
// Restore last model state from json- file.
Dictionary<string, string> settingsJSON = new Dictionary<string, string>();
try
{
settingsJSON = JsonSettingsDictionary.Deserialize(internalPersonalDir);
}
catch (Exception exception)
{
Log.Error("Reading application settings from file failed.", exception);
}
// Restore last model state from json- file.
Dictionary<string, string> settingsJSON = new Dictionary<string, string>();
try
{
settingsJSON = JsonSettingsDictionary.Deserialize(internalPersonalDir);
}
catch (Exception exception)
{
Log.Error("Reading application settings from file failed.", exception);
}
Model.Settings.Settings settings;
try
{
settings = new Model.Settings.Settings(
null, // Turn off filtering for LastenradBayern- context
null, // Turn off filtering for LastenradBayern- context
JsonSettingsDictionary.GetCopriHostUri(settingsJSON),
JsonSettingsDictionary.GetPollingParameters(settingsJSON),
JsonSettingsDictionary.GetMinimumLoggingLevel(settingsJSON),
JsonSettingsDictionary.GetIsReportLevelVerbose(settingsJSON),
JsonSettingsDictionary.GetExpiresAfter(settingsJSON),
JsonSettingsDictionary.GetActiveLockService(settingsJSON),
JsonSettingsDictionary.GetConnectTimeout(settingsJSON),
JsonSettingsDictionary.GetActiveGeolocationService(settingsJSON),
JsonSettingsDictionary.GetCenterMapToCurrentLocation(settingsJSON),
Xamarin.Forms.GoogleMaps.MapSpan.FromCenterAndRadius(new Xamarin.Forms.GoogleMaps.Position(49.30881083492271, 11.358449625922889), Xamarin.Forms.GoogleMaps.Distance.FromKilometers(2.9)),
JsonSettingsDictionary.GetLogToExternalFolder(settingsJSON),
JsonSettingsDictionary.GetIsSiteCachingOn(settingsJSON),
JsonSettingsDictionary.GetActiveTheme(settingsJSON) ?? typeof(Themes.LastenradBayern).Name);
}
catch (Exception exception)
{
Log.Error("Deserializing application settings from dictionary failed.", exception);
settings = new Model.Settings.Settings();
}
Model.Settings.Settings settings;
try
{
settings = new Model.Settings.Settings(
null, // Turn off filtering for LastenradBayern- context
null, // Turn off filtering for LastenradBayern- context
JsonSettingsDictionary.GetCopriHostUri(settingsJSON),
JsonSettingsDictionary.GetPollingParameters(settingsJSON),
JsonSettingsDictionary.GetMinimumLoggingLevel(settingsJSON),
JsonSettingsDictionary.GetIsReportLevelVerbose(settingsJSON),
JsonSettingsDictionary.GetExpiresAfter(settingsJSON),
JsonSettingsDictionary.GetActiveLockService(settingsJSON),
JsonSettingsDictionary.GetConnectTimeout(settingsJSON),
JsonSettingsDictionary.GetActiveGeolocationService(settingsJSON),
JsonSettingsDictionary.GetCenterMapToCurrentLocation(settingsJSON),
Xamarin.Forms.GoogleMaps.MapSpan.FromCenterAndRadius(new Xamarin.Forms.GoogleMaps.Position(49.30881083492271, 11.358449625922889), Xamarin.Forms.GoogleMaps.Distance.FromKilometers(2.9)),
JsonSettingsDictionary.GetLogToExternalFolder(settingsJSON),
JsonSettingsDictionary.GetIsSiteCachingOn(settingsJSON),
JsonSettingsDictionary.GetActiveTheme(settingsJSON) ?? typeof(Themes.LastenradBayern).Name);
}
catch (Exception exception)
{
Log.Error("Deserializing application settings from dictionary failed.", exception);
settings = new Model.Settings.Settings();
}
if (settings.MinimumLogEventLevel != Model.Settings.Settings.DEFAULTLOGGINLEVEL
|| settings.LogToExternalFolder)
{
// Eigher
// - logging is not set to default value or
// - logging is performed to external folder.
// Need to reconfigure.
Log.CloseAndFlush(); // Close before modifying logger configuration. Otherwise a sharing vialation occurs.
if (settings.MinimumLogEventLevel != Model.Settings.Settings.DEFAULTLOGGINLEVEL
|| settings.LogToExternalFolder)
{
// Eigher
// - logging is not set to default value or
// - logging is performed to external folder.
// Need to reconfigure.
Log.CloseAndFlush(); // Close before modifying logger configuration. Otherwise a sharing vialation occurs.
TinkApp.SetupLogging(
new LoggingLevelSwitch(settings.MinimumLogEventLevel),
!settings.LogToExternalFolder
? internalPersonalDir
: specialFolders.GetExternalFilesDir());
}
TinkApp.SetupLogging(
new LoggingLevelSwitch(settings.MinimumLogEventLevel),
!settings.LogToExternalFolder
? internalPersonalDir
: specialFolders.GetExternalFilesDir());
}
// Get auth cookie
Log.Debug("Get auth cookie.");
IStore store = null;
// Get auth cookie
Log.Debug("Get auth cookie.");
IStore store = null;
var lastVersion = JsonSettingsDictionary.GetAppVersion(settingsJSON);
if (new Version(3, 0, 290) <= lastVersion)
{
// App versions newer than 3.0.173 stored geolocation service in configuration.
// Version 3.0.290: Geolocation service "GeolocationService" is no more supported.
// For this reasons a swich of geolocation service is forced when loading configurations from ealier versions.
LocationServicesContainer.SetActive(settings.ActiveGeolocationService);
}
var lastVersion = JsonSettingsDictionary.GetAppVersion(settingsJSON);
if (new Version(3, 0, 290) <= lastVersion)
{
// App versions newer than 3.0.173 stored geolocation service in configuration.
// Version 3.0.290: Geolocation service "GeolocationService" is no more supported.
// For this reasons a swich of geolocation service is forced when loading configurations from ealier versions.
LocationServicesContainer.SetActive(settings.ActiveGeolocationService);
}
store = new Store();
store = new Store();
Barrel.ApplicationId = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
Barrel.ApplicationId = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
var context = SynchronizationContext.Current;
var context = SynchronizationContext.Current;
var appInfoService = DependencyService.Get<IAppInfo>();
var appInfoService = DependencyService.Get<IAppInfo>();
const string MERCHANTID = "0000000000";
const string MERCHANTID = "0000000000";
// Create new app instnace.
Log.Debug("Constructing main model...");
m_oModelRoot = new TinkApp(
settings,
store, // Manages user account
isConnectedFunc: () => CrossConnectivity.Current.IsConnected,
connectorFactory: (isConnected, activeUri, sessionCookie, mail, expiresAfter) => ConnectorFactory.Create(
isConnected,
activeUri,
new Repository.AppContextInfo(MERCHANTID, AppFlavor.LastenradBayern.GetDisplayName().Replace(" ", ""), appInfoService.Version),
CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
sessionCookie,
mail,
expiresAfter),
merchantId: MERCHANTID,
bluetoothService: BluetoothService, /* locksService */
locationPermissionsService: PermissionsService,
locationServicesContainer: LocationServicesContainer,
locksService: null,
device: DependencyService.Get<ISmartDevice>(),
specialFolder: specialFolders,
cipher: new Cipher(),
new TINK.Services.ThemeNS.Theme(Application.Current.Resources.MergedDictionaries),
arendiCentral:
// Create new app instnace.
Log.Debug("Constructing main model...");
m_oModelRoot = new TinkApp(
settings,
store, // Manages user account
isConnectedFunc: () => CrossConnectivity.Current.IsConnected,
connectorFactory: (isConnected, activeUri, sessionCookie, mail, expiresAfter) => ConnectorFactory.Create(
isConnected,
activeUri,
new Repository.AppContextInfo(MERCHANTID, AppFlavor.LastenradBayern.GetDisplayName().Replace(" ", ""), appInfoService.Version),
CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
sessionCookie,
mail,
expiresAfter),
merchantId: MERCHANTID,
bluetoothService: BluetoothService, /* locksService */
locationPermissionsService: PermissionsService,
locationServicesContainer: LocationServicesContainer,
locksService: null,
device: DependencyService.Get<ISmartDevice>(),
specialFolder: specialFolders,
cipher: new Cipher(),
new TINK.Services.ThemeNS.Theme(Application.Current.Resources.MergedDictionaries),
arendiCentral:
#if ARENDI
DependencyService.Get<ICentral>(),
#else
null,
null,
#endif
postAction: (d, obj) => context.Post(d, obj),
currentVersion: appInfoService.Version,
lastVersion: lastVersion,
whatsNewShownInVersion: JsonSettingsDictionary.GetWhatsNew(settingsJSON) ?? settingsJSON.GetAppVersion(),
appFlavor: AppFlavor.LastenradBayern);
postAction: (d, obj) => context.Post(d, obj),
currentVersion: appInfoService.Version,
lastVersion: lastVersion,
whatsNewShownInVersion: JsonSettingsDictionary.GetWhatsNew(settingsJSON) ?? settingsJSON.GetAppVersion(),
flavor: AppFlavor.LastenradBayern);
Log.Debug("Main model successfully constructed.");
return m_oModelRoot;
}
}
Log.Debug("Main model successfully constructed.");
return m_oModelRoot;
}
}
/// <summary>
/// Entry point of application.
/// </summary>
public App()
{
InitializeComponent();
/// <summary>
/// Entry point of application.
/// </summary>
public App()
{
InitializeComponent();
#if USEFLYOUT
// Use flyout page.
@ -197,147 +197,147 @@ namespace TINK
? new View.WhatsNew.WhatsNewPage(() => MainPage = new View.Root.RootPage()) // Show whats new info.
: (Page)new View.Root.RootPage(); // Just start sharee- app
#else
// Use shell.
MainPage = ModelRoot.WhatsNew.IsShowRequired
? new View.WhatsNew.WhatsNewPage(() => MainPage = new View.RootShell.AppShell()) // Show whats new info.
: (Page)new View.RootShell.AppShell(); // Just start sharee- app
// Use shell.
MainPage = ModelRoot.WhatsNew.IsShowRequired
? new View.WhatsNew.WhatsNewPage(() => MainPage = new View.RootShell.AppShell()) // Show whats new info.
: (Page)new View.RootShell.AppShell(); // Just start sharee- app
#endif
}
}
/// <summary> Concatenates all log files to a single one. </summary>
/// <returns>Full file name of attachment.</returns>
public static string CreateAttachment()
{
var sessionLogFiles = Log.Logger.GetLogFiles().ToArray();
/// <summary> Concatenates all log files to a single one. </summary>
/// <returns>Full file name of attachment.</returns>
public static string CreateAttachment()
{
var sessionLogFiles = Log.Logger.GetLogFiles().ToArray();
if (sessionLogFiles.Length < 1)
{
// Either
// - there is no logging file
// - an error occurred getting list of log files.
return string.Empty;
}
if (sessionLogFiles.Length < 1)
{
// Either
// - there is no logging file
// - an error occurred getting list of log files.
return string.Empty;
}
var fullLogFileName = System.IO.Path.Combine(ModelRoot.LogFileParentFolder, ATTACHMENTTITLE);
var fullLogFileName = System.IO.Path.Combine(ModelRoot.LogFileParentFolder, ATTACHMENTTITLE);
// Stop logging to avoid file access exception.
Log.CloseAndFlush();
// Stop logging to avoid file access exception.
Log.CloseAndFlush();
System.IO.File.WriteAllLines(
fullLogFileName,
sessionLogFiles.SelectMany(name =>
(new List<string> { $"{{\"SessionFileName\":\"{name}\"}}" })
.Concat(System.IO.File.ReadLines(name).ToArray())));
System.IO.File.WriteAllLines(
fullLogFileName,
sessionLogFiles.SelectMany(name =>
(new List<string> { $"{{\"SessionFileName\":\"{name}\"}}" })
.Concat(System.IO.File.ReadLines(name).ToArray())));
// Resume logging
TinkApp.SetupLogging(
ModelRoot.Level,
ModelRoot.LogFileParentFolder);
// Resume logging
TinkApp.SetupLogging(
ModelRoot.Level,
ModelRoot.LogFileParentFolder);
return fullLogFileName;
}
return fullLogFileName;
}
/// <summary>Deletes an attachment if there is one.</summary>
/// <param name="folder">Folder to delete, is null folder is queried from model.</param>
private static void DeleteAttachment(string folder = null)
{
var attachment = System.IO.Path.Combine(folder ?? ModelRoot.LogFileParentFolder, ATTACHMENTTITLE);
if (!System.IO.File.Exists(attachment))
{
// No attachment found.
return;
}
/// <summary>Deletes an attachment if there is one.</summary>
/// <param name="folder">Folder to delete, is null folder is queried from model.</param>
private static void DeleteAttachment(string folder = null)
{
var attachment = System.IO.Path.Combine(folder ?? ModelRoot.LogFileParentFolder, ATTACHMENTTITLE);
if (!System.IO.File.Exists(attachment))
{
// No attachment found.
return;
}
System.IO.File.Delete(attachment);
}
System.IO.File.Delete(attachment);
}
protected override void OnSleep()
{
// Handle when your app sleeps
Log.CloseAndFlush();
}
protected override void OnSleep()
{
// Handle when your app sleeps
Log.CloseAndFlush();
}
protected override void OnResume()
{
DeleteAttachment();
protected override void OnResume()
{
DeleteAttachment();
TinkApp.SetupLogging(
ModelRoot.Level,
ModelRoot.LogFileParentFolder);
}
TinkApp.SetupLogging(
ModelRoot.Level,
ModelRoot.LogFileParentFolder);
}
/// <param name="uri">The URI for the request.</param>
/// <summary>Overriden to respond when the user initiates an app link request.</summary>
protected override void OnAppLinkRequestReceived(Uri uri)
{
base.OnAppLinkRequestReceived(uri);
if (uri.Host.ToLower() == "sharee.bike")
{
// Input e.g. sharee.bike/sharee?lat=49.921&long=32.51
Array segments = Array.ConvertAll(uri.Segments, segment => segment.Replace("/", "")).Skip(1).ToArray();
if (uri.Query.Length > 0)
{
Dictionary<string, string> queryDict = uri.Query
.Substring(1)
.Split("&")
.Select(query => query.Split('='))
.ToDictionary(query => query.FirstOrDefault(), query => query.Skip(1).FirstOrDefault());
}
// segments == ["sharee"]
// queryDict == [{["lat", "49.921"]}], {["long", "32.51"]}]
// => Navigate and pass params depending on linkinput
// If no custom navigation is configured, the app just opens as if the user opened it
}
}
/// <param name="uri">The URI for the request.</param>
/// <summary>Overriden to respond when the user initiates an app link request.</summary>
protected override void OnAppLinkRequestReceived(Uri uri)
{
base.OnAppLinkRequestReceived(uri);
if (uri.Host.ToLower() == "sharee.bike")
{
// Input e.g. sharee.bike/sharee?lat=49.921&long=32.51
Array segments = Array.ConvertAll(uri.Segments, segment => segment.Replace("/", "")).Skip(1).ToArray();
if (uri.Query.Length > 0)
{
Dictionary<string, string> queryDict = uri.Query
.Substring(1)
.Split("&")
.Select(query => query.Split('='))
.ToDictionary(query => query.FirstOrDefault(), query => query.Skip(1).FirstOrDefault());
}
// segments == ["sharee"]
// queryDict == [{["lat", "49.921"]}], {["long", "32.51"]}]
// => Navigate and pass params depending on linkinput
// If no custom navigation is configured, the app just opens as if the user opened it
}
}
/// <summary> Gets the current logging level.</summary>
/// <returns></returns>
private static LogEventLevel GetCurrentLogEventLevel()
{
foreach (LogEventLevel level in Enum.GetValues(typeof(LogEventLevel)))
{
if (Log.IsEnabled(level))
return level;
}
/// <summary> Gets the current logging level.</summary>
/// <returns></returns>
private static LogEventLevel GetCurrentLogEventLevel()
{
foreach (LogEventLevel level in Enum.GetValues(typeof(LogEventLevel)))
{
if (Log.IsEnabled(level))
return level;
}
return LogEventLevel.Error;
}
return LogEventLevel.Error;
}
/// <summary>
/// Holds the permission service instance.
/// </summary>
private static ILocationPermission _PermissionsService = null;
/// <summary>
/// Holds the permission service instance.
/// </summary>
private static ILocationPermission _PermissionsService = null;
/// <summary>
/// Service to manage permissions (location) of the app.
/// </summary>
public static ILocationPermission PermissionsService
{
get
{
if (_PermissionsService != null)
return _PermissionsService;
/// <summary>
/// Service to manage permissions (location) of the app.
/// </summary>
public static ILocationPermission PermissionsService
{
get
{
if (_PermissionsService != null)
return _PermissionsService;
_PermissionsService = new TINK.Services.Permissions.Essentials.Permissions();
return _PermissionsService;
}
}
_PermissionsService = new TINK.Services.Permissions.Essentials.Permissions();
return _PermissionsService;
}
}
/// <summary> Service to manage bluetooth stack.</summary>
public static Plugin.BLE.Abstractions.Contracts.IBluetoothLE BluetoothService => Plugin.BLE.CrossBluetoothLE.Current;
/// <summary> Service to manage bluetooth stack.</summary>
public static Plugin.BLE.Abstractions.Contracts.IBluetoothLE BluetoothService => Plugin.BLE.CrossBluetoothLE.Current;
/// <summary>
/// Service container to manage geolocation services.
/// </summary>
public static IServicesContainer<IGeolocation> LocationServicesContainer { get; }
= new ServicesContainerMutableT<IGeolocation>(
new HashSet<IGeolocation> {
new LastKnownGeolocationService(DependencyService.Get<IGeolodationDependent>()),
new SimulatedGeolocationService(DependencyService.Get<IGeolodationDependent>()),
new GeolocationAccuracyMediumService(DependencyService.Get<IGeolodationDependent>()),
new GeolocationAccuracyHighService(DependencyService.Get<IGeolodationDependent>()),
new GeolocationAccuracyBestService(DependencyService.Get<IGeolodationDependent>())},
Model.Settings.Settings.DefaultLocationService.FullName);
}
/// <summary>
/// Service container to manage geolocation services.
/// </summary>
public static IServicesContainer<IGeolocation> LocationServicesContainer { get; }
= new ServicesContainerMutableT<IGeolocation>(
new HashSet<IGeolocation> {
new LastKnownGeolocationService(DependencyService.Get<IGeolodationDependent>()),
new SimulatedGeolocationService(DependencyService.Get<IGeolodationDependent>()),
new GeolocationAccuracyMediumService(DependencyService.Get<IGeolodationDependent>()),
new GeolocationAccuracyHighService(DependencyService.Get<IGeolodationDependent>()),
new GeolocationAccuracyBestService(DependencyService.Get<IGeolodationDependent>())},
Model.Settings.Settings.DefaultLocationService.FullName);
}
}

View file

@ -5,34 +5,34 @@ using Xamarin.Forms;
namespace TINK
{
public static class BackdoorMethodHelpers
{
public static void DoTapPage(string stationId)
{
Serilog.Log.Information($"Request via backdoor to tap station {stationId}.");
var currentPage = GetCurrentPage();
var mapPageViewModel = (currentPage as MapPage)?.BindingContext as MapPageViewModel;
if (mapPageViewModel == null)
{
Serilog.Log.Error($"Request via backdoor to tap station {stationId} aborted because current page is not of expected type {typeof(MapPage).Name}. Type detected is {currentPage.GetType().Name}.");
return;
}
public static class BackdoorMethodHelpers
{
public static void DoTapPage(string stationId)
{
Serilog.Log.Information($"Request via backdoor to tap station {stationId}.");
var currentPage = GetCurrentPage();
var mapPageViewModel = (currentPage as MapPage)?.BindingContext as MapPageViewModel;
if (mapPageViewModel == null)
{
Serilog.Log.Error($"Request via backdoor to tap station {stationId} aborted because current page is not of expected type {typeof(MapPage).Name}. Type detected is {currentPage.GetType().Name}.");
return;
}
Serilog.Log.Information($"Invoking member to tap.");
mapPageViewModel?.OnStationClicked(stationId);
}
Serilog.Log.Information($"Invoking member to tap.");
mapPageViewModel?.OnStationClicked(stationId);
}
/// <summary> Gets the current page assumed that app is master detail page.</summary>
/// <returns></returns>
static Page GetCurrentPage()
{
/// <summary> Gets the current page assumed that app is master detail page.</summary>
/// <returns></returns>
static Page GetCurrentPage()
{
#if USEFLYOUT
return (Application.Current.MainPage as FlyoutPage)?.Detail.Navigation.NavigationStack.LastOrDefault();
#else
return Shell.Current.CurrentPage;
return Shell.Current.CurrentPage;
#endif
}
}
}
}
}

View file

@ -3,22 +3,22 @@ using Xamarin.Forms;
namespace TINK.Model.Device
{
public class SpecialFolder : ISpecialFolder
{
/// <summary>
/// Get the folder name of external folder to write to.
/// </summary>
/// <returns></returns>
public string GetExternalFilesDir()
{
return DependencyService.Get<ISpecialFolder>().GetExternalFilesDir();
}
public class SpecialFolder : ISpecialFolder
{
/// <summary>
/// Get the folder name of external folder to write to.
/// </summary>
/// <returns></returns>
public string GetExternalFilesDir()
{
return DependencyService.Get<ISpecialFolder>().GetExternalFilesDir();
}
/// <summary> Gets the folder name of the personal data folder dir on internal storage. </summary>
/// <returns>Directory name.</returns>
public string GetInternalPersonalDir()
{
return DependencyService.Get<ISpecialFolder>().GetInternalPersonalDir();
}
}
/// <summary> Gets the folder name of the personal data folder dir on internal storage. </summary>
/// <returns>Directory name.</returns>
public string GetInternalPersonalDir()
{
return DependencyService.Get<ISpecialFolder>().GetInternalPersonalDir();
}
}
}

View file

@ -12,80 +12,80 @@ using TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
namespace TINK.View.Account
{
[XamlCompilation(XamlCompilationOptions.Compile)]
[XamlCompilation(XamlCompilationOptions.Compile)]
#if USEFLYOUT
public partial class AccountPage : ContentPage, IViewService, IDetailPage
#else
public partial class AccountPage : ContentPage, IViewService
public partial class AccountPage : ContentPage, IViewService
#endif
{
/// <summary> Refernce to view model. </summary>
AccountPageViewModel m_oViewModel = null;
{
/// <summary> Refernce to view model. </summary>
AccountPageViewModel m_oViewModel = null;
/// <summary> Constructs a account page. </summary>
public AccountPage()
{
InitializeComponent();
/// <summary> Constructs a account page. </summary>
public AccountPage()
{
InitializeComponent();
var l_oModel = App.ModelRoot;
var l_oModel = App.ModelRoot;
m_oViewModel = new AccountPageViewModel(
l_oModel,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url),
this);
m_oViewModel = new AccountPageViewModel(
l_oModel,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url),
this);
BindingContext = m_oViewModel;
}
BindingContext = m_oViewModel;
}
/// <summary> Displays alert message. </summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="cancel">Type of buttons.</param>
public new async Task DisplayAlert(string title, string message, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, message, cancel);
/// <summary> Displays alert message. </summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="cancel">Type of buttons.</param>
public new async Task DisplayAlert(string title, string message, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, message, cancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of button.</param>
/// <returns>True if user pressed accept.</returns>
public new async Task<bool> DisplayAlert(string title, string message, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, message, accept, cancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of button.</param>
/// <returns>True if user pressed accept.</returns>
public new async Task<bool> DisplayAlert(string title, string message, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, message, accept, cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary>
/// Displays an action sheet.
/// </summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="cancel">Text of button.</param>
/// <param name="destruction"></param>
/// <param name="p_oButtons">Buttons holding options to select.</param>
/// <returns>Text selected</returns>
public new async Task<string> DisplayActionSheet(String title, String cancel, String destruction, params String[] p_oButtons)
=> await base.DisplayActionSheet(title, cancel, destruction, p_oButtons);
/// <summary>
/// Displays an action sheet.
/// </summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="cancel">Text of button.</param>
/// <param name="destruction"></param>
/// <param name="p_oButtons">Buttons holding options to select.</param>
/// <returns>Text selected</returns>
public new async Task<string> DisplayActionSheet(String title, String cancel, String destruction, params String[] p_oButtons)
=> await base.DisplayActionSheet(title, cancel, destruction, p_oButtons);
#if USEFLYOUT
/// <summary>
@ -95,19 +95,19 @@ namespace TINK.View.Account
public void ShowPage(ViewTypes p_oType, string title = null)
=> m_oNavigation.ShowPage(p_oType.GetViewType(), title);
#else
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
#endif
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushModalAsync(ViewTypes typeOfPage)
=> Navigation.PushModalAsync((Page)Activator.CreateInstance(typeOfPage.GetViewType()));
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushModalAsync(ViewTypes typeOfPage)
=> Navigation.PushModalAsync((Page)Activator.CreateInstance(typeOfPage.GetViewType()));
/// <summary> Pops a page from the modal stack. </summary>
public Task PopModalAsync()
=> throw new NotSupportedException();
/// <summary> Pops a page from the modal stack. </summary>
public Task PopModalAsync()
=> throw new NotSupportedException();
#if USEFLYOUT
@ -123,34 +123,34 @@ namespace TINK.View.Account
}
#endif
/// <summary>
/// Invoked when page is shown.
/// Starts update process.
/// </summary>
protected async override void OnAppearing()
=> await m_oViewModel.OnAppearing();
/// <summary>
/// Invoked when pages is closed/ hidden.
/// Stops update process.
/// </summary>
protected async override void OnDisappearing()
{
if (m_oViewModel == null)
{
// View model might be null.
return;
}
await m_oViewModel.OnDisappearing();
}
/// <summary>
/// Invoked when page is shown.
/// Starts update process.
/// </summary>
protected async override void OnAppearing()
=> await m_oViewModel.OnAppearing();
/// <summary>
/// Invoked when pages is closed/ hidden.
/// Stops update process.
/// </summary>
protected async override void OnDisappearing()
{
if (m_oViewModel == null)
{
// View model might be null.
return;
}
await m_oViewModel.OnDisappearing();
}
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public async Task PushAsync(ViewTypes p_oTypeOfPage)
=> await Navigation.PushAsync((Page)Activator.CreateInstance(p_oTypeOfPage.GetViewType()));
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public async Task PushAsync(ViewTypes p_oTypeOfPage)
=> await Navigation.PushAsync((Page)Activator.CreateInstance(p_oTypeOfPage.GetViewType()));
#if USCSHARP9
public Task<IViewService.IUserFeedback> DisplayUserFeedbackPopup() => throw new NotSupportedException();
#else
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => throw new NotSupportedException();
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => throw new NotSupportedException();
#endif
}
}
}

View file

@ -9,12 +9,12 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.Bike
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class BCBike : ViewCell
{
public BCBike()
{
InitializeComponent();
}
}
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class BCBike : ViewCell
{
public BCBike()
{
InitializeComponent();
}
}
}

View file

@ -2,24 +2,24 @@
namespace TINK.View.Bike
{
/// <summary>
/// Selects different templates for different bike types (BordComputer bikes, iLockIt bikes).
/// </summary>
public class BikeViewCellTemplateSelector : DataTemplateSelector
{
DataTemplate bCBike;
DataTemplate iLockIBike;
/// <summary>
/// Selects different templates for different bike types (BordComputer bikes, iLockIt bikes).
/// </summary>
public class BikeViewCellTemplateSelector : DataTemplateSelector
{
DataTemplate bCBike;
DataTemplate iLockIBike;
public BikeViewCellTemplateSelector()
{
bCBike = new DataTemplate(typeof(BCBike));
iLockIBike = new DataTemplate(typeof(ILockItBike));
}
public BikeViewCellTemplateSelector()
{
bCBike = new DataTemplate(typeof(BCBike));
iLockIBike = new DataTemplate(typeof(ILockItBike));
}
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
=> item is TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel ||
item is TINK.ViewModel.Bikes.Bike.CopriLock.BikeViewModel
? iLockIBike
: bCBike;
}
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
=> item is TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel ||
item is TINK.ViewModel.Bikes.Bike.CopriLock.BikeViewModel
? iLockIBike
: bCBike;
}
}

View file

@ -9,36 +9,36 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.Bike
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ILockItBike : ViewCell
{
public ILockItBike()
{
InitializeComponent();
}
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ILockItBike : ViewCell
{
public ILockItBike()
{
InitializeComponent();
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
if (Device.RuntimePlatform != Device.iOS)
// Update of size is only required for iOS.
return;
if (Device.RuntimePlatform != Device.iOS)
// Update of size is only required for iOS.
return;
var viewModel = BindingContext as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel;
if (viewModel == null)
return;
var viewModel = BindingContext as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel;
if (viewModel == null)
return;
viewModel.PropertyChanged += (sender, e) =>
{
if (e.PropertyName == nameof(TINK.ViewModel.Bikes.Bike.BC.RequestHandler.Base<IBikeInfoMutable>.IsButtonVisible)
|| e.PropertyName == nameof(TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler.Base.IsLockitButtonVisible))
{
// Force update of view cell on iOS.
// https://hausource.visualstudio.com/TINK/_workitems/edit/132
ForceUpdateSize();
}
};
}
}
viewModel.PropertyChanged += (sender, e) =>
{
if (e.PropertyName == nameof(TINK.ViewModel.Bikes.Bike.BC.RequestHandler.Base<IBikeInfoMutable>.IsButtonVisible)
|| e.PropertyName == nameof(TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler.Base.IsLockitButtonVisible))
{
// Force update of view cell on iOS.
// https://hausource.visualstudio.com/TINK/_workitems/edit/132
ForceUpdateSize();
}
};
}
}
}

View file

@ -5,38 +5,38 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.BikesAtStation
{
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using TINK.Model.Device;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using TINK.Model.Device;
#if USEFLYOUT
using TINK.View.MasterDetail;
#endif
using TINK.ViewModel;
using TINK.Model;
using TINK.Services.BluetoothLock.Tdo;
using System.Collections.Generic;
using Serilog;
using TINK.Services.BluetoothLock;
using Plugin.BLE;
using TINK.ViewModel.BikesAtStation;
using TINK.ViewModel.Bikes;
using Xamarin.CommunityToolkit.Extensions;
using TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
using TINK.ViewModel;
using TINK.Model;
using TINK.Services.BluetoothLock.Tdo;
using System.Collections.Generic;
using Serilog;
using TINK.Services.BluetoothLock;
using Plugin.BLE;
using TINK.ViewModel.BikesAtStation;
using TINK.ViewModel.Bikes;
using Xamarin.CommunityToolkit.Extensions;
using TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
[XamlCompilation(XamlCompilationOptions.Compile)]
[XamlCompilation(XamlCompilationOptions.Compile)]
#if USEFLYOUT
public partial class BikesAtStationPage : ContentPage, IViewService, IDetailPage
#else
public partial class BikesAtStationPage : ContentPage, IViewService
public partial class BikesAtStationPage : ContentPage, IViewService
#endif
{
{
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;
/// <summary> Initialization status to ensure initialization logic is not called multiple times. </summary>
private bool isInitializationStarted = false;
#if TRYNOTBACKSTYLE
public BikesAtStationPage()
{
@ -55,140 +55,140 @@ namespace TINK.View.BikesAtStation
}
#else
public BikesAtStationPage()
{
}
public BikesAtStationPage()
{
}
#endif
/// <summary>
/// Invoked when page is shown.
/// Starts update process.
/// </summary>
protected async override void OnAppearing()
{
// Don't repeat the initialization if it has been completed already.
if (isInitializationStarted) return;
isInitializationStarted = true;
/// <summary>
/// Invoked when page is shown.
/// Starts update process.
/// </summary>
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
// Hide master- detail menu to force user to navigate using back button.
m_oNavigation.IsGestureEnabled = false;
#endif
// 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).
await m_oViewModel.OnAppearing();
isInitializationStarted = false;
return;
}
// 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).
await m_oViewModel.OnAppearing();
isInitializationStarted = false;
return;
}
try
{
var model = App.ModelRoot;
try
{
var model = App.ModelRoot;
// Backup synchronization context when called from GUI-thread.
var synchronizationContext = SynchronizationContext.Current;
// Backup synchronization context when called from GUI-thread.
var synchronizationContext = SynchronizationContext.Current;
m_oViewModel = new BikesAtStationPageViewModel(
model.ActiveUser,
App.PermissionsService,
App.BluetoothService,
Device.RuntimePlatform,
model.SelectedStation,
() => model.GetIsConnected(),
(isConnected) => model.GetConnector(isConnected),
App.LocationServicesContainer.Active,
model.LocksServices.Active,
model.Polling,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url),
(d, obj) => synchronizationContext.Post(d, obj),
model.SmartDevice,
this)
{
IsReportLevelVerbose = model.IsReportLevelVerbose
};
}
catch (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");
isInitializationStarted = false;
return;
}
m_oViewModel = new BikesAtStationPageViewModel(
model.ActiveUser,
App.PermissionsService,
App.BluetoothService,
Device.RuntimePlatform,
model.SelectedStation,
() => model.GetIsConnected(),
(isConnected) => model.GetConnector(isConnected),
App.LocationServicesContainer.Active,
model.LocksServices.Active,
model.Polling,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url),
(d, obj) => synchronizationContext.Post(d, obj),
model.SmartDevice,
this)
{
IsReportLevelVerbose = model.IsReportLevelVerbose
};
}
catch (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");
isInitializationStarted = false;
return;
}
InitializeComponent();
InitializeComponent();
#if BACKSTYLE
// Hide master- detail menu to force user to navigate using back button.
m_oNavigation.IsGestureEnabled = false;
#endif
BindingContext = m_oViewModel;
BikesAtStationListView.ItemsSource = m_oViewModel;
BindingContext = m_oViewModel;
BikesAtStationListView.ItemsSource = m_oViewModel;
await m_oViewModel.OnAppearing();
isInitializationStarted = false;
}
await m_oViewModel.OnAppearing();
isInitializationStarted = false;
}
/// <summary>
/// Invoked when pages is closed/ hidden.
/// Stops update process.
/// </summary>
protected async override void OnDisappearing()
{
if (m_oViewModel != null)
{
// View model might be null.
await m_oViewModel?.OnDisappearing();
}
/// <summary>
/// Invoked when pages is closed/ hidden.
/// Stops update process.
/// </summary>
protected async override void OnDisappearing()
{
if (m_oViewModel != null)
{
// View model might be null.
await m_oViewModel?.OnDisappearing();
}
#if BACKSTYLE
if (m_oNavigation!= null)
m_oNavigation.IsGestureEnabled = true; // Enables master- detail menu navigation again when page is unloaded.
#endif
}
}
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="cancel">Type of buttons.</param>
public new async Task DisplayAlert(string title, string message, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, message, cancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="cancel">Type of buttons.</param>
public new async Task DisplayAlert(string title, string message, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, message, cancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of button.</param>
/// <returns>True if user pressed accept.</returns>
public new async Task<bool> DisplayAlert(string title, string message, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, message, accept, cancel);
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of button.</param>
/// <returns>True if user pressed accept.</returns>
public new async Task<bool> DisplayAlert(string title, string message, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, message, accept, cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
#if USEFLYOUT
@ -198,27 +198,27 @@ namespace TINK.View.BikesAtStation
public void ShowPage(ViewTypes p_oType, string title = null)
=> m_oNavigation.ShowPage(p_oType.GetViewType(), title);
#else
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
#endif
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="typeOfPage">Page to display.</param>
public async Task PushModalAsync(ViewTypes typeOfPage)
=> await Navigation.PushModalAsync((Page)Activator.CreateInstance(typeOfPage.GetViewType()));
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="typeOfPage">Page to display.</param>
public async Task PushModalAsync(ViewTypes typeOfPage)
=> await Navigation.PushModalAsync((Page)Activator.CreateInstance(typeOfPage.GetViewType()));
/// <summary> Pops a page from the modal stack. </summary>
public Task PopModalAsync()
{
throw new NotSupportedException();
}
/// <summary> Pops a page from the modal stack. </summary>
public Task PopModalAsync()
{
throw new NotSupportedException();
}
public Task PushAsync(ViewTypes p_oTypeOfPage)
{
throw new NotImplementedException();
}
public Task PushAsync(ViewTypes p_oTypeOfPage)
{
throw new NotImplementedException();
}
#if USEFLYOUT
/// <summary>
@ -239,10 +239,10 @@ namespace TINK.View.BikesAtStation
#if USCSHARP9
public async Task<IViewService.IUserFeedback> DisplayUserFeedbackPopup() => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup());
#else
/// <summary> Displays user feedback popup.</summary>
/// <param name="co2Saving"> Co2 saving information.</param>
/// <returns>User feedback.</returns>
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup(battery, co2Saving));
/// <summary> Displays user feedback popup.</summary>
/// <param name="co2Saving"> Co2 saving information.</param>
/// <returns>User feedback.</returns>
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup(battery, co2Saving));
#endif
}
}
}

View file

@ -4,16 +4,16 @@ using Xamarin.Forms;
namespace TINK.View
{
/// <summary> Inverts a bool.</summary>
public class BoolInverterConverter : IValueConverter
{
/// <summary> Inverts a bool.</summary>
/// <param name="value">Bool to invert.</param>
/// <returns>Inverted bool.</returns>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
=> value is bool flag && !flag;
/// <summary> Inverts a bool.</summary>
public class BoolInverterConverter : IValueConverter
{
/// <summary> Inverts a bool.</summary>
/// <param name="value">Bool to invert.</param>
/// <returns>Inverted bool.</returns>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
=> value is bool flag && !flag;
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
=> value is bool flag && !flag;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
=> value is bool flag && !flag;
}
}

View file

@ -50,7 +50,7 @@
IsVisible="{Binding MailAddressText, Converter={StaticResource StringNotNullOrEmpty_Converter}}"
Text="{Binding MailAddressText}"
IsEnabled="{Binding IsSendMailAvailable}"
Command="{Binding OnMailRequest}"/>
Command="{Binding OnMailToOperatorRequest}"/>
<!--- Phone -->
<Label
IsVisible="{Binding PhoneNumberText, Converter={StaticResource StringNotNullOrEmpty_Converter}}"

View file

@ -10,116 +10,117 @@ using TINK.ViewModel.Info;
using Xamarin.Essentials;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using TINK.Model;
namespace TINK.View.Contact
{
[XamlCompilation(XamlCompilationOptions.Compile)]
[XamlCompilation(XamlCompilationOptions.Compile)]
#if USEFLYOUT
public partial class ContactPage : ContentPage, IViewService, IDetailPage
#else
public partial class ContactPage : ContentPage, IViewService
public partial class ContactPage : ContentPage, IViewService
#endif
{
/// <summary> View model to notify view model if page appears. </summary>
private ContactPageViewModel ViewModel { get; set; }
{
/// <summary> View model to notify view model if page appears. </summary>
private ContactPageViewModel ViewModel { get; set; }
public ContactPage()
{
InitializeComponent();
public ContactPage()
{
InitializeComponent();
ViewModel = new ContactPageViewModel(App.ModelRoot.Uris.ActiveUri,
AppInfo.Name,
() => App.CreateAttachment(),
() => DependencyService.Get<IExternalBrowserService>().OpenUrl(DependencyService.Get<IAppInfo>().StoreUrl),
this);
ViewModel = new ContactPageViewModel(
App.ModelRoot.Flavor.GetDisplayName(),
() => App.CreateAttachment(),
() => DependencyService.Get<IExternalBrowserService>().OpenUrl(DependencyService.Get<IAppInfo>().StoreUrl),
this);
ContactPageView.BindingContext = ViewModel;
}
ContactPageView.BindingContext = ViewModel;
}
/// <summary> Invoked when page is shown. </summary>
protected async override void OnAppearing()
{
try
{
Log.ForContext<ContentPage>().Verbose("OnAppearing...");
/// <summary> Invoked when page is shown. </summary>
protected async override void OnAppearing()
{
try
{
Log.ForContext<ContentPage>().Verbose("OnAppearing...");
await ViewModel.OnAppearing(App.ModelRoot.SelectedStation);
}
catch (Exception exception)
{
Log.ForContext<ContentPage>().Error("Invoking OnAppearing on view model failed. {Exception}", exception);
return;
}
}
await ViewModel.OnAppearing(App.ModelRoot.SelectedStation);
}
catch (Exception exception)
{
Log.ForContext<ContentPage>().Error("Invoking OnAppearing on view model failed. {Exception}", exception);
return;
}
}
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
#if USEFLYOUT
public void ShowPage(ViewTypes p_oType, string title = null)
=> NavigationMasterDetail.ShowPage(p_oType.GetViewType(), title);
#else
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
#endif
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushModalAsync(ViewTypes p_oTypeOfPage)
{
throw new NotSupportedException();
}
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushModalAsync(ViewTypes p_oTypeOfPage)
{
throw new NotSupportedException();
}
/// <summary> Pops a page from the modal stack. </summary>
public Task PopModalAsync()
{
throw new NotSupportedException();
}
/// <summary> Pops a page from the modal stack. </summary>
public Task PopModalAsync()
{
throw new NotSupportedException();
}
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="typeOfPage">Page to display.</param>
public async Task PushAsync(ViewTypes typeOfPage)
{
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="typeOfPage">Page to display.</param>
public async Task PushAsync(ViewTypes typeOfPage)
{
#if USEFLYOUT
var page = Activator.CreateInstance(typeOfPage.GetViewType()) as IDetailPage;
#else
var page = Activator.CreateInstance(typeOfPage.GetViewType());
var page = Activator.CreateInstance(typeOfPage.GetViewType());
#endif
if (page == null)
{
return;
}
if (page == null)
{
return;
}
#if USEFLYOUT
page.NavigationMasterDetail = NavigationMasterDetail;
#endif
await Navigation.PushAsync((Page)page);
}
await Navigation.PushAsync((Page)page);
}
#if USCSHARP9
public Task<IViewService.IUserFeedback> DisplayUserFeedbackPopup() => throw new NotSupportedException();
#else
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => throw new NotSupportedException();
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => throw new NotSupportedException();
#endif
#if USEFLYOUT
@ -129,5 +130,5 @@ namespace TINK.View.Contact
/// </summary>
public INavigationMasterDetail NavigationMasterDetail { set; private get; }
#endif
}
}
}

View file

@ -8,67 +8,67 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.Contact
{
using Serilog;
using TINK.Model;
using TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
using TINK.ViewModel.Contact;
using Serilog;
using TINK.Model;
using TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
using TINK.ViewModel.Contact;
[XamlCompilation(XamlCompilationOptions.Compile)]
[XamlCompilation(XamlCompilationOptions.Compile)]
#if USEFLYOUT
public partial class SelectStationPage : ContentPage, IViewService, IDetailPage
#else
public partial class SelectStationPage : ContentPage, IViewService
public partial class SelectStationPage : ContentPage, IViewService
#endif
{
/// <summary> View model to notify about whether page appears or hides. </summary>
private SelectStationPageViewModel SelectStationPageViewModel { get; set; }
{
/// <summary> View model to notify about whether page appears or hides. </summary>
private SelectStationPageViewModel SelectStationPageViewModel { get; set; }
public SelectStationPage()
{
InitializeComponent();
}
public SelectStationPage()
{
InitializeComponent();
}
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="cancel">Type of buttons.</param>
public new async Task DisplayAlert(string title, string message, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, message, cancel);
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="cancel">Type of buttons.</param>
public new async Task DisplayAlert(string title, string message, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, message, cancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of button.</param>
/// <returns>True if user pressed accept.</returns>
public new async Task<bool> DisplayAlert(string title, string message, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, message, accept, cancel);
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of button.</param>
/// <returns>True if user pressed accept.</returns>
public new async Task<bool> DisplayAlert(string title, string message, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, message, accept, cancel);
#if USEFLYOUT
/// <summary>
@ -78,45 +78,45 @@ namespace TINK.View.Contact
public void ShowPage(ViewTypes type, string title = null)
=> NavigationMasterDetail.ShowPage(type.GetViewType(), title);
#else
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
#endif
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="typeOfPage">Type of page to display.</param>
public async Task PushModalAsync(ViewTypes typeOfPage)
=> await Navigation.PushModalAsync((Page)Activator.CreateInstance(typeOfPage.GetViewType()));
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="typeOfPage">Type of page to display.</param>
public async Task PushModalAsync(ViewTypes typeOfPage)
=> await Navigation.PushModalAsync((Page)Activator.CreateInstance(typeOfPage.GetViewType()));
/// <summary> Pops a page from the modal stack. </summary>
public async Task PopModalAsync()
=> await Navigation.PopModalAsync();
/// <summary> Pops a page from the modal stack. </summary>
public async Task PopModalAsync()
=> await Navigation.PopModalAsync();
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="typeOfPage">Page to display.</param>
public async Task PushAsync(ViewTypes typeOfPage)
{
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="typeOfPage">Page to display.</param>
public async Task PushAsync(ViewTypes typeOfPage)
{
#if USEFLYOUT
var page = Activator.CreateInstance(typeOfPage.GetViewType()) as IDetailPage;
#else
var page = Activator.CreateInstance(typeOfPage.GetViewType());
var page = Activator.CreateInstance(typeOfPage.GetViewType());
#endif
if (page == null)
{
return;
}
if (page == null)
{
return;
}
#if USEFLYOUT
page.NavigationMasterDetail = NavigationMasterDetail;
#endif
await Navigation.PushAsync((Page)page);
}
await Navigation.PushAsync((Page)page);
}
#if USCSHARP9
public Task<IViewService.IUserFeedback> DisplayUserFeedbackPopup() => throw new NotSupportedException();
#else
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => throw new NotSupportedException();
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => throw new NotSupportedException();
#endif
#if USEFLYOUT
@ -124,86 +124,86 @@ namespace TINK.View.Contact
public INavigationMasterDetail NavigationMasterDetail { private get; set; }
#endif
/// <summary>
/// Invoked when page is shown.
/// Starts update process.
/// </summary>
protected async override void OnAppearing()
{
// Pass reference to member Navigation to show bikes at station x dialog.
try
{
Log.ForContext<SelectStationPageViewModel>().Verbose("Constructing select station view model.");
/// <summary>
/// Invoked when page is shown.
/// Starts update process.
/// </summary>
protected async override void OnAppearing()
{
// Pass reference to member Navigation to show bikes at station x dialog.
try
{
Log.ForContext<SelectStationPageViewModel>().Verbose("Constructing select station view model.");
#if TRYNOTBACKSTYLE
SelectStationPageViewModel = new SelectStationPageViewModel();
#else
SelectStationPageViewModel = new SelectStationPageViewModel(
App.ModelRoot,
App.PermissionsService,
App.BluetoothService,
App.LocationServicesContainer.Active,
(mapspan) => MyMap.MoveToRegion(mapspan),
this,
Navigation);
SelectStationPageViewModel = new SelectStationPageViewModel(
App.ModelRoot,
App.PermissionsService,
App.BluetoothService,
App.LocationServicesContainer.Active,
(mapspan) => MyMap.MoveToRegion(mapspan),
this,
Navigation);
#endif
}
catch (Exception exception)
{
}
catch (Exception exception)
{
Log.ForContext<SelectStationPageViewModel>().Error("Constructing select station view model failed. {Exception}", exception);
return;
}
Log.ForContext<SelectStationPageViewModel>().Error("Constructing select station view model failed. {Exception}", exception);
return;
}
try
{
BindingContext = SelectStationPageViewModel;
try
{
BindingContext = SelectStationPageViewModel;
#if USEFLYOUT
SelectStationPageViewModel.NavigationMasterDetail = NavigationMasterDetail;
#endif
}
catch (Exception exception)
{
Log.ForContext<SelectStationPageViewModel>().Error("Setting binding/ navigaton on select station failed. {Exception}", exception);
return;
}
}
catch (Exception exception)
{
Log.ForContext<SelectStationPageViewModel>().Error("Setting binding/ navigaton on select station failed. {Exception}", exception);
return;
}
try
{
base.OnAppearing();
}
catch (Exception exception)
{
// Continue because styling is not essential.
Log.ForContext<SelectStationPageViewModel>().Error("Invoking OnAppearing of base failed. {Exception}", exception);
return;
}
try
{
base.OnAppearing();
}
catch (Exception exception)
{
// Continue because styling is not essential.
Log.ForContext<SelectStationPageViewModel>().Error("Invoking OnAppearing of base failed. {Exception}", exception);
return;
}
try
{
// Pre move and scanle maps to avoid initial display of map in Rome.
Log.ForContext<SelectStationPageViewModel>().Verbose("Moving and scaling map.");
SelectStationPageViewModel.MoveAndScale(
(mapSpan) => MyMap.MoveToRegion(mapSpan),
App.ModelRoot.Uris.ActiveUri);
}
catch (Exception exception)
{
// Continue because a map not beeing moved/ scaled is no reason for aborting startup.
Log.ForContext<SelectStationPageViewModel>().Error("Moving and scaling map failed. {Exception}", exception);
}
try
{
// Pre move and scanle maps to avoid initial display of map in Rome.
Log.ForContext<SelectStationPageViewModel>().Verbose("Moving and scaling map.");
SelectStationPageViewModel.MoveAndScale(
(mapSpan) => MyMap.MoveToRegion(mapSpan),
App.ModelRoot.Uris.ActiveUri);
}
catch (Exception exception)
{
// Continue because a map not beeing moved/ scaled is no reason for aborting startup.
Log.ForContext<SelectStationPageViewModel>().Error("Moving and scaling map failed. {Exception}", exception);
}
try
{
Log.ForContext<SelectStationPageViewModel>().Verbose("Invoking OnAppearing on select station view model.");
await SelectStationPageViewModel.OnAppearing();
}
catch (Exception exception)
{
Log.ForContext<SelectStationPageViewModel>().Error("Invoking OnAppearing on select station view model failed. {Exception}", exception);
return;
}
}
}
try
{
Log.ForContext<SelectStationPageViewModel>().Verbose("Invoking OnAppearing on select station view model.");
await SelectStationPageViewModel.OnAppearing();
}
catch (Exception exception)
{
Log.ForContext<SelectStationPageViewModel>().Error("Invoking OnAppearing on select station view model failed. {Exception}", exception);
return;
}
}
}
}

View file

@ -7,53 +7,53 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.CopriWebView
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ManageAccountPage : ContentPage
{
public ManageAccountPage()
{
InitializeComponent();
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ManageAccountPage : ContentPage
{
public ManageAccountPage()
{
InitializeComponent();
ManageAccount.Navigating += (sender, ev) =>
{
if (!ev.Url.ToUpper().EndsWith(".PDF"))
{
// Stay inside web view except for downloading pdf- files.
this.IsEnabled = false;
ActivityIndicatorLoading.IsVisible = true;
ActivityIndicatorLoading.IsRunning = true;
return;
}
ManageAccount.Navigating += (sender, ev) =>
{
if (!ev.Url.ToUpper().EndsWith(".PDF"))
{
// Stay inside web view except for downloading pdf- files.
this.IsEnabled = false;
ActivityIndicatorLoading.IsVisible = true;
ActivityIndicatorLoading.IsRunning = true;
return;
}
DependencyService.Get<IExternalBrowserService>().OpenUrl(ev.Url);
};
DependencyService.Get<IExternalBrowserService>().OpenUrl(ev.Url);
};
ManageAccount.Navigated += (sender, ev) =>
{
if (ev.Result == WebNavigationResult.Success)
{
this.IsEnabled = true;
ActivityIndicatorLoading.IsVisible = false;
ActivityIndicatorLoading.IsRunning = false;
return;
}
ManageAccount.Navigated += (sender, ev) =>
{
if (ev.Result == WebNavigationResult.Success)
{
this.IsEnabled = true;
ActivityIndicatorLoading.IsVisible = false;
ActivityIndicatorLoading.IsRunning = false;
return;
}
Log.ForContext<ManageAccountPage>().Error("Navigation did not succeed.{@Event}{@Sender}", ev, sender);
ManageAccount.Source = new HtmlWebViewSource
{
Html = "<html><b>Kann persönliche Daten nicht anzeigen/ verwalten!</b><br>Verbindung mit Internet ok?</html>"
};
Log.ForContext<ManageAccountPage>().Error("Navigation did not succeed.{@Event}{@Sender}", ev, sender);
ManageAccount.Source = new HtmlWebViewSource
{
Html = "<html><b>Kann persönliche Daten nicht anzeigen/ verwalten!</b><br>Verbindung mit Internet ok?</html>"
};
this.IsEnabled = true;
ActivityIndicatorLoading.IsVisible = false;
ActivityIndicatorLoading.IsRunning = false;
};
this.IsEnabled = true;
ActivityIndicatorLoading.IsVisible = false;
ActivityIndicatorLoading.IsRunning = false;
};
ManageAccount.BindingContext = new ManageAccountViewModel(
App.ModelRoot.ActiveUser.SessionCookie,
Model.TinkApp.MerchantId,
CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
App.ModelRoot.NextActiveUri.Host);
}
}
ManageAccount.BindingContext = new ManageAccountViewModel(
App.ModelRoot.ActiveUser.SessionCookie,
Model.TinkApp.MerchantId,
CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
App.ModelRoot.NextActiveUri.Host);
}
}
}

View file

@ -7,45 +7,45 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.CopriWebView
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class PasswordForgottenPage : ContentPage
{
public PasswordForgottenPage()
{
InitializeComponent();
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class PasswordForgottenPage : ContentPage
{
public PasswordForgottenPage()
{
InitializeComponent();
PasswordForgottenWebView.Navigating += (sender, ev) =>
{
this.IsEnabled = false;
ActivityIndicatorLoading.IsVisible = true;
ActivityIndicatorLoading.IsRunning = true;
};
PasswordForgottenWebView.Navigating += (sender, ev) =>
{
this.IsEnabled = false;
ActivityIndicatorLoading.IsVisible = true;
ActivityIndicatorLoading.IsRunning = true;
};
PasswordForgottenWebView.Navigated += (sender, ev) =>
{
if (ev.Result == WebNavigationResult.Success)
{
this.IsEnabled = true;
ActivityIndicatorLoading.IsVisible = false;
ActivityIndicatorLoading.IsRunning = false;
return;
}
PasswordForgottenWebView.Navigated += (sender, ev) =>
{
if (ev.Result == WebNavigationResult.Success)
{
this.IsEnabled = true;
ActivityIndicatorLoading.IsVisible = false;
ActivityIndicatorLoading.IsRunning = false;
return;
}
Log.ForContext<PasswordForgottenPage>().Error("Navigation did not succeed. {@Event}", ev);
PasswordForgottenWebView.Source = new HtmlWebViewSource
{
Html = "<html><b>Kann Passwort vergessen Seite nicht anzeigen!</b><br>Verbindung mit Internet ok?</html>"
};
Log.ForContext<PasswordForgottenPage>().Error("Navigation did not succeed. {@Event}", ev);
PasswordForgottenWebView.Source = new HtmlWebViewSource
{
Html = "<html><b>Kann Passwort vergessen Seite nicht anzeigen!</b><br>Verbindung mit Internet ok?</html>"
};
this.IsEnabled = true;
ActivityIndicatorLoading.IsVisible = false;
ActivityIndicatorLoading.IsRunning = false;
};
this.IsEnabled = true;
ActivityIndicatorLoading.IsVisible = false;
ActivityIndicatorLoading.IsRunning = false;
};
PasswordForgottenWebView.BindingContext = new PasswordForgottonViewModel(
Model.TinkApp.MerchantId,
CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
App.ModelRoot.NextActiveUri.Host);
}
}
PasswordForgottenWebView.BindingContext = new PasswordForgottonViewModel(
Model.TinkApp.MerchantId,
CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
App.ModelRoot.NextActiveUri.Host);
}
}
}

View file

@ -8,48 +8,48 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.CopriWebView
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class RegisterPage : ContentPage
{
public RegisterPage()
{
DependencyService.Get<IWebView>().ClearCookies();
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class RegisterPage : ContentPage
{
public RegisterPage()
{
DependencyService.Get<IWebView>().ClearCookies();
InitializeComponent();
InitializeComponent();
RegisterView.Navigating += (sender, ev) =>
{
this.IsEnabled = false;
ActivityIndicatorLoading.IsVisible = true;
ActivityIndicatorLoading.IsRunning = true;
};
RegisterView.Navigating += (sender, ev) =>
{
this.IsEnabled = false;
ActivityIndicatorLoading.IsVisible = true;
ActivityIndicatorLoading.IsRunning = true;
};
RegisterView.Navigated += (sender, ev) =>
{
if (ev.Result == WebNavigationResult.Success)
{
this.IsEnabled = true;
ActivityIndicatorLoading.IsVisible = false;
ActivityIndicatorLoading.IsRunning = false;
return;
}
RegisterView.Navigated += (sender, ev) =>
{
if (ev.Result == WebNavigationResult.Success)
{
this.IsEnabled = true;
ActivityIndicatorLoading.IsVisible = false;
ActivityIndicatorLoading.IsRunning = false;
return;
}
Log.ForContext<RegisterPage>().Error("Navigation did not succeed. {@Event}", ev);
RegisterView.Source = new HtmlWebViewSource
{
Html = "<html><b>Kann Anmeldeseite nicht anzeigen</b>!<br>Verbindung mit Internet ok?</html>"
};
Log.ForContext<RegisterPage>().Error("Navigation did not succeed. {@Event}", ev);
RegisterView.Source = new HtmlWebViewSource
{
Html = "<html><b>Kann Anmeldeseite nicht anzeigen</b>!<br>Verbindung mit Internet ok?</html>"
};
this.IsEnabled = true;
ActivityIndicatorLoading.IsVisible = false;
ActivityIndicatorLoading.IsRunning = false;
};
this.IsEnabled = true;
ActivityIndicatorLoading.IsVisible = false;
ActivityIndicatorLoading.IsRunning = false;
};
RegisterView.BindingContext = new RegisterPageViewModel(
Model.TinkApp.MerchantId,
CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
App.ModelRoot.NextActiveUri.Host);
RegisterView.BindingContext = new RegisterPageViewModel(
Model.TinkApp.MerchantId,
CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
App.ModelRoot.NextActiveUri.Host);
}
}
}
}
}

View file

@ -10,105 +10,75 @@
<xct:Popup.Resources>
<x:String x:Key="check_circle">&#xf058;</x:String>
</xct:Popup.Resources>
<Grid>
<Grid.RowDefinitions>
<!-- Head and title row -->
<RowDefinition Height="auto"/>
<!--- Co2saving-->
<RowDefinition Height="auto"/>
<!--- checkbox and input elements-->
<RowDefinition Height="*"/>
<!--- ok button-->
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<!-- Head and title - Grid.Row 0 -->
<Grid Grid.Row="0"
<StackLayout>
<!-- Head and title -->
<StackLayout
Padding="30"
BackgroundColor="{DynamicResource primary-back-title-color}">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Label Grid.Row="0"
<Label
HorizontalTextAlignment="Center"
FontSize="Large"
TextColor="White"
Text="{x:Static resources:AppResources.MarkingReturnBikeMainMessage}"/>
<Image Grid.Row="1">
<Image>
<Image.Source>
<FontImageSource Size="Title" Glyph="{StaticResource check_circle}" FontFamily="FA-S"/>
<FontImageSource Size="60" Glyph="{StaticResource check_circle}" FontFamily="FA-S" Color="White"/>
</Image.Source>
</Image>
</Grid>
<!-- Co2saving - Grid.Row 1 -->
</StackLayout>
<!-- Co2saving -->
<Frame
x:Name="Co2SavingFrame"
Grid.Row="1">
x:Name="Co2SavingFrame">
<Label
x:Name="Co2SavingLabel"
Text=""/>
</Frame>
<!-- Checkbox and input elements - Grid.Row 2-->
<ScrollView Grid.Row="2">
<Grid>
<Grid.RowDefinitions>
<!--- Battery charge level -->
<RowDefinition Height="Auto"/>
<!--- Bike is ok GUI -->
<RowDefinition Height="Auto"/>
<!--- Feedback edit GUI -->
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Checkbox and input elements -->
<ScrollView>
<StackLayout>
<!-- Battery level -->
<sharedGui:BarLevelInputView Grid.Row="0"
<sharedGui:BarLevelInputView
x:Name="BarLevelInputView"
HorizontalOptions="Center"
IsVisible="False"/>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- Checkbox Is Broken -->
<CheckBox x:Name="brockenCheckBox" IsChecked="True" Grid.Column="0"/>
<Label
Grid.Column="1"
<!-- Checkbox Is Broken -->
<StackLayout Orientation="Horizontal">
<CheckBox x:Name="brockenCheckBox" IsChecked="True" HeightRequest="20"/>
<Label
FontSize="Medium"
Text= "{x:Static resources:AppResources.MarkingReturnBikeBikeStateIsOK}"/>
</Grid>
<Editor
Grid.Row="2"
</StackLayout>
<Editor
x:Name="feedbackMessage"
AutoSize="TextChanges"
Placeholder="{x:Static resources:AppResources.MarkingReturnBikeFeedbackInputPlaceholder}"
Text="">
<Editor.Triggers>
<DataTrigger TargetType="Editor"
<Editor.Triggers>
<DataTrigger TargetType="Editor"
Binding="{Binding Source={x:Reference brockenCheckBox}, Path=IsChecked}"
Value="true">
<Setter Property="Placeholder"
<Setter Property="Placeholder"
Value="{x:Static resources:AppResources.MarkingReturnBikeFeedbackInputPlaceholder}" />
</DataTrigger>
<DataTrigger TargetType="Editor"
</DataTrigger>
<DataTrigger TargetType="Editor"
Binding="{Binding Source={x:Reference brockenCheckBox}, Path=IsChecked}"
Value="false">
<Setter Property="Placeholder"
<Setter Property="Placeholder"
Value="{x:Static resources:AppResources.MarkingReturnBikeErrorDescriptionInputPlaceholder}" />
</DataTrigger>
</Editor.Triggers>
</Editor>
</Grid>
</DataTrigger>
</Editor.Triggers>
</Editor>
</StackLayout>
</ScrollView>
<!-- Buttons - Grid.Row 3 -->
<!-- Buttons -->
<Button
Grid.Row="3"
WidthRequest="100"
Clicked="OnOkClicked"
Text="OK"
Margin="0,0,0,3"/>
</Grid>
</StackLayout>
</xct:Popup>

View file

@ -5,86 +5,86 @@ using Xamarin.Forms.Xaml;
namespace TINK.View
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class FeedbackPopup : Popup<FeedbackPopup.Result>
{
/// <summary> Constructs user feedback popup.</summary>
/// <param name="battery">Object holding info about battery. For some batteries charging level might need to be updated by user.</param>
/// <param name="co2Saving"> Co2 saving information.</param>
public FeedbackPopup(
IBattery battery = null,
string co2Saving = null)
{
InitializeComponent();
if (string.IsNullOrEmpty(co2Saving))
Co2SavingFrame.IsVisible = false;
else
Co2SavingLabel.Text = co2Saving;
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class FeedbackPopup : Popup<FeedbackPopup.Result>
{
/// <summary> Constructs user feedback popup.</summary>
/// <param name="battery">Object holding info about battery. For some batteries charging level might need to be updated by user.</param>
/// <param name="co2Saving"> Co2 saving information.</param>
public FeedbackPopup(
IBattery battery = null,
string co2Saving = null)
{
InitializeComponent();
if (string.IsNullOrEmpty(co2Saving))
Co2SavingFrame.IsVisible = false;
else
Co2SavingLabel.Text = co2Saving;
if (battery == null
|| (battery.IsBackendAccessible.HasValue && battery.IsBackendAccessible.Value))
{
// Either
// - bike has no engine or
// - backend can access battery level information
// No need to ask user for input.
return;
}
if (battery == null
|| (battery.IsBackendAccessible.HasValue && battery.IsBackendAccessible.Value))
{
// Either
// - bike has no engine or
// - backend can access battery level information
// No need to ask user for input.
return;
}
BarLevelInputView.IsVisible = battery?.MaxChargeBars != null;
BarLevelInputView.Current = battery?.CurrentChargeBars?.ToString() ?? string.Empty;
BarLevelInputView.Maximum = battery?.MaxChargeBars != null ? battery?.MaxChargeBars.ToString() : String.Empty;
BarLevelInputView.IsVisible = battery?.MaxChargeBars != null;
BarLevelInputView.Current = battery?.CurrentChargeBars?.ToString() ?? string.Empty;
BarLevelInputView.Maximum = battery?.MaxChargeBars != null ? battery?.MaxChargeBars.ToString() : String.Empty;
}
}
protected override FeedbackPopup.Result GetLightDismissResult()
{
return new Result
{
CurrentChargeBars = int.TryParse(BarLevelInputView.Current, out int current) ? (int?)current : null,
IsBikeBroken = brockenCheckBox.IsChecked,
Message = feedbackMessage.Text
};
}
protected override FeedbackPopup.Result GetLightDismissResult()
{
return new Result
{
CurrentChargeBars = int.TryParse(BarLevelInputView.Current, out int current) ? (int?)current : null,
IsBikeBroken = brockenCheckBox.IsChecked,
Message = feedbackMessage.Text
};
}
private void OnOkClicked(object sender, EventArgs eventArgs)
{
var result = new Result
{
CurrentChargeBars = int.TryParse(BarLevelInputView.Current, out int current) ? (int?)current : null,
IsBikeBroken = brockenCheckBox.IsChecked,
Message = feedbackMessage.Text
};
private void OnOkClicked(object sender, EventArgs eventArgs)
{
var result = new Result
{
CurrentChargeBars = int.TryParse(BarLevelInputView.Current, out int current) ? (int?)current : null,
IsBikeBroken = brockenCheckBox.IsChecked,
Message = feedbackMessage.Text
};
Dismiss(result);
}
Dismiss(result);
}
/// <summary>
/// Feedback given by user when returning bike.
/// </summary>
/// <summary>
/// Feedback given by user when returning bike.
/// </summary>
#if USCSHARP9
public class Result : IViewService.IUserFeedback
#else
public new class Result : IUserFeedback
public new class Result : IUserFeedback
#endif
{
/// <summary>
/// Holds the current chargeing level of the battery entered by user in bars, null if unkonwn.
/// </summary>
public int? CurrentChargeBars { get; set; }
{
/// <summary>
/// Holds the current chargeing level of the battery entered by user in bars, null if unkonwn.
/// </summary>
public int? CurrentChargeBars { get; set; }
/// <summary>
/// Holds whether bike is broken or not.
/// </summary>
public bool IsBikeBroken { get; set; }
/// <summary>
/// Holds whether bike is broken or not.
/// </summary>
public bool IsBikeBroken { get; set; }
/// <summary>
/// Holds either
/// - general feedback
/// - error description of broken bike
/// or both.
/// </summary>
public string Message { get; set; }
}
}
/// <summary>
/// Holds either
/// - general feedback
/// - error description of broken bike
/// or both.
/// </summary>
public string Message { get; set; }
}
}
}

View file

@ -5,34 +5,34 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.Contact
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class FeesAndBikesPage : TabbedPage
{
public FeesAndBikesPageViewModel ViewModel { get; }
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class FeesAndBikesPage : TabbedPage
{
public FeesAndBikesPageViewModel ViewModel { get; }
public FeesAndBikesPage()
{
InitializeComponent();
public FeesAndBikesPage()
{
InitializeComponent();
ViewModel = new FeesAndBikesPageViewModel(
App.ModelRoot.NextActiveUri.Host,
App.ModelRoot.ResourceUrls.FeesResourcePath,
App.ModelRoot.ResourceUrls.BikesResourcePath,
App.ModelRoot.IsSiteCachingOn);
ViewModel = new FeesAndBikesPageViewModel(
App.ModelRoot.NextActiveUri.Host,
App.ModelRoot.ResourceUrls.FeesResourcePath,
App.ModelRoot.ResourceUrls.BikesResourcePath,
App.ModelRoot.IsSiteCachingOn);
BindingContext = ViewModel;
BindingContext = ViewModel;
/// Info about renting.
InfoRentBikeWebView.Navigating += ViewModelHelper.OnNavigating;
/// Info about renting.
InfoRentBikeWebView.Navigating += ViewModelHelper.OnNavigating;
/// Info about types of bikes.
InfoTypesOfBikesWebView.Navigating += ViewModelHelper.OnNavigating;
}
/// Info about types of bikes.
InfoTypesOfBikesWebView.Navigating += ViewModelHelper.OnNavigating;
}
/// <summary> Called when page is shown. </summary>
protected override void OnAppearing()
{
ViewModel.OnAppearing();
}
}
/// <summary> Called when page is shown. </summary>
protected override void OnAppearing()
{
ViewModel.OnAppearing();
}
}
}

View file

@ -12,141 +12,141 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.FindBike
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class FindBikePage : ContentPage, IViewService
{
/// <summary> Refernce to view model. </summary>
FindBikePageViewModel m_oViewModel = null;
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class FindBikePage : ContentPage, IViewService
{
/// <summary> Refernce to view model. </summary>
FindBikePageViewModel m_oViewModel = null;
public FindBikePage() { }
public FindBikePage() { }
/// <summary>
/// Invoked when page is shown.
/// Starts update process.
/// </summary>
protected async override void OnAppearing()
{
if (m_oViewModel != null)
{
// 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).
await m_oViewModel.OnAppearing();
return;
}
/// <summary>
/// Invoked when page is shown.
/// Starts update process.
/// </summary>
protected async override void OnAppearing()
{
if (m_oViewModel != null)
{
// 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).
await m_oViewModel.OnAppearing();
return;
}
try
{
var model = App.ModelRoot;
try
{
var model = App.ModelRoot;
// Backup synchronization context when called from GUI-thread.
var synchronizationContext = SynchronizationContext.Current;
// Backup synchronization context when called from GUI-thread.
var synchronizationContext = SynchronizationContext.Current;
m_oViewModel = new FindBikePageViewModel(
model.ActiveUser,
App.PermissionsService,
App.BluetoothService,
Device.RuntimePlatform,
() => model.GetIsConnected(),
(isConnected) => model.GetConnector(isConnected),
App.LocationServicesContainer.Active,
model.LocksServices.Active,
model.Stations,
model.Polling,
(d, obj) => synchronizationContext.Post(d, obj),
model.SmartDevice,
this,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url))
{
IsReportLevelVerbose = model.IsReportLevelVerbose
};
}
catch (Exception exception)
{
Log.ForContext<FindBikePage>().Error("Displaying bikes at station page failed. {Exception}", exception);
await DisplayAlert("Fehler", $"Seite Fahrrad Wählen kann nicht angezeigt werden. ${exception.Message}", "OK");
return;
m_oViewModel = new FindBikePageViewModel(
model.ActiveUser,
App.PermissionsService,
App.BluetoothService,
Device.RuntimePlatform,
() => model.GetIsConnected(),
(isConnected) => model.GetConnector(isConnected),
App.LocationServicesContainer.Active,
model.LocksServices.Active,
model.Stations,
model.Polling,
(d, obj) => synchronizationContext.Post(d, obj),
model.SmartDevice,
this,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url))
{
IsReportLevelVerbose = model.IsReportLevelVerbose
};
}
catch (Exception exception)
{
Log.ForContext<FindBikePage>().Error("Displaying bikes at station page failed. {Exception}", exception);
await DisplayAlert("Fehler", $"Seite Fahrrad Wählen kann nicht angezeigt werden. ${exception.Message}", "OK");
return;
}
}
InitializeComponent();
InitializeComponent();
BindingContext = m_oViewModel;
FindBikeListView.ItemsSource = m_oViewModel;
BindingContext = m_oViewModel;
FindBikeListView.ItemsSource = m_oViewModel;
await m_oViewModel.OnAppearing();
}
await m_oViewModel.OnAppearing();
}
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strCancel">Type of buttons.</param>
public new async Task DisplayAlert(string p_strTitle, string p_strMessage, string p_strCancel)
=> await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strCancel);
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strCancel">Type of buttons.</param>
public new async Task DisplayAlert(string p_strTitle, string p_strMessage, string p_strCancel)
=> await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strCancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strAccept">Text of accept button.</param>
/// <param name="p_strCancel">Text of button.</param>
/// <returns>True if user pressed accept.</returns>
public new async Task<bool> DisplayAlert(string p_strTitle, string p_strMessage, string p_strAccept, string p_strCancel)
=> await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strAccept, p_strCancel);
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strAccept">Text of accept button.</param>
/// <param name="p_strCancel">Text of button.</param>
/// <returns>True if user pressed accept.</returns>
public new async Task<bool> DisplayAlert(string p_strTitle, string p_strMessage, string p_strAccept, string p_strCancel)
=> await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strAccept, p_strCancel);
#if USEFLYOUT
public void ShowPage(ViewTypes p_oType, string p_strTitle = null)
=> throw new NotImplementedException();
#else
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
#endif
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="typeOfPage">Page to display.</param>
public async Task PushModalAsync(ViewTypes typeOfPage)
=> await Navigation.PushModalAsync((Page)Activator.CreateInstance(typeOfPage.GetViewType()));
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="typeOfPage">Page to display.</param>
public async Task PushModalAsync(ViewTypes typeOfPage)
=> await Navigation.PushModalAsync((Page)Activator.CreateInstance(typeOfPage.GetViewType()));
/// <summary> Pops a page from the modal stack. </summary>
public Task PopModalAsync() => throw new NotSupportedException();
/// <summary> Pops a page from the modal stack. </summary>
public Task PopModalAsync() => throw new NotSupportedException();
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushAsync(ViewTypes p_oTypeOfPage) => throw new NotSupportedException();
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushAsync(ViewTypes p_oTypeOfPage) => throw new NotSupportedException();
#if USCSHARP9
public async Task<IViewService.IUserFeedback> DisplayUserFeedbackPopup() => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup());
#else
/// <summary> Displays user feedback popup.</summary>
/// <param name="co2Saving"> Co2 saving information.</param>
/// <returns>User feedback.</returns>
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup(battery, co2Saving));
/// <summary> Displays user feedback popup.</summary>
/// <param name="co2Saving"> Co2 saving information.</param>
/// <returns>User feedback.</returns>
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup(battery, co2Saving));
#endif
}
}
}

View file

@ -11,65 +11,65 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.Info.BikeInfo
{
[XamlCompilation(XamlCompilationOptions.Compile)]
[XamlCompilation(XamlCompilationOptions.Compile)]
#if USEFLYOUT
public partial class BikeInfoCarouselPage : CarouselPage, IViewService, IDetailPage
#else
public partial class BikeInfoCarouselPage : CarouselPage, IViewService
public partial class BikeInfoCarouselPage : CarouselPage, IViewService
#endif
{
public BikeInfoCarouselPage()
{
InitializeComponent();
{
public BikeInfoCarouselPage()
{
InitializeComponent();
ItemsSource = new BikeInfoViewModel(
resourceName => ImageSource.FromResource($"{ViewModelResourceHelper.RessourcePrefix}Images.{resourceName}"),
this).CarouselItems;
}
ItemsSource = new BikeInfoViewModel(
resourceName => ImageSource.FromResource($"{ViewModelResourceHelper.RessourcePrefix}Images.{resourceName}"),
this).CarouselItems;
}
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strCancel">Type of buttons.</param>
public new async Task DisplayAlert(string p_strTitle, string p_strMessage, string p_strCancel)
=> await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strCancel);
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strCancel">Type of buttons.</param>
public new async Task DisplayAlert(string p_strTitle, string p_strMessage, string p_strCancel)
=> await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strCancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strAccept">Text of accept button.</param>
/// <param name="p_strCancel">Text of button.</param>
/// <returns>True if user pressed accept.</returns>
public new async Task<bool> DisplayAlert(string p_strTitle, string p_strMessage, string p_strAccept, string p_strCancel)
{
return await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strAccept, p_strCancel);
}
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strAccept">Text of accept button.</param>
/// <param name="p_strCancel">Text of button.</param>
/// <returns>True if user pressed accept.</returns>
public new async Task<bool> DisplayAlert(string p_strTitle, string p_strMessage, string p_strAccept, string p_strCancel)
{
return await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strAccept, p_strCancel);
}
#if USEFLYOUT
/// <summary>
@ -79,31 +79,31 @@ namespace TINK.View.Info.BikeInfo
public void ShowPage(ViewTypes p_oType, string p_strTitle = null)
=> m_oNavigation.ShowPage(p_oType.GetViewType(), p_strTitle);
#else
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
#endif
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushModalAsync(ViewTypes p_oTypeOfPage)
{
throw new NotSupportedException();
}
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushModalAsync(ViewTypes p_oTypeOfPage)
{
throw new NotSupportedException();
}
/// <summary> Pops a page from the modal stack. </summary>
public Task PopModalAsync()
{
throw new NotSupportedException();
}
/// <summary> Pops a page from the modal stack. </summary>
public Task PopModalAsync()
{
throw new NotSupportedException();
}
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushAsync(ViewTypes p_oTypeOfPage)
{
throw new NotImplementedException();
}
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushAsync(ViewTypes p_oTypeOfPage)
{
throw new NotImplementedException();
}
#if USEFLYOUT
/// <summary>
@ -123,7 +123,7 @@ namespace TINK.View.Info.BikeInfo
#if USCSHARP9
public Task<IViewService.IUserFeedback> DisplayUserFeedbackPopup() => throw new NotSupportedException();
#else
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => throw new NotSupportedException();
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => throw new NotSupportedException();
#endif
}
}
}

View file

@ -6,36 +6,36 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.Info
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class InfoPage : TabbedPage
{
public InfoPageViewModel ViewModel { get; }
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class InfoPage : TabbedPage
{
public InfoPageViewModel ViewModel { get; }
public InfoPage()
{
InitializeComponent();
public InfoPage()
{
InitializeComponent();
ViewModel = new InfoPageViewModel(
App.ModelRoot.NextActiveUri.Host,
App.ModelRoot.ResourceUrls.AgbResourcePath,
App.ModelRoot.ResourceUrls.PrivacyResourcePath,
App.ModelRoot.ResourceUrls.ImpressResourcePath,
App.ModelRoot.IsSiteCachingOn,
CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
resourceName => ViewModelResourceHelper.GetSource(resourceName));
TabbedInfoPage.BindingContext = ViewModel;
ViewModel = new InfoPageViewModel(
App.ModelRoot.NextActiveUri.Host,
App.ModelRoot.ResourceUrls.AgbResourcePath,
App.ModelRoot.ResourceUrls.PrivacyResourcePath,
App.ModelRoot.ResourceUrls.ImpressResourcePath,
App.ModelRoot.IsSiteCachingOn,
CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
resourceName => ViewModelResourceHelper.GetSource(resourceName));
TabbedInfoPage.BindingContext = ViewModel;
InfoLicenses.Navigating += ViewModelHelper.OnNavigating;
InfoDatenschutz.Navigating += ViewModelHelper.OnNavigating;
InfoABG.Navigating += ViewModelHelper.OnNavigating;
InfoLicenses.Navigating += ViewModelHelper.OnNavigating;
InfoDatenschutz.Navigating += ViewModelHelper.OnNavigating;
InfoABG.Navigating += ViewModelHelper.OnNavigating;
InfoImpressum.Navigating += ViewModelHelper.OnNavigating;
}
InfoImpressum.Navigating += ViewModelHelper.OnNavigating;
}
/// <summary> Called when page is shown. </summary>
protected override void OnAppearing()
{
ViewModel.OnAppearing();
}
}
/// <summary> Called when page is shown. </summary>
protected override void OnAppearing()
{
ViewModel.OnAppearing();
}
}
}

View file

@ -3,33 +3,33 @@ using Xamarin.Forms;
namespace TINK.View
{
public static class ListViewAttachedBehavior
{
public static readonly BindableProperty CommandProperty =
BindableProperty.CreateAttached(
"Command",
typeof(ICommand),
typeof(ListViewAttachedBehavior),
null,
propertyChanged: OnCommandChanged);
public static class ListViewAttachedBehavior
{
public static readonly BindableProperty CommandProperty =
BindableProperty.CreateAttached(
"Command",
typeof(ICommand),
typeof(ListViewAttachedBehavior),
null,
propertyChanged: OnCommandChanged);
static void OnCommandChanged(BindableObject view, object oldValue, object newValue)
{
var entry = view as ListView;
if (entry == null)
return;
static void OnCommandChanged(BindableObject view, object oldValue, object newValue)
{
var entry = view as ListView;
if (entry == null)
return;
entry.ItemTapped += (sender, e) =>
{
var command = (newValue as ICommand);
if (command == null)
return;
entry.ItemTapped += (sender, e) =>
{
var command = (newValue as ICommand);
if (command == null)
return;
if (command.CanExecute(e.Item))
{
command.Execute(e.Item);
}
};
}
}
if (command.CanExecute(e.Item))
{
command.Execute(e.Item);
}
};
}
}
}

View file

@ -11,60 +11,60 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.Login
{
[XamlCompilation(XamlCompilationOptions.Compile)]
[XamlCompilation(XamlCompilationOptions.Compile)]
#if USEFLYOUT
public partial class LoginPage : ContentPage, IViewService, IDetailPage
#else
public partial class LoginPage : ContentPage, IViewService
public partial class LoginPage : ContentPage, IViewService
#endif
{
public LoginPage()
{
InitializeComponent();
{
public LoginPage()
{
InitializeComponent();
var l_oModel = App.ModelRoot;
var l_oModel = App.ModelRoot;
#if !BACKSTYLE
var l_oViewModel = new LoginPageViewModel(
l_oModel,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url),
this);
var l_oViewModel = new LoginPageViewModel(
l_oModel,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url),
this);
LoginPageView.BindingContext = l_oViewModel;
LoginPageView.BindingContext = l_oViewModel;
#else
LoginPageView.BindingContext = new LoginPageViewModel(l_oModel.ActiveUser, this, Navigation);
#endif
}
}
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strCancel">Type of buttons.</param>
public new async Task DisplayAlert(string p_strTitle, string p_strMessage, string p_strCancel)
=> await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strCancel);
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strCancel">Type of buttons.</param>
public new async Task DisplayAlert(string p_strTitle, string p_strMessage, string p_strCancel)
=> await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strCancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
#if USEFLYOUT
/// <summary>
@ -74,30 +74,30 @@ namespace TINK.View.Login
public void ShowPage(ViewTypes p_oType, string p_strTitle = null)
=> m_oNavigation.ShowPage(p_oType.GetViewType(), p_strTitle);
#else
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
#endif
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public async Task PushModalAsync(ViewTypes typeOfPage)
=> await Navigation.PushModalAsync((Page)Activator.CreateInstance(typeOfPage.GetViewType()));
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public async Task PushModalAsync(ViewTypes typeOfPage)
=> await Navigation.PushModalAsync((Page)Activator.CreateInstance(typeOfPage.GetViewType()));
/// <summary> Pops a page from the modal stack. </summary>
public Task PopModalAsync()
{
throw new NotSupportedException();
}
/// <summary> Pops a page from the modal stack. </summary>
public Task PopModalAsync()
{
throw new NotSupportedException();
}
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public async Task PushAsync(ViewTypes p_oTypeOfPage)
{
await Navigation.PushAsync((Page)Activator.CreateInstance(p_oTypeOfPage.GetViewType()));
}
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public async Task PushAsync(ViewTypes p_oTypeOfPage)
{
await Navigation.PushAsync((Page)Activator.CreateInstance(p_oTypeOfPage.GetViewType()));
}
#if USEFLYOUT
/// <summary>
@ -117,7 +117,7 @@ namespace TINK.View.Login
#if USCSHARP9
public Task<IViewService.IUserFeedback> DisplayUserFeedbackPopup() => throw new NotSupportedException();
#else
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => throw new NotSupportedException();
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => throw new NotSupportedException();
#endif
}
}
}

View file

@ -8,72 +8,72 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.Map
{
using Serilog;
using TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
using TINK.ViewModel.Map;
using Serilog;
using TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
using TINK.ViewModel.Map;
[XamlCompilation(XamlCompilationOptions.Compile)]
[XamlCompilation(XamlCompilationOptions.Compile)]
#if USEFLYOUT
public partial class MapPage : ContentPage, IViewService, IDetailPage
#else
public partial class MapPage : ContentPage, IViewService
public partial class MapPage : ContentPage, IViewService
#endif
{
/// <summary> View model to notify about whether page appears or hides. </summary>
private MapPageViewModel MapPageViewModel { get; set; }
{
/// <summary> View model to notify about whether page appears or hides. </summary>
private MapPageViewModel MapPageViewModel { get; set; }
/// <summary> Initialization status to ensure initialization logic is not called multiple times. </summary>
private bool isInitializationStarted = false;
/// <summary> Initialization status to ensure initialization logic is not called multiple times. </summary>
private bool isInitializationStarted = false;
/// <summary>
/// Constructs map page instance.
/// </summary>
public MapPage()
{
InitializeComponent();
}
/// <summary>
/// Constructs map page instance.
/// </summary>
public MapPage()
{
InitializeComponent();
}
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="cancel">Type of buttons.</param>
public new async Task DisplayAlert(string title, string message, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, message, cancel);
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="cancel">Type of buttons.</param>
public new async Task DisplayAlert(string title, string message, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, message, cancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of button.</param>
/// <returns>True if user pressed accept.</returns>
public new async Task<bool> DisplayAlert(string title, string message, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, message, accept, cancel);
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of button.</param>
/// <returns>True if user pressed accept.</returns>
public new async Task<bool> DisplayAlert(string title, string message, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, message, accept, cancel);
#if USEFLYOUT
/// <summary>
@ -83,45 +83,45 @@ namespace TINK.View.Map
public void ShowPage(ViewTypes type, string title = null)
=> NavigationMasterDetail.ShowPage(type.GetViewType(), title);
#else
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
#endif
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="typeOfPage">Type of page to display.</param>
public async Task PushModalAsync(ViewTypes typeOfPage)
=> await Navigation.PushModalAsync((Page)Activator.CreateInstance(typeOfPage.GetViewType()));
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="typeOfPage">Type of page to display.</param>
public async Task PushModalAsync(ViewTypes typeOfPage)
=> await Navigation.PushModalAsync((Page)Activator.CreateInstance(typeOfPage.GetViewType()));
/// <summary> Pops a page from the modal stack. </summary>
public async Task PopModalAsync()
=> await Navigation.PopModalAsync();
/// <summary> Pops a page from the modal stack. </summary>
public async Task PopModalAsync()
=> await Navigation.PopModalAsync();
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="typeOfPage">Page to display.</param>
public async Task PushAsync(ViewTypes typeOfPage)
{
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="typeOfPage">Page to display.</param>
public async Task PushAsync(ViewTypes typeOfPage)
{
#if USEFLYOUT
var page = Activator.CreateInstance(typeOfPage.GetViewType()) as IDetailPage;
#else
var page = Activator.CreateInstance(typeOfPage.GetViewType());
var page = Activator.CreateInstance(typeOfPage.GetViewType());
#endif
if (page == null)
{
return;
}
if (page == null)
{
return;
}
#if USEFLYOUT
page.NavigationMasterDetail = NavigationMasterDetail;
#endif
await Navigation.PushAsync((Page)page);
}
await Navigation.PushAsync((Page)page);
}
#if USCSHARP9
public Task<IViewService.IUserFeedback> DisplayUserFeedbackPopup() => throw new NotSupportedException();
#else
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => throw new NotSupportedException();
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => throw new NotSupportedException();
#endif
#if USEFLYOUT
@ -129,153 +129,153 @@ namespace TINK.View.Map
public INavigationMasterDetail NavigationMasterDetail { private get; set; }
#endif
/// <summary>
/// Invoked when page is shown.
/// Starts update process.
/// </summary>
protected async override void OnAppearing()
{
// Don't repeat the initialization if it has been completed already.
if (isInitializationStarted) return;
isInitializationStarted = true;
/// <summary>
/// Invoked when page is shown.
/// Starts update process.
/// </summary>
protected async override void OnAppearing()
{
// Don't repeat the initialization if it has been completed already.
if (isInitializationStarted) return;
isInitializationStarted = true;
// Pass reference to member Navigation to show bikes at station x dialog.
try
{
Log.ForContext<MapPage>().Verbose("Constructing map page view model.");
// Pass reference to member Navigation to show bikes at station x dialog.
try
{
Log.ForContext<MapPage>().Verbose("Constructing map page view model.");
#if TRYNOTBACKSTYLE
MapPageViewModel = new MapPageViewModel();
#else
MapPageViewModel = CreateMapPageViewModel();
MapPageViewModel = CreateMapPageViewModel();
#endif
}
catch (Exception exception)
{
Log.ForContext<MapPage>().Error("Constructing map page view model failed. {Exception}", exception);
isInitializationStarted = false;
return;
}
}
catch (Exception exception)
{
Log.ForContext<MapPage>().Error("Constructing map page view model failed. {Exception}", exception);
isInitializationStarted = false;
return;
}
try
{
BindingContext = MapPageViewModel;
try
{
BindingContext = MapPageViewModel;
#if USEFLYOUT
MapPageViewModel.NavigationMasterDetail = NavigationMasterDetail;
#endif
}
catch (Exception exception)
{
Log.ForContext<MapPage>().Error("Setting binding/ navigaton on map page failed. {Exception}", exception);
isInitializationStarted = false;
return;
}
}
catch (Exception exception)
{
Log.ForContext<MapPage>().Error("Setting binding/ navigaton on map page failed. {Exception}", exception);
isInitializationStarted = false;
return;
}
try
{
ApplyCustomiOSStyling();
}
catch (Exception exception)
{
// Continue because styling is not essential.
Log.ForContext<MapPage>().Error("IOS specific styling of map page failed. {Exception}", exception);
}
try
{
ApplyCustomiOSStyling();
}
catch (Exception exception)
{
// Continue because styling is not essential.
Log.ForContext<MapPage>().Error("IOS specific styling of map page failed. {Exception}", exception);
}
try
{
base.OnAppearing();
}
catch (Exception exception)
{
// Continue because styling is not essential.
Log.ForContext<MapPage>().Error("Invoking OnAppearing of base failed. {Exception}", exception);
isInitializationStarted = false;
return;
}
try
{
base.OnAppearing();
}
catch (Exception exception)
{
// Continue because styling is not essential.
Log.ForContext<MapPage>().Error("Invoking OnAppearing of base failed. {Exception}", exception);
isInitializationStarted = false;
return;
}
try
{
// Pre move and scanle maps to avoid initial display of map in Rome.
PremoveAndScaleMap();
}
catch (Exception exception)
{
// Continue because a map not beeing moved/ scaled is no reason for aborting startup.
Log.ForContext<MapPage>().Error("Moving and scaling map failed. {Exception}", exception);
}
try
{
// Pre move and scanle maps to avoid initial display of map in Rome.
PremoveAndScaleMap();
}
catch (Exception exception)
{
// Continue because a map not beeing moved/ scaled is no reason for aborting startup.
Log.ForContext<MapPage>().Error("Moving and scaling map failed. {Exception}", exception);
}
try
{
Log.ForContext<MapPage>().Verbose("Invoking OnAppearing on map page view model.");
await MapPageViewModel.OnAppearing();
try
{
Log.ForContext<MapPage>().Verbose("Invoking OnAppearing on map page view model.");
await MapPageViewModel.OnAppearing();
isInitializationStarted = false;
}
catch (Exception exception)
{
Log.ForContext<MapPage>().Error("Invoking OnAppearing on map page view model failed. {Exception}", exception);
isInitializationStarted = false;
return;
}
}
isInitializationStarted = false;
}
catch (Exception exception)
{
Log.ForContext<MapPage>().Error("Invoking OnAppearing on map page view model failed. {Exception}", exception);
isInitializationStarted = false;
return;
}
}
/// <summary>
/// Premoves the Map to a certain location.
/// </summary>
private void PremoveAndScaleMap()
{
Log.ForContext<MapPage>().Verbose("Moving and scaling map.");
MapPageViewModel.MoveAndScale(
(mapSpan) => MyMap.MoveToRegion(mapSpan),
App.ModelRoot.ActiveMapSpan);
}
/// <summary>
/// Premoves the Map to a certain location.
/// </summary>
private void PremoveAndScaleMap()
{
Log.ForContext<MapPage>().Verbose("Moving and scaling map.");
MapPageViewModel.MoveAndScale(
(mapSpan) => MyMap.MoveToRegion(mapSpan),
App.ModelRoot.ActiveMapSpan);
}
/// <summary>
/// Creates the Map Page's view model.
/// </summary>
private MapPageViewModel CreateMapPageViewModel()
{
Log.ForContext<MapPage>().Verbose("Constructing map page view model.");
return new MapPageViewModel(
App.ModelRoot,
App.PermissionsService,
App.BluetoothService,
App.LocationServicesContainer.Active,
(mapspan) => MyMap.MoveToRegion(mapspan),
this,
Navigation);
}
/// <summary>
/// Creates the Map Page's view model.
/// </summary>
private MapPageViewModel CreateMapPageViewModel()
{
Log.ForContext<MapPage>().Verbose("Constructing map page view model.");
return new MapPageViewModel(
App.ModelRoot,
App.PermissionsService,
App.BluetoothService,
App.LocationServicesContainer.Active,
(mapspan) => MyMap.MoveToRegion(mapspan),
this,
Navigation);
}
/// <summary>
/// Applies iOS specific styling to branded Buttons.
/// </summary>
private void ApplyCustomiOSStyling()
{
if (Device.RuntimePlatform == Device.iOS)
{
TINKButton.BackgroundColor = Color.LightGray;
TINKButton.BorderColor = Color.Black;
TINKButton.Margin = new Thickness(10, 10, 10, 10);
KonradButton.BackgroundColor = Color.LightGray;
KonradButton.BorderColor = Color.Black;
KonradButton.Margin = new Thickness(10, 10, 10, 10);
}
}
/// <summary>
/// Applies iOS specific styling to branded Buttons.
/// </summary>
private void ApplyCustomiOSStyling()
{
if (Device.RuntimePlatform == Device.iOS)
{
TINKButton.BackgroundColor = Color.LightGray;
TINKButton.BorderColor = Color.Black;
TINKButton.Margin = new Thickness(10, 10, 10, 10);
KonradButton.BackgroundColor = Color.LightGray;
KonradButton.BorderColor = Color.Black;
KonradButton.Margin = new Thickness(10, 10, 10, 10);
}
}
/// <summary>
/// Invoked when pages is closed/ hidden.
/// Stops update process.
/// </summary>
protected override async void OnDisappearing()
{
if (MapPageViewModel != null)
{
// View model might be null.
await MapPageViewModel?.OnDisappearing();
}
/// <summary>
/// Invoked when pages is closed/ hidden.
/// Stops update process.
/// </summary>
protected override async void OnDisappearing()
{
if (MapPageViewModel != null)
{
// View model might be null.
await MapPageViewModel?.OnDisappearing();
}
base.OnDisappearing();
}
}
base.OnDisappearing();
}
}
}

View file

@ -8,93 +8,93 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.MiniSurvey
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MiniSurveyPage : ContentPage, IViewService
{
public MiniSurveyPage()
{
var model = App.ModelRoot;
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MiniSurveyPage : ContentPage, IViewService
{
public MiniSurveyPage()
{
var model = App.ModelRoot;
var vm = new MiniSurveyViewModel(
() => model.GetIsConnected(),
(isConnected) => model.GetConnector(isConnected),
this);
var vm = new MiniSurveyViewModel(
() => model.GetIsConnected(),
(isConnected) => model.GetConnector(isConnected),
this);
InitializeComponent();
InitializeComponent();
BindingContext = vm;
MiniSurveyListView.ItemsSource = vm;
}
BindingContext = vm;
MiniSurveyListView.ItemsSource = vm;
}
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strCancel">Type of buttons.</param>
public new async Task DisplayAlert(string p_strTitle, string p_strMessage, string p_strCancel)
=> await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strCancel);
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strCancel">Type of buttons.</param>
public new async Task DisplayAlert(string p_strTitle, string p_strMessage, string p_strCancel)
=> await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strCancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strAccept">Text of accept button.</param>
/// <param name="p_strCancel">Text of button.</param>
/// <returns>True if user pressed accept.</returns>
public new async Task<bool> DisplayAlert(string p_strTitle, string p_strMessage, string p_strAccept, string p_strCancel)
=> await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strAccept, p_strCancel);
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strAccept">Text of accept button.</param>
/// <param name="p_strCancel">Text of button.</param>
/// <returns>True if user pressed accept.</returns>
public new async Task<bool> DisplayAlert(string p_strTitle, string p_strMessage, string p_strAccept, string p_strCancel)
=> await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strAccept, p_strCancel);
#if USEFLYOUT
public void ShowPage(ViewTypes p_oType, string p_strTitle = null)
=> throw new NotImplementedException();
#else
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
#endif
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushModalAsync(ViewTypes p_oTypeOfPage) => throw new NotSupportedException();
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushModalAsync(ViewTypes p_oTypeOfPage) => throw new NotSupportedException();
/// <summary> Pops a page from the modal stack. </summary>
public Task PopModalAsync() => Navigation.PopModalAsync();
/// <summary> Pops a page from the modal stack. </summary>
public Task PopModalAsync() => Navigation.PopModalAsync();
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushAsync(ViewTypes p_oTypeOfPage) => throw new NotSupportedException();
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushAsync(ViewTypes p_oTypeOfPage) => throw new NotSupportedException();
#if USCSHARP9
public async Task<IViewService.IUserFeedback> DisplayUserFeedbackPopup() => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup());
#else
/// <summary> Displays user feedback popup.</summary>
/// <param name="co2Saving"> Co2 saving information.</param>
/// <returns>User feedback.</returns>
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup(battery, co2Saving));
/// <summary> Displays user feedback popup.</summary>
/// <param name="co2Saving"> Co2 saving information.</param>
/// <returns>User feedback.</returns>
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup(battery, co2Saving));
#endif
}
}
}

View file

@ -3,12 +3,12 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.MiniSurvey.Question
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CheckOneViewCell : ViewCell
{
public CheckOneViewCell()
{
InitializeComponent();
}
}
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CheckOneViewCell : ViewCell
{
public CheckOneViewCell()
{
InitializeComponent();
}
}
}

View file

@ -4,12 +4,12 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.MiniSurvey.Question
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class FreeTextViewCell : ViewCell
{
public FreeTextViewCell()
{
InitializeComponent();
}
}
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class FreeTextViewCell : ViewCell
{
public FreeTextViewCell()
{
InitializeComponent();
}
}
}

View file

@ -2,25 +2,25 @@
namespace TINK.View.MiniSurvey.Question
{
/// <summary>
/// Selects different templates for different question types.
/// </summary>
public class QuestionViewCellTemplateSelector : DataTemplateSelector
{
DataTemplate checkOneViewCell;
DataTemplate freeTextViewCell;
/// <summary>
/// Selects different templates for different question types.
/// </summary>
public class QuestionViewCellTemplateSelector : DataTemplateSelector
{
DataTemplate checkOneViewCell;
DataTemplate freeTextViewCell;
public QuestionViewCellTemplateSelector()
{
checkOneViewCell = new DataTemplate(typeof(CheckOneViewCell));
freeTextViewCell = new DataTemplate(typeof(FreeTextViewCell));
}
public QuestionViewCellTemplateSelector()
{
checkOneViewCell = new DataTemplate(typeof(CheckOneViewCell));
freeTextViewCell = new DataTemplate(typeof(FreeTextViewCell));
}
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
return item is ViewModel.MiniSurvey.Question.FreeTextViewModel
? freeTextViewCell
: checkOneViewCell;
}
}
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
return item is ViewModel.MiniSurvey.Question.FreeTextViewModel
? freeTextViewCell
: checkOneViewCell;
}
}
}

View file

@ -10,177 +10,177 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.MyBikes
{
using Serilog;
using TINK.Model;
using TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
using TINK.Model.Device;
using TINK.ViewModel.MyBikes;
using Xamarin.CommunityToolkit.Extensions;
using Serilog;
using TINK.Model;
using TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
using TINK.Model.Device;
using TINK.ViewModel.MyBikes;
using Xamarin.CommunityToolkit.Extensions;
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MyBikesPage : ContentPage, IViewService
{
/// <summary> Refernce to view model. </summary>
MyBikesPageViewModel m_oViewModel = null;
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MyBikesPage : ContentPage, IViewService
{
/// <summary> Refernce to view model. </summary>
MyBikesPageViewModel m_oViewModel = null;
/// <summary> Initialization status to ensure initialization logic is not called multiple times. </summary>
private bool isInitializationStarted = false;
/// <summary> Initialization status to ensure initialization logic is not called multiple times. </summary>
private bool isInitializationStarted = false;
/// <summary>
/// Constructs a my bikes page.
/// </summary>
public MyBikesPage()
{
}
/// <summary>
/// Constructs a my bikes page.
/// </summary>
public MyBikesPage()
{
}
/// <summary>
/// Invoked when page is shown.
/// Starts update process.
/// </summary>
protected async override void OnAppearing()
{
// Don't repeat the initialization if it has been completed already.
if (isInitializationStarted) return;
isInitializationStarted = true;
/// <summary>
/// Invoked when page is shown.
/// Starts update process.
/// </summary>
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)
{
// 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).
await m_oViewModel.OnAppearing();
isInitializationStarted = false;
return;
}
if (m_oViewModel != null)
{
// 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).
await m_oViewModel.OnAppearing();
isInitializationStarted = false;
return;
}
try
{
var model = App.ModelRoot;
try
{
var model = App.ModelRoot;
// Backup synchronization context when called from GUI-thread.
var synchronizationContext = SynchronizationContext.Current;
// Backup synchronization context when called from GUI-thread.
var synchronizationContext = SynchronizationContext.Current;
m_oViewModel = new MyBikesPageViewModel(
model.ActiveUser,
App.PermissionsService,
App.BluetoothService,
Device.RuntimePlatform,
() => model.GetIsConnected(),
(isConnected) => model.GetConnector(isConnected),
App.LocationServicesContainer.Active,
model.LocksServices.Active,
model.Stations,
model.Polling,
(d, obj) => synchronizationContext.Post(d, obj),
model.SmartDevice,
this,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url))
{
IsReportLevelVerbose = model.IsReportLevelVerbose
};
}
catch (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");
isInitializationStarted = false;
return;
}
m_oViewModel = new MyBikesPageViewModel(
model.ActiveUser,
App.PermissionsService,
App.BluetoothService,
Device.RuntimePlatform,
() => model.GetIsConnected(),
(isConnected) => model.GetConnector(isConnected),
App.LocationServicesContainer.Active,
model.LocksServices.Active,
model.Stations,
model.Polling,
(d, obj) => synchronizationContext.Post(d, obj),
model.SmartDevice,
this,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url))
{
IsReportLevelVerbose = model.IsReportLevelVerbose
};
}
catch (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");
isInitializationStarted = false;
return;
}
InitializeComponent();
InitializeComponent();
BindingContext = m_oViewModel;
MyBikesListView.ItemsSource = m_oViewModel;
BindingContext = m_oViewModel;
MyBikesListView.ItemsSource = m_oViewModel;
await m_oViewModel.OnAppearing();
isInitializationStarted = false;
}
await m_oViewModel.OnAppearing();
isInitializationStarted = false;
}
/// <summary>
/// Invoked when pages is closed/ hidden.
/// Stops update process.
/// </summary>
protected async override void OnDisappearing()
{
if (m_oViewModel == null)
{
// View model might be null (Example: Occured when page to querry for location permissions was opened)
return;
}
/// <summary>
/// Invoked when pages is closed/ hidden.
/// Stops update process.
/// </summary>
protected async override void OnDisappearing()
{
if (m_oViewModel == null)
{
// View model might be null (Example: Occured when page to querry for location permissions was opened)
return;
}
await m_oViewModel.OnDisappearing();
}
await m_oViewModel.OnDisappearing();
}
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strCancel">Type of buttons.</param>
public new async Task DisplayAlert(string p_strTitle, string p_strMessage, string p_strCancel)
=> await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strCancel);
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strCancel">Type of buttons.</param>
public new async Task DisplayAlert(string p_strTitle, string p_strMessage, string p_strCancel)
=> await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strCancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strAccept">Text of accept button.</param>
/// <param name="p_strCancel">Text of button.</param>
/// <returns>True if user pressed accept.</returns>
public new async Task<bool> DisplayAlert(string p_strTitle, string p_strMessage, string p_strAccept, string p_strCancel)
=> await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strAccept, p_strCancel);
/// <summary>
/// Displays alert message.
/// </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strAccept">Text of accept button.</param>
/// <param name="p_strCancel">Text of button.</param>
/// <returns>True if user pressed accept.</returns>
public new async Task<bool> DisplayAlert(string p_strTitle, string p_strMessage, string p_strAccept, string p_strCancel)
=> await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strAccept, p_strCancel);
#if USEFLYOUT
public void ShowPage(ViewTypes p_oType, string p_strTitle = null)
=> throw new NotImplementedException();
#else
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
#endif
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="typeOfPage">Page to display.</param>
public async Task PushModalAsync(ViewTypes typeOfPage)
=> await Navigation.PushModalAsync((Page)Activator.CreateInstance(typeOfPage.GetViewType()));
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="typeOfPage">Page to display.</param>
public async Task PushModalAsync(ViewTypes typeOfPage)
=> await Navigation.PushModalAsync((Page)Activator.CreateInstance(typeOfPage.GetViewType()));
/// <summary> Pops a page from the modal stack. </summary>
public Task PopModalAsync() => throw new NotSupportedException();
/// <summary> Pops a page from the modal stack. </summary>
public Task PopModalAsync() => throw new NotSupportedException();
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushAsync(ViewTypes p_oTypeOfPage) => throw new NotSupportedException();
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushAsync(ViewTypes p_oTypeOfPage) => throw new NotSupportedException();
#if USCSHARP9
public async Task<IViewService.IUserFeedback> DisplayUserFeedbackPopup() => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup());
#else
/// <summary> Displays user feedback popup.</summary>
/// <param name="co2Saving"> Co2 saving information.</param>
/// <returns>User feedback.</returns>
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup(battery, co2Saving));
/// <summary> Displays user feedback popup.</summary>
/// <param name="co2Saving"> Co2 saving information.</param>
/// <returns>User feedback.</returns>
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup(battery, co2Saving));
#endif
}
}
}

View file

@ -8,35 +8,35 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.Root
{
/// <summary>
/// Mamages creation of detail pages if a flyout page menu entry is selected.
/// Exposes flyout page style navigation which is used by detail pages.
/// </summary>
/// <remarks>
/// Examples of use cases when detail pages do navigation:
// - switch to map page after succesfully logging in/ logging out
// - switch to login page form bikes at station page if not yet logged in
/// </remarks>
[XamlCompilation(XamlCompilationOptions.Compile)]
/// <summary>
/// Mamages creation of detail pages if a flyout page menu entry is selected.
/// Exposes flyout page style navigation which is used by detail pages.
/// </summary>
/// <remarks>
/// Examples of use cases when detail pages do navigation:
// - switch to map page after succesfully logging in/ logging out
// - switch to login page form bikes at station page if not yet logged in
/// </remarks>
[XamlCompilation(XamlCompilationOptions.Compile)]
#if USEFLYOUT
public partial class RootPage : FlyoutPage, INavigationMasterDetail
#else
public partial class RootPage : FlyoutPage
public partial class RootPage : FlyoutPage
#endif
{
public RootPage()
{
InitializeComponent();
FlyoutPage.ListView.ItemSelected += OnListViewItemSelected;
{
public RootPage()
{
InitializeComponent();
FlyoutPage.ListView.ItemSelected += OnListViewItemSelected;
// Any type of split behaviour conflics with map shifting functionality (assuming FlyoutPage behaves same like MasterDetailPage).
FlyoutLayoutBehavior = FlyoutLayoutBehavior.Popover;
// Any type of split behaviour conflics with map shifting functionality (assuming FlyoutPage behaves same like MasterDetailPage).
FlyoutLayoutBehavior = FlyoutLayoutBehavior.Popover;
var navigationPage = Detail as NavigationPage;
if (navigationPage == null)
{
return;
}
var navigationPage = Detail as NavigationPage;
if (navigationPage == null)
{
return;
}
#if USEFLYOUT
var detailPage = navigationPage.RootPage as IDetailPage;
@ -47,38 +47,38 @@ namespace TINK.View.Root
detailPage.NavigationMasterDetail = this;
#endif
}
}
/// <summary>
/// Is called if a flyout page menu entry is selected.
/// Creates a new page.
/// </summary>
private void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs e)
{
if (!(e.SelectedItem is RootPageFlyoutMenuItem item))
{
// Unexpected argument detected.
return;
}
/// <summary>
/// Is called if a flyout page menu entry is selected.
/// Creates a new page.
/// </summary>
private void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs e)
{
if (!(e.SelectedItem is RootPageFlyoutMenuItem item))
{
// Unexpected argument detected.
return;
}
// Set selected station to new
App.ModelRoot.SelectedStation = new NullStation();
// Set selected station to new
App.ModelRoot.SelectedStation = new NullStation();
ShowPage(item.TargetType, item.Title);
ShowPage(item.TargetType, item.Title);
IsPresented = false;
FlyoutPage.ListView.SelectedItem = null;
}
IsPresented = false;
FlyoutPage.ListView.SelectedItem = null;
}
/// <summary>
/// Shows a detail page.
/// </summary>
/// <param name="typeOfPage">Type of page to show.</param>
/// <param name="title">Title of page.</param>
public void ShowPage(Type typeOfPage, string title)
{
var page = (Page)Activator.CreateInstance(typeOfPage);
page.Title = title;
/// <summary>
/// Shows a detail page.
/// </summary>
/// <param name="typeOfPage">Type of page to show.</param>
/// <param name="title">Title of page.</param>
public void ShowPage(Type typeOfPage, string title)
{
var page = (Page)Activator.CreateInstance(typeOfPage);
page.Title = title;
#if USEFLYOUT
if (page is IDetailPage detailPage)
@ -89,7 +89,7 @@ namespace TINK.View.Root
}
#endif
Detail = new NavigationPage(page);
}
}
Detail = new NavigationPage(page);
}
}
}

View file

@ -18,19 +18,19 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.Root
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class RootPageFlyout : ContentPage
{
public ListView ListView;
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class RootPageFlyout : ContentPage
{
public ListView ListView;
public RootPageFlyout()
{
InitializeComponent();
public RootPageFlyout()
{
InitializeComponent();
BindingContext = new RootPageFlyoutViewModel();
BindingContext = new RootPageFlyoutViewModel();
ListView = MenuItemsListView;
}
ListView = MenuItemsListView;
}
}
}
}

View file

@ -3,18 +3,18 @@
namespace TINK.View.Root
{
public class RootPageFlyoutMenuItem
{
public RootPageFlyoutMenuItem()
{
TargetType = typeof(RootPageFlyoutMenuItem);
}
public int Id { get; set; }
public class RootPageFlyoutMenuItem
{
public RootPageFlyoutMenuItem()
{
TargetType = typeof(RootPageFlyoutMenuItem);
}
public int Id { get; set; }
public string GlyphCode { get; set; }
public string GlyphCode { get; set; }
public string Title { get; set; }
public string Title { get; set; }
public Type TargetType { get; set; }
}
public Type TargetType { get; set; }
}
}

View file

@ -4,39 +4,39 @@ using TINK.ViewModel.MasterDetail;
namespace TINK.View
{
public class MainPageMenuItem
{
public MainPageMenuItem()
{
TargetType = typeof(MapPage);
}
public class MainPageMenuItem
{
public MainPageMenuItem()
{
TargetType = typeof(MapPage);
}
public MainPageMenuItem(
int p_iId,
Type p_oTypeOfPage,
string p_strTitle = null)
{
TargetType = p_oTypeOfPage;
Id = p_iId;
Title = p_strTitle ?? Helper.GetCaption(p_oTypeOfPage);
}
public MainPageMenuItem(
int p_iId,
Type p_oTypeOfPage,
string p_strTitle = null)
{
TargetType = p_oTypeOfPage;
Id = p_iId;
Title = p_strTitle ?? Helper.GetCaption(p_oTypeOfPage);
}
public int Id
{
get;
private set;
}
public int Id
{
get;
private set;
}
public string Title
{
get;
private set;
}
public string Title
{
get;
private set;
}
public Type TargetType
{
get;
private set;
}
}
public Type TargetType
{
get;
private set;
}
}
}

View file

@ -4,12 +4,12 @@ using Xamarin.Forms;
namespace TINK.View.RootShell
{
public partial class AppShell : Shell
{
public AppShell()
{
InitializeComponent();
BindingContext = new AppShellViewModel();
}
}
public partial class AppShell : Shell
{
public AppShell()
{
InitializeComponent();
BindingContext = new AppShellViewModel();
}
}
}

View file

@ -9,12 +9,12 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.RootShell
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class FlyoutHeader : ContentView
{
public FlyoutHeader()
{
InitializeComponent();
}
}
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class FlyoutHeader : ContentView
{
public FlyoutHeader()
{
InitializeComponent();
}
}
}

View file

@ -12,82 +12,82 @@ using TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
namespace TINK.View.Settings
{
[XamlCompilation(XamlCompilationOptions.Compile)]
[XamlCompilation(XamlCompilationOptions.Compile)]
#if USEFLYOUT
public partial class SettingsPage : ContentPage, IViewService, IDetailPage
#else
public partial class SettingsPage : ContentPage, IViewService
public partial class SettingsPage : ContentPage, IViewService
#endif
{
/// <summary> Refernce to view model. </summary>
SettingsPageViewModel m_oViewModel = null;
{
/// <summary> Refernce to view model. </summary>
SettingsPageViewModel m_oViewModel = null;
/// <summary> Constructs a settings page. </summary>
public SettingsPage()
{
InitializeComponent();
/// <summary> Constructs a settings page. </summary>
public SettingsPage()
{
InitializeComponent();
var l_oModel = App.ModelRoot;
var l_oModel = App.ModelRoot;
m_oViewModel = new SettingsPageViewModel(
l_oModel,
App.LocationServicesContainer,
this);
m_oViewModel = new SettingsPageViewModel(
l_oModel,
App.LocationServicesContainer,
this);
BindingContext = m_oViewModel;
BindingContext = m_oViewModel;
Filters.ItemsSource = m_oViewModel.GroupFilter;
}
Filters.ItemsSource = m_oViewModel.GroupFilter;
}
/// <summary> Displays alert message. </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strCancel">Type of buttons.</param>
public new async Task DisplayAlert(string p_strTitle, string p_strMessage, string p_strCancel)
=> await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strCancel);
/// <summary> Displays alert message. </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strCancel">Type of buttons.</param>
public new async Task DisplayAlert(string p_strTitle, string p_strMessage, string p_strCancel)
=> await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strCancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary> Displays alert message.</summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strAccept">Text of accept button.</param>
/// <param name="p_strCancel">Text of button.</param>
/// <returns>True if user pressed accept.</returns>
public new async Task<bool> DisplayAlert(string p_strTitle, string p_strMessage, string p_strAccept, string p_strCancel)
=> await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strAccept, p_strCancel);
/// <summary> Displays alert message.</summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strAccept">Text of accept button.</param>
/// <param name="p_strCancel">Text of button.</param>
/// <returns>True if user pressed accept.</returns>
public new async Task<bool> DisplayAlert(string p_strTitle, string p_strMessage, string p_strAccept, string p_strCancel)
=> await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strAccept, p_strCancel);
/// <summary>
/// Displays an action sheet.
/// </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strCancel">Text of button.</param>
/// <param name="destruction"></param>
/// <param name="p_oButtons">Buttons holding options to select.</param>
/// <returns>Text selected</returns>
public new async Task<string> DisplayActionSheet(String p_strTitle, String p_strCancel, String destruction, params String[] p_oButtons)
=> await base.DisplayActionSheet(p_strTitle, p_strCancel, destruction, p_oButtons);
/// <summary>
/// Displays an action sheet.
/// </summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
/// <param name="p_strCancel">Text of button.</param>
/// <param name="destruction"></param>
/// <param name="p_oButtons">Buttons holding options to select.</param>
/// <returns>Text selected</returns>
public new async Task<string> DisplayActionSheet(String p_strTitle, String p_strCancel, String destruction, params String[] p_oButtons)
=> await base.DisplayActionSheet(p_strTitle, p_strCancel, destruction, p_oButtons);
#if USEFLYOUT
/// <summary>
@ -97,19 +97,19 @@ namespace TINK.View.Settings
public void ShowPage(ViewTypes p_oType, string p_strTitle = null)
=> m_oNavigation.ShowPage(p_oType.GetViewType(), p_strTitle);
#else
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
#endif
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushModalAsync(ViewTypes p_oTypeOfPage)
=> throw new NotImplementedException();
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushModalAsync(ViewTypes p_oTypeOfPage)
=> throw new NotImplementedException();
/// <summary> Pops a page from the modal stack. </summary>
public Task PopModalAsync()
=> throw new NotSupportedException();
/// <summary> Pops a page from the modal stack. </summary>
public Task PopModalAsync()
=> throw new NotSupportedException();
#if USEFLYOUT
/// <summary>Delegate to perform navigation.</summary>
@ -124,33 +124,33 @@ namespace TINK.View.Settings
}
#endif
/// <summary>
/// Invoked when pages is closed/ hidden.
/// Stops update process.
/// </summary>
protected async override void OnDisappearing()
{
if (m_oViewModel == null)
{
// View model might be null.
return;
}
/// <summary>
/// Invoked when pages is closed/ hidden.
/// Stops update process.
/// </summary>
protected async override void OnDisappearing()
{
if (m_oViewModel == null)
{
// View model might be null.
return;
}
await m_oViewModel?.OnDisappearing();
}
await m_oViewModel?.OnDisappearing();
}
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public async Task PushAsync(ViewTypes p_oTypeOfPage)
=> await Navigation.PushAsync((Page)Activator.CreateInstance(p_oTypeOfPage.GetViewType()));
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public async Task PushAsync(ViewTypes p_oTypeOfPage)
=> await Navigation.PushAsync((Page)Activator.CreateInstance(p_oTypeOfPage.GetViewType()));
#if USCSHARP9
public async Task<IViewService.IUserFeedback> DisplayUserFeedbackPopup() => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup());
#else
/// <summary> Displays user feedback popup.</summary>
/// <param name="co2Saving"> Co2 saving information.</param>
/// <returns>User feedback.</returns>
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup(battery, co2Saving));
/// <summary> Displays user feedback popup.</summary>
/// <param name="co2Saving"> Co2 saving information.</param>
/// <returns>User feedback.</returns>
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup(battery, co2Saving));
#endif
#if USERFEEDBACKDLG_TRYOUT
@ -164,5 +164,5 @@ namespace TINK.View.Settings
"OK");
}
#endif
}
}
}

View file

@ -4,20 +4,20 @@ using Xamarin.Forms;
namespace TINK.View
{
/// <summary> Converts a string into visible state. If string is null or empty element becomes invisible.</summary>
public class StringNotNullOrEmptyToVisibleConverter : IValueConverter
{
/// <summary> Converts a string into visible state.</summary>
/// <param name="value">Text value from view model used to derive whether object is visible or not.</param>
/// <returns>Boolean value indicating whether object is visible or not.</returns>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value != null && value is string text && !string.IsNullOrEmpty(text);
}
/// <summary> Converts a string into visible state. If string is null or empty element becomes invisible.</summary>
public class StringNotNullOrEmptyToVisibleConverter : IValueConverter
{
/// <summary> Converts a string into visible state.</summary>
/// <param name="value">Text value from view model used to derive whether object is visible or not.</param>
/// <returns>Boolean value indicating whether object is visible or not.</returns>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value != null && value is string text && !string.IsNullOrEmpty(text);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return "";
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return "";
}
}
}

View file

@ -15,63 +15,63 @@ using Xamarin.Forms;
namespace TINK.View
{
public static class ViewTypesTypeProvider
{
public static Type GetViewType(this ViewTypes viewType)
{
switch (viewType)
{
case ViewTypes.LoginPage:
return typeof(LoginPage);
public static class ViewTypesTypeProvider
{
public static Type GetViewType(this ViewTypes viewType)
{
switch (viewType)
{
case ViewTypes.LoginPage:
return typeof(LoginPage);
case ViewTypes.MapPage:
return typeof(MapPage);
case ViewTypes.MapPage:
return typeof(MapPage);
case ViewTypes.RegisterPage:
return typeof(RegisterPage);
case ViewTypes.RegisterPage:
return typeof(RegisterPage);
case ViewTypes.PasswordForgottenPage:
return typeof(PasswordForgottenPage);
case ViewTypes.PasswordForgottenPage:
return typeof(PasswordForgottenPage);
case ViewTypes.BikeInfoCarouselPage:
return typeof(BikeInfoCarouselPage);
case ViewTypes.BikeInfoCarouselPage:
return typeof(BikeInfoCarouselPage);
case ViewTypes.MyBikesPage:
return typeof(MyBikesPage);
case ViewTypes.MyBikesPage:
return typeof(MyBikesPage);
case ViewTypes.SettingsPage:
return typeof(SettingsPage);
case ViewTypes.SettingsPage:
return typeof(SettingsPage);
case ViewTypes.TabbedPageInfo:
return typeof(InfoPage);
case ViewTypes.TabbedPageInfo:
return typeof(InfoPage);
case ViewTypes.FeesAndBikesPage:
return typeof(FeesAndBikesPage);
case ViewTypes.FeesAndBikesPage:
return typeof(FeesAndBikesPage);
case ViewTypes.ManageAccountPage:
return typeof(ManageAccountPage);
case ViewTypes.ManageAccountPage:
return typeof(ManageAccountPage);
case ViewTypes.AgbPage:
return typeof(AgbPage);
case ViewTypes.AgbPage:
return typeof(AgbPage);
case ViewTypes.WhatsNewPage:
return typeof(WhatsNewPage);
case ViewTypes.WhatsNewPage:
return typeof(WhatsNewPage);
case ViewTypes.BikesAtStation:
return typeof(BikesAtStationPage);
case ViewTypes.BikesAtStation:
return typeof(BikesAtStationPage);
case ViewTypes.ContactPage:
return typeof(ContactPage);
case ViewTypes.ContactPage:
return typeof(ContactPage);
case ViewTypes.SelectStationPage:
return typeof(SelectStationPage);
case ViewTypes.SelectStationPage:
return typeof(SelectStationPage);
case ViewTypes.MiniSurvey:
return typeof(MiniSurveyPage);
case ViewTypes.MiniSurvey:
return typeof(MiniSurveyPage);
default:
return typeof(ContentPage);
}
}
}
default:
return typeof(ContentPage);
}
}
}
}

View file

@ -9,76 +9,76 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.WhatsNew.Agb
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class AgbPage : ContentPage, IViewService
{
public AgbPage()
{
InitializeComponent();
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class AgbPage : ContentPage, IViewService
{
public AgbPage()
{
InitializeComponent();
agbViewModel = new AgbViewModel(
App.ModelRoot.NextActiveUri.Host,
App.ModelRoot.IsSiteCachingOn,
CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
(resourceName) => ViewModelResourceHelper.GetSource(resourceName),
this);
agbViewModel = new AgbViewModel(
App.ModelRoot.NextActiveUri.Host,
App.ModelRoot.IsSiteCachingOn,
CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
(resourceName) => ViewModelResourceHelper.GetSource(resourceName),
this);
BindingContext = agbViewModel;
}
BindingContext = agbViewModel;
}
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary> Invoked when page is shown. </summary>
protected async override void OnAppearing()
=> await agbViewModel.OnAppearing();
/// <summary> Invoked when page is shown. </summary>
protected async override void OnAppearing()
=> await agbViewModel.OnAppearing();
/// <summary> Reference to view model.</summary>
AgbViewModel agbViewModel;
/// <summary> Reference to view model.</summary>
AgbViewModel agbViewModel;
public async Task PopModalAsync()
=> await Navigation.PopModalAsync();
public async Task PopModalAsync()
=> await Navigation.PopModalAsync();
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushAsync(ViewTypes p_oTypeOfPage)
=> throw new NotImplementedException();
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushAsync(ViewTypes p_oTypeOfPage)
=> throw new NotImplementedException();
public Task PushModalAsync(ViewTypes p_oTypeOfPage)
=> throw new NotImplementedException();
public Task PushModalAsync(ViewTypes p_oTypeOfPage)
=> throw new NotImplementedException();
#if USEFLYOUT
public void ShowPage(ViewTypes p_oType, string p_strTitle = null)
=> throw new NotImplementedException();
#else
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
#endif
#if USCSHARP9
public Task<IViewService.IUserFeedback> DisplayUserFeedbackPopup() => throw new NotSupportedException();
#else
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => throw new NotSupportedException();
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => throw new NotSupportedException();
#endif
}
}
}

View file

@ -7,100 +7,100 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.WhatsNew
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class WhatsNewPage : ContentPage, IViewService
{
/// <summary> Holds a reference on the view model. </summary>
private ViewModel.WhatsNew.WhatsNewViewModel WhatsNewViewModel;
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class WhatsNewPage : ContentPage, IViewService
{
/// <summary> Holds a reference on the view model. </summary>
private ViewModel.WhatsNew.WhatsNewViewModel WhatsNewViewModel;
/// <summary> Constructs whats new page.</summary>
/// <param name="showMasterDetail">Action to invoke master detail page.</param>
public WhatsNewPage(Action showMasterDetail)
{
InitializeComponent();
/// <summary> Constructs whats new page.</summary>
/// <param name="showMasterDetail">Action to invoke master detail page.</param>
public WhatsNewPage(Action showMasterDetail)
{
InitializeComponent();
WhatsNewViewModel = new ViewModel.WhatsNew.WhatsNewViewModel(
DependencyService.Get<IAppInfo>().Version,
App.ModelRoot.WhatsNew.WhatsNewText,
App.ModelRoot.WhatsNew.IsShowAgbRequired,
showMasterDetail,
this);
WhatsNewViewModel = new ViewModel.WhatsNew.WhatsNewViewModel(
DependencyService.Get<IAppInfo>().Version,
App.ModelRoot.WhatsNew.WhatsNewText,
App.ModelRoot.WhatsNew.IsShowAgbRequired,
showMasterDetail,
this);
BindingContext = WhatsNewViewModel;
}
BindingContext = WhatsNewViewModel;
}
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
string cancel)
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
/// <summary> Displays detailed alert message.</summary>
/// <param name="title">Title of message.</param>
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="accept">Text of accept button.</param>
/// <param name="cancel">Text of cancel button.</param>
/// <returns>True if user pressed accept.</returns>
public async Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel)
=> await App.Current.MainPage.DisplayAlert(title, !string.IsNullOrEmpty(details) ? $"{message}\r\nDetails:\r\n{details}" : $"{message}", accept, cancel);
public Task PopModalAsync()
{
throw new NotImplementedException(); ;
}
public Task PopModalAsync()
{
throw new NotImplementedException(); ;
}
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushAsync(ViewTypes p_oTypeOfPage)
{
throw new NotImplementedException();
}
/// <summary> Pushes a page onto the stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushAsync(ViewTypes p_oTypeOfPage)
{
throw new NotImplementedException();
}
public async Task PushModalAsync(ViewTypes p_oTypeOfPage)
{
await Navigation.PushModalAsync((Page)Activator.CreateInstance(p_oTypeOfPage.GetViewType()));
}
public async Task PushModalAsync(ViewTypes p_oTypeOfPage)
{
await Navigation.PushModalAsync((Page)Activator.CreateInstance(p_oTypeOfPage.GetViewType()));
}
#if USEFLYOUT
public void ShowPage(ViewTypes p_oType, string p_strTitle = null)
=> throw new NotImplementedException();
#else
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
/// <summary> Shows a page.</summary>
/// <param name="route">Route of the page to show.</param>
public async Task ShowPage(string route) => await Shell.Current.GoToAsync(route);
#endif
#if USCSHARP9
public Task<IViewService.IUserFeedback> DisplayUserFeedbackPopup() => throw new NotSupportedException();
#else
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => throw new NotSupportedException();
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => throw new NotSupportedException();
#endif
/// <summary>
/// Invoked when pages is closed/ hidden.
/// /// </summary>
protected override void OnDisappearing()
{
base.OnDisappearing();
/// <summary>
/// Invoked when pages is closed/ hidden.
/// /// </summary>
protected override void OnDisappearing()
{
base.OnDisappearing();
if (WhatsNewViewModel == null)
{
// View model might be null.
return;
}
if (WhatsNewViewModel == null)
{
// View model might be null.
return;
}
WhatsNewViewModel?.OnDisappearing(() =>
{
App.ModelRoot.WhatsNew.WasShownInCurrentSession = true;
App.ModelRoot.Save();
});
}
}
WhatsNewViewModel?.OnDisappearing(() =>
{
App.ModelRoot.WhatsNew.WasShownInCurrentSession = true;
App.ModelRoot.Save();
});
}
}
}

View file

@ -24,175 +24,175 @@ using TINK.View.Themes;
namespace TINK.ViewModel.Root
{
/// <summary>
/// View model for flyout menu entries. Respositility
/// - populates entries depending on app state on showing menu
/// - updates menu denpending on app state change, i.e. user logs in/ out.
/// </summary>
public class RootPageFlyoutViewModel : INotifyPropertyChanged
{
/// <summary>
/// Dictionary to manage collection of menu items.
/// </summary>
private Dictionary<Type, int> m_oEntryDictionary;
/// <summary>
/// View model for flyout menu entries. Respositility
/// - populates entries depending on app state on showing menu
/// - updates menu denpending on app state change, i.e. user logs in/ out.
/// </summary>
public class RootPageFlyoutViewModel : INotifyPropertyChanged
{
/// <summary>
/// Dictionary to manage collection of menu items.
/// </summary>
private Dictionary<Type, int> m_oEntryDictionary;
public event PropertyChangedEventHandler PropertyChanged;
public event PropertyChangedEventHandler PropertyChanged;
/// <summary> Updates menu entries depending on state. </summary>
private void UpdateMenuEntries()
{
for (int l_iIndex = MenuItems.Count - 1; l_iIndex >= 0; l_iIndex--)
{
MenuItems.Clear();
m_oEntryDictionary.Clear();
}
/// <summary> Updates menu entries depending on state. </summary>
private void UpdateMenuEntries()
{
for (int l_iIndex = MenuItems.Count - 1; l_iIndex >= 0; l_iIndex--)
{
MenuItems.Clear();
m_oEntryDictionary.Clear();
}
CheckAddItem(typeof(MapPage));
CheckAddItem(typeof(MapPage));
if (App.ModelRoot.ActiveUser.IsLoggedIn)
{
CheckAddItem(typeof(MyBikesPage));
CheckAddItem(typeof(FindBikePage));
CheckAddItem(typeof(AccountPage));
}
else
{
CheckAddItem(typeof(LoginPage));
}
if (App.ModelRoot.ActiveUser.IsLoggedIn)
{
CheckAddItem(typeof(MyBikesPage));
CheckAddItem(typeof(FindBikePage));
CheckAddItem(typeof(AccountPage));
}
else
{
CheckAddItem(typeof(LoginPage));
}
if (App.ModelRoot.Uris.ActiveUri.Host.GetIsCopri()
|| App.ModelRoot.ActiveUser.IsLoggedIn)
{
CheckAddItem(typeof(SettingsPage));
}
if (App.ModelRoot.Uris.ActiveUri.Host.GetIsCopri()
|| App.ModelRoot.ActiveUser.IsLoggedIn)
{
CheckAddItem(typeof(SettingsPage));
}
CheckAddItem(typeof(FeesAndBikesPage)); // Fees and bikes
CheckAddItem(typeof(FeesAndBikesPage)); // Fees and bikes
CheckAddItem(typeof(ContactPage)); // Feedback and contact
CheckAddItem(typeof(ContactPage)); // Feedback and contact
CheckAddItem(typeof(InfoPage)); // About sharee.bike
}
CheckAddItem(typeof(InfoPage)); // About sharee.bike
}
/// <summary>Adds a menu item to master detail menu.</summary>
/// <param name="p_oType">Type decribing entry to be added.</param>
private void CheckAddItem(Type p_oType)
{
if (m_oEntryDictionary.ContainsKey(p_oType))
{
// Nothing to do because has already been added.
return;
}
/// <summary>Adds a menu item to master detail menu.</summary>
/// <param name="p_oType">Type decribing entry to be added.</param>
private void CheckAddItem(Type p_oType)
{
if (m_oEntryDictionary.ContainsKey(p_oType))
{
// Nothing to do because has already been added.
return;
}
m_oEntryDictionary.Add(
p_oType,
m_oEntryDictionary.Count);
m_oEntryDictionary.Add(
p_oType,
m_oEntryDictionary.Count);
MenuItems.Add(new RootPageFlyoutMenuItem
{
TargetType = p_oType,
GlyphCode = Helper.GetGlyphCode(p_oType),
Title = Helper.GetCaption(p_oType),
Id = m_oEntryDictionary[p_oType]
});
}
MenuItems.Add(new RootPageFlyoutMenuItem
{
TargetType = p_oType,
GlyphCode = Helper.GetGlyphCode(p_oType),
Title = Helper.GetCaption(p_oType),
Id = m_oEntryDictionary[p_oType]
});
}
/// <summary> Removes a page from menu.</summary>
/// <param name="p_oType"></param>
private void RemoveItem(Type p_oType)
{
if (!m_oEntryDictionary.ContainsKey(p_oType))
{
// Nothing to do because item was never added/ already removed.
return;
}
/// <summary> Removes a page from menu.</summary>
/// <param name="p_oType"></param>
private void RemoveItem(Type p_oType)
{
if (!m_oEntryDictionary.ContainsKey(p_oType))
{
// Nothing to do because item was never added/ already removed.
return;
}
MenuItems.Remove(MenuItems[m_oEntryDictionary[p_oType]]);
m_oEntryDictionary.Remove(p_oType);
}
MenuItems.Remove(MenuItems[m_oEntryDictionary[p_oType]]);
m_oEntryDictionary.Remove(p_oType);
}
public RootPageFlyoutViewModel()
{
MenuItems = new ObservableCollection<RootPageFlyoutMenuItem>();
m_oEntryDictionary = new Dictionary<Type, int>();
public RootPageFlyoutViewModel()
{
MenuItems = new ObservableCollection<RootPageFlyoutMenuItem>();
m_oEntryDictionary = new Dictionary<Type, int>();
// Update menu entries on login/ logout actions.
App.ModelRoot.ActiveUser.StateChanged += (sender, eventargs) => OnUpdateRequired();
// Update menu entries on login/ logout actions.
App.ModelRoot.ActiveUser.StateChanged += (sender, eventargs) => OnUpdateRequired();
// Update flyout view model whenever theme is switched.
App.ModelRoot.Themes.PropertyChanged += (sender, eventargs) =>
{
if (!(sender is ServicesContainerMutableT<object> themes))
return;
// Update flyout view model whenever theme is switched.
App.ModelRoot.Themes.PropertyChanged += (sender, eventargs) =>
{
if (!(sender is ServicesContainerMutableT<object> themes))
return;
MasterDetailMenuTitlte = GetMasterDetailMenuTitle(themes.Active);
MasterDetailMenuTitlte = GetMasterDetailMenuTitle(themes.Active);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MasterDetailMenuTitlte)));
};
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MasterDetailMenuTitlte)));
};
MasterDetailMenuTitlte = GetMasterDetailMenuTitle(App.ModelRoot.Themes.Active);
MasterDetailMenuTitlte = GetMasterDetailMenuTitle(App.ModelRoot.Themes.Active);
UpdateMenuEntries();
}
UpdateMenuEntries();
}
/// <summary>
/// Gets the flyout title from theme name
/// </summary>
/// <param name="theme">Name of theme.</param>
/// <returns>Flyout title.</returns>
private string GetMasterDetailMenuTitle(object theme)
{
if (!(theme is ITheme active))
return TINK.Themes.LastenradBayern.OPERATORINFO;
/// <summary>
/// Gets the flyout title from theme name
/// </summary>
/// <param name="theme">Name of theme.</param>
/// <returns>Flyout title.</returns>
private string GetMasterDetailMenuTitle(object theme)
{
if (!(theme is ITheme active))
return TINK.Themes.LastenradBayern.OPERATORINFO;
return $"{(!string.IsNullOrEmpty(active.OperatorInfo) ? ($"{active.OperatorInfo}") : "sharee.bike")}";
}
return $"{(!string.IsNullOrEmpty(active.OperatorInfo) ? ($"{active.OperatorInfo}") : "sharee.bike")}";
}
/// <summary>
/// Holds the title of the fylout page.
/// </summary>
public string MasterDetailMenuTitlte { get; private set; }
/// <summary>
/// Holds the title of the fylout page.
/// </summary>
public string MasterDetailMenuTitlte { get; private set; }
/// <summary>
/// Provides collection of menu items for master page.
/// </summary>
public ObservableCollection<RootPageFlyoutMenuItem> MenuItems
{
get; private set;
}
/// <summary>
/// Provides collection of menu items for master page.
/// </summary>
public ObservableCollection<RootPageFlyoutMenuItem> MenuItems
{
get; private set;
}
/// <summary>
/// Gets or sets the selected item.
/// </summary>
public MainPageMenuItem SelectedMenuItem
{
get;
set;
}
/// <summary>
/// Gets or sets the selected item.
/// </summary>
public MainPageMenuItem SelectedMenuItem
{
get;
set;
}
/// <summary>
/// Command object which is invoked from view when an item is selected.
/// </summary>
public Command MenuItemSelected
{
get
{
return new Command(OnUpdateRequired);
}
/// <summary>
/// Command object which is invoked from view when an item is selected.
/// </summary>
public Command MenuItemSelected
{
get
{
return new Command(OnUpdateRequired);
}
}
}
/// <summary> Manges updates required due to selection of a menu or login events.</summary>
public void OnUpdateRequired()
{
/// <summary> Manges updates required due to selection of a menu or login events.</summary>
public void OnUpdateRequired()
{
UpdateMenuEntries();
UpdateMenuEntries();
if (SelectedMenuItem == null)
{
// Nothing to do if no menu entry is selected.
return;
}
}
}
if (SelectedMenuItem == null)
{
// Nothing to do if no menu entry is selected.
return;
}
}
}
}

View file

@ -12,104 +12,104 @@ using TINK.ViewModel.Info;
namespace TINK.ViewModel.MasterDetail
{
public static class Helper
{
/// <summary>
/// Gets a description for a map page used as menu item entry and caption.
/// </summary>
/// <param name="type">Type of page to get caption for.</param>
/// <returns></returns>
public static string GetCaption(Type type)
{
if (type == typeof(MapPage)) // Bikes sites
{
return AppResources.MarkingMapPage;
}
else if (type == typeof(FindBikePage)) // Find Bike
{
return AppResources.MarkingFindBike;
}
else if (type == typeof(MyBikesPage)) // My Bikes
{
return AppResources.MarkingMyBikes;
}
else if (type == typeof(AccountPage)) // Account
{
return AppResources.MarkingAccount;
}
else if (type == typeof(LoginPage)) // Login
{
return AppResources.MarkingLogin;
}
else if (type == typeof(SettingsPage)) // Settings
{
return AppResources.MarkingSettings;
}
else if (type == typeof(FeesAndBikesPage))
{
return AppResources.MarkingFeesAndBikes;
}
else if (type == typeof(ContactPage))
{
return AppResources.MarkingFeedbackAndContact;
}
else if (type == typeof(InfoPage))
{
return AppResources.MarkingAbout;
}
else
{
return type.Name;
}
}
public static class Helper
{
/// <summary>
/// Gets a description for a map page used as menu item entry and caption.
/// </summary>
/// <param name="type">Type of page to get caption for.</param>
/// <returns></returns>
public static string GetCaption(Type type)
{
if (type == typeof(MapPage)) // Bikes sites
{
return AppResources.MarkingMapPage;
}
else if (type == typeof(FindBikePage)) // Find Bike
{
return AppResources.MarkingFindBike;
}
else if (type == typeof(MyBikesPage)) // My Bikes
{
return AppResources.MarkingMyBikes;
}
else if (type == typeof(AccountPage)) // Account
{
return AppResources.MarkingAccount;
}
else if (type == typeof(LoginPage)) // Login
{
return AppResources.MarkingLogin;
}
else if (type == typeof(SettingsPage)) // Settings
{
return AppResources.MarkingSettings;
}
else if (type == typeof(FeesAndBikesPage))
{
return AppResources.MarkingFeesAndBikes;
}
else if (type == typeof(ContactPage))
{
return AppResources.MarkingFeedbackAndContact;
}
else if (type == typeof(InfoPage))
{
return AppResources.MarkingAbout;
}
else
{
return type.Name;
}
}
/// <summary>
/// Gets a description for a map page used as menu item entry and caption.
/// </summary>
/// <param name="type">Type of page to get caption for.</param>
/// <returns></returns>
public static string GetGlyphCode(Type type)
{
if (type == typeof(MapPage)) // Bikes sites
{
return "\uf5a0";
}
else if (type == typeof(FindBikePage)) // My Bikes
{
return "\uf002";
}
else if (type == typeof(MyBikesPage)) // My Bikes
{
return "\uf206";
}
else if (type == typeof(AccountPage)) // Account
{
return "\uf007";
}
else if (type == typeof(LoginPage)) // Login
{
return "\uf2f6";
}
else if (type == typeof(SettingsPage)) // Settings
{
return "\uf013";
}
else if (type == typeof(FeesAndBikesPage))
{
return "\uf7d9";
}
else if (type == typeof(ContactPage))
{
return "\uf095";
}
else if (type == typeof(InfoPage))
{
return "\uf05a";
}
else
{
return type.Name;
}
}
}
/// <summary>
/// Gets a description for a map page used as menu item entry and caption.
/// </summary>
/// <param name="type">Type of page to get caption for.</param>
/// <returns></returns>
public static string GetGlyphCode(Type type)
{
if (type == typeof(MapPage)) // Bikes sites
{
return "\uf5a0";
}
else if (type == typeof(FindBikePage)) // My Bikes
{
return "\uf002";
}
else if (type == typeof(MyBikesPage)) // My Bikes
{
return "\uf206";
}
else if (type == typeof(AccountPage)) // Account
{
return "\uf007";
}
else if (type == typeof(LoginPage)) // Login
{
return "\uf2f6";
}
else if (type == typeof(SettingsPage)) // Settings
{
return "\uf013";
}
else if (type == typeof(FeesAndBikesPage))
{
return "\uf7d9";
}
else if (type == typeof(ContactPage))
{
return "\uf095";
}
else if (type == typeof(InfoPage))
{
return "\uf05a";
}
else
{
return type.Name;
}
}
}
}

View file

@ -7,66 +7,66 @@ using TINK.ViewModel.Info;
namespace TINK.ViewModel.RootShell
{
public class AppShellViewModel : INotifyPropertyChanged
{
public AppShellViewModel()
{
App.ModelRoot.ActiveUser.StateChanged += (sender, eventargs) =>
{
// Login state changed. Update related menu entries.
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsMyBikesPageVisible)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsFindBikePageVisible)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsAccountPageVisible)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsLoginPageVisible)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsSettingsPageVisible)));
};
public class AppShellViewModel : INotifyPropertyChanged
{
public AppShellViewModel()
{
App.ModelRoot.ActiveUser.StateChanged += (sender, eventargs) =>
{
// Login state changed. Update related menu entries.
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsMyBikesPageVisible)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsFindBikePageVisible)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsAccountPageVisible)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsLoginPageVisible)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsSettingsPageVisible)));
};
// Update flyout view model whenever theme is switched.
App.ModelRoot.Themes.PropertyChanged += (sender, eventargs) =>
{
if (!(sender is ServicesContainerMutableT<object> themes))
return;
// Update flyout view model whenever theme is switched.
App.ModelRoot.Themes.PropertyChanged += (sender, eventargs) =>
{
if (!(sender is ServicesContainerMutableT<object> themes))
return;
MasterDetailMenuTitlte = GetMasterDetailMenuTitle(themes.Active);
MasterDetailMenuTitlte = GetMasterDetailMenuTitle(themes.Active);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MasterDetailMenuTitlte)));
};
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MasterDetailMenuTitlte)));
};
MasterDetailMenuTitlte = GetMasterDetailMenuTitle(App.ModelRoot.Themes.Active);
}
MasterDetailMenuTitlte = GetMasterDetailMenuTitle(App.ModelRoot.Themes.Active);
}
/// <summary>
/// Gets the flyout title from theme name
/// </summary>
/// <param name="theme">Name of theme.</param>
/// <returns>Flyout title.</returns>
private string GetMasterDetailMenuTitle(object theme)
{
if (!(theme is ITheme active))
return TINK.Themes.ShareeBike.OPERATORINFO;
/// <summary>
/// Gets the flyout title from theme name
/// </summary>
/// <param name="theme">Name of theme.</param>
/// <returns>Flyout title.</returns>
private string GetMasterDetailMenuTitle(object theme)
{
if (!(theme is ITheme active))
return TINK.Themes.ShareeBike.OPERATORINFO;
return $"{(!string.IsNullOrEmpty(active.OperatorInfo) ? ($"{active.OperatorInfo}") : "sharee.bike")}";
}
return $"{(!string.IsNullOrEmpty(active.OperatorInfo) ? ($"{active.OperatorInfo}") : "sharee.bike")}";
}
/// <summary>
/// Holds the title of the fylout page.
/// </summary>
public string MasterDetailMenuTitlte { get; private set; }
/// <summary>
/// Holds the title of the fylout page.
/// </summary>
public string MasterDetailMenuTitlte { get; private set; }
public event PropertyChangedEventHandler PropertyChanged;
public event PropertyChangedEventHandler PropertyChanged;
public bool IsMyBikesPageVisible => App.ModelRoot.ActiveUser.IsLoggedIn;
public bool IsMyBikesPageVisible => App.ModelRoot.ActiveUser.IsLoggedIn;
public bool IsFindBikePageVisible => App.ModelRoot.ActiveUser.IsLoggedIn;
public bool IsFindBikePageVisible => App.ModelRoot.ActiveUser.IsLoggedIn;
public bool IsAccountPageVisible => App.ModelRoot.ActiveUser.IsLoggedIn;
public bool IsAccountPageVisible => App.ModelRoot.ActiveUser.IsLoggedIn;
public bool IsLoginPageVisible => !App.ModelRoot.ActiveUser.IsLoggedIn;
public bool IsLoginPageVisible => !App.ModelRoot.ActiveUser.IsLoggedIn;
public bool IsSettingsPageVisible => App.ModelRoot.Uris.ActiveUri.Host.GetIsCopri()
|| App.ModelRoot.ActiveUser.IsLoggedIn;
public bool IsSettingsPageVisible => App.ModelRoot.Uris.ActiveUri.Host.GetIsCopri()
|| App.ModelRoot.ActiveUser.IsLoggedIn;
public string TabbedPageIngoTitle => AppResources.MarkingAbout;
public string TabbedPageIngoTitle => AppResources.MarkingAbout;
}
}
}

View file

@ -5,38 +5,38 @@ using Serilog;
namespace TINK.ViewModel
{
public static class ViewModelResourceHelper
{
/// <summary> Get ressource prefix depending on platform.</summary>
public static string RessourcePrefix
{
get
{
public static class ViewModelResourceHelper
{
/// <summary> Get ressource prefix depending on platform.</summary>
public static string RessourcePrefix
{
get
{
#if __IOS__
return "TINK.iOS.";
return "TINK.iOS.";
#endif
#if __ANDROID__
return "TINK.Droid.";
return "TINK.Droid.";
#endif
#if WINDOWS_UWP
return "TINK.WinPhone.";
#endif
}
}
}
}
/// <summary> Gets an an embedded html ressource.</summary>
/// <param name="resrouceName">Name of resource to get.</param>
/// <returns></returns>
public static string GetSource(string resrouceName)
{
var l_oRessourceName = RessourcePrefix + resrouceName;
Log.Verbose($"Using this resource prefix {RessourcePrefix}.");
// note that the prefix includes the trailing period '.' that is required
var assembly = typeof(ViewModelResourceHelper).GetTypeInfo().Assembly;
var stream = assembly.GetManifestResourceStream(l_oRessourceName);
return stream != null
? (new StreamReader(stream, Encoding.UTF8)).ReadToEnd()
: string.Format("<!DOCTYPE html><html lang=\"de\"><body>An error occurred loading html- ressource {0}.</body>", l_oRessourceName);
}
}
/// <summary> Gets an an embedded html ressource.</summary>
/// <param name="resrouceName">Name of resource to get.</param>
/// <returns></returns>
public static string GetSource(string resrouceName)
{
var l_oRessourceName = RessourcePrefix + resrouceName;
Log.Verbose($"Using this resource prefix {RessourcePrefix}.");
// note that the prefix includes the trailing period '.' that is required
var assembly = typeof(ViewModelResourceHelper).GetTypeInfo().Assembly;
var stream = assembly.GetManifestResourceStream(l_oRessourceName);
return stream != null
? (new StreamReader(stream, Encoding.UTF8)).ReadToEnd()
: string.Format("<!DOCTYPE html><html lang=\"de\"><body>An error occurred loading html- ressource {0}.</body>", l_oRessourceName);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -16,147 +16,147 @@ using Xamarin.Essentials;
namespace TINK.Services.BluetoothLock.BLE
{
public class LockItByGuidService : LockItServiceBase, ILocksService
{
/// <summary> Constructs a LockItByGuidService object.</summary>
/// <param name="cipher">Encrpyting/ decrypting object.</param>
public LockItByGuidService(ICipher cipher) : base(cipher)
{
}
public class LockItByGuidService : LockItServiceBase, ILocksService
{
/// <summary> Constructs a LockItByGuidService object.</summary>
/// <param name="cipher">Encrpyting/ decrypting object.</param>
public LockItByGuidService(ICipher cipher) : base(cipher)
{
}
/// <summary> Checks for locks which have not yet been discoverted and connects them. </summary>
/// <remarks> Consists of a bluetooth connect plus invocation of an authentication sequence. </remarks>
/// <param name="locksInfo">Locks to reconnect.</param>
/// <param name="connectTimeout">Timeout for connect operation of a single lock.</param>
protected override async Task<IEnumerable<ILockService>> CheckConnectMissing(IEnumerable<LockInfoAuthTdo> locksInfo, TimeSpan connectTimeout)
{
if (DeviceInfo.Platform != DevicePlatform.Unknown && MainThread.IsMainThread == false)
{
throw new System.Exception("Can not connect to locks by guid. Platform must not be unknown and bluetooth code must be run on main thread.");
}
/// <summary> Checks for locks which have not yet been discoverted and connects them. </summary>
/// <remarks> Consists of a bluetooth connect plus invocation of an authentication sequence. </remarks>
/// <param name="locksInfo">Locks to reconnect.</param>
/// <param name="connectTimeout">Timeout for connect operation of a single lock.</param>
protected override async Task<IEnumerable<ILockService>> CheckConnectMissing(IEnumerable<LockInfoAuthTdo> locksInfo, TimeSpan connectTimeout)
{
if (DeviceInfo.Platform != DevicePlatform.Unknown && MainThread.IsMainThread == false)
{
throw new System.Exception("Can not connect to locks by guid. Platform must not be unknown and bluetooth code must be run on main thread.");
}
// Get list of target locks without invalid entries.
var validLocksInfo = locksInfo
.Where(x => x.IsGuidValid)
.Where(x => x.K_seed.Length > 0 && x.K_u.Length > 0)
.ToList();
// Get list of target locks without invalid entries.
var validLocksInfo = locksInfo
.Where(x => x.IsGuidValid)
.Where(x => x.K_seed.Length > 0 && x.K_u.Length > 0)
.ToList();
var locksList = new List<ILockService>();
var locksList = new List<ILockService>();
// Connect to
foreach (var lockInfo in validLocksInfo)
{
if (DeviceList.Any(x => x.Name.GetBluetoothLockId() == lockInfo.Id || x.Guid == lockInfo.Guid))
{
// Device is already connected.
continue;
}
// Connect to
foreach (var lockInfo in validLocksInfo)
{
if (DeviceList.Any(x => x.Name.GetBluetoothLockId() == lockInfo.Id || x.Guid == lockInfo.Guid))
{
// Device is already connected.
continue;
}
// Connect to device and authenticate.
ILockService lockIt = null;
try
{
lockIt = await ConnectByGuid(lockInfo, connectTimeout);
}
catch (System.Exception exception)
{
// Member is called for background update of missing devices.
// Do not display any error messages.
Log.ForContext<LockItByGuidService>().Error($"Authentication failed. {exception.Message}");
continue;
}
if (lockIt == null)
{
continue;
}
// Connect to device and authenticate.
ILockService lockIt = null;
try
{
lockIt = await ConnectByGuid(lockInfo, connectTimeout);
}
catch (System.Exception exception)
{
// Member is called for background update of missing devices.
// Do not display any error messages.
Log.ForContext<LockItByGuidService>().Error($"Authentication failed. {exception.Message}");
continue;
}
if (lockIt == null)
{
continue;
}
locksList.Add(lockIt);
}
locksList.Add(lockIt);
}
return locksList;
}
return locksList;
}
/// <summary> Connects to lock.</summary>
/// <remarks> Consists of a bluetooth connect plus invocation of an authentication sequence. </remarks>