Code updated to 3.0.238

This commit is contained in:
Oliver Hauff 2021-06-26 20:57:55 +02:00
parent 3302d80678
commit 9c6a1fa92b
257 changed files with 7763 additions and 2861 deletions

View file

@ -1,16 +1,23 @@
using TINK.Model.Device;
using Xamarin.Essentials;
using Xamarin.Forms;
[assembly: Dependency(typeof(TINK.Droid.Model.Device.Device))]
namespace TINK.Droid.Model.Device
{
public class Device : IDevice
public class Device : ISmartDevice
{
public string Manufacturer => DeviceInfo.Manufacturer;
public string Model => DeviceInfo.Model;
public string PlatformText => DeviceInfo.Platform.ToString();
public string VersionText => DeviceInfo.VersionString;
/// <summary> Gets unitque device identifier. </summary>
/// <returns>Gets the identifies specifying device.</returns>
public string GetIdentifier()
{
return Android.Provider.Settings.Secure.GetString(Forms.Context.ContentResolver, Android.Provider.Settings.Secure.AndroidId);
}
public string Identifier
=> Android.Provider.Settings.Secure.GetString(Forms.Context.ContentResolver, Android.Provider.Settings.Secure.AndroidId);
}
}

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="preferExternal" package="com.hauffware.sharee" android:versionName="3.0.222" android:versionCode="222">
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="preferExternal" package="com.hauffware.sharee" android:versionName="3.0.238" android:versionCode="238">
<uses-sdk android:minSdkVersion="18" android:targetSdkVersion="30" />
<!-- Google Maps related permissions -->
<permission android:name="com.ecs.google.maps.v2.actionbarsherlock.permission.MAPS_RECEIVE" android:protectionLevel="signature" />
@ -15,6 +15,6 @@
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
<application android:icon="@drawable/sharee" android:label="sharee.bike"></application>
<application android:icon="@drawable/sharee" android:label="sharee.bike" android:allowBackup="false"></application>
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="000000000-000000000000000000000000000-0" />
</manifest>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="preferExternal" package="com.hauffware.sharee" android:versionName="3.0.222" android:versionCode="222">
<uses-sdk android:minSdkVersion="18" android:targetSdkVersion="30" />
<!-- Google Maps related permissions -->
<permission android:name="com.ecs.google.maps.v2.actionbarsherlock.permission.MAPS_RECEIVE" android:protectionLevel="signature" />
<!-- Network connectivity permissions -->
<!-- Access Google based webservices -->
<!-- External storage for caching. -->
<!-- My Location -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.location" android:required="false" />
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
<uses-feature android:name="android.hardware.location.network" android:required="false" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
<application android:icon="@drawable/sharee" android:label="sharee.bike"></application>
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="000000000-000000000000000000000000000-0" />
</manifest>

File diff suppressed because it is too large Load diff

View file

@ -30,7 +30,7 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;USESHELL</DefineConstants>
<DefineConstants>TRACE;DEBUG;USEFLYOUT</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>0</WarningLevel>
<AndroidUseSharedRuntime>true</AndroidUseSharedRuntime>
@ -49,7 +49,7 @@
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<DefineConstants>TRACE;USEFLYOUT</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
@ -63,16 +63,16 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="5.0.1" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="5.0.2" />
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
<PackageReference Include="MonkeyCache">
<Version>1.3.0</Version>
<Version>1.5.2</Version>
</PackageReference>
<PackageReference Include="MonkeyCache.FileStore">
<Version>1.3.0</Version>
<Version>1.5.2</Version>
</PackageReference>
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="PCLCrypto" Version="2.0.147" />
<PackageReference Include="PCLStorage" Version="1.0.2" />
<PackageReference Include="PInvoke.BCrypt" Version="0.7.104" />
@ -161,11 +161,17 @@
<PackageReference Include="Xamarin.Android.Support.v7.Palette" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.v7.RecyclerView" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Vector.Drawable" Version="28.0.0.3" />
<PackageReference Include="Xamarin.AndroidX.Core">
<Version>1.5.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.MediaRouter">
<Version>1.2.1</Version>
<Version>1.2.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.Palette">
<Version>1.0.0.6</Version>
<Version>1.0.0.7</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.RecyclerView">
<Version>1.2.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Auth" Version="1.7.0" />
<PackageReference Include="Xamarin.Build.Download" Version="0.10.0" />
@ -182,7 +188,7 @@
<PackageReference Include="Xamarin.Forms.GoogleMaps.Bindings" Version="2.2.0" />
<PackageReference Include="Xamarin.GooglePlayServices.Base" Version="117.6.0" />
<PackageReference Include="Xamarin.GooglePlayServices.Basement" Version="117.6.0" />
<PackageReference Include="Xamarin.GooglePlayServices.Maps" Version="117.0.0" />
<PackageReference Include="Xamarin.GooglePlayServices.Maps" Version="117.0.1" />
<PackageReference Include="Xamarin.GooglePlayServices.Tasks" Version="117.2.1" />
</ItemGroup>
<ItemGroup>

View file

@ -1,8 +0,0 @@
<Application
x:Class="TINK.UWP.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TINK.UWP"
RequestedTheme="Light">
</Application>

View file

@ -1,107 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
namespace TINK.UWP
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
sealed partial class App : Application
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used such as when the application is launched to open a specific file.
/// </summary>
/// <param name="e">Details about the launch request and process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
#if DEBUG
if (System.Diagnostics.Debugger.IsAttached)
{
this.DebugSettings.EnableFrameRateCounter = true;
}
#endif
Frame rootFrame = Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
Xamarin.Forms.Forms.Init(e);
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
if (rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
rootFrame.Navigate(typeof(MainPage), e.Arguments);
}
// Ensure the current window is active
Window.Current.Activate();
}
/// <summary>
/// Invoked when Navigation to a certain page fails
/// </summary>
/// <param name="sender">The Frame which failed navigation</param>
/// <param name="e">Details about the navigation failure</param>
void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
{
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
}
/// <summary>
/// Invoked when application execution is being suspended. Application state is saved
/// without knowing whether the application will be terminated or resumed with the contents
/// of memory still intact.
/// </summary>
/// <param name="sender">The source of the suspend request.</param>
/// <param name="e">Details about the suspend request.</param>
private void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
//TODO: Save application state and stop any background activity
deferral.Complete();
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 305 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 347 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 758 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 394 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 483 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 563 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 658 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 392 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 921 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

View file

@ -1,32 +0,0 @@
using System;
using TINK.Model.Device;
using TINK.UWP.Device;
using Windows.System.Profile;
using Windows.UI.Xaml;
[assembly: Xamarin.Forms.Dependency(typeof(WinPhoneDevice))]
namespace TINK.UWP.Device
{
public class WinPhoneDevice : IDevice
{
/// <summary> Gets unitque device identifier. </summary>
/// <returns>Gets the identifies specifying device.</returns>
public string GetIdentifier()
{
var token = HardwareIdentification.GetPackageSpecificToken(null);
var hardwareId = token.Id;
var dataReader = Windows.Storage.Streams.DataReader.FromBuffer(hardwareId);
byte[] bytes = new byte[hardwareId.Length];
dataReader.ReadBytes(bytes);
return BitConverter.ToString(bytes);
}
/// <summary> Close the application. </summary>
public void CloseApplication()
{
Application.Current.Exit();
}
}
}

View file

@ -1,15 +0,0 @@
<forms:WindowsPage
x:Class="TINK.UWP.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:forms="using:Xamarin.Forms.Platform.UWP"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TINK.UWP"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
</Grid>
</forms:WindowsPage>

View file

@ -1,19 +0,0 @@
namespace TINK.UWP
{
public sealed partial class MainPage
{
public MainPage()
{
this.InitializeComponent();
// Todo: Token hier eingeben
// Required for initialization of Maps, see https://developer.xamarin.com/guides/xamarin-forms/user-interface/map/
Xamarin.FormsGoogleMaps.Init("AIzaSyDOd-_356QgShjVGUPGH1LatYJKWdzk9-U");
// Required for initialization of binding package, see https://github.com/nuitsjp/Xamarin.Forms.GoogleMaps.Bindings.
Xamarin.FormsGoogleMapsBindings.Init();
LoadApplication(new TINK.App());
}
}
}

View file

@ -1,49 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
IgnorableNamespaces="uap mp">
<Identity
Name="4fa9c991-fff2-493e-b399-75bf6354090c"
Publisher="CN=Oliver"
Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="f736c883-f105-4d30-a719-4bf328872f5e" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Properties>
<DisplayName>TINK.UWP</DisplayName>
<PublisherDisplayName>Oliver</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="TINK.UWP.App">
<uap:VisualElements
DisplayName="TINK.UWP"
Square150x150Logo="Assets\Square150x150Logo.png"
Square44x44Logo="Assets\Square44x44Logo.png"
Description="TINK.UWP"
BackgroundColor="transparent">
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png"/>
<uap:SplashScreen Image="Assets\SplashScreen.png" />
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient" />
</Capabilities>
</Package>

