mirror of
https://dev.azure.com/TeilRad/sharee.bike%20App/_git/Code
synced 2024-11-15 22:56:37 +01:00
330 lines
12 KiB
C#
330 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Input;
|
|
using Plugin.Messaging;
|
|
using Serilog;
|
|
using TINK.Model;
|
|
using TINK.Model.Stations.StationNS;
|
|
using TINK.MultilingualResources;
|
|
using TINK.View;
|
|
using Xamarin.Essentials;
|
|
using Xamarin.Forms;
|
|
|
|
namespace TINK.ViewModel.Info
|
|
{
|
|
/// <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> Reference on the tink app instance. </summary>
|
|
private ITinkApp TinkApp { 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,
|
|
ITinkApp tinkApp,
|
|
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 centered.");
|
|
|
|
TinkApp = tinkApp
|
|
?? throw new ArgumentException("Can not instantiate settings page view model- object. No tink app object 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.");
|
|
}
|
|
|
|
/// <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(SelectedStationId)));
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedStationName)));
|
|
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)));
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsDoPhoncallAvailable)));
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsSendMailAvailable)));
|
|
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
/// <summary> Command object to bind mail button to view model. </summary>
|
|
public ICommand OnMailToOperatorRequest
|
|
=> new Command(async () => await DoSendMailToOperator());
|
|
|
|
/// <summary> Command object to bind mail app related button to model. </summary>
|
|
public ICommand OnMailAppRelatedRequest
|
|
=> new Command(async () => await DoSendMailAppRelated());
|
|
|
|
/// <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 available. </summary>
|
|
public bool IsOperatorInfoAvaliable
|
|
=> MailAddressText.Length > 0 || PhoneNumberText.Length > 0;
|
|
|
|
/// <returns> Returns true if either mail was sent or if no mailer available.</returns>
|
|
public async Task DoSendMailToOperator()
|
|
{
|
|
if (!IsSendMailAvailable)
|
|
{
|
|
await ViewService.DisplayAlert(
|
|
String.Empty,
|
|
AppResources.ErrorSupportmailMailingFailed,
|
|
AppResources.MessageAnswerOk);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
// Send operator related support mail to operator.
|
|
await Email.ComposeAsync(new EmailMessage
|
|
{
|
|
To = new List<string> { MailAddressText },
|
|
Cc = APPSUPPORTMAILADDRESS.ToUpper() != MailAddressText.ToUpper() // do not sent copy if same mail address
|
|
&& MailAddressText != "konrad@sharee.bike" // do not sent copy if Mein konrad
|
|
? new List<string> { APPSUPPORTMAILADDRESS } : new List<string>(),
|
|
Subject = string.Format(AppResources.SupportmailSubjectOperatormail, AppFlavorName, SelectedStation?.Id),
|
|
Body = TinkApp.ActiveUser.Mail != null ? $"{AppResources.SupportmailBodyText}\r\n\r\n\r\n\r\n{string.Format(AppResources.MarkingLoggedInStateInfoLoggedIn, TinkApp.ActiveUser.Mail)}" : $"{AppResources.SupportmailBodyText}\r\n\r\n\r\n\r\n{string.Format(AppResources.SupportmailBodyNotLoggedIn)}"
|
|
});
|
|
|
|
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()
|
|
{
|
|
if (!IsSendMailAvailable)
|
|
{
|
|
await ViewService.DisplayAlert(
|
|
String.Empty,
|
|
AppResources.ErrorSupportmailMailingFailed,
|
|
AppResources.MessageAnswerOk);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
// Ask for permission to append diagnostics.
|
|
await ViewService.DisplayAlert(
|
|
AppResources.QuestionSupportmailAttachmentTitle,
|
|
AppResources.QuestionSupportmailAttachment,
|
|
AppResources.MessageAnswerOk);
|
|
|
|
var message = new EmailMessage
|
|
{
|
|
To = new List<string> { APPSUPPORTMAILADDRESS },
|
|
Subject = SelectedStation?.Id != null ? string.Format(AppResources.SupportmailSubjectAppmailWithStation, AppFlavorName, SelectedStation?.Id) : string.Format(AppResources.SupportmailSubjectAppmail, AppFlavorName),
|
|
Body = TinkApp.ActiveUser.Mail != null ? $"{AppResources.SupportmailBodyText}\r\n\r\n\r\n\r\n{string.Format(AppResources.MarkingLoggedInStateInfoLoggedIn, TinkApp.ActiveUser.Mail)}" : $"{AppResources.SupportmailBodyText}\r\n\r\n\r\n\r\n{string.Format(AppResources.SupportmailBodyNotLoggedIn)}"
|
|
};
|
|
|
|
// 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
|
|
=> new Xamarin.Forms.Command(async () => await OpenSelectStationPageAsync());
|
|
|
|
/// <summary> Opens login page. </summary>
|
|
public async Task OpenSelectStationPageAsync()
|
|
{
|
|
try
|
|
{
|
|
// Switch to map page
|
|
|
|
await ViewService.PushAsync(ViewTypes.SelectStationPage);
|
|
}
|
|
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());
|
|
|
|
/// <summary> Request to do a phone call. </summary>
|
|
public async Task DoPhoneCall()
|
|
{
|
|
if (!IsDoPhoncallAvailable)
|
|
{
|
|
await ViewService.DisplayAlert(
|
|
String.Empty,
|
|
AppResources.ErrorSupportmailPhoningFailed,
|
|
AppResources.MessageAnswerOk);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
// Make Phone Call
|
|
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 the id of the selected station.</summary>
|
|
public string SelectedStationId
|
|
=> SelectedStation?.Id != null ? SelectedStation?.Id : string.Empty;
|
|
|
|
public string SelectedStationName
|
|
=> SelectedStation?.StationName;
|
|
|
|
/// <summary> Text providing the name of the operator of the selected station </summary>
|
|
public string ProviderNameText
|
|
=> SelectedStation?.OperatorData?.Name;
|
|
|
|
/// <summary> Text providing mail address and possible 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 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;
|
|
}
|
|
}
|
|
}
|
|
}
|