mirror of
https://dev.azure.com/TeilRad/sharee.bike%20App/_git/Code
synced 2025-04-20 03:56:29 +02:00
Initial version.
This commit is contained in:
parent
193aaa1a56
commit
b72c67a53e
228 changed files with 25924 additions and 0 deletions
423
TINKLib/Model/TinkApp.cs
Normal file
423
TINKLib/Model/TinkApp.cs
Normal file
|
@ -0,0 +1,423 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using TINK.Model.Connector;
|
||||
using TINK.Model.Device;
|
||||
using TINK.Settings;
|
||||
using TINK.Model.User.Account;
|
||||
using TINK.Model.Settings;
|
||||
using TINK.Model.Logging;
|
||||
using Serilog.Events;
|
||||
using Serilog.Core;
|
||||
using Serilog;
|
||||
using Plugin.Connectivity;
|
||||
using System.Threading;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Model.Services.CopriApi.ServerUris;
|
||||
using Plugin.Permissions.Abstractions;
|
||||
using TINK.Services.BluetoothLock.Crypto;
|
||||
using TINK.ViewModel.Map;
|
||||
using TINK.ViewModel.Settings;
|
||||
using TINK.Services;
|
||||
using TINK.Services.BluetoothLock.BLE;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace TINK.Model
|
||||
{
|
||||
[DataContract]
|
||||
public class TinkApp : ITinkApp
|
||||
{
|
||||
/// <summary> Delegate used by login view to commit user name and password. </summary>
|
||||
/// <param name="p_strMailAddress">Mail address used as id login.</param>
|
||||
/// <param name="p_strPassword">Password for login.</param>
|
||||
/// <returns>True if setting credentials succeeded.</returns>
|
||||
public delegate bool SetCredentialsDelegate(string p_strMailAddress, string p_strPassword);
|
||||
|
||||
/// <summary>Returns the id of the app to be identified by copri.</summary>
|
||||
public static string MerchantId => "oiF2kahH";
|
||||
|
||||
/// <summary>
|
||||
/// Holds status about whants new page.
|
||||
/// </summary>
|
||||
public WhatsNew WhatsNew { get; private set; }
|
||||
|
||||
/// <summary>Sets flag whats new page was already shown to true. </summary>
|
||||
public void SetWhatsNewWasShown() => WhatsNew = WhatsNew.SetWasShown();
|
||||
|
||||
/// <summary>Holds uris of copri servers. </summary>
|
||||
public CopriServerUriList Uris { get; }
|
||||
|
||||
/// <summary> Holds the filters loaded from settings. </summary>
|
||||
public IGroupFilterSettings FilterGroupSetting { get; set; }
|
||||
|
||||
/// <summary> Holds the filter which is applied on the map view. Either TINK or Konrad stations are displayed. </summary>
|
||||
private IGroupFilterMapPage m_oFilterDictionaryMapPage;
|
||||
|
||||
/// <summary> Holds the filter which is applied on the map view. Either TINK or Konrad stations are displayed. </summary>
|
||||
public IGroupFilterMapPage GroupFilterMapPage
|
||||
{
|
||||
get => m_oFilterDictionaryMapPage;
|
||||
set => m_oFilterDictionaryMapPage = value ?? new GroupFilterMapPage();
|
||||
}
|
||||
|
||||
/// <summary> Value indicating whether map is centerted to current position or not. </summary>
|
||||
public bool CenterMapToCurrentLocation { get; set; }
|
||||
|
||||
/// <summary> Gets the minimum logging level. </summary>
|
||||
public LogEventLevel MinimumLogEventLevel { get; set; }
|
||||
|
||||
/// <summary> Holds the uri which is applied after restart. </summary>
|
||||
public Uri NextActiveUri { get; set; }
|
||||
|
||||
/// <summary> Saves object to file. </summary>
|
||||
public void Save()
|
||||
=> JsonSettingsDictionary.Serialize(
|
||||
SettingsFileFolder,
|
||||
new Dictionary<string, string>()
|
||||
.SetGroupFilterMapPage(GroupFilterMapPage)
|
||||
.SetCopriHostUri(NextActiveUri.AbsoluteUri)
|
||||
.SetPollingParameters(Polling)
|
||||
.SetGroupFilterSettings(FilterGroupSetting)
|
||||
.SetAppVersion(AppVersion)
|
||||
.SetMinimumLoggingLevel(MinimumLogEventLevel)
|
||||
.SetExpiresAfter(ExpiresAfter)
|
||||
.SetWhatsNew(AppVersion)
|
||||
.SetActiveLockService(LocksServices.Active.GetType().FullName)
|
||||
.SetActiveGeolocationService(GeolocationServices.Active.GetType().FullName)
|
||||
.SetCenterMapToCurrentLocation(CenterMapToCurrentLocation)
|
||||
.SetLogToExternalFolder(LogToExternalFolder)
|
||||
.SetConnectTimeout(LocksServices.Active.TimeOut.MultiConnect)
|
||||
.SetIsSiteCachingOn(IsSiteCachingOn)
|
||||
.SetActiveTheme(Themes.Active.GetType().FullName));
|
||||
|
||||
/// <summary>
|
||||
/// Update connector from filters when
|
||||
/// - login state changes
|
||||
/// - view is toggled (TINK to Kornrad and vice versa)
|
||||
/// </summary>
|
||||
public void UpdateConnector()
|
||||
{
|
||||
// Create filtered connector.
|
||||
m_oConnector = FilteredConnectorFactory.Create(
|
||||
FilterGroupSetting.DoFilter(ActiveUser.DoFilter(GroupFilterMapPage.DoFilter())),
|
||||
m_oConnector.Connector);
|
||||
}
|
||||
|
||||
/// <summary>Polling periode.</summary>
|
||||
public PollingParameters Polling { get; set; }
|
||||
|
||||
public TimeSpan ExpiresAfter { get; set; }
|
||||
|
||||
/// <summary> Holds the version of the app.</summary>
|
||||
public Version AppVersion { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds the default polling value.
|
||||
/// </summary>
|
||||
public TimeSpan DefaultPolling => new TimeSpan(0, 0, 10);
|
||||
|
||||
/// <summary> Constructs TinkApp object. </summary>
|
||||
/// <param name="settings"></param>
|
||||
/// <param name="accountStore"></param>
|
||||
/// <param name="passwordValidator"></param>
|
||||
/// <param name="p_oConnectorFactory"></param>
|
||||
/// <param name="geolocationService">Null in productive context. Service to querry geoloation for testing purposes. Parameter can be made optional.</param>
|
||||
/// <param name="locksService">Null in productive context. Service to control locks/ get locks information for testing proposes. Parameter can be made optional.</param>
|
||||
/// <param name="device">Object allowing platform specific operations.</param>
|
||||
/// <param name="specialFolder"></param>
|
||||
/// <param name="p_oDateTimeProvider"></param>
|
||||
/// <param name="isConnectedFunc">True if connector has access to copri server, false if cached values are used.</param>
|
||||
/// <param name="currentVersion">Version of the app. If null version is set to a fixed dummy value (3.0.122) for testing purposes.</param>
|
||||
/// <param name="lastVersion">Version of app which was used before this session.</param>
|
||||
/// <param name="whatsNewShownInVersion"> Holds
|
||||
/// - the version when whats new info was shown last or
|
||||
/// - version of application used last if whats new functionality was not implemented in this version or
|
||||
/// - null if app is installed for the first time.
|
||||
/// /// </param>
|
||||
public TinkApp(
|
||||
Settings.Settings settings,
|
||||
IStore accountStore,
|
||||
Func<bool, Uri, string, string, TimeSpan, IConnector> connectorFactory,
|
||||
IGeolocation geolocationService,
|
||||
IGeolodationDependent geolodationServiceDependent,
|
||||
ILocksService locksService,
|
||||
IDevice device,
|
||||
ISpecialFolder specialFolder,
|
||||
ICipher cipher,
|
||||
IPermissions permissions = null,
|
||||
object arendiCentral = null,
|
||||
Func<bool> isConnectedFunc = null,
|
||||
Action<SendOrPostCallback, object> postAction = null,
|
||||
Version currentVersion = null,
|
||||
Version lastVersion = null,
|
||||
Version whatsNewShownInVersion = null)
|
||||
{
|
||||
PostAction = postAction
|
||||
?? ((d, obj) => d(obj));
|
||||
|
||||
ConnectorFactory = connectorFactory
|
||||
?? throw new ArgumentException("Can not instantiate TinkApp- object. No connector factory object available.");
|
||||
|
||||
Cipher = cipher ?? new Cipher();
|
||||
|
||||
var locksServices = locksService != null
|
||||
? new HashSet<ILocksService> { locksService }
|
||||
: new HashSet<ILocksService> {
|
||||
new LockItByScanServiceEventBased(Cipher),
|
||||
new LockItByScanServicePolling(Cipher),
|
||||
new LockItByGuidService(Cipher),
|
||||
#if BLUETOOTHLE // Requires LockItBluetoothle library.
|
||||
new Bluetoothle.LockItByGuidService(Cipher),
|
||||
#endif
|
||||
#if ARENDI // Requires LockItArendi library.
|
||||
new Arendi.LockItByGuidService(Cipher, arendiCentral),
|
||||
new Arendi.LockItByScanService(Cipher, arendiCentral),
|
||||
#endif
|
||||
new LocksServiceInReach(),
|
||||
new LocksServiceOutOfReach(),
|
||||
};
|
||||
|
||||
LocksServices = new LocksServicesContainerMutable(
|
||||
lastVersion >= new Version(3, 0, 173) ? settings.ActiveLockService : LocksServicesContainerMutable.DefaultLocksservice,
|
||||
locksServices);
|
||||
|
||||
LocksServices.SetTimeOut(settings.ConnectTimeout);
|
||||
|
||||
Themes = new ServicesContainerMutable<object>(
|
||||
new HashSet<object> { new Themes.Konrad() , new Themes.ShareeBike() },
|
||||
settings.ActiveTheme);
|
||||
|
||||
GeolocationServices = new ServicesContainerMutable<IGeolocation>(
|
||||
geolocationService == null
|
||||
? new HashSet<IGeolocation> { new LastKnownGeolocationService(geolodationServiceDependent), new SimulatedGeolocationService(geolodationServiceDependent), new GeolocationService(geolodationServiceDependent) }
|
||||
: new HashSet<IGeolocation> { geolocationService },
|
||||
geolocationService == null
|
||||
? (lastVersion >= new Version(3, 0, 173) ? settings.ActiveGeolocationService : typeof(LastKnownGeolocationService).FullName)
|
||||
: geolocationService.GetType().FullName);
|
||||
|
||||
// Load filters from settings or apply defaults if no settings are available
|
||||
var l_oAccount = accountStore.Load();
|
||||
|
||||
if (settings.ActiveUri == new Uri(CopriServerUriList.TINK_LIVE) ||
|
||||
settings.ActiveUri == new Uri(CopriServerUriList.TINK_DEVEL))
|
||||
{
|
||||
FilterGroupSetting = settings.GroupFilterSettings;
|
||||
GroupFilterMapPage = settings.GroupFilterMapPage;
|
||||
//} else if (settings.ActiveUri == new Uri(CopriServerUriList.SHAREE_LIVE) ||
|
||||
// settings.ActiveUri == new Uri(CopriServerUriList.SHAREE_DEVEL))
|
||||
//{
|
||||
// FilterGroupSetting = new GroupFilterSettings(new Dictionary<string, FilterState> { { "300001", FilterState.On }, { "300029", FilterState.On } });
|
||||
// FilterGroupMapPage = new GroupFilterMapPage();
|
||||
} else
|
||||
{
|
||||
FilterGroupSetting = new GroupFilterSettings();
|
||||
GroupFilterMapPage = new GroupFilterMapPage();
|
||||
}
|
||||
|
||||
CenterMapToCurrentLocation = settings.CenterMapToCurrentLocation;
|
||||
|
||||
Device = device
|
||||
?? throw new ArgumentException("Can not instantiate TinkApp- object. No device information provider available.");
|
||||
|
||||
if (specialFolder == null)
|
||||
{
|
||||
throw new ArgumentException("Can not instantiate TinkApp- object. No special folder provider available.");
|
||||
}
|
||||
|
||||
// Set logging level.
|
||||
Level.MinimumLevel = settings.MinimumLogEventLevel;
|
||||
|
||||
LogToExternalFolder = settings.LogToExternalFolder;
|
||||
|
||||
IsSiteCachingOn = settings.IsSiteCachingOn;
|
||||
|
||||
ExternalFolder = specialFolder.GetExternalFilesDir();
|
||||
|
||||
SettingsFileFolder = specialFolder.GetInternalPersonalDir();
|
||||
|
||||
SelectedStation = null;
|
||||
|
||||
ActiveUser = new User.User(
|
||||
accountStore,
|
||||
l_oAccount,
|
||||
device.GetIdentifier());
|
||||
|
||||
this.isConnectedFunc = isConnectedFunc ?? (() => CrossConnectivity.Current.IsConnected);
|
||||
|
||||
ExpiresAfter = settings.ExpiresAfter;
|
||||
|
||||
// Create filtered connector for offline mode.
|
||||
m_oConnector = FilteredConnectorFactory.Create(
|
||||
FilterGroupSetting.DoFilter(l_oAccount.DoFilter(GroupFilterMapPage.DoFilter())),
|
||||
ConnectorFactory(GetIsConnected(), settings.ActiveUri, ActiveUser.SessionCookie, ActiveUser.Mail, ExpiresAfter));
|
||||
|
||||
// Get uris from file.
|
||||
// Initialize all settings to defaults
|
||||
// Process uris.
|
||||
Uris = new CopriServerUriList(settings.ActiveUri);
|
||||
|
||||
NextActiveUri = Uris.ActiveUri;
|
||||
|
||||
Polling = settings.PollingParameters ??
|
||||
throw new ArgumentException("Can not instantiate TinkApp- object. Polling parameters must never be null.");
|
||||
|
||||
AppVersion = currentVersion ?? new Version(3, 0, 122);
|
||||
|
||||
MinimumLogEventLevel = settings.MinimumLogEventLevel;
|
||||
|
||||
Permissions = permissions ??
|
||||
throw new ArgumentException("Can not instantiate TinkApp- object. Permissions object must never be null.");
|
||||
|
||||
WhatsNew = new WhatsNew(AppVersion, lastVersion, whatsNewShownInVersion);
|
||||
|
||||
if (Themes.Active.GetType().FullName == typeof(Themes.ShareeBike).FullName)
|
||||
return;
|
||||
|
||||
// Set active app theme
|
||||
ICollection<ResourceDictionary> mergedDictionaries = Application.Current.Resources.MergedDictionaries;
|
||||
if (mergedDictionaries == null)
|
||||
{
|
||||
Log.ForContext<TinkApp>().Error("No merged dictionary available.");
|
||||
return;
|
||||
}
|
||||
|
||||
mergedDictionaries.Clear();
|
||||
|
||||
if (Themes.Active.GetType().FullName == typeof(Themes.Konrad).FullName)
|
||||
{
|
||||
mergedDictionaries.Add(new Themes.Konrad());
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<TinkApp>().Debug($"No theme {Themes.Active} found.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Holds the user of the app. </summary>
|
||||
[DataMember]
|
||||
public User.User ActiveUser { get; }
|
||||
|
||||
/// <summary> Reference of object which provides device information. </summary>
|
||||
public IDevice Device { get; }
|
||||
|
||||
/// <summary> Os permission.</summary>
|
||||
public IPermissions Permissions { get; }
|
||||
|
||||
/// <summary> Holds delegate to determine whether device is connected or not.</summary>
|
||||
private Func<bool> isConnectedFunc;
|
||||
|
||||
/// <summary> Gets whether device is connected to internet or not. </summary>
|
||||
public bool GetIsConnected() => isConnectedFunc();
|
||||
|
||||
/// <summary> Holds the folder where settings files are stored. </summary>
|
||||
public string SettingsFileFolder { get; }
|
||||
|
||||
/// <summary> Holds folder parent of the folder where log files are stored. </summary>
|
||||
public string LogFileParentFolder => LogToExternalFolder && !string.IsNullOrEmpty(ExternalFolder) ? ExternalFolder : SettingsFileFolder;
|
||||
|
||||
/// <summary> Holds a value indicating whether to log to external or internal folder. </summary>
|
||||
public bool LogToExternalFolder { get; set; }
|
||||
|
||||
/// <summary> Holds a value indicating whether Site caching is on or off. </summary>
|
||||
public bool IsSiteCachingOn { get; set; }
|
||||
|
||||
/// <summary> External folder. </summary>
|
||||
public string ExternalFolder { get; }
|
||||
|
||||
public ICipher Cipher { get; }
|
||||
|
||||
/// <summary> Name of the station which is selected. </summary>
|
||||
public int? SelectedStation { get; set; }
|
||||
|
||||
/// <summary> Action to post to GUI thread.</summary>
|
||||
public Action<SendOrPostCallback, object> PostAction { get; }
|
||||
|
||||
/// <summary> Function which creates a connector depending on connected status.</summary>
|
||||
private Func<bool, Uri, string, string, TimeSpan, IConnector> ConnectorFactory { get; }
|
||||
|
||||
/// <summary> Holds the object which provides offline data.</summary>
|
||||
private IFilteredConnector m_oConnector;
|
||||
|
||||
/// <summary> Holds the system to copri.</summary>
|
||||
public IFilteredConnector GetConnector(bool isConnected)
|
||||
{
|
||||
if (m_oConnector.IsConnected == isConnected
|
||||
&& m_oConnector.Command.SessionCookie == ActiveUser.SessionCookie)
|
||||
{
|
||||
// Neither connection nor logged in stated changed.
|
||||
return m_oConnector;
|
||||
}
|
||||
|
||||
// Connected state changed. New connection object has to be created.
|
||||
m_oConnector = FilteredConnectorFactory.Create(
|
||||
FilterGroupSetting.DoFilter(ActiveUser.DoFilter(GroupFilterMapPage.DoFilter())),
|
||||
ConnectorFactory(
|
||||
isConnected,
|
||||
Uris.ActiveUri,
|
||||
ActiveUser.SessionCookie,
|
||||
ActiveUser.Mail,
|
||||
ExpiresAfter));
|
||||
|
||||
return m_oConnector;
|
||||
}
|
||||
|
||||
/// <summary> Query geolocation. </summary>
|
||||
public IGeolocation Geolocation => GeolocationServices.Active;
|
||||
|
||||
/// <summary> Manages the different types of LocksService objects.</summary>
|
||||
public LocksServicesContainerMutable LocksServices { get; set; }
|
||||
|
||||
/// <summary> Holds available app themes.</summary>
|
||||
public ServicesContainerMutable<IGeolocation> GeolocationServices { get; }
|
||||
|
||||
/// <summary> Manages the different types of LocksService objects.</summary>
|
||||
public ServicesContainerMutable<object> Themes { get; }
|
||||
|
||||
/// <summary> Object to switch logging level. </summary>
|
||||
private LoggingLevelSwitch m_oLoggingLevelSwitch;
|
||||
|
||||
/// <summary>
|
||||
/// Object to allow swithing logging level
|
||||
/// </summary>
|
||||
public LoggingLevelSwitch Level
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_oLoggingLevelSwitch == null)
|
||||
{
|
||||
m_oLoggingLevelSwitch = new LoggingLevelSwitch
|
||||
{
|
||||
|
||||
// Set warning level to error.
|
||||
MinimumLevel = Settings.Settings.DEFAULTLOGGINLEVEL
|
||||
};
|
||||
}
|
||||
|
||||
return m_oLoggingLevelSwitch;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Updates logging level. </summary>
|
||||
/// <param name="p_oNewLevel">New level to set.</param>
|
||||
public void UpdateLoggingLevel(LogEventLevel p_oNewLevel)
|
||||
{
|
||||
if (Level.MinimumLevel == p_oNewLevel)
|
||||
{
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
Log.CloseAndFlush(); // Close before modifying logger configuration. Otherwise a sharing vialation occurs.
|
||||
|
||||
Level.MinimumLevel = p_oNewLevel;
|
||||
|
||||
// Update logging
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.MinimumLevel.ControlledBy(Level)
|
||||
.WriteTo.Debug()
|
||||
.WriteTo.File(LogFileParentFolder, Logging.RollingInterval.Session)
|
||||
.CreateLogger();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue