sharee.bike-App/TINKLib/ViewModel/Contact/ContactPageViewModel.cs

392 lines
15 KiB
C#
Raw Normal View History

2022-08-30 15:42:25 +02:00
using System;
2021-05-13 20:03:07 +02:00
using System.Collections.Generic;
2022-04-10 17:38:34 +02:00
using System.ComponentModel;
2021-05-13 20:03:07 +02:00
using System.Threading.Tasks;
using System.Windows.Input;
2022-08-30 15:42:25 +02:00
using Plugin.Messaging;
using Serilog;
2021-05-13 20:03:07 +02:00
using TINK.Model.Services.CopriApi.ServerUris;
using TINK.Model.Station;
2021-05-13 20:03:07 +02:00
using TINK.MultilingualResources;
using TINK.View;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace TINK.ViewModel.Info
{
/// <summary> View model for contact page.</summary>
2022-04-10 17:38:34 +02:00
public class ContactPageViewModel : INotifyPropertyChanged
2021-05-13 20:03:07 +02:00
{
2022-08-30 15:42:25 +02:00
/// <summary>
/// Mail address for app related support.
/// </summary>
public const string APPSUPPORTMAILADDRESS = "hotline@sharee.bike";
2021-05-13 20:03:07 +02:00
/// <summary> Reference on view service to show modal notifications and to perform navigation. </summary>
private IViewService ViewService { get; }
/// <summary> Station selected by user. </summary>
2022-04-10 17:38:34 +02:00
private IStation SelectedStation { get; set; } = new NullStation();
2021-05-13 20:03:07 +02:00
Uri ActiveUri { get; }
2022-04-10 17:38:34 +02:00
/// <summary> Holds the name of the app (sharee.bike, Mein konrad, ...)</summary>
string AppName { get; }
2021-05-13 20:03:07 +02:00
/// <summary> Holds a reference to the external trigger service. </summary>
private Action OpenUrlInExternalBrowser { get; }
Func<string> CreateAttachment { get; }
2022-04-10 17:38:34 +02:00
/// <summary> Notifies view about changes. </summary>
public event PropertyChangedEventHandler PropertyChanged;
2021-05-13 20:03:07 +02:00
/// <summary> Constructs a contact page view model. </summary>
/// <param name="openUrlInExternalBrowser">Action to open an external browser.</param>
/// <param name="viewService">View service to notify user.</param>
public ContactPageViewModel(
Uri activeUri,
2022-04-10 17:38:34 +02:00
string appName,
2021-05-13 20:03:07 +02:00
Func<string> createAttachment,
Action openUrlInExternalBrowser,
IViewService viewService)
{
ActiveUri = activeUri
?? throw new ArgumentException("Can not instantiate contact page view model- object. No active uri available.");
2022-04-10 17:38:34 +02:00
AppName = !string.IsNullOrEmpty(appName)
? appName
: throw new ArgumentException("Can not instantiate contact page view model- object. No app name availalbe.");
2021-05-13 20:03:07 +02:00
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.");
2022-04-10 17:38:34 +02:00
}
/// <summary> Is invoked when page is shown. </summary>
public async Task OnAppearing(
IStation selectedStation)
{
if (SelectedStation?.Id == selectedStation?.Id)
{
// Nothing to do because either both are null or of same id.
return;
}
SelectedStation = selectedStation;
2022-04-10 17:38:34 +02:00
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MailAddressText)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(OfficeHoursText)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(PhoneNumberText)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ProviderNameText)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsOperatorInfoAvaliable)));
await Task.CompletedTask;
2021-05-13 20:03:07 +02:00
}
2022-08-30 15:42:25 +02:00
/// <summary> Command object to bind mail button to view model. </summary>
2021-05-13 20:03:07 +02:00
public ICommand OnMailRequest
=> new Command(
2022-08-30 15:42:25 +02:00
async () =>
{
if (await DoSendMailToOperator())
{
// Mail sent to operator or no mailer availble.
return;
}
await DoSendMailAppRelated(
new List<string> { MailAddressText },
MailAddressText.ToUpper() != APPSUPPORTMAILADDRESS.ToUpper()
? new List<string> { APPSUPPORTMAILADDRESS }
: new List<string>());
},
2021-05-13 20:03:07 +02:00
() => IsSendMailAvailable);
2022-08-30 15:42:25 +02:00
/// <summary> Command object to bind mail app releated button to model. </summary>
public ICommand OnSendAppFeedbackMailRequest
=> new Command(
async () => await DoSendMailToOperator(),
() => IsSendMailAvailable);
/// <summary> Command object to bind mail app releated button to model. </summary>
public ICommand OnMailAppRelatedRequest
=> new Command(
async () => await DoSendMailAppRelated(new List<string> { APPSUPPORTMAILADDRESS }, new List<string>()),
() => IsSendMailAvailable);
2021-05-13 20:03:07 +02:00
/// <summary>True if sending mail is possible.</summary>
public bool IsSendMailAvailable =>
CrossMessaging.Current.EmailMessenger.CanSendEmail;
2022-08-30 15:42:25 +02:00
2021-05-13 20:03:07 +02:00
/// <summary>cTrue if doing a phone call is possible.</summary>
public bool IsDoPhoncallAvailable
=> CrossMessaging.Current.PhoneDialer.CanMakePhoneCall;
/// <summary>Holds the mail address to mail to.</summary>
public string MailAddressText
=> SelectedStation?.OperatorData?.MailAddressText ?? string.Empty;
2021-05-13 20:03:07 +02:00
/// <summary>Holds the mail address to send mail to.</summary>
public string PhoneNumberText
=> SelectedStation?.OperatorData?.PhoneNumberText ?? string.Empty;
2021-05-13 20:03:07 +02:00
/// <summary>Holds the mail address to send mail to.</summary>
public string OfficeHoursText
=> SelectedStation?.OperatorData?.Hours ?? string.Empty;
2021-05-13 20:03:07 +02:00
/// <summary> Gets whether any operator support info is avaliable. </summary>
public bool IsOperatorInfoAvaliable
=> MailAddressText.Length > 0 || PhoneNumberText.Length > 0;
2021-05-13 20:03:07 +02:00
2022-08-30 15:42:25 +02:00
/// <returns> Returns true if eithe mail was sent or if no mailer available.</returns>
public async Task<bool> DoSendMailToOperator()
2021-05-13 20:03:07 +02:00
{
try
{
if (!IsSendMailAvailable)
{
// Nothing to do because email can not be sent.
2022-08-30 15:42:25 +02:00
return true;
2021-05-13 20:03:07 +02:00
}
2022-08-30 15:42:25 +02:00
// Ask whether mail is operator or app specific.
var operatorRelatedMail = await ViewService.DisplayAlert(
2021-05-13 20:03:07 +02:00
AppResources.QuestionTitle,
string.Format(AppResources.QuestionSupportmailSubject, GetAppName(ActiveUri)),
string.Format(AppResources.QuestionSupportmailAnswerOperator, GetAppName(ActiveUri)),
string.Format(AppResources.QuestionSupportmailAnswerApp, GetAppName(ActiveUri)));
2022-08-30 15:42:25 +02:00
if (operatorRelatedMail)
2021-05-13 20:03:07 +02:00
{
2022-08-30 15:42:25 +02:00
// Send operator related support mail.
2021-05-13 20:03:07 +02:00
await Email.ComposeAsync(new EmailMessage { To = new List<string> { MailAddressText }, Subject = $"{GetAppName(ActiveUri)} Anfrage" });
2022-08-30 15:42:25 +02:00
return true;
2021-05-13 20:03:07 +02:00
}
2022-08-30 15:42:25 +02:00
return false;
}
catch (Exception exception)
{
Log.Error("An unexpected error occurred sending mail to operator. {@Exception}", exception);
await ViewService.DisplayAdvancedAlert(
AppResources.MessageWaring,
AppResources.ErrorSupportmailMailingFailed,
exception.Message,
AppResources.MessageAnswerOk);
return true;
}
}
/// <summary> Request to send a app related mail. </summary>
public async Task DoSendMailAppRelated(List<string> to, List<string> cc)
{
try
{
// Send app related mail
2021-05-13 20:03:07 +02:00
var appendFile = false;
appendFile = await ViewService.DisplayAlert(
AppResources.QuestionTitle,
AppResources.QuestionSupportmailAttachment,
AppResources.QuestionAnswerYes,
AppResources.QuestionAnswerNo);
2022-08-30 15:42:25 +02:00
var message = new EmailMessage
{
To = to,
Cc = cc,
Subject = $"{GetAppName(ActiveUri)}-App Anfrage"
};
2021-05-13 20:03:07 +02:00
if (appendFile == false)
{
2022-08-30 15:42:25 +02:00
// Send without attachment
2021-05-13 20:03:07 +02:00
await Email.ComposeAsync(message);
return;
}
2022-08-30 15:42:25 +02:00
// Send with attachment.
2021-05-13 20:03:07 +02:00
var logFileName = string.Empty;
try
{
logFileName = CreateAttachment();
}
2022-08-30 15:42:25 +02:00
catch (Exception exception)
2021-05-13 20:03:07 +02:00
{
await ViewService.DisplayAdvancedAlert(
AppResources.MessageWaring,
AppResources.ErrorSupportmailCreateAttachment,
2022-08-30 15:42:25 +02:00
exception.Message,
2021-05-13 20:03:07 +02:00
AppResources.MessageAnswerOk);
2022-08-30 15:42:25 +02:00
Log.Error("An error occurred creating attachment. {@Exception)", exception);
2021-05-13 20:03:07 +02:00
}
if (!string.IsNullOrEmpty(logFileName))
{
message.Attachments.Add(new Xamarin.Essentials.EmailAttachment(logFileName));
}
// Send a tink app related mail
await Email.ComposeAsync(message);
}
2022-08-30 15:42:25 +02:00
catch (Exception exception)
2021-05-13 20:03:07 +02:00
{
2022-08-30 15:42:25 +02:00
Log.Error("An unexpected error occurred sending mail. {@Exception}", exception);
2021-05-13 20:03:07 +02:00
await ViewService.DisplayAdvancedAlert(
AppResources.MessageWaring,
2022-08-30 15:42:25 +02:00
AppResources.ErrorSupportmailMailingFailed,
exception.Message,
2021-05-13 20:03:07 +02:00
AppResources.MessageAnswerOk);
return;
}
}
/// <summary> Command object to bind login button to view model. </summary>
public ICommand OnSelectStationRequest
#if USEFLYOUT
=> new Xamarin.Forms.Command(() => OpenSelectStationPage());
#else
=> new Xamarin.Forms.Command(async () => await OpenSelectStationPageAsync());
#endif
/// <summary> Opens login page. </summary>
#if USEFLYOUT
public void OpenSelectStationPage()
#else
public async Task OpenSelectStationPageAsync()
#endif
{
try
{
// Switch to map page
#if USEFLYOUT
ViewService.PushAsync(ViewTypes.SelectStationPage);
#else
2022-04-10 17:38:34 +02:00
await ViewService.PushAsync(ViewTypes.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;
}
}
/// <summary> Command object to bind phone call button. </summary>
2021-05-13 20:03:07 +02:00
public ICommand OnPhoneRequest
=> new Command(
async () => await DoPhoneCall(),
() => IsDoPhoncallAvailable);
/// <summary> Request to do a phone call. </summary>
public async Task DoPhoneCall()
{
try
{
// Make Phone Call
if (IsDoPhoncallAvailable)
{
CrossMessaging.Current.PhoneDialer.MakePhoneCall(PhoneNumberText);
}
}
2022-08-30 15:42:25 +02:00
catch (Exception exception)
2021-05-13 20:03:07 +02:00
{
2022-08-30 15:42:25 +02:00
Log.Error("An unexpected error occurred doing a phone call. {@Exception}", exception);
2021-05-13 20:03:07 +02:00
await ViewService.DisplayAdvancedAlert(
AppResources.MessageWaring,
2022-08-30 15:42:25 +02:00
AppResources.ErrorSupportmailPhoningFailed,
exception.Message,
2021-05-13 20:03:07 +02:00
AppResources.MessageAnswerOk);
return;
}
}
2021-08-01 17:24:15 +02:00
/// <summary> Text providing mail address and possilbe reasons to contact. </summary>
public string ProviderNameText
=> string.Format("Betreiber: {0}", SelectedStation?.OperatorData?.Name)
;
2021-05-13 20:03:07 +02:00
/// <summary> Text providing mail address and possilbe reasons to contact. </summary>
2021-08-01 17:24:15 +02:00
public FormattedString MailAddressAndMotivationsText
2021-05-13 20:03:07 +02:00
{
get
{
var hint = new FormattedString();
hint.Spans.Add(new Span { Text = AppResources.MessageContactMail });
return hint;
}
}
/// <summary> Invitation to rate app.</summary>
public FormattedString LikeTinkApp
{
get
{
var l_oHint = new FormattedString();
2022-04-10 17:38:34 +02:00
l_oHint.Spans.Add(new Span { Text = string.Format(AppResources.MessageRateMail, AppName) });
2021-05-13 20:03:07 +02:00
return l_oHint;
}
}
/// <summary> User clicks rate button.</summary>
public ICommand OnRateRequest
=> new Command(() => RegisterRequest());
/// <summary> Opens login page.</summary>
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;
}
}
/// <summary> Invitation to rate app.</summary>
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)}"
});
2021-05-13 20:03:07 +02:00
return l_oHint;
}
}
/// <summary>Gets the application name.</summary>
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";
}
}
}
}