View file

@ -1,29 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("TINK.UWP")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TINK.UWP")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: ComVisible(false)]

View file

@ -1,31 +0,0 @@
<!--
This file contains Runtime Directives used by .NET Native. The defaults here are suitable for most
developers. However, you can modify these parameters to modify the behavior of the .NET Native
optimizer.
Runtime Directives are documented at http://go.microsoft.com/fwlink/?LinkID=391919
To fully enable reflection for App1.MyClass and all of its public/private members
<Type Name="App1.MyClass" Dynamic="Required All"/>
To enable dynamic creation of the specific instantiation of AppClass<T> over System.Int32
<TypeInstantiation Name="App1.AppClass" Arguments="System.Int32" Activate="Required Public" />
Using the Namespace directive to apply reflection policy to all the types in a particular namespace
<Namespace Name="DataClasses.ViewModels" Seralize="All" />
-->
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Application>
<!--
An Assembly element with Name="*Application*" applies to all assemblies in
the application package. The asterisks are not wildcards.
-->
<Assembly Name="*Application*" Dynamic="Required All" />
<!-- Add your application specific runtime directives here. -->
</Application>
</Directives>

View file

@ -1,171 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProjectGuid>{B3DC74E1-DA60-4844-BB25-A7F6D2BB6A9D}</ProjectGuid>
<OutputType>AppContainerExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>TINK.UWP</RootNamespace>
<AssemblyName>TINK.UWP</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion>10.0.15063.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.10586.0</TargetPlatformMinVersion>
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<EnableDotNetNativeCompatibleProfile>true</EnableDotNetNativeCompatibleProfile>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PackageCertificateKeyFile>TINK.UWP_TemporaryKey.pfx</PackageCertificateKeyFile>
<ReleaseVersion>3.0</ReleaseVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\ARM\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
<OutputPath>bin\ARM\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .Net Framework and Windows SDK are automatically included -->
<None Include="project.json" />
</ItemGroup>
<ItemGroup>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
</Compile>
<Compile Include="Device\WinPhoneDevice .cs" />
<Compile Include="MainPage.xaml.cs">
<DependentUpon>MainPage.xaml</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
<None Include="TINK.UWP_TemporaryKey.pfx" />
</ItemGroup>
<ItemGroup>
<Content Include="Assets\tink2.png" />
<Content Include="Properties\Default.rd.xml" />
<Content Include="Assets\LockScreenLogo.scale-100.png" />
<Content Include="Assets\LockScreenLogo.scale-125.png" />
<Content Include="Assets\LockScreenLogo.scale-150.png" />
<Content Include="Assets\LockScreenLogo.scale-200.png" />
<Content Include="Assets\LockScreenLogo.scale-400.png" />
<Content Include="Assets\SplashScreen.scale-100.png" />
<Content Include="Assets\SplashScreen.scale-125.png" />
<Content Include="Assets\SplashScreen.scale-150.png" />
<Content Include="Assets\SplashScreen.scale-200.png" />
<Content Include="Assets\SplashScreen.scale-400.png" />
<Content Include="Assets\Square150x150Logo.scale-200.png" />
<Content Include="Assets\Square44x44Logo.scale-100.png" />
<Content Include="Assets\Square44x44Logo.scale-125.png" />
<Content Include="Assets\Square44x44Logo.scale-150.png" />
<Content Include="Assets\Square44x44Logo.scale-200.png" />
<Content Include="Assets\Square44x44Logo.scale-400.png" />
<Content Include="Assets\Square44x44Logo.targetsize-16_altform-unplated.png" />
<Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
<Content Include="Assets\Square44x44Logo.targetsize-32_altform-unplated.png" />
<Content Include="Assets\Square44x44Logo.targetsize-48_altform-unplated.png" />
<Content Include="Assets\Square44x44Logo.targetsize-256_altform-unplated.png" />
<Content Include="Assets\StoreLogo.png" />
<Content Include="Assets\Wide310x150Logo.scale-100.png" />
<Content Include="Assets\Wide310x150Logo.scale-125.png" />
<Content Include="Assets\Wide310x150Logo.scale-150.png" />
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
<Content Include="Assets\Wide310x150Logo.scale-400.png" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Page Include="MainPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\TINKLib\TINKLib.csproj">
<Project>{b77f4222-0860-4494-a07c-ee8e09fa9983}</Project>
<Name>TINKLib</Name>
</ProjectReference>
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
<Import Project="..\TINK\TINK.projitems" Label="Shared" Condition="Exists('..\TINK\TINK.projitems')" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View file

@ -1,28 +0,0 @@
{
"dependencies": {
"Microsoft.Net.Http": "2.2.29",
"Microsoft.NETCore.UniversalWindowsPlatform": "6.1.4",
"PCLStorage": "1.0.2",
"Serilog": "2.7.1",
"Serilog.Sinks.File": "4.0.0",
"System.Collections.Immutable": "1.4.0",
"System.Private.DataContractSerialization": "4.3.0",
"System.Runtime.Serialization.Formatters": "4.3.0",
"System.Runtime.Serialization.Primitives": "4.3.0",
"Xam.Plugins.Messaging": "5.2.0",
"Xamarin.Forms": "3.0.0.482510",
"Xamarin.Forms.GoogleMaps": "2.3.0",
"Xamarin.Forms.GoogleMaps.Bindings": "2.1.0"
},
"frameworks": {
"uap10.0.10586": {}
},
"runtimes": {
"win10-arm": {},
"win10-arm-aot": {},
"win10-x86": {},
"win10-x86-aot": {},
"win10-x64": {},
"win10-x64-aot": {}
}
}

View file

@ -1,11 +1,12 @@
using System;
using System.Runtime.InteropServices;
using TINK.Model.Device;
using Xamarin.Essentials;
[assembly: Xamarin.Forms.Dependency(typeof(TINK.iOS.Device.Device))]
namespace TINK.iOS.Device
{
public class Device : IDevice
public class Device : ISmartDevice
{
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern uint IOServiceGetMatchingService(uint masterPort, IntPtr matching);
@ -19,11 +20,16 @@ namespace TINK.iOS.Device
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern int IOObjectRelease(uint o);
public string Manufacturer => DeviceInfo.Manufacturer;
public string Model => DeviceInfo.Model;
public string PlatformText => DeviceInfo.Platform.ToString();
public string VersionText => DeviceInfo.VersionString;
/// <summary> Gets unitque device identifier. </summary>
/// <returns>Gets the identifies specifying device.</returns>
public string GetIdentifier()
{
return UIKit.UIDevice.CurrentDevice?.IdentifierForVendor?.AsString() ?? string.Empty;
}
public string Identifier
=> UIKit.UIDevice.CurrentDevice?.IdentifierForVendor?.AsString() ?? string.Empty;
}
}

View file

@ -1,7 +1,10 @@
<?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>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)com.TeilRad.sharee.bike</string>
</array>
</dict>
</plist>

View file

@ -49,8 +49,8 @@
<key>CFBundleDisplayName</key>
<string>sharee.bike</string>
<key>CFBundleVersion</key>
<string>222</string>
<string>238</string>
<key>CFBundleShortVersionString</key>
<string>3.0.222</string>
<string>3.0.238</string>
</dict>
</plist>

View file

@ -47,7 +47,7 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\iPhone\Debug</OutputPath>
<DefineConstants>__IOS__;__MOBILE__;__UNIFIED__;DEBUG;SHOWAGBV1;USEBROWSERFORUSERMANAGEMENT</DefineConstants>
<DefineConstants>DEBUG;USEFLYOUT</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
@ -61,7 +61,7 @@
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\iPhone\Release</OutputPath>
<DefineConstants>__IOS__;__MOBILE__;__UNIFIED__;SHOWAGBV1;USEBROWSERFORUSERMANAGEMENT</DefineConstants>
<DefineConstants>USEFLYOUT</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<MtouchArch>ARMv7, ARM64</MtouchArch>
@ -78,7 +78,7 @@
<DebugType>none</DebugType>
<Optimize>True</Optimize>
<OutputPath>bin\iPhone\Ad-Hoc</OutputPath>
<DefineConstants>__IOS__;__MOBILE__;__UNIFIED__;SHOWAGBV1;USEBROWSERFORUSERMANAGEMENT</DefineConstants>
<DefineConstants>USEFLYOUT</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>False</ConsolePause>
@ -94,7 +94,7 @@
<DebugType>none</DebugType>
<Optimize>True</Optimize>
<OutputPath>bin\iPhone\AppStore</OutputPath>
<DefineConstants>__IOS__;__MOBILE__;__UNIFIED__;SHOWAGBV1;USEBROWSERFORUSERMANAGEMENT</DefineConstants>
<DefineConstants>USEFLYOUT</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>False</ConsolePause>
@ -109,16 +109,16 @@
<ItemGroup>
<PackageReference Include="Microsoft.Bcl.Build" Version="1.0.21" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="5.0.1" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="5.0.2" />
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
<PackageReference Include="MonkeyCache">
<Version>1.3.0</Version>
<Version>1.5.2</Version>
</PackageReference>
<PackageReference Include="MonkeyCache.FileStore">
<Version>1.3.0</Version>
<Version>1.5.2</Version>
</PackageReference>
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="PCLCrypto" Version="2.0.147" />
<PackageReference Include="PCLStorage" Version="1.0.2" />
<PackageReference Include="Plugin.BluetoothLE">

