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-07-20 23:06:09 +02:00
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
{
2022-09-06 16:08:19 +02:00
/// <summary> View model for contact page.</summary>
public class ContactPageViewModel : INotifyPropertyChanged
{
/// <summary>
/// Mail address for app related support.
/// </summary>
public const string APPSUPPORTMAILADDRESS = "hotline@sharee.bike" ;
/// <summary> Reference on view service to show modal notifications and to perform navigation. </summary>
private IViewService ViewService { get ; }
/// <summary> Station selected by user. </summary>
private IStation SelectedStation { get ; set ; } = new NullStation ( ) ;
/// <summary> Holds the name of the app (sharee.bike, Mein konrad, ...)</summary>
string AppFlavorName { get ; }
/// <summary> Holds a reference to the external trigger service. </summary>
private Action OpenUrlInExternalBrowser { get ; }
Func < string > CreateAttachment { get ; }
/// <summary> Notifies view about changes. </summary>
public event PropertyChangedEventHandler PropertyChanged ;
/// <summary> Constructs a contact page view model. </summary>
/// <param name="appFlavorName">Holds the name of the app.</param>
/// <param name="openUrlInExternalBrowser">Action to open an external browser.</param>
/// <param name="viewService">View service to notify user.</param>
public ContactPageViewModel (
string appFlavorName ,
Func < string > createAttachment ,
Action openUrlInExternalBrowser ,
IViewService viewService )
{
AppFlavorName = ! string . IsNullOrEmpty ( appFlavorName )
? appFlavorName
: throw new ArgumentException ( "Can not instantiate contact page view model- object. No app name availalbe." ) ;
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." ) ;
}
/// <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 ;
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 ;
}
/// <summary> Command object to bind mail button to view model. </summary>
public ICommand OnMailToOperatorRequest
= > 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 ( ) ,
( ) = > IsSendMailAvailable ) ;
/// <summary>True if sending mail is possible.</summary>
public bool IsSendMailAvailable = >
CrossMessaging . Current . EmailMessenger . CanSendEmail ;
/// <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 ;
/// <summary>Holds the mail address to send mail to.</summary>
public string PhoneNumberText
= > SelectedStation ? . OperatorData ? . PhoneNumberText ? ? string . Empty ;
/// <summary>Holds the mail address to send mail to.</summary>
public string OfficeHoursText
= > SelectedStation ? . OperatorData ? . Hours ? ? string . Empty ;
/// <summary> Gets whether any operator support info is avaliable. </summary>
public bool IsOperatorInfoAvaliable
= > MailAddressText . Length > 0 | | PhoneNumberText . Length > 0 ;
/// <returns> Returns true if eithe mail was sent or if no mailer available.</returns>
public async Task DoSendMailToOperator ( )
{
try
{
if ( ! IsSendMailAvailable )
{
// Nothing to do because email can not be sent.
return ;
}
// Ask whether mail is operator or app specific.
var operatorRelatedMail = await ViewService . DisplayAlert (
AppResources . QuestionTitle ,
string . Format ( AppResources . QuestionSupportmailSubject , AppFlavorName ) ,
string . Format ( AppResources . QuestionSupportmailAnswerOperator , AppFlavorName ) ,
string . Format ( AppResources . QuestionSupportmailAnswerApp , AppFlavorName ) ) ;
if ( operatorRelatedMail )
{
// Send operator related support mail to operator.
await Email . ComposeAsync ( new EmailMessage
{
To = new List < string > { MailAddressText } ,
Subject = string . Format ( AppResources . SupportmailSubjectOperatormail , AppFlavorName )
} ) ;
return ;
}
// Send app-related related support mail to operator.
await Email . ComposeAsync ( new EmailMessage
{
To = new List < string > { MailAddressText } ,
Cc = APPSUPPORTMAILADDRESS . ToUpper ( ) ! = MailAddressText . ToUpper ( ) ? new List < string > { APPSUPPORTMAILADDRESS } : new List < string > ( ) ,
Subject = string . Format ( AppResources . SupportmailSubjectAppmail , AppFlavorName )
} ) ;
return ;
}
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 ;
}
}
/// <summary> Request to send a app related mail. </summary>
public async Task DoSendMailAppRelated ( )
{
try
{
// Ask for permission to append diagnostics.
var appendFile = false ;
appendFile = await ViewService . DisplayAlert (
AppResources . QuestionSupportmailTitle ,
AppResources . QuestionSupportmailAttachment ,
AppResources . QuestionAnswerYes ,
AppResources . QuestionSupportmailAnswerNo ) ;
var message = new EmailMessage
{
To = new List < string > { APPSUPPORTMAILADDRESS } ,
Subject = string . Format ( AppResources . SupportmailSubjectAppmail , AppFlavorName )
} ;
if ( appendFile = = false )
{
// Send without attachment
await Email . ComposeAsync ( message ) ;
return ;
}
// Send with attachment.
var logFileName = string . Empty ;
try
{
logFileName = CreateAttachment ( ) ;
}
catch ( Exception exception )
{
await ViewService . DisplayAdvancedAlert (
AppResources . MessageWaring ,
AppResources . ErrorSupportmailCreateAttachment ,
exception . Message ,
AppResources . MessageAnswerOk ) ;
Log . ForContext < ContactPageViewModel > ( ) . Error ( "An error occurred creating attachment for app mail. {@Exception)" , exception ) ;
}
if ( ! string . IsNullOrEmpty ( logFileName ) )
{
message . Attachments . Add ( new Xamarin . Essentials . EmailAttachment ( logFileName ) ) ;
}
// Send a tink app related mail
await Email . ComposeAsync ( message ) ;
}
catch ( Exception exception )
{
Log . ForContext < ContactPageViewModel > ( ) . Error ( "An unexpected error occurred sending mail. {@Exception}" , exception ) ;
await ViewService . DisplayAdvancedAlert (
AppResources . MessageWaring ,
AppResources . ErrorSupportmailMailingFailed ,
exception . Message ,
AppResources . MessageAnswerOk ) ;
return ;
}
}
/// <summary> Command object to bind login button to view model. </summary>
public ICommand OnSelectStationRequest
2021-08-28 10:04:10 +02:00
#if USEFLYOUT
2021-07-22 22:41:35 +02:00
= > new Xamarin . Forms . Command ( ( ) = > OpenSelectStationPage ( ) ) ;
#else
2022-09-06 16:08:19 +02:00
= > new Xamarin . Forms . Command ( async ( ) = > await OpenSelectStationPageAsync ( ) ) ;
2021-07-22 22:41:35 +02:00
#endif
2022-09-06 16:08:19 +02:00
/// <summary> Opens login page. </summary>
2021-08-28 10:04:10 +02:00
#if USEFLYOUT
2021-07-22 22:41:35 +02:00
public void OpenSelectStationPage ( )
#else
2022-09-06 16:08:19 +02:00
public async Task OpenSelectStationPageAsync ( )
2021-07-22 22:41:35 +02:00
#endif
2022-09-06 16:08:19 +02:00
{
try
{
// Switch to map page
2021-07-22 22:41:35 +02:00
2021-08-28 10:04:10 +02:00
#if USEFLYOUT
2021-07-22 22:41:35 +02:00
ViewService . PushAsync ( ViewTypes . SelectStationPage ) ;
#else
2022-09-06 16:08:19 +02:00
await ViewService . PushAsync ( ViewTypes . SelectStationPage ) ;
2021-07-22 22:41:35 +02:00
#endif
2022-09-06 16:08:19 +02:00
}
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>
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 ) ;
}
}
catch ( Exception exception )
{
Log . Error ( "An unexpected error occurred doing a phone call. {@Exception}" , exception ) ;
await ViewService . DisplayAdvancedAlert (
AppResources . MessageWaring ,
AppResources . ErrorSupportmailPhoningFailed ,
exception . Message ,
AppResources . MessageAnswerOk ) ;
return ;
}
}
/// <summary> Text providing mail address and possilbe reasons to contact. </summary>
public string ProviderNameText
= > string . Format ( "Betreiber: {0}" , SelectedStation ? . OperatorData ? . Name )
2021-08-01 17:24:15 +02:00
;
2022-09-06 16:08:19 +02:00
/// <summary> Text providing mail address and possilbe reasons to contact. </summary>
public FormattedString MailAddressAndMotivationsText
{
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 hint = new FormattedString ( ) ;
hint . Spans . Add ( new Span { Text = string . Format ( AppResources . MessageRateMail , AppFlavorName ) } ) ;
return hint ;
}
}
/// <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 , AppFlavorName ) + $"{(OfficeHoursText.Length > 0 ? $" { OfficeHoursText } " : string.Empty)}"
} ) ;
return l_oHint ;
}
}
}
2021-05-13 20:03:07 +02:00
}