sharee.bike-App/TINKLib/ViewModel/ViewModelHelper.cs
2022-04-10 17:38:34 +02:00

303 lines
12 KiB
C#

using MonkeyCache.FileStore;
using Serilog;
using System;
using System.Threading.Tasks;
using TINK.Repository.Exception;
using TINK.Model.Device;
using TINK.Model.State;
using TINK.Model.Station;
using TINK.Model.User;
using Xamarin.Forms;
using TINK.Model.Bikes.Bike.BC;
using TINK.Repository;
using System.Net;
using TINK.MultilingualResources;
using System.Linq;
namespace TINK.ViewModel
{
public static class ViewModelHelper
{
/// <summary> First part of text making up a station name.</summary>
private const string USER_FIENDLY_STATIONNUMBER_PREFIX = "Station";
/// <summary>Holds the color which marks link to TINK- app pages, web sites, ...</summary>
public static Color LINK_COLOR = Color.Blue;
/// <summary>
/// Gets station name from station object.
/// </summary>
/// <param name="station">Station to get id from</param>
/// <returns></returns>
public static string GetStationName(this IStation station)
{
if (station == null)
{
return string.Empty;
}
if (!string.IsNullOrEmpty(station.StationName))
{
return $"{station.StationName}, Nr. {station.Id}.";
}
return GetStationName(station.Id);
}
/// <summary>
/// Gets station name from station object.
/// </summary>
/// <param name="p_oStation">Station to get id from</param>
/// <returns></returns>
public static string GetStationName(string station)
{
return string.Format("{0} {1}", USER_FIENDLY_STATIONNUMBER_PREFIX, station);
}
/// <summary>
/// Gets station id from station name.
/// </summary>
/// <param name="p_oStation">Station to get id from</param>
/// <returns></returns>
public static int GetStationId(string stationName)
{
return int.Parse(stationName.Replace(USER_FIENDLY_STATIONNUMBER_PREFIX, "").Trim());
}
/// <summary> Get full display name of a bike which includes id. </summary>
/// <remarks>
/// If name is empty return Id as name.
/// </remarks>
/// <param name="bike">bike to get name for.</param>
/// <returns>Display name of bike.</returns>
public static string GetFullDisplayName(this IBikeInfoMutable bike)
=> $"{(!string.IsNullOrEmpty(bike.Description) ? $"{bike.Description}, " : string.Empty)}Nr. {bike.Id}";
/// <summary> Get the display name of a bike. </summary>
/// <param name="bike">bike to get name for.</param>
/// <returns>Display name of bike.</returns>
public static string GetDisplayName(this IBikeInfoMutable bike)
=> $"{(!string.IsNullOrEmpty(bike.Description) ? $"{bike.Description}" : $"{bike.Id}")}";
/// <summary> Get the display id of a bike.</summary>
/// <remarks>
/// If name is empty id is used as name. For this reason return nothing in this case to avoid duplicate output of id.
/// </remarks>
/// <param name="bike">bike to get name for.</param>
/// <returns>Display name of bike.</returns>
public static string GetDisplayId(this IBikeInfoMutable bike)
=> $"{(!string.IsNullOrEmpty(bike.Description) ? $"{bike.Id}" : string.Empty)}";
/// <summary>
/// Maps state to color.
/// </summary>
/// <param name="state"></param>
/// <returns></returns>
public static Color GetColor(this InUseStateEnum state)
{
switch (state)
{
case InUseStateEnum.Disposable:
return Color.Default;
case InUseStateEnum.Reserved:
return Color.Orange;
case InUseStateEnum.Booked:
return Color.Green;
default:
return Color.Default;
}
}
/// <summary> Gets message that logged in user has not booked any bikes. </summary>
/// <param name="isReportLevelVerbose">Holds whether report level is verbose or not.</param>
public static string GetShortErrorInfoText(this Exception exception, bool isReportLevelVerbose)
{
if (exception == null)
{
return string.Empty;
}
if (exception is AuthcookieNotDefinedException)
return AppResources.ActivityTextAuthcookieNotDefinedException;
if (!isReportLevelVerbose)
{
return AppResources.ActivityTextException;
}
// An error occurred getting bikes information.
#if USCSHARP9
switch (exception)
{
case WebConnectFailureException:
return AppResources.ActivityTextErrorWebConnectFailureException;
case InvalidResponseException:
return AppResources.ActivityTextErrorInvalidResponseException;
case WebForbiddenException:
return AppResources.ActivityTextErrorWebForbiddenException;
case DeserializationException:
return AppResources.ActivityTextErrorDeserializationException;
case WebException webException:
return webException.Status == WebExceptionStatus.ProtocolError && webException.Response is HttpWebResponse webResponse
? string.Format(AppResources.ActivityTextErrorWebExceptionProtocolError, webResponse.StatusDescription)
: string.Format(AppResources.ActivityTextErrorWebExceptionGeneralError, webException.Status.ToString());
default:
return AppResources.ActivityTextErrorException;
}
#else
if (exception is WebConnectFailureException)
return AppResources.ActivityTextErrorWebConnectFailureException;
if (exception is InvalidResponseException)
return AppResources.ActivityTextErrorInvalidResponseException;
if (exception is WebForbiddenException)
return AppResources.ActivityTextErrorWebForbiddenException;
if (exception is DeserializationException)
return AppResources.ActivityTextErrorDeserializationException;
if (exception is WebException webException)
{
return webException.Status == WebExceptionStatus.ProtocolError && webException.Response is HttpWebResponse webResponse
? string.Format(AppResources.ActivityTextErrorWebExceptionProtocolError, webResponse.StatusDescription)
: string.Format(AppResources.ActivityTextErrorWebExceptionGeneralError, webException.Status.ToString());
}
return AppResources.ActivityTextErrorException;
#endif
}
/// <summary> Gets error message and handles aggegate exceptions. </summary>
public static string GetErrorMessage(this Exception exception)
{
if (exception == null)
return string.Empty;
if (!(exception is AggregateException aggregateException))
return exception.Message;
if (aggregateException.InnerExceptions.Count == 1)
return aggregateException.InnerExceptions[0].Message;
return new AggregateException().Message + "\r\n"+ string.Join("\r\n", aggregateException.InnerExceptions.Select(x => x.Message));
}
/// <summary> Gets message that logged in user has not booked any bikes. </summary>
public static FormattedString GetErrorInfoText(this Exception exception)
{
if (exception == null)
{
return string.Empty;
}
FormattedString l_oError;
// An error occurred getting bikes information.
if (exception is WebConnectFailureException)
{
l_oError = new FormattedString();
l_oError.Spans.Add(new Span { Text = "Information!\r\n", FontAttributes = FontAttributes.Bold });
l_oError.Spans.Add(new Span { Text = $"{exception.Message}\r\n{WebConnectFailureException.GetHintToPossibleExceptionsReasons}" });
return l_oError;
}
else if (exception is InvalidResponseException)
{
l_oError = new FormattedString();
l_oError.Spans.Add(new Span { Text = "Fehler, ungültige Serverantwort!\r\n", FontAttributes = FontAttributes.Bold });
l_oError.Spans.Add(new Span { Text = $"{exception.Message}" });
return l_oError;
}
else if (exception is WebForbiddenException)
{
l_oError = new FormattedString();
l_oError.Spans.Add(new Span { Text = "Beschäftigt... Einen Moment bitte!" });
return l_oError;
}
l_oError = new FormattedString();
l_oError.Spans.Add(new Span { Text = "Allgemeiner Fehler!\r\n", FontAttributes = FontAttributes.Bold });
l_oError.Spans.Add(new Span { Text = $"{exception}" });
return l_oError;
}
/// <summary> User tabbed a URI. </summary>
/// <param name="sender">Sender of the event.</param>
/// <param name="eventArgs">Event arguments</param>
public static void OnNavigating(object sender, WebNavigatingEventArgs eventArgs)
{
if (!eventArgs.Url.ToUpper().StartsWith("HTTP"))
{
// An internal link was detected.
// Stay inside WebView
eventArgs.Cancel = false;
return;
}
// Do not navigate outside the document.
eventArgs.Cancel = true;
DependencyService.Get<IExternalBrowserService>().OpenUrl(eventArgs.Url);
}
/// <summary> Gets the user group if a user friendly name.</summary>
/// <param name="user"></param>
/// <returns></returns>
public static string GetUserGroupDisplayName(this User user)
{
return string.Join(" & ", user.Group);
}
/// <summary> Called when page is shown. </summary>
/// <param name="resourceUrl">Url to load data from.</param>
/// <param name="isSiteCachingOn">Holds value wether site caching is on or off.</param>
/// <param name="resourceProvider"> Provides resource from embedded ressources.</param>
public static async Task<string> GetSource(
string resourceUrl,
bool isSiteCachingOn,
Func<string> resourceProvider = null)
{
if (!Barrel.Current.IsExpired(resourceUrl) && isSiteCachingOn)
{
// Cached html is still valid and caching is on.
return Barrel.Current.Get<string>(resourceUrl);
}
string htmlContent = string.Empty;
try
{
// Get info from web server.
htmlContent = await CopriCallsHttps.Get(resourceUrl);
}
catch (Exception l_oException)
{
// Getting html failed.
Log.Error($"Requesting {resourceUrl} failed. {l_oException.Message}");
}
switch (string.IsNullOrEmpty(htmlContent))
{
case true:
// An error occurred getting resource from web
htmlContent = Barrel.Current.Exists(resourceUrl)
? Barrel.Current.Get<string>(key: resourceUrl) // Get from MonkeyCache
: resourceProvider != null ? resourceProvider() : $"<DOCTYPE html>Error loading {resourceUrl}."; // Get build in ressource.
break;
default:
// Add resource to cache.
Barrel.Current.Add(key: resourceUrl, data: htmlContent, expireIn: isSiteCachingOn ? TimeSpan.FromDays(1) : TimeSpan.FromMilliseconds(1) );
break;
}
return htmlContent ?? FromBody("An error occurred loading html- ressource.");
}
public static string FromBody(string message) => $"<!DOCTYPE html><html lang=\"de\"><head><title>Error Information</title></head><body>{message}</body></html>";
}
}