View file

@ -17,6 +17,10 @@ using System.Threading;
using TINK.Model.Settings;
using Plugin.Permissions;
using TINK.Services.BluetoothLock.Crypto;
using TINK.Model.Services.Geolocation;
using TINK.Services;
using System.Threading.Tasks;
using Xamarin.Essentials;
#if ARENDI
using Arendi.BleLibrary.Local;
#endif
@ -45,38 +49,100 @@ namespace TINK
// 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();
// Delete attachtment from previous session.
DeleteAttachment(internalPersonalDir);
// Setup logger using default settings.
Log.Logger = new LoggerConfiguration()
.MinimumLevel.ControlledBy(new LoggingLevelSwitch { MinimumLevel = Model.Settings.Settings.DEFAULTLOGGINLEVEL })
.WriteTo.Debug()
.WriteTo.File(internalPersonalDir, Model.Logging.RollingInterval.Session)
.CreateLogger();
// 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(specialFolders.GetInternalPersonalDir());
settingsJSON = JsonSettingsDictionary.Deserialize(internalPersonalDir);
}
catch (Exception l_oException)
catch (Exception exception)
{
Log.Error("Reading application settings from file failed.", l_oException);
Log.Error("Reading application settings from file failed.", exception);
}
var settings = new Model.Settings.Settings(
JsonSettingsDictionary.GetGroupFilterMapPage(settingsJSON),
JsonSettingsDictionary.GetGoupFilterSettings(settingsJSON),
JsonSettingsDictionary.GetCopriHostUri(settingsJSON),
JsonSettingsDictionary.GetPollingParameters(settingsJSON),
JsonSettingsDictionary.GetMinimumLoggingLevel(settingsJSON),
JsonSettingsDictionary.GetExpiresAfter(settingsJSON),
JsonSettingsDictionary.GetActiveLockService(settingsJSON),
JsonSettingsDictionary.GetConnectTimeout(settingsJSON),
JsonSettingsDictionary.GetActiveGeolocationService(settingsJSON),
JsonSettingsDictionary.GetCenterMapToCurrentLocation(settingsJSON),
JsonSettingsDictionary.GetLogToExternalFolder(settingsJSON),
JsonSettingsDictionary.GetIsSiteCachingOn(settingsJSON),
JsonSettingsDictionary.GetActiveTheme(settingsJSON));
Model.Settings.Settings settings;
try
{
settings = new Model.Settings.Settings(
JsonSettingsDictionary.GetGroupFilterMapPage(settingsJSON),
JsonSettingsDictionary.GetGoupFilterSettings(settingsJSON),
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),
JsonSettingsDictionary.GetLogToExternalFolder(settingsJSON),
JsonSettingsDictionary.GetIsSiteCachingOn(settingsJSON),
JsonSettingsDictionary.GetActiveTheme(settingsJSON));
}
catch (Exception exception)
{
Log.Error("Deserializing application settings from dictionary failed.", exception);
settings = new Model.Settings.Settings();
}
var store = new Store(settings.ActiveUri.GetHashCode().ToString());
var l_oAccount = new Account(store.Load());
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.
Log.Logger = new LoggerConfiguration()
.MinimumLevel.ControlledBy(new LoggingLevelSwitch(settings.MinimumLogEventLevel))
.WriteTo.Debug()
.WriteTo.File(!settings.LogToExternalFolder ? internalPersonalDir : specialFolders.GetExternalFilesDir(), Model.Logging.RollingInterval.Session)
.CreateLogger();
}
// Get auth cookie
Log.Debug("Get auth cookie.");
IStore store = null;
var lastVersion = JsonSettingsDictionary.GetAppVersion(settingsJSON);
if (lastVersion > new Version(3, 0, 173))
GeolocationServicesContainer.SetActive(settings.ActiveGeolocationService);
if (new Version(0, 0, 0) < lastVersion
&& lastVersion <= new Version(3, 0, 234))
{
// Version 3.0.245 and older used Xamarin.Auth.AccountStore to securely store data.
// Later version s use Xamarin.Essentials Secure Storage.
store = new StoreLegacy(settings.ActiveUri.GetHashCode().ToString());
}
else
{
// Either
// - frist install or
// - version whitch uses secure storage
// detected.
store = new Store();
}
Barrel.ApplicationId = "TINKApp";
@ -85,17 +151,17 @@ namespace TINK
var appInfoService = DependencyService.Get<IAppInfo>();
// Create new app instnace.
Log.Debug("Constructing main model...");
m_oModelRoot = new TinkApp(
settings,
store, // Manages user account
(isConnected, activeUri, sessionCookie, mail, expiresAfter) => ConnectorFactory.Create(isConnected, activeUri, $"TINKApp/{appInfoService.Version}", sessionCookie, mail, expiresAfter),
null, /* geolocationService */
DependencyService.Get<IGeolodationDependent>(),
(isConnected, activeUri, sessionCookie, mail, expiresAfter) => ConnectorFactory.Create(isConnected, activeUri, $"sharee.bike/{appInfoService.Version}", sessionCookie, mail, expiresAfter),
GeolocationServicesContainer,
null, /* locksService */
DependencyService.Get<IDevice>(),
DependencyService.Get<ISmartDevice>(),
specialFolders,
new Cipher(),
CrossPermissions.Current,
null, // Permissions, no more used.
#if ARENDI
DependencyService.Get<ICentral>(),
#else
@ -107,6 +173,7 @@ namespace TINK
lastVersion: JsonSettingsDictionary.GetAppVersion(settingsJSON),
whatsNewShownInVersion: JsonSettingsDictionary.GetWhatsNew(settingsJSON) ?? settingsJSON.GetAppVersion());
Log.Debug("Main model successfully constructed.");
return m_oModelRoot;
}
}
@ -123,7 +190,7 @@ namespace TINK
MainPage = ModelRoot.WhatsNew.IsShowRequired
? new View.WhatsNew.WhatsNewPage(() => MainPage = new View.MainPage()) // Show whats new info.
: (Page) new View.MainPage(); // Just use TINKApp
#elif USEFLYOU
#elif USEFLYOUT
// Use flyout page.
MainPage = ModelRoot.WhatsNew.IsShowRequired
? new View.WhatsNew.WhatsNewPage(() => MainPage = new View.Root.RootPage()) // Show whats new info.
@ -138,12 +205,12 @@ namespace TINK
}
/// <summary> Concatenates all log files to a single one. </summary>
/// <returns>File name of attachment.</returns>
/// <returns>Full file name of attachment.</returns>
public static string CreateAttachment()
{
var l_oLogFiles = Log.Logger.GetLogFiles().ToArray();
var sessionLogFiles = Log.Logger.GetLogFiles().ToArray();
if (l_oLogFiles.Length < 1)
if (sessionLogFiles.Length < 1)
{
// Either
// - there is no logging file
@ -151,14 +218,14 @@ namespace TINK
return string.Empty;
}
var l_oLogPath = 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();
System.IO.File.WriteAllLines(
l_oLogPath,
l_oLogFiles.SelectMany(name =>
fullLogFileName,
sessionLogFiles.SelectMany(name =>
(new List<string> { $"{{\"SessionFileName\":\"{name}\"}}" })
.Concat(System.IO.File.ReadLines(name).ToArray())));
@ -169,33 +236,21 @@ namespace TINK
.WriteTo.File(ModelRoot.LogFileParentFolder, Model.Logging.RollingInterval.Session)
.CreateLogger();
return l_oLogPath;
return fullLogFileName;
}
/// <summary>Deletes an attachment if there is one.</summary>
private static void DeleteAttachment()
/// <param name="folder">Folder to delete, is null folder is queried from model.</param>
private static void DeleteAttachment(string folder = null)
{
var l_oAttachment = System.IO.Path.Combine(ModelRoot.LogFileParentFolder, ATTACHMENTTITLE);
if (!System.IO.File.Exists(l_oAttachment))
var attachment = System.IO.Path.Combine(folder ?? ModelRoot.LogFileParentFolder, ATTACHMENTTITLE);
if (!System.IO.File.Exists(attachment))
{
// No attachment found.
return;
}
System.IO.File.Delete(l_oAttachment);
}
/// <summary> TINK app starts up.</summary>
protected override void OnStart()
{
DeleteAttachment();
Log.Logger = new LoggerConfiguration()
.MinimumLevel.ControlledBy(new LoggingLevelSwitch { MinimumLevel = ModelRoot.Level.MinimumLevel })
.WriteTo.Debug()
.WriteTo.File(ModelRoot.LogFileParentFolder, Model.Logging.RollingInterval.Session)
.CreateLogger();
System.IO.File.Delete(attachment);
}
protected override void OnSleep()
@ -227,5 +282,26 @@ namespace TINK
return LogEventLevel.Error;
}
/// <summary>
/// Service to manage permissions (location) of the app.
/// </summary>
public static Plugin.Permissions.Abstractions.IPermissions PermissionsService => CrossPermissions.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> GeolocationServicesContainer { get; }
= new Services.ServicesContainerMutable<Model.Services.Geolocation.IGeolocation>(
new HashSet<Model.Services.Geolocation.IGeolocation> {
new LastKnownGeolocationService(DependencyService.Get<IGeolodationDependent>()),
new SimulatedGeolocationService(DependencyService.Get<IGeolodationDependent>()),
new GeolocationService(DependencyService.Get<IGeolodationDependent>()) },
typeof(LastKnownGeolocationService).FullName);
}
}

View file

@ -7,19 +7,19 @@ namespace TINK
{
public static class BackdoorMethodHelpers
{
public static void DoTapPage(string stationIndex )
public static void DoTapPage(string stationId )
{
Serilog.Log.Information($"Request via backdoor to tap station {stationIndex}.");
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 {stationIndex} aborted because current page is not of expected type {typeof(MapPage).Name}. Type detected is {currentPage.GetType().Name}.");
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(int.Parse(stationIndex));
mapPageViewModel?.OnStationClicked(stationId);
}
/// <summary> Gets the current page assumed that app is master detail page.</summary>

View file

@ -1,11 +1,13 @@
using System;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TINK.Model.Connector;
namespace TINK.Model.User.Account
{
public class Store : IStore
public class StoreLegacy : IStore
{
/// <summary>
/// Holds the name of the application.
@ -21,12 +23,9 @@ namespace TINK.Model.User.Account
/// <summary> Holds the id of the session. </summary>
private const string KEY_DEBUGLEVEL = "DebugLevel";
private Store()
{ }
public Store(string p_strCopriHostHash)
public StoreLegacy(string copriHostHash)
{
m_strCopriHostHash = p_strCopriHostHash
m_strCopriHostHash = copriHostHash
?? throw new ArgumentException("Can not construct account object. Copri hash must not be null.");
}
@ -36,26 +35,26 @@ namespace TINK.Model.User.Account
/// Reads mail address and password from account store.
/// </summary>
/// <returns></returns>
public IAccount Load()
public async Task<IAccount> Load()
{
#if !WINDOWS_UWP
#if !__IOS__
var account = Xamarin.Auth.AccountStore.Create("System.Char[]").FindAccountsForService($"{M_STR_APPNAME}_{m_strCopriHostHash}").FirstOrDefault();
var xamAccountStore = Xamarin.Auth.AccountStore.Create("System.Char[]").FindAccountsForService($"{M_STR_APPNAME}_{m_strCopriHostHash}").FirstOrDefault();
#else
var account = Xamarin.Auth.AccountStore.Create().FindAccountsForService($"{M_STR_APPNAME}_{m_strCopriHostHash}").FirstOrDefault();
var xamAccountStore = Xamarin.Auth.AccountStore.Create().FindAccountsForService($"{M_STR_APPNAME}_{m_strCopriHostHash}").FirstOrDefault();
#endif
if (account == null)
if (xamAccountStore == null)
{
// Nothing t do if account cannot be accessed.
return new EmptyAccount();
}
return new Account(
account.Username,
xamAccountStore.Username,
string.Empty,
account.Properties.ContainsKey(KEY_SESSIONID) ? account.Properties[KEY_SESSIONID] : null,
account.Properties.ContainsKey(KEY_GROUP) ? TextToTypeHelper.GetGroup(account.Properties[KEY_GROUP]) : new List<string>(),
account.Properties.ContainsKey(KEY_DEBUGLEVEL) && !string.IsNullOrEmpty(account.Properties[KEY_DEBUGLEVEL]) ? Permissions.Parse<Permissions>(account.Properties[KEY_DEBUGLEVEL]) : Permissions.None);
xamAccountStore.Properties.ContainsKey(KEY_SESSIONID) ? xamAccountStore.Properties[KEY_SESSIONID] : null,
xamAccountStore.Properties.ContainsKey(KEY_GROUP) && !string.IsNullOrEmpty(xamAccountStore.Properties[KEY_GROUP]) ? JsonConvert.DeserializeObject<IEnumerable<string>>(xamAccountStore.Properties[KEY_GROUP]) : new string[0],
xamAccountStore.Properties.ContainsKey(KEY_DEBUGLEVEL) && !string.IsNullOrEmpty(xamAccountStore.Properties[KEY_DEBUGLEVEL]) ? Permissions.Parse<Permissions>(xamAccountStore.Properties[KEY_DEBUGLEVEL]) : Permissions.None);
#else
return new Account(
string.Empty,
@ -70,22 +69,22 @@ namespace TINK.Model.User.Account
/// <summary>
/// Writes mail address and password to account store.
/// </summary>
/// <param name="p_oAccount"></param>
public void Save(IAccount p_oAccount)
/// <param name="account"></param>
public async Task Save(IAccount account)
{
#if !WINDOWS_UWP
Xamarin.Auth.Account account = new Xamarin.Auth.Account
Xamarin.Auth.Account xamAccount = new Xamarin.Auth.Account
{
Username = p_oAccount.Mail
Username = account.Mail
};
account.Properties.Add(KEY_SESSIONID, p_oAccount?.SessionCookie);
account.Properties.Add(KEY_GROUP, p_oAccount?.Group?.GetGroup());
account.Properties.Add(KEY_DEBUGLEVEL, p_oAccount.DebugLevel.ToString());
xamAccount.Properties.Add(KEY_SESSIONID, account?.SessionCookie);
xamAccount.Properties.Add(KEY_GROUP, JsonConvert.SerializeObject(account?.Group ?? new string[0]));
xamAccount.Properties.Add(KEY_DEBUGLEVEL, account.DebugLevel.ToString());
#if !__IOS__
Xamarin.Auth.AccountStore.Create("System.Char[]").Save(account, $"{M_STR_APPNAME}_{m_strCopriHostHash}");
Xamarin.Auth.AccountStore.Create("System.Char[]").Save(xamAccount, $"{M_STR_APPNAME}_{m_strCopriHostHash}");
#else
Xamarin.Auth.AccountStore.Create().Save(account, $"{M_STR_APPNAME}_{m_strCopriHostHash}");
Xamarin.Auth.AccountStore.Create().Save(xamAccount, $"{M_STR_APPNAME}_{m_strCopriHostHash}");
#endif
#endif
}
@ -93,26 +92,25 @@ namespace TINK.Model.User.Account
/// <summary>
/// Deletes mail address and password from account store.
/// </summary>
public IAccount Delete(IAccount p_oAccount)
public IAccount Delete(IAccount account)
{
#if !WINDOWS_UWP
#if !__IOS__
var account = Xamarin.Auth.AccountStore.Create("System.Char[]").FindAccountsForService($"{M_STR_APPNAME}_{m_strCopriHostHash}").FirstOrDefault();
var xamAccountStore = Xamarin.Auth.AccountStore.Create("System.Char[]").FindAccountsForService($"{M_STR_APPNAME}_{m_strCopriHostHash}").FirstOrDefault();
#else
var account = Xamarin.Auth.AccountStore.Create().FindAccountsForService($"{M_STR_APPNAME}_{m_strCopriHostHash}").FirstOrDefault();
var xamAccountStore = Xamarin.Auth.AccountStore.Create().FindAccountsForService($"{M_STR_APPNAME}_{m_strCopriHostHash}").FirstOrDefault();
#endif
if (account == null)
if (xamAccountStore == null)
{
return new EmptyAccount();
}
#if !__IOS__
Xamarin.Auth.AccountStore.Create("System.Char[]").Delete(account, $"{M_STR_APPNAME}_{m_strCopriHostHash}");
Xamarin.Auth.AccountStore.Create("System.Char[]").Delete(xamAccountStore, $"{M_STR_APPNAME}_{m_strCopriHostHash}");
#else
Xamarin.Auth.AccountStore.Create().Delete(account, $"{M_STR_APPNAME}_{m_strCopriHostHash}");
Xamarin.Auth.AccountStore.Create().Delete(xamAccountStore, $"{M_STR_APPNAME}_{m_strCopriHostHash}");
#endif
#endif
return new EmptyAccount();
}
}
}

View file

@ -14,7 +14,6 @@
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)BackdoorMethodHelpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Services\BluetoothLock\Arendi\Central.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModel\FeesAndBikes\HelpContactViewModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModel\RootShell\AppShellViewModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModel\RootFlyout\RootPageViewModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)View\Account\AccountPage.xaml.cs">
@ -76,6 +75,7 @@
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)View\WhatsNew\WhatsNewPage.xaml.cs">
<DependentUpon>WhatsNewPage.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Model\User\Account\Store.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModel\ViewModelResourceHelper.cs" />

View file

@ -2,7 +2,9 @@
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using System.Threading.Tasks;
#if USEMASTERDETAIL || USEFLYOUT
using TINK.View.MasterDetail;
#endif
using System;
using TINK.Model.Device;
using TINK.ViewModel.Account;
@ -10,7 +12,11 @@ using TINK.ViewModel.Account;
namespace TINK.View.Account
{
[XamlCompilation(XamlCompilationOptions.Compile)]
#if USEMASTERDETAIL || USEFLYOUT
public partial class AccountPage : ContentPage, IViewService, IDetailPage
#else
public partial class AccountPage : ContentPage, IViewService
#endif
{
/// <summary> Refernce to view model. </summary>
AccountPageViewModel m_oViewModel = null;
@ -31,18 +37,18 @@ namespace TINK.View.Account
}
/// <summary> Displays altert 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);
/// <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 altert 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 new async Task DisplayAdvancedAlert(
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
@ -50,32 +56,48 @@ namespace TINK.View.Account
=> await App.Current.MainPage.DisplayAlert(title, $"{message}\r\nDetails:\r\n{details}", 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>
/// <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 p_strTitle, string p_strMessage, string p_strAccept, string p_strCancel)
=> await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strAccept, p_strCancel);
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, $"{message}\r\nDetails:\r\n{details}", accept, cancel);
/// <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="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 p_strTitle, String p_strCancel, String destruction, params String[] p_oButtons)
=> await base.DisplayActionSheet(p_strTitle, p_strCancel, destruction, p_oButtons);
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 USEMASTERDETAIL || USEFLYOUT
/// <summary>
/// Creates and a page an shows it.
/// </summary>
/// <param name="p_oTypeOfPage">Type of page to show.</param>
public void ShowPage(ViewTypes p_oType, string p_strTitle = null)
=> m_oNavigation.ShowPage(p_oType.GetViewType(), p_strTitle);
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);
#endif
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
@ -86,6 +108,7 @@ namespace TINK.View.Account
public Task PopModalAsync()
=> throw new NotSupportedException();
#if USEMASTERDETAIL || USEFLYOUT
/// <summary>Delegate to perform navigation.</summary>
private INavigationMasterDetail m_oNavigation;
@ -98,6 +121,7 @@ namespace TINK.View.Account
set { m_oNavigation = value; }
}
#endif
/// <summary>
/// Invoked when page is shown.
/// Starts update process.
@ -122,7 +146,10 @@ namespace TINK.View.Account
/// <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 Task<IUserFeedback> DisplayUserFeedbackPopup() => throw new NotSupportedException();
#endif
}
}

View file

@ -15,7 +15,14 @@
Padding="10">
<Label
FontAttributes="Bold"
FontSize="Large"
HorizontalTextAlignment="Center"
Text="{Binding Name}"/>
<Label
FontAttributes="Bold"
HorizontalTextAlignment="Center"
IsVisible="{Binding DisplayId, Converter={StaticResource Label_Converter}}"
Text="{Binding DisplayId}"/>
<Label
Text="{Binding StateText}"
TextColor="{Binding StateColor}"/>

View file

@ -10,7 +10,9 @@ namespace TINK.View.BikesAtStation
using System.Threading;
using System.Threading.Tasks;
using TINK.Model.Device;
using TINK.View.MasterDetail;
#if USEMASTERDETAIL || USEFLYOUT
using TINK.View.MasterDetail;
#endif
using TINK.ViewModel;
using TINK.Model;
using TINK.Services.BluetoothLock.Tdo;
@ -23,7 +25,11 @@ namespace TINK.View.BikesAtStation
using Xamarin.CommunityToolkit.Extensions;
[XamlCompilation(XamlCompilationOptions.Compile)]
#if USEMASTERDETAIL || USEFLYOUT
public partial class BikesAtStationPage : ContentPage, IViewService, IDetailPage
#else
public partial class BikesAtStationPage : ContentPage, IViewService
#endif
{
private BikesAtStationPageViewModel m_oViewModel;
@ -78,23 +84,27 @@ namespace TINK.View.BikesAtStation
m_oViewModel = new BikesAtStationPageViewModel(
model.ActiveUser,
model.Permissions,
CrossBluetoothLE.Current,
App.PermissionsService,
App.BluetoothService,
Device.RuntimePlatform,
model.SelectedStation,
() => model.GetIsConnected(),
(isConnected) => model.GetConnector(isConnected),
model.Geolocation,
App.GeolocationServicesContainer.Active,
model.LocksServices.Active,
model.Polling,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url),
(d, obj) => synchronizationContext.Post(d, obj),
this);
model.SmartDevice,
this)
{
IsReportLevelVerbose = model.IsReportLevelVerbose
};
}
catch (Exception exception)
{
Log.ForContext<BikesAtStationPage>().Error("Displaying bikes at station page failed. {Exception}", exception);
this.DisplayAlert("Fehler", $"Seite Räder an Station kann nicht angezeigt werden. ${exception.Message}", "OK");
await DisplayAlert("Fehler", $"Seite Räder an Station kann nicht angezeigt werden. ${exception.Message}", "OK");
return;
}
@ -130,12 +140,12 @@ namespace TINK.View.BikesAtStation
}
/// <summary> Displays altert 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)
/// <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(p_strTitle, p_strMessage, p_strCancel);
await App.Current.MainPage.DisplayAlert(title, message, cancel);
}
/// <summary> Displays altert message.</summary>
@ -143,7 +153,7 @@ namespace TINK.View.BikesAtStation
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public new async Task DisplayAdvancedAlert(
public async Task DisplayAdvancedAlert(
string title,
string message,
string details,
@ -153,23 +163,37 @@ namespace TINK.View.BikesAtStation
/// <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>
/// <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 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);
}
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, $"{message}\r\nDetails:\r\n{details}", accept, cancel);
#if USEMASTERDETAIL || USEFLYOUT
/// <summary> Creates and a page an shows it.</summary>
/// <remarks> When user is not logged in navigation to Login page is supported.</remarks>
/// <param name="p_oTypeOfPage">Type of page to show.</param>
public void ShowPage(ViewTypes p_oType, string p_strTitle = null)
{
m_oNavigation.ShowPage(p_oType.GetViewType(), p_strTitle);
}
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);
#endif
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
@ -189,6 +213,7 @@ namespace TINK.View.BikesAtStation
throw new NotImplementedException();
}
#if USEMASTERDETAIL || USEFLYOUT
/// <summary>
/// Delegate to perform navigation.
/// </summary>
@ -202,6 +227,12 @@ namespace TINK.View.BikesAtStation
set { m_oNavigation = value; }
}
#endif
#if USCSHARP9
public async Task<IViewService.IUserFeedback> DisplayUserFeedbackPopup() => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup());
}
}
#else
public async Task<IUserFeedback> DisplayUserFeedbackPopup() => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup());
#endif
}
}

View file

@ -27,21 +27,31 @@ namespace TINK.View.Contact
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public new async Task DisplayAdvancedAlert(
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>
/// Creates and a page an shows it.
/// </summary>
/// <param name="p_oTypeOfPage">Type of page to show.</param>
/// <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, $"{message}\r\nDetails:\r\n{details}", accept, cancel);
#if USEMASTERDETAIL || USEFLYOUT
public void ShowPage(ViewTypes p_oType, string p_strTitle = null)
{
throw new NotSupportedException();
}
=> 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);
#endif
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
@ -62,7 +72,10 @@ namespace TINK.View.Contact
{
throw new NotImplementedException();
}
#if USCSHARP9
public Task<IViewService.IUserFeedback> DisplayUserFeedbackPopup() => throw new NotSupportedException();
#else
public Task<IUserFeedback> DisplayUserFeedbackPopup() => throw new NotSupportedException();
#endif
}
}

View file

@ -1,15 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.CommunityToolkit.UI.Views;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace TINK.View
{
[XamlCompilation(XamlCompilationOptions.Compile)]
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class FeedbackPopup : Popup<FeedbackPopup.Result>
{
public FeedbackPopup ()
@ -40,7 +35,11 @@ namespace TINK.View
/// <summary>
/// Feedback given by user when returning bike.
/// </summary>
#if USCSHARP9
public class Result : IViewService.IUserFeedback
#else
public class Result : IUserFeedback
#endif
{
/// <summary>
/// Holds whether bike is broken or not.
@ -54,7 +53,6 @@ namespace TINK.View
/// or both.
/// </summary>
public string Message { get; set; }
}
}
}

View file

@ -2,7 +2,6 @@
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using TINK.ViewModel.Contact;
using TINK.Model;
namespace TINK.View.Contact
{
@ -16,8 +15,10 @@ namespace TINK.View.Contact
InitializeComponent();
ViewModel = new HelpContactViewModel(
TINK.App.ModelRoot.NextActiveUri.Host,
TINK.App.ModelRoot.IsSiteCachingOn);
App.ModelRoot.NextActiveUri.Host,
App.ModelRoot.IsSiteCachingOn,
resourceName => ViewModelResourceHelper.GetSource(resourceName));
BindingContext = ViewModel;
/// Info about renting.

View file

@ -1,6 +1,8 @@
using System;
using System.Threading.Tasks;
#if USEMASTERDETAIL || USEFLYOUT
using TINK.View.MasterDetail;
#endif
using TINK.ViewModel;
using TINK.ViewModel.Info.BikeInfo;
using Xamarin.Forms;
@ -9,9 +11,13 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.Info.BikeInfo
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class BikeInfoCarouselPage : CarouselPage, IViewService, IDetailPage
#if USEMASTERDETAIL || USEFLYOUT
public partial class BikeInfoCarouselPage : CarouselPage, IViewService, IDetailPage
#else
public partial class BikeInfoCarouselPage : CarouselPage, IViewService
#endif
{
public BikeInfoCarouselPage ()
public BikeInfoCarouselPage ()
{
InitializeComponent ();
@ -36,13 +42,23 @@ namespace TINK.View.Info.BikeInfo
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public new async Task DisplayAdvancedAlert(
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, $"{message}\r\nDetails:\r\n{details}", accept, cancel);
/// <summary>
/// Displays alert message.
/// </summary>
@ -56,14 +72,19 @@ namespace TINK.View.Info.BikeInfo
return await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strAccept, p_strCancel);
}
#if USEMASTERDETAIL || USEFLYOUT
/// <summary>
/// Creates and a page an shows it.
/// </summary>
/// <param name="p_oTypeOfPage">Type of page to show.</param>
public void ShowPage(ViewTypes p_oType, string p_strTitle = null)
{
m_oNavigation.ShowPage(p_oType.GetViewType(), p_strTitle);
}
=> 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);
#endif
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
@ -85,6 +106,7 @@ namespace TINK.View.Info.BikeInfo
throw new NotImplementedException();
}
#if USEMASTERDETAIL || USEFLYOUT
/// <summary>
/// Delegate to perform navigation.
/// </summary>
@ -98,6 +120,11 @@ namespace TINK.View.Info.BikeInfo
set { m_oNavigation = value; }
}
#endif
#if USCSHARP9
public Task<IViewService.IUserFeedback> DisplayUserFeedbackPopup() => throw new NotSupportedException();
#else
public Task<IUserFeedback> DisplayUserFeedbackPopup() => throw new NotSupportedException();
#endif
}
}

View file

@ -1,7 +1,9 @@
using System;
using System.Threading.Tasks;
using TINK.Model.Device;
#if USEMASTERDETAIL || USEFLYOUT
using TINK.View.MasterDetail;
#endif
using TINK.ViewModel;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
@ -9,9 +11,13 @@ using Xamarin.Forms.Xaml;
namespace TINK.View.Login
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class LoginPage : ContentPage, IViewService, IDetailPage
#if USEMASTERDETAIL || USEFLYOUT
public partial class LoginPage : ContentPage, IViewService, IDetailPage
#else
public partial class LoginPage : ContentPage, IViewService
#endif
{
public LoginPage ()
public LoginPage ()
{
InitializeComponent ();
@ -44,25 +50,40 @@ namespace TINK.View.Login
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public new async Task DisplayAdvancedAlert(
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, $"{message}\r\nDetails:\r\n{details}", accept, cancel);
#if USEMASTERDETAIL || USEFLYOUT
/// <summary>
/// Creates and a page an shows it.
/// </summary>
/// <param name="p_oTypeOfPage">Type of page to show.</param>
public void ShowPage(ViewTypes p_oType, string p_strTitle = null)
{
m_oNavigation.ShowPage(p_oType.GetViewType(), p_strTitle);
}
=> 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);
#endif
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
public Task PushModalAsync(ViewTypes p_oTypeOfPage)
public Task PushModalAsync(ViewTypes p_oTypeOfPage)
{
throw new NotSupportedException();
}
@ -80,6 +101,7 @@ namespace TINK.View.Login
await Navigation.PushAsync((Page)Activator.CreateInstance(p_oTypeOfPage.GetViewType()));
}
#if USEMASTERDETAIL || USEFLYOUT
/// <summary>
/// Delegate to perform navigation.
/// </summary>
@ -93,6 +115,11 @@ namespace TINK.View.Login
set { m_oNavigation = value; }
}
#endif
#if USCSHARP9
public Task<IViewService.IUserFeedback> DisplayUserFeedbackPopup() => throw new NotSupportedException();
}
}
#else
public Task<IUserFeedback> DisplayUserFeedbackPopup() => throw new NotSupportedException();
#endif
}
}

View file

