Merge branch 'master' into US-166/location-permission

# Conflicts:
#	TINK/TINK/View/Map/MapPage.xaml.cs
#	TINKLib/ViewModel/Map/MapPageViewModel.cs
#	TestFramework/Services/Permissions/PermissionsMock.cs
#	TestTINKLib/TestTINKLib.csproj
This commit is contained in:
Tobias Reski 2021-11-15 10:06:55 +01:00
commit 30c4e4879b
80 changed files with 2737 additions and 481 deletions

View file

@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Linq;
namespace TINK.Model.Connector.Filter
{

View file

@ -14,6 +14,6 @@
/// Was "TINK" up to version 3.0.258.
/// Specified first: "KN300029" (RG).
/// </remarks>
public const string FILTERTINKGENERAL = "300102";
public const string FILTERTINKGENERAL = "300103";
}
}

View file

@ -60,6 +60,9 @@ namespace TINK.Model
/// <summary> Value indicating whether map is centerted to current position or not. </summary>
bool CenterMapToCurrentLocation { get; set; }
/// <summary> Holds the map area to display. </summary>
Xamarin.Forms.GoogleMaps.MapSpan MapSpan { get; set; }
bool LogToExternalFolder { get; set; }
bool IsSiteCachingOn { get; set; }

View file

@ -22,7 +22,7 @@ namespace TINK.ViewModel.Settings
private IGroupFilter Filter { get; }
/// <summary> Performs filtering on response-group. </summary>
/// <summary> Performs filtering on response -group. </summary>
public IEnumerable<string> DoFilter(IEnumerable<string> filter = null) => Filter.DoFilter(filter);
public FilterState this[string key] { get => FilterDictionary[key]; set => FilterDictionary[key] = value; }

View file

@ -495,11 +495,15 @@ namespace TINK.Model.Settings
// Process legacy entries.
var updatedFilterCollection = legacyFilterCollection.Where(x => x.Key.ToUpper() != "TINK.SMS" && x.Key.ToUpper() != "TINK.COPRI").ToDictionary(x => x.Key, x => x.Value);
if (legacyFilterCollection.Count() <= updatedFilterCollection.Count())
{
// No legacy entries "INK.SMS" or "TINK.COPRI" found.
return legacyFilterCollection;
}
var list = updatedFilterCollection.ToList();
updatedFilterCollection.Add(
FilterHelper.FILTERTINKGENERAL,
"TINK",
legacyFilterCollection.Any(x => x.Key.ToUpper() == "TINK.COPRI") ? legacyFilterCollection.FirstOrDefault(x => x.Key.ToUpper() == "TINK.COPRI").Value : FilterState.Off);
return new GroupFilterSettings(updatedFilterCollection);

View file

@ -46,6 +46,7 @@ namespace TINK.Model.Settings
TimeSpan? connectTimeout = null,
string activeGeolocationService = null,
bool? centerMapToCurrentLocation = null,
Xamarin.Forms.GoogleMaps.MapSpan mapSpan = null,
bool? logToExternalFolder = null,
bool? isSiteCachingOn = null,
string activeTheme = null)
@ -61,6 +62,7 @@ namespace TINK.Model.Settings
ConnectTimeout = connectTimeout ?? new TimeSpan(0, 0, TimeOutProvider.DEFAULT_BLUETOOTHCONNECT_TIMEOUTSECONDS); // Try one sec. to connect.
ActiveGeolocationService = activeGeolocationService ?? DefaultLocationService.Name;
CenterMapToCurrentLocation = centerMapToCurrentLocation ?? GetCenterMapToCurrentLocation(activeUri);
MapSpan = mapSpan;
LogToExternalFolder = logToExternalFolder ?? false;
IsSiteCachingOn = isSiteCachingOn ?? true;
ActiveTheme = activeTheme ?? typeof(Themes.ShareeBike).FullName;
@ -93,8 +95,12 @@ namespace TINK.Model.Settings
/// <summary> Gets the geolocation service to use.</summary>
public string ActiveGeolocationService { get; }
/// <summary> True if map is centered to current positon, false if not to center map.</summary>
public bool CenterMapToCurrentLocation { get; }
/// <summary> Holds the map area to display. </summary>
public Xamarin.Forms.GoogleMaps.MapSpan MapSpan { get; }
public bool LogToExternalFolder { get; }
public bool IsSiteCachingOn { get; }

View file

