using Plugin.Messaging; using Serilog; using System; using System.Collections.Generic; using System.Threading.Tasks; using System.Windows.Input; using TINK.Model.Services.CopriApi.ServerUris; using TINK.Model.Station; using TINK.MultilingualResources; using TINK.View; using Xamarin.Essentials; using Xamarin.Forms; namespace TINK.ViewModel.Info { /// View model for contact page. public class ContactPageViewModel { /// Reference on view service to show modal notifications and to perform navigation. private IViewService ViewService { get; } /// Station selected by user. private IStation SelectedStation; Uri ActiveUri { get; } /// Holds a reference to the external trigger service. private Action OpenUrlInExternalBrowser { get; } Func CreateAttachment { get; } /// Constructs a contact page view model. /// Action to open an external browser. /// View service to notify user. public ContactPageViewModel( IStation selectedStation, Uri activeUri, Func createAttachment, Action openUrlInExternalBrowser, IViewService viewService) { ActiveUri = activeUri ?? throw new ArgumentException("Can not instantiate contact page view model- object. No active uri available."); CreateAttachment = createAttachment ?? throw new ArgumentException("Can not instantiate contact page view model- object. No create attachment provider available."); ViewService = viewService ?? throw new ArgumentException("Can not instantiate contact page view model- object. No user view service available."); OpenUrlInExternalBrowser = openUrlInExternalBrowser ?? throw new ArgumentException("Can not instantiate contact page view model- object. No user external browse service available."); // Station might be null-station, if no station info is avialable. SelectedStation = selectedStation; } /// Command object to bind login button to view model. public ICommand OnMailRequest => new Command( async () => await DoSendMail(), () => IsSendMailAvailable); /// True if sending mail is possible. public bool IsSendMailAvailable => CrossMessaging.Current.EmailMessenger.CanSendEmail; /// cTrue if doing a phone call is possible. public bool IsDoPhoncallAvailable => CrossMessaging.Current.PhoneDialer.CanMakePhoneCall; /// Holds the mail address to mail to. public string MailAddressText => SelectedStation?.OperatorData?.MailAddressText ?? string.Empty; /// Holds the mail address to send mail to. public string PhoneNumberText => SelectedStation?.OperatorData?.PhoneNumberText ?? string.Empty; /// Holds the mail address to send mail to. public string OfficeHoursText => SelectedStation?.OperatorData?.Hours ?? string.Empty; /// Gets whether any operator support info is avaliable. public bool IsOperatorInfoAvaliable => MailAddressText.Length > 0 || PhoneNumberText.Length > 0; /// Request to do a phone call. public async Task DoSendMail() { try { if (!IsSendMailAvailable) { // Nothing to do because email can not be sent. return; } var tinkMail = await ViewService.DisplayAlert( AppResources.QuestionTitle, string.Format(AppResources.QuestionSupportmailSubject, GetAppName(ActiveUri)), string.Format(AppResources.QuestionSupportmailAnswerOperator, GetAppName(ActiveUri)), string.Format(AppResources.QuestionSupportmailAnswerApp, GetAppName(ActiveUri))); if (tinkMail) { // Send TINK- related support mail. await Email.ComposeAsync(new EmailMessage { To = new List { MailAddressText }, Subject = $"{GetAppName(ActiveUri)} Anfrage" }); return; } // Send a tink app related mail var appendFile = false; appendFile = await ViewService.DisplayAlert( AppResources.QuestionTitle, AppResources.QuestionSupportmailAttachment, AppResources.QuestionAnswerYes, AppResources.QuestionAnswerNo); var message = new EmailMessage { To = new List { MailAddressText }, Subject = $"{GetAppName(ActiveUri)}-App Anfrage" }; if (appendFile == false) { // Send a tink app related mail await Email.ComposeAsync(message); return; } var logFileName = string.Empty; try { logFileName = CreateAttachment(); } catch (Exception l_oException) { await ViewService.DisplayAdvancedAlert( AppResources.MessageWaring, AppResources.ErrorSupportmailCreateAttachment, l_oException.Message, AppResources.MessageAnswerOk); Log.Error("An error occurred creating attachment. {@l_oException)", l_oException); } if (!string.IsNullOrEmpty(logFileName)) { message.Attachments.Add(new Xamarin.Essentials.EmailAttachment(logFileName)); } // Send a tink app related mail await Email.ComposeAsync(message); } catch (Exception p_oException) { Log.Error("An unexpected error occurred sending mail. {@Exception}", p_oException); await ViewService.DisplayAdvancedAlert( AppResources.MessageWaring, AppResources.ErrorSupportmailMailingFailed, p_oException.Message, AppResources.MessageAnswerOk); return; } } /// Command object to bind login button to view model. public ICommand OnSelectStationRequest #if USEMASTERDETAIL || USEFLYOUT => new Xamarin.Forms.Command(() => OpenSelectStationPage()); #else => new Xamarin.Forms.Command(async () => await OpenSelectStationPageAsync()); #endif /// Opens login page. #if USEMASTERDETAIL || USEFLYOUT public void OpenSelectStationPage() #else public async Task OpenSelectStationPageAsync() #endif { try { // Switch to map page #if USEMASTERDETAIL || USEFLYOUT ViewService.PushAsync(ViewTypes.SelectStationPage); #else await ViewService.ShowPage("//SelectStationPage"); #endif } catch (Exception p_oException) { Log.Error("Ein unerwarteter Fehler ist in der Klasse ContactPageViewModel aufgetreten. Kontext: Klick auf Hinweistext auf Station N- seite ohne Anmeldung. {@Exception}", p_oException); return; } } /// Command object to bind phone call button. public ICommand OnPhoneRequest => new Command( async () => await DoPhoneCall(), () => IsDoPhoncallAvailable); /// Request to do a phone call. public async Task DoPhoneCall() { try { // Make Phone Call if (IsDoPhoncallAvailable) { CrossMessaging.Current.PhoneDialer.MakePhoneCall(PhoneNumberText); } } catch (Exception p_oException) { Log.Error("An unexpected error occurred doing a phone call. {@Exception}", p_oException); await ViewService.DisplayAdvancedAlert( AppResources.MessageWaring, AppResources.ErrorSupportmailPhoningFailed, p_oException.Message, AppResources.MessageAnswerOk); return; } } /// Text providing mail address and possilbe reasons to contact. public string ProviderNameText => string.Format("Betreiber: {0}", SelectedStation?.OperatorData?.Name) ; /// Text providing mail address and possilbe reasons to contact. public FormattedString MailAddressAndMotivationsText { get { var hint = new FormattedString(); hint.Spans.Add(new Span { Text = AppResources.MessageContactMail }); return hint; } } /// Invitation to rate app. public FormattedString LikeTinkApp { get { var l_oHint = new FormattedString(); l_oHint.Spans.Add(new Span { Text = string.Format(AppResources.MessageRateMail, GetAppName(ActiveUri)) }); return l_oHint; } } /// User clicks rate button. public ICommand OnRateRequest => new Command(() => RegisterRequest()); /// Opens login page. public void RegisterRequest() { try { OpenUrlInExternalBrowser(); } catch (Exception p_oException) { Log.Error("Ein unerwarteter Fehler ist auf der Login Seite beim Öffnen eines Browsers, Seite {url}, aufgetreten. {@Exception}", p_oException); return; } } /// Invitation to rate app. public FormattedString PhoneContactText { get { var l_oHint = new FormattedString(); l_oHint.Spans.Add(new Span { Text = string.Format(AppResources.MessagePhoneMail, GetAppName(ActiveUri)) + $"{(OfficeHoursText.Length > 0 ? $" {OfficeHoursText}" : string.Empty)}" }); return l_oHint; } } /// Gets the application name. public static string GetAppName(Uri activeUri) { switch (activeUri.AbsoluteUri) { case CopriServerUriList.TINK_DEVEL: case CopriServerUriList.TINK_LIVE: return "TINK"; case CopriServerUriList.SHAREE_DEVEL: case CopriServerUriList.SHAREE_LIVE: return "sharee.bike"; default: return "Teilrad"; } } } }