@ -1,21 +1,26 @@
using Plugin.Connectivity;
using System;
using System.Threading.Tasks;
#if USEMASTERDETAIL || USEFLYOUT
using TINK.View.MasterDetail;
#endif
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace TINK.View.Map
{
using TINK.Model.Services.CopriApi.ServerUris;
using Serilog;
using TINK.ViewModel.Map;
using Xamarin.Forms.GoogleMaps;
[XamlCompilation(XamlCompilationOptions.Compile)]
#if USEMASTERDETAIL || USEFLYOUT
public partial class MapPage : ContentPage, IViewService, IDetailPage
#else
public partial class MapPage : ContentPage, IViewService
#endif
{
/// <summary> View model to notify about whether page appears or hides. </summary>
private MapPageViewModel m_oMapPageViewModel;
private MapPageViewModel MapPageViewModel { get; set; }
/// <summary>
/// Constructs map page instance.
@ -41,13 +46,23 @@ namespace TINK.View.Map
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public new async Task DisplayAdvancedAlert(
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, $"{message}\r\nDetails:\r\n{details}", accept, cancel);
/// <summary>
/// Displays alert message.
/// </summary>
@ -61,14 +76,18 @@ namespace TINK.View.Map
return await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strAccept, p_strCancel);
}
#if USEMASTERDETAIL || USEFLYOUT
/// <summary>
/// Creates and a page an shows it.
/// </summary>
/// <param name="p_oTypeOfPage">Type of page to show.</param>
public void ShowPage(ViewTypes p_oType, string p_strTitle = null)
{
m_oNavigationMasterDetail.ShowPage(p_oType.GetViewType(), p_strTitle);
}
=> NavigationMasterDetail.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);
#endif
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="p_oTypeOfPage">Type of page to display.</param>
@ -87,31 +106,34 @@ namespace TINK.View.Map
/// <param name="p_oTypeOfPage">Page to display.</param>
public async Task PushAsync(ViewTypes p_oTypeOfPage)
{
#if USEMASTERDETAIL || USEFLYOUT
var page = Activator.CreateInstance(p_oTypeOfPage.GetViewType()) as IDetailPage;
#else
var page = Activator.CreateInstance(p_oTypeOfPage.GetViewType());
#endif
if (page == null)
{
return;
}
page.NavigationMasterDetail = m_oNavigationMasterDetail;
#if USEMASTERDETAIL || USEFLYOUT
page.NavigationMasterDetail = NavigationMasterDetail;
#endif
await Navigation.PushAsync((Page)page);
}
#if USCSHARP9
public Task<IViewService.IUserFeedback> DisplayUserFeedbackPopup() => throw new NotSupportedException();
#else
public Task<IUserFeedback> DisplayUserFeedbackPopup() => throw new NotSupportedException();
#endif
/// <summary> Delegate to perform navigation. </summary>
private INavigationMasterDetail m_oNavigationMasterDetail;
#if USEMASTERDETAIL || USEFLYOUT
/// <summary> Delegate to perform navigation.</summary>
public INavigationMasterDetail NavigationMasterDetail
{
set
{
m_oNavigationMasterDetail = value;
}
}
public INavigationMasterDetail NavigationMasterDetail { private get; set; }
#endif
/// <summary>
/// Invoked when page is shown.
/// Starts update process.
@ -119,39 +141,99 @@ namespace TINK.View.Map
protected async override void OnAppearing()
{
// Pass reference to member Navigation to show bikes at station x dialog.
#if TRYNOTBACKSTYLE
m_oMapPageViewModel = new MapPageViewModel();
#else
m_oMapPageViewModel = new MapPageViewModel(
App.ModelRoot,
(mapspan) => MyMap.MoveToRegion(mapspan),
this,
Navigation);
#endif
BindingContext = m_oMapPageViewModel;
if (Device.RuntimePlatform == Device.iOS)
try
{
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);
Log.ForContext<MainPage>().Verbose("Constructing map page view model.");
#if TRYNOTBACKSTYLE
m_oMapPageViewModel = new MapPageViewModel();
#else
MapPageViewModel = new MapPageViewModel(
App.ModelRoot,
App.PermissionsService,
App.BluetoothService,
App.GeolocationServicesContainer.Active,
(mapspan) => MyMap.MoveToRegion(mapspan),
this,
Navigation);
#endif
} catch (Exception exception)
{
Log.ForContext<MainPage>().Error("Constructing map page view model failed. {Exception}", exception);
return;
}
m_oMapPageViewModel.NavigationMasterDetail = m_oNavigationMasterDetail;
try
{
BindingContext = MapPageViewModel;
base.OnAppearing();
#if USEMASTERDETAIL || USEFLYOUT
MapPageViewModel.NavigationMasterDetail = NavigationMasterDetail;
#endif
}
catch (Exception exception)
{
Log.ForContext<MainPage>().Error("Setting binding/ navigaton on map page failed. {Exception}", exception);
return;
}
// Pre move and scanle maps to avoid initial display of map in Rome.
MapPageViewModel.MoveAndScale(
(mapSpan) => MyMap.MoveToRegion(mapSpan),
App.ModelRoot.Uris.ActiveUri,
App.ModelRoot.GroupFilterMapPage);
await m_oMapPageViewModel.OnAppearing();
try
{
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);
}
}
catch (Exception exception)
{
// Continue because styling is not essential.
Log.ForContext<MainPage>().Error("IOS specific styling of map page failed. {Exception}", exception);
}
try
{
base.OnAppearing();
}
catch (Exception exception)
{
// Continue because styling is not essential.
Log.ForContext<MainPage>().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<MainPage>().Verbose("Moving and scaling map.");
MapPageViewModel.MoveAndScale(
(mapSpan) => MyMap.MoveToRegion(mapSpan),
App.ModelRoot.Uris.ActiveUri,
App.ModelRoot.GroupFilterMapPage);
}
catch(Exception exception)
{
// Continue because a map not beeing moved/ scaled is no reason for aborting startup.
Log.ForContext<MainPage>().Error("Moving and scaling map failed. {Exception}", exception);
}
try
{
Log.ForContext<MainPage>().Verbose("Invoking OnAppearing on map page view model.");
await MapPageViewModel.OnAppearing();
}
catch (Exception exception)
{
Log.ForContext<MainPage>().Error("Invoking OnAppearing on map page view model failed. {Exception}", exception);
return;
}
}
/// <summary>
@ -160,10 +242,10 @@ namespace TINK.View.Map
/// </summary>
protected override async void OnDisappearing()
{
if (m_oMapPageViewModel != null)
if (MapPageViewModel != null)
{
// View model might be null.
await m_oMapPageViewModel?.OnDisappearing();
await MapPageViewModel?.OnDisappearing();
}
base.OnDisappearing();

View file

@ -4,7 +4,9 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using TINK.Model.Bike.BluetoothLock;
#if USEMASTERDETAIL || USEFLYOUT
using TINK.View.MasterDetail;
#endif
using TINK.ViewModel;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
@ -58,21 +60,25 @@ namespace TINK.View.MyBikes
m_oViewModel = new MyBikesPageViewModel(
model.ActiveUser,
model.Permissions,
CrossBluetoothLE.Current,
App.PermissionsService,
App.BluetoothService,
Device.RuntimePlatform,
() => model.GetIsConnected(),
(isConnected) => model.GetConnector(isConnected),
model.Geolocation,
App.GeolocationServicesContainer.Active,
model.LocksServices.Active,
model.Polling,
(d, obj) => synchronizationContext.Post(d, obj),
this);
model.SmartDevice,
this)
{
IsReportLevelVerbose = model.IsReportLevelVerbose
};
}
catch (Exception exception)
{
Log.ForContext<MyBikesPage>().Error("Displaying bikes at station page failed. {Exception}", exception);
this.DisplayAlert("Fehler", $"Seite Räder an Station kann nicht angezeigt werden. ${exception.Message}", "OK");
await DisplayAlert("Fehler", $"Seite Räder an Station kann nicht angezeigt werden. ${exception.Message}", "OK");
return;
}
@ -123,6 +129,16 @@ namespace TINK.View.MyBikes
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, $"{message}\r\nDetails:\r\n{details}", accept, cancel);
/// <summary>
/// Displays alert message.
/// </summary>
@ -136,14 +152,14 @@ namespace TINK.View.MyBikes
return await App.Current.MainPage.DisplayAlert(p_strTitle, p_strMessage, p_strAccept, p_strCancel);
}
/// <summary>
/// Creates and a page an shows it.
/// </summary>
/// <param name="p_oTypeOfPage">Type of page to show.</param>
#if USEMASTERDETAIL || USEFLYOUT
public void ShowPage(ViewTypes p_oType, string p_strTitle = null)
{
throw new NotSupportedException();
}
=> 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);
#endif
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
@ -165,6 +181,10 @@ namespace TINK.View.MyBikes
throw new NotSupportedException();
}
#if USCSHARP9
public async Task<IViewService.IUserFeedback> DisplayUserFeedbackPopup() => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup());
#else
public async Task<IUserFeedback> DisplayUserFeedbackPopup() => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup());
#endif
}
}

View file

@ -3,7 +3,9 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
#if USEMASTERDETAIL || USEFLYOUT
using TINK.View.MasterDetail;
#endif
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
@ -19,7 +21,11 @@ namespace TINK.View.Root
// - switch to login page form bikes at station page if not yet logged in
/// </remarks>
[XamlCompilation(XamlCompilationOptions.Compile)]
#if USEMASTERDETAIL || USEFLYOUT
public partial class RootPage : FlyoutPage, INavigationMasterDetail
#else
public partial class RootPage : FlyoutPage
#endif
{
public RootPage()
{
@ -35,6 +41,7 @@ namespace TINK.View.Root
return;
}
#if USEMASTERDETAIL || USEFLYOUT
var detailPage = navigationPage.RootPage as IDetailPage;
if (detailPage == null)
{
@ -42,6 +49,7 @@ namespace TINK.View.Root
}
detailPage.NavigationMasterDetail = this;
#endif
}
/// <summary>
@ -70,12 +78,14 @@ namespace TINK.View.Root
var page = (Page)Activator.CreateInstance(typeOfPage);
page.Title = title;
#if USEMASTERDETAIL || USEFLYOUT
if (page is IDetailPage detailPage)
{
// Detail page needs reference to perform navigation.
// Examples see above in xdoc of class.
detailPage.NavigationMasterDetail = this;
}
#endif
Detail = new NavigationPage(page);
}

View file

@ -8,7 +8,9 @@ using System.Text;
using System.Threading.Tasks;
using TINK.Model;
using TINK.Services;
#if USEMASTERDETAIL || USEFLYOUT
using TINK.View.MasterDetail;
#endif
using TINK.View.Themes;
using TINK.ViewModel.Root;
using Xamarin.Forms;

View file