@ -64,6 +64,9 @@ namespace TINK.Model
/// <summary> Value indicating whether map is centerted to current position or not. </summary>
public bool CenterMapToCurrentLocation { get; set; }
/// <summary> Holds the map area to display. </summary>
public Xamarin.Forms.GoogleMaps.MapSpan MapSpan { get; set; }
/// <summary> Gets the minimum logging level. </summary>
public LogEventLevel MinimumLogEventLevel { get; set; }
@ -206,6 +209,8 @@ namespace TINK.Model
CenterMapToCurrentLocation = settings.CenterMapToCurrentLocation;
MapSpan = settings.MapSpan;
SmartDevice = device
?? throw new ArgumentException("Can not instantiate TinkApp- object. No device information provider available.");

View file

@ -3,6 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TINK.Themes.Konrad">
<!-- Pallete -->
<!-- Red #ff0000 -->
<Color x:Key="primary-back-title-color">Red</Color>
<!-- Pallete-end -->
<Style ApplyToDerivedTypes="true" TargetType="NavigationPage">

View file

@ -158,9 +158,7 @@ namespace TINK.ViewModel.Account
return AppResources.MarkingLoggedInStateInfoNotLoggedIn;
}
return TinkApp.ActiveUser.Group.Intersect(new List<string> { FilterHelper.FILTERTINKGENERAL, FilterHelper.FILTERKONRAD }).Any()
? string.Format(AppResources.MarkingLoggedInStateInfoLoggedInGroup, TinkApp.ActiveUser.Mail, TinkApp.ActiveUser.GetUserGroupDisplayName())
: string.Format(AppResources.MarkingLoggedInStateInfoLoggedIn, TinkApp.ActiveUser.Mail);
return string.Format(AppResources.MarkingLoggedInStateInfoLoggedIn, TinkApp.ActiveUser.Mail);
}
}

View file

@ -23,7 +23,6 @@ using Xamarin.Essentials;
using System.Threading;
using TINK.MultilingualResources;
using TINK.Services.BluetoothLock;
using TINK.Model.Services.CopriApi.ServerUris;
using TINK.ViewModel.Info;
using TINK.Repository;
using TINK.Model.Services.Geolocation;
@ -208,7 +207,7 @@ namespace TINK.ViewModel.Map
var l_oPin = new Pin
{
Position = new Xamarin.Forms.GoogleMaps.Position(station.Position.Latitude, station.Position.Longitude),
Label = long.TryParse(station.Id, out long stationId) && stationId > CUSTOM_ICONS_COUNT
? station.GetStationName()
@ -232,13 +231,13 @@ namespace TINK.ViewModel.Map
for (int pinIndex = 0; pinIndex < stationsColorList.Count; pinIndex++)
{
var indexPartPrefix = int.TryParse(Pins[pinIndex].Tag.ToString(), out int stationId)
var indexPartPrefix = int.TryParse(Pins[pinIndex].Tag.ToString(), out int stationId)
&& stationId <= CUSTOM_ICONS_COUNT
? $"{stationId}" // there is a station marker with index letter for given station id
: "Open"; // there is no station marker. Use open marker.
var colorPartPrefix = GetRessourceNameColorPart(stationsColorList[pinIndex]);
var l_iName = $"{indexPartPrefix.ToString().PadLeft(2, '0')}_{colorPartPrefix}{(DeviceInfo.Platform == DevicePlatform.Android ? ".png" : string.Empty)}";
try
{
@ -293,7 +292,7 @@ namespace TINK.ViewModel.Map
}
/// <summary>
/// Invoked when page is shown.
/// Invoked when page is shown.
/// Starts update process.
/// </summary>
/// <param name="p_oFilterDictionaryMapPage">Holds map page filter settings.</param>
@ -308,10 +307,10 @@ namespace TINK.ViewModel.Map
Polling = TinkApp.Polling;
Log.ForContext<MapPageViewModel>().Information(
$"{(Polling != null && Polling.IsActivated ? $"Map page is appearing. Update periode is {Polling.Periode.TotalSeconds} sec." : "Map page is appearing. Polling is off.")}" +
$"{(Polling != null && Polling.IsActivated ? $"Map page is appearing. Update periode is {Polling.Periode.TotalSeconds} sec." : "Map page is appearing. Polling is off.")}" +
$"Current UI language is {Thread.CurrentThread.CurrentUICulture.Name}.");
// Update map page filter
// Update map page filter
ActiveFilterMap = TinkApp.GroupFilterMapPage;
ActionText = AppResources.ActivityTextRequestingLocationPermissions;
@ -325,7 +324,7 @@ namespace TINK.ViewModel.Map
await SetStationsOnMap(resultStationsAndBikes.Response.StationsAll);
await HandleAuthCookieNotDefinedException(resultStationsAndBikes.Exception);
// Update pin colors.
Log.ForContext<MapPageViewModel>().Verbose("Starting update pins color...");
@ -378,7 +377,7 @@ namespace TINK.ViewModel.Map
/// <summary>
/// Invoked when the auth cookie is not defined.
/// Invoked when the auth cookie is not defined.
/// </summary>
private async Task HandleAuthCookieNotDefinedException(Exception exception)
{
@ -410,7 +409,7 @@ namespace TINK.ViewModel.Map
Pins.Clear();
}
// Check if there are alreay any pins to the map
// Check if there are alreay any pins to the map
// i.e detecte first call of member OnAppearing after construction
if (Pins.Count <= 0)
{
@ -439,8 +438,8 @@ namespace TINK.ViewModel.Map
Log.ForContext<MapPageViewModel>().Error($"Outdated version of app detected. Version expected is {stations.CopriVersion}.");
}
// Set pins to their positions on map.
InitializePins(stations);
// Set pins to their positions on map.
InitializePins(resultStationsAndBikes.Response.StationsAll);
Log.ForContext<MapPageViewModel>().Verbose("Update of pins done.");
}
@ -457,20 +456,27 @@ namespace TINK.ViewModel.Map
Status status = await RequestLocationPermission();
if (status == Status.Granted)
{
Location currentLocation = null;
try
ActionText = AppResources.ActivityTextCenterMap;
if (TinkApp.CenterMapToCurrentLocation)
{
currentLocation = TinkApp.CenterMapToCurrentLocation
? await GeolocationService.GetAsync()
: null;
}
catch (Exception ex)
{
Log.ForContext<MapPageViewModel>().Error("Getting location failed. {Exception}", ex);
}
Location currentLocation = null;
try
{
currentLocation = await GeolocationService.GetAsync();
}
catch (Exception ex)
{
Log.ForContext<MapPageViewModel>().Error("Getting location failed. {Exception}", ex);
}
MoveAndScale(m_oMoveToRegionDelegate, TinkApp.Uris.ActiveUri, ActiveFilterMap, currentLocation);
};
TinkApp.MapSpan = MapSpan.FromCenterAndRadius(
new Xamarin.Forms.GoogleMaps.Position(currentLocation.Latitude, currentLocation.Longitude),
TinkApp.MapSpan.Radius);
TinkApp.Save();
}
MoveAndScale(m_oMoveToRegionDelegate, TinkApp.MapSpan);
}
}
/// <summary>
@ -512,44 +518,14 @@ namespace TINK.ViewModel.Map
/// <summary> Moves map and scales visible region depending on active filter. </summary>
public static void MoveAndScale(
Action<MapSpan> moveToRegionDelegate,
Uri activeUri,
IGroupFilterMapPage groupFilterMapPage,
Location currentLocation = null)
MapSpan currentMapSpan = null)
{
if (currentLocation != null)
if (currentMapSpan != null)
{
// Move to current location.
moveToRegionDelegate(MapSpan.FromCenterAndRadius(
new Xamarin.Forms.GoogleMaps.Position(currentLocation.Latitude, currentLocation.Longitude),
Distance.FromKilometers(1.0)));
moveToRegionDelegate(currentMapSpan);
return;
}
if (activeUri.AbsoluteUri == CopriServerUriList.SHAREE_LIVE ||
activeUri.AbsoluteUri == CopriServerUriList.SHAREE_DEVEL)
{
// Center map to Freiburg
moveToRegionDelegate(MapSpan.FromCenterAndRadius(
new Xamarin.Forms.GoogleMaps.Position(47.995865, 7.815086),
Distance.FromKilometers(2.9)));
return;
}
// Depending on whether TINK or Conrad is active set center of map and scale.
if (groupFilterMapPage.GetGroup().Contains(FilterHelper.FILTERKONRAD))
{
// Konrad is activated,
moveToRegionDelegate(MapSpan.FromCenterAndRadius(
new Xamarin.Forms.GoogleMaps.Position(47.680, 9.180),
Distance.FromKilometers(2.9)));
}
else
{
// TINK
moveToRegionDelegate(MapSpan.FromCenterAndRadius(
new Xamarin.Forms.GoogleMaps.Position(47.667, 9.172),
Distance.FromKilometers(0.9)));
}
}
/// <summary> Creates a update task object. </summary>
@ -582,7 +558,7 @@ namespace TINK.ViewModel.Map
Log.ForContext<MapPageViewModel>().Error("Getting bikes and stations in polling context failed with exception {Exception}.", exception);
}
// Check if there are alreay any pins to the map.
// Check if there are alreay any pins to the map.
// If no initialze pins.
if (Pins.Count <= 0)
{
@ -627,7 +603,7 @@ namespace TINK.ViewModel.Map
}
/// <summary>
/// Invoked when pages is closed/ hidden.
/// Invoked when pages is closed/ hidden.
/// Stops update process.
/// </summary>
public async Task OnDisappearing()
@ -648,7 +624,7 @@ namespace TINK.ViewModel.Map
// Lock action to prevent multiple instances of "BikeAtStation" being opened.
IsMapPageEnabled = false;
TinkApp.SelectedStation = TinkApp.Stations.FirstOrDefault(x => x.Id == selectedStationId)
TinkApp.SelectedStation = TinkApp.Stations.FirstOrDefault(x => x.Id == selectedStationId)
?? new Station(selectedStationId, new List<string>(), null); // Station might not be in list StationDictinaly because this list is not updatd in background task.
#if TRYNOTBACKSTYLE
@ -904,7 +880,7 @@ namespace TINK.ViewModel.Map
if (permissionResult != Status.Granted)
{
var dialogResult = await ViewService.DisplayAlert(
AppResources.MessageTitleHint,
AppResources.MessageTitleHint,
AppResources.MessageBikesManagementLocationPermission,
"Ja",
"Nein");
@ -919,14 +895,14 @@ namespace TINK.ViewModel.Map
}
}
// Do not use property .State to get bluetooth state due
// to issue https://hausource.visualstudio.com/TINK/_workitems/edit/116 /
// Do not use property .State to get bluetooth state due
// to issue https://hausource.visualstudio.com/TINK/_workitems/edit/116 /
// see https://github.com/xabre/xamarin-bluetooth-le/issues/112#issuecomment-380994887
if (await BluetoothService.GetBluetoothState() != Plugin.BLE.Abstractions.Contracts.BluetoothState.On)
{
await ViewService.DisplayAlert(
AppResources.MessageTitleHint,
AppResources.MessageBikesManagementBluetoothActivation,
AppResources.MessageBikesManagementBluetoothActivation,
AppResources.MessageAnswerOk);
IsMapPageEnabled = true;
ActionText = "";
@ -935,21 +911,27 @@ namespace TINK.ViewModel.Map
}
// Move and scale before getting stations and bikes which takes some time.
Location currentLocation = null;
try
if (TinkApp.CenterMapToCurrentLocation)
{
currentLocation = TinkApp.CenterMapToCurrentLocation
? await GeolocationService.GetAsync()
: null;
}
catch (Exception ex)
{
Log.ForContext<MapPageViewModel>().Error("Getting location failed. {Exception}", ex);
Location currentLocation = null;
try
{
currentLocation = await GeolocationService.GetAsync();
}
catch (Exception ex)
{
Log.ForContext<MapPageViewModel>().Error("Getting location failed. {Exception}", ex);
}
TinkApp.MapSpan = MapSpan.FromCenterAndRadius(
new Xamarin.Forms.GoogleMaps.Position(currentLocation.Latitude, currentLocation.Longitude),
TinkApp.MapSpan.Radius);
TinkApp.Save();
}
// Update stations
// Depending on whether TINK or Conrad is active set center of map and scale.
MoveAndScale(m_oMoveToRegionDelegate, TinkApp.Uris.ActiveUri, ActiveFilterMap, currentLocation);
MoveAndScale(m_oMoveToRegionDelegate, TinkApp.MapSpan);
IsConnected = TinkApp.GetIsConnected();
var resultStationsAndBikes = await TinkApp.GetConnector(IsConnected).Query.GetBikesAndStationsAsync();
@ -998,4 +980,4 @@ namespace TINK.ViewModel.Map
public bool IsToggleVisible => tinkKonradToggleViewModel.IsToggleVisible;
}
}
}