using System; using System.ComponentModel; using System.Threading.Tasks; using Serilog; using TINK.Model; using TINK.Model.Device; using TINK.Model.Services.CopriApi; using Xamarin.Essentials; using Xamarin.Forms; using TINK.Model.Connector; using TINK.ViewModel.Contact; namespace TINK.ViewModel.LegalInformation { /// Manges the tabbed info page. public class LegalInformationPageViewModel : INotifyPropertyChanged { /// Fired whenever a property changed. public event PropertyChangedEventHandler PropertyChanged; /// Holds the name of the host. private string HostName { get; } /// Holds value whether site caching is on or off. bool IsSiteCachingOn { get; } /// /// Relative path to agb resources of empty if value was not yet querried from backend. /// private string GtcResourcePath { get; set; } /// /// Relative path to privacy resources of empty if value was not yet querried from backend. /// private string PrivacyResourcePath { get; set; } /// /// Relative path to impress resources of empty if value was not yet querried from backend. /// private string ImpressResourcePath { get; set; } private bool _IsIdle = false; /// /// Is true if no action is pending, false otherwise. /// public bool IsIdle { get => _IsIdle; private set { if (_IsIdle == value) { // Nothing to do. return; } _IsIdle = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsIdle))); return; } } /// /// Object to query resources urls object from backend if required. /// This object is used to update resources path values , and from. /// private Func QueryProvider { get; } /// /// Action to update shared resources urls object exposed by main model. /// private Action UpdateUrlsAction { get; } /// Constructs Info view model /// Name of the host to get html resources from. /// Holds value whether site caching is on or off. /// Agb resource path received from backend. /// PrivacyHtml resource path received from backend. /// ImpressHtml resource path received from backend. /// Delegate to get embedded html resource. Used as fallback if download from web page does not work and cache is empty. /// Object to query resources urls object from backend if required. /// Action to update shared resources urls object public LegalInformationPageViewModel( string hostName, string gtcResourcePath, string privacyResourcePath, string impressResourcePath, bool isSiteCachingOn, Func resourceProvider, Func queryProvider, Action updateUrlsAction) { HostName = hostName; GtcResourcePath = gtcResourcePath; PrivacyResourcePath = privacyResourcePath; ImpressResourcePath = impressResourcePath; IsSiteCachingOn = isSiteCachingOn; QueryProvider = queryProvider; UpdateUrlsAction = updateUrlsAction; GtcHtml = new HtmlWebViewSource { Html = "Loading..." }; ResourceProvider = resourceProvider ?? throw new ArgumentException($"Can not instantiate {typeof(LegalInformationPageViewModel)}-object. No resource provider centered."); } // Get resource urls object from backend. public async Task GetUrls() { Result stations; try { stations = await QueryProvider().GetBikesAndStationsAsync(); } catch (Exception ex) { Log.ForContext().Error($"Getting resource urls from COPRI failed. {ex.Message}"); return new ResourceUrls(); } return stations?.GeneralData?.ResourceUrls ?? new ResourceUrls(); } /// Called when page is shown. public async void OnAppearing() { // Set state to busy. IsIdle = false; // Check if urls to show info from are already known. if (string.IsNullOrEmpty(PrivacyResourcePath)) { var urls = await GetUrls(); PrivacyResourcePath = urls.PrivacyResourcePath; ImpressResourcePath = urls.ImpressResourcePath; GtcResourcePath = urls.GtcResourcePath; UpdateUrlsAction(urls); // Update main model to prevent duplicate queries. } //set font size for html content (necessary for iOS) string headerString = "
"; // Gets privacy info from server. async Task GetPrivacy() { string GetUriText() => $"https://{HostName}/{PrivacyResourcePath}"; if (string.IsNullOrEmpty(PrivacyResourcePath)) { // Information to access resource is missing return new HtmlWebViewSource { Html = headerString + await Task.FromResult(ViewModelHelper.FromBody("No privacy resource available. Resource path is null or empty.")) }; } Log.Debug($"Request to open url {GetUriText()} to get privacy info."); return new HtmlWebViewSource { Html = headerString + await ViewModelHelper.GetSource( GetUriText(), // "site/privacy.html" IsSiteCachingOn) }; } // Gets impress info from server. async Task GetImpress() { string GetUriText() => $"https://{HostName}/{ImpressResourcePath}"; if (string.IsNullOrEmpty(ImpressResourcePath)) { // Information to access resource is missing return new HtmlWebViewSource { Html = headerString + await Task.FromResult(ViewModelHelper.FromBody("No impress resource available. Resource path is null or empty.")) }; } Log.Debug($"Request to open url {GetUriText()} to get impress info."); return new HtmlWebViewSource { Html = headerString + await ViewModelHelper.GetSource( GetUriText(), // "site/privacy.html" IsSiteCachingOn) }; } GtcHtml = await GetGtc(HostName, GtcResourcePath, IsSiteCachingOn); PrivacyHtml = await GetPrivacy(); ImpressHtml = await GetImpress(); // Set state to idle. IsIdle = true; } /// Gets the AGBs /// /// AGBs public static async Task GetGtc( string hostName, string gtcResourcePath, bool isSiteCachingOn) { string GetUriText() => $"https://{hostName}/{gtcResourcePath}"; //set font size for html content (necessary for iOS) string headerString = "
"; if (string.IsNullOrEmpty(gtcResourcePath)) { return new HtmlWebViewSource { Html = headerString + await Task.FromResult(ViewModelHelper.FromBody("No terms resource available. Resource path is null or empty.")) }; } Log.Debug($"Request to open url {GetUriText()} to get AGB infos."); return new HtmlWebViewSource { Html = headerString + await ViewModelHelper.GetSource( GetUriText(), // "agb.html" isSiteCachingOn) }; } /// Gets the platfrom specific prefix. private Func ResourceProvider { get; set; } /// Gets the app related information (app version and licenses). public HtmlWebViewSource AppHtml => new HtmlWebViewSource { Html = ResourceProvider("HtmlResouces.V02.InfoLicenses.html") .Replace("CURRENT_VERSION_TINKAPP", DependencyService.Get().Version.ToString()) .Replace("ACTIVE_APPNAME", AppInfo.Name) .Replace("APPSUPPORTMAILADDRESS", ContactPageViewModel.APPSUPPORTMAILADDRESS) }; /// PrivacyHtml text. private HtmlWebViewSource impressHtml; /// Gets the privacy related information. public HtmlWebViewSource ImpressHtml { get => impressHtml; set { impressHtml = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ImpressHtml))); } } /// Agb information text. private HtmlWebViewSource gtcHtml; /// PrivacyHtml text. private HtmlWebViewSource privacyHtml; /// Agb information text. public HtmlWebViewSource GtcHtml { get => gtcHtml; set { gtcHtml = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(GtcHtml))); } } /// Agb information text. public HtmlWebViewSource PrivacyHtml { get => privacyHtml; set { privacyHtml = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(PrivacyHtml))); } } } }