@ -1,6 +1,8 @@
using System;
using TINK.View.Info.BikeInfo;
#if USEMASTERDETAIL || USEFLYOUT
using TINK.View.MasterDetail;
#endif
using TINK.ViewModel.MasterDetail;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
@ -13,8 +15,12 @@ namespace TINK.View
public delegate void ShowPageDelegate(Type p_oType, string p_strTitle = null);
[XamlCompilation(XamlCompilationOptions.Compile)]
#if USEMASTERDETAIL || USEFLYOUT
public partial class MainPage : MasterDetailPage, INavigationMasterDetail
{
#else
public partial class MainPage : MasterDetailPage
#endif
{
public MainPage()
{
InitializeComponent();
@ -29,6 +35,7 @@ namespace TINK.View
return;
}
#if USEMASTERDETAIL || USEFLYOUT
var detailPage = navigationPage.RootPage as IDetailPage;
if (detailPage == null)
{
@ -36,6 +43,7 @@ namespace TINK.View
}
detailPage.NavigationMasterDetail = this;
#endif
}
/// <summary> Creates and a page an shows it.</summary>
@ -50,11 +58,13 @@ namespace TINK.View
var page = (Page)Activator.CreateInstance(p_oTypeOfPage);
page.Title = p_strTitle ?? Helper.GetCaption(p_oTypeOfPage);
#if USEMASTERDETAIL || USEFLYOUT
var l_oPage = page as IDetailPage;
if (l_oPage != null)
{
l_oPage.NavigationMasterDetail = this;
}
#endif
#if !BACKSTYLE
// When bike info page is shown do not allow to close this carousel before all pages were displayed.

View file

@ -20,6 +20,7 @@
<FlyoutItem FlyoutDisplayOptions="AsMultipleItems">
<ShellContent
Title="{x:Static resources:AppResources.MarkingMapPage}"
Route="MapPage"
ContentTemplate="{DataTemplate mappage:MapPage}">
<ShellContent.FlyoutIcon>
<FontImageSource Glyph="{StaticResource IconMap}" Color="Black" FontFamily="FA-S" />
@ -49,6 +50,7 @@
<FlyoutItem FlyoutDisplayOptions="AsMultipleItems">
<ShellContent
Title="{x:Static resources:AppResources.MarkingLogin}"
Route="LoginPage"
IsVisible="{Binding IsLoginPageVisible}"
ContentTemplate="{DataTemplate login:LoginPage}">
<ShellContent.FlyoutIcon>

View file

@ -12,6 +12,7 @@
<conv:PermissionToVisibleConverter x:Key="PickLockServiceImplementation_Converter" VisibleFlag="PickLockServiceImplementation"/>
<conv:PermissionToVisibleConverter x:Key="PickLocationServiceImplementation_Converter" VisibleFlag="PickLocationServiceImplementation"/>
<conv:PermissionToVisibleConverter x:Key="PickLoggingLevel_Converter" VisibleFlag="PickLoggingLevel"/>
<conv:PermissionToVisibleConverter x:Key="ReportLevel_Converter" VisibleFlag="ReportLevel"/>
<conv:PermissionToVisibleConverter x:Key="ShowDiagnostics_Converter" VisibleFlag="ShowDiagnostics"/>
<conv:PermissionToVisibleConverter x:Key="SwitchSiteCaching_Converter" VisibleFlag="SwitchNoSiteCaching"/>
</ContentPage.Resources>
@ -176,6 +177,18 @@
IsEnabled="{Binding IsLogToExternalFolderVisible}"/>
</StackLayout>
</Frame>
<Frame
IsVisible="{Binding DebugLevel, Converter={StaticResource Frame_Converter}}">
<!-- Logging -->
<StackLayout>
<Label
IsVisible="{Binding DebugLevel, Converter={StaticResource ReportLevel_Converter}}"
Text="Verbose error messages" />
<Switch
IsVisible="{Binding DebugLevel, Converter={StaticResource ReportLevel_Converter}}"
IsToggled="{Binding IsReportLevelVerbose}"/>
</StackLayout>
</Frame>
<Frame
IsVisible="{Binding DebugLevel, Converter={StaticResource Frame_Converter}}">
<!-- Display of parameters -->

View file

@ -2,7 +2,9 @@
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using System.Threading.Tasks;
#if USEMASTERDETAIL || USEFLYOUT
using TINK.View.MasterDetail;
#endif
using System;
using TINK.Model.Device;
using Xamarin.CommunityToolkit.Extensions;
@ -10,7 +12,11 @@ using Xamarin.CommunityToolkit.Extensions;
namespace TINK.View.Settings
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class SettingsPage : ContentPage, IViewService, IDetailPage
#if USEMASTERDETAIL || USEFLYOUT
public partial class SettingsPage : ContentPage, IViewService, IDetailPage
#else
public partial class SettingsPage : ContentPage, IViewService
#endif
{
/// <summary> Refernce to view model. </summary>
SettingsPageViewModel m_oViewModel = null;
@ -24,6 +30,7 @@ namespace TINK.View.Settings
m_oViewModel = new SettingsPageViewModel(
l_oModel,
App.GeolocationServicesContainer,
this);
BindingContext = m_oViewModel;
@ -43,13 +50,23 @@ namespace TINK.View.Settings
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public new async Task DisplayAdvancedAlert(
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, $"{message}\r\nDetails:\r\n{details}", accept, cancel);
/// <summary> Displays alert message.</summary>
/// <param name="p_strTitle">Title of message.</param>
/// <param name="p_strMessage">Message to display.</param>
@ -71,12 +88,18 @@ namespace TINK.View.Settings
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 USEMASTERDETAIL || USEFLYOUT
/// <summary>
/// Creates and a page an shows it.
/// </summary>
/// <param name="p_oTypeOfPage">Type of page to show.</param>
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);
#endif
/// <summary> Pushes a page onto the modal stack. </summary>
/// <param name="p_oTypeOfPage">Page to display.</param>
@ -87,6 +110,7 @@ namespace TINK.View.Settings
public Task PopModalAsync()
=> throw new NotSupportedException();
#if USEMASTERDETAIL || USEFLYOUT
/// <summary>Delegate to perform navigation.</summary>
private INavigationMasterDetail m_oNavigation;
@ -98,6 +122,7 @@ namespace TINK.View.Settings
set { m_oNavigation = value; }
}
#endif
/// <summary>
/// Invoked when pages is closed/ hidden.
/// Stops update process.
@ -118,7 +143,11 @@ namespace TINK.View.Settings
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
public async Task<IUserFeedback> DisplayUserFeedbackPopup() => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup());
#endif
#if USERFEEDBACKDLG_TRYOUT
public async void OnFeedbackClickedAsync(object sender, EventArgs ev)

View file

@ -28,13 +28,23 @@ namespace TINK.View.WhatsNew.Agb
/// <param name="message">Message to display.</param>
/// <param name="details">Detailed error description.</param>
/// <param name="cancel">Type of buttons.</param>
public new async Task DisplayAdvancedAlert(
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, $"{message}\r\nDetails:\r\n{details}", accept, cancel);
/// <summary> Invoked when page is shown. </summary>
protected async override void OnAppearing()
{
@ -61,11 +71,19 @@ namespace TINK.View.WhatsNew.Agb
throw new NotImplementedException();
}
#if USEMASTERDETAIL || USEFLYOUT
public void ShowPage(ViewTypes p_oType, string p_strTitle = null)
{
throw new NotImplementedException();
}
=> 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);
#endif
#if USCSHARP9
public Task<IViewService.IUserFeedback> DisplayUserFeedbackPopup() => throw new NotSupportedException();
#else
public Task<IUserFeedback> DisplayUserFeedbackPopup() => throw new NotSupportedException();
#endif
}
}

View file

@ -40,6 +40,16 @@ namespace TINK.View.WhatsNew
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, $"{message}\r\nDetails:\r\n{details}", accept, cancel);
public Task PopModalAsync()
{
throw new NotImplementedException(); ;
@ -57,12 +67,20 @@ namespace TINK.View.WhatsNew
await Navigation.PushModalAsync((Page)Activator.CreateInstance(p_oTypeOfPage.GetViewType()));
}
#if USEMASTERDETAIL || USEFLYOUT
public void ShowPage(ViewTypes p_oType, string p_strTitle = null)
{
throw new NotImplementedException();
}
=> 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);
#endif
#if USCSHARP9
public Task<IViewService.IUserFeedback> DisplayUserFeedbackPopup() => throw new NotSupportedException();
#else
public Task<IUserFeedback> DisplayUserFeedbackPopup() => throw new NotSupportedException();
#endif
/// <summary>
/// Invoked when pages is closed/ hidden.

View file

@ -1,69 +0,0 @@
using System.ComponentModel;
using Xamarin.Forms;
using TINK.Services.CopriApi.ServerUris;
using TINK.Model.User.Account;
namespace TINK.ViewModel.Contact
{
public class HelpContactViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
/// <summary> Holds value wether site caching is on or off.</summary>
bool IsSiteCachingOn { get; }
/// <summary> Constructs view model.</summary>
/// <param name="isSiteCachingOn">Set of user permissions</param>
public HelpContactViewModel(
string hostName,
bool isSiteCachingOn)
{
HostName = hostName;
IsSiteCachingOn = isSiteCachingOn;
}
/// <summary> Holds the name of the host.</summary>
private string HostName { get; }
/// <summary> Called when page is shown. </summary>
public async void OnAppearing()
{
RentBikeText = new HtmlWebViewSource
{
Html = HostName.GetIsCopri()
? ViewModelResourceHelper.GetSource("HtmlResouces.V02.InfoRentBike.html")
: await ViewModelHelper.GetSource($"https://{HostName}/{CopriHelper.SHAREE_SILTEFOLDERNAME}/tariff_info.html", IsSiteCachingOn)
};
TypesOfBikesText = new HtmlWebViewSource
{
Html = HostName.GetIsCopri()
? ViewModelResourceHelper.GetSource("HtmlResouces.V02.InfoTypesOfBikes.html")
: await ViewModelHelper.GetSource($"https://{HostName}/{CopriHelper.SHAREE_SILTEFOLDERNAME}/bike_info.html", IsSiteCachingOn)
};
}
private HtmlWebViewSource rentBikeText;
private HtmlWebViewSource typesOfBikesText;
public HtmlWebViewSource RentBikeText
{
get => rentBikeText;
set
{
rentBikeText = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(RentBikeText)));
}
}
public HtmlWebViewSource TypesOfBikesText
{
get => typesOfBikesText;
set
{
typesOfBikesText = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TypesOfBikesText)));
}
}
}
}

View file

@ -15,7 +15,9 @@ using TINK.View.Root;
using TINK.View.Settings;
using Xamarin.Forms;
using TINK.ViewModel.MasterDetail;
#if USEMASTERDETAIL || USEFLYOUT
using TINK.View.MasterDetail;
#endif
using TINK.Services;
using TINK.View.Themes;

View file

@ -87,7 +87,7 @@ namespace TINK.ViewModel.MasterDetail
}
else if (type == typeof(FeesAndBikesPage))
{
return "\uf153";
return "\uf7d9";
}
else if (type == typeof(ContactPage))
{