Refactor email provider display logic

This commit is contained in:
Ben Olden-Cooligan 2023-03-25 10:39:52 -07:00
parent 1a20fdcebd
commit f0cb9481b0
3 changed files with 178 additions and 168 deletions

View File

@ -2,113 +2,16 @@ using Eto.Drawing;
using Eto.Forms;
using NAPS2.EtoForms.Layout;
using NAPS2.ImportExport.Email;
using NAPS2.ImportExport.Email.Mapi;
using NAPS2.ImportExport.Email.Oauth;
using NAPS2.Scan;
namespace NAPS2.EtoForms.Ui;
public class EmailProviderForm : EtoDialogBase
{
private readonly SystemEmailClients _systemEmailClients;
private readonly GmailOauthProvider _gmailOauthProvider;
private readonly OutlookWebOauthProvider _outlookWebOauthProvider;
private readonly ThunderbirdEmailProvider _thunderbirdProvider;
private readonly EmailProviderController _controller;
private readonly List<EmailProviderWidget> _providerWidgets;
private readonly string[] _systemClientNames;
private readonly string? _defaultSystemClientName;
public EmailProviderForm(Naps2Config config, SystemEmailClients systemEmailClients,
GmailOauthProvider gmailOauthProvider, OutlookWebOauthProvider outlookWebOauthProvider,
ThunderbirdEmailProvider thunderbirdProvider) : base(config)
public EmailProviderForm(Naps2Config config, EmailProviderController controller) : base(config)
{
_systemEmailClients = systemEmailClients;
_gmailOauthProvider = gmailOauthProvider;
_outlookWebOauthProvider = outlookWebOauthProvider;
_thunderbirdProvider = thunderbirdProvider;
_providerWidgets = new List<EmailProviderWidget>();
#if NET6_0_OR_GREATER
if (!OperatingSystem.IsWindowsVersionAtLeast(7))
{
_systemClientNames = Array.Empty<string>();
_defaultSystemClientName = null;
}
else
{
#endif
_systemClientNames = _systemEmailClients.GetNames();
_defaultSystemClientName = _systemEmailClients.GetDefaultName();
foreach (var clientName in _systemClientNames.OrderBy(x => x == _defaultSystemClientName ? 0 : 1))
{
var exePath = _systemEmailClients.GetExePath(clientName);
var icon = exePath == null ? null : EtoPlatform.Current.ExtractAssociatedIcon(exePath);
_providerWidgets.Add(new EmailProviderWidget
{
ProviderType = EmailProviderType.System,
ProviderIcon = icon ?? Icons.mail_yellow.ToEtoImage(),
ProviderName = clientName,
ClickAction = () => ChooseSystem(clientName)
});
}
#if NET6_0_OR_GREATER
}
// For Windows we expect Thunderbird to be used through MAPI. For Linux we need to handle it specially.
if (!OperatingSystem.IsWindows())
{
_providerWidgets.Add(new EmailProviderWidget
{
ProviderType = EmailProviderType.Thunderbird,
ProviderIcon = Icons.thunderbird.ToEtoImage(),
ProviderName = EmailProviderType.Thunderbird.Description(),
ClickAction = ChooseThunderbird,
// When Thunderbird isn't available, we disable it rather than hide it.
// The point is to give a hint to the user that Thunderbird support is present.
Enabled = _thunderbirdProvider.IsAvailable
});
}
#endif
if (_gmailOauthProvider.HasClientCreds)
{
_providerWidgets.Add(new EmailProviderWidget
{
ProviderType = EmailProviderType.Gmail,
ProviderIcon = Icons.gmail.ToEtoImage(),
ProviderName = EmailProviderType.Gmail.Description(),
ClickAction = () => ChooseOauth(_gmailOauthProvider)
});
}
if (_outlookWebOauthProvider.HasClientCreds)
{
_providerWidgets.Add(new EmailProviderWidget
{
ProviderType = EmailProviderType.OutlookWeb,
ProviderIcon = Icons.outlookweb.ToEtoImage(),
ProviderName = EmailProviderType.OutlookWeb.Description(),
ClickAction = () => ChooseOauth(_outlookWebOauthProvider)
});
}
//providerWidgets.Add(new EmailProviderWidget
//{
// ProviderType = EmailProviderType.CustomSmtp,
// ProviderIcon = Icons.email_setting,
// ProviderName = EmailProviderType.CustomSmtp.Description(),
// ClickAction = ChooseCustomSmtp
//});
// Put the configured provider at the top
var defaultWidget = GetDefaultWidget();
if (defaultWidget != null)
{
_providerWidgets.Remove(defaultWidget);
_providerWidgets.Insert(0, defaultWidget);
}
_controller = controller;
}
protected override void BuildLayout()
@ -120,7 +23,14 @@ public class EmailProviderForm : EtoDialogBase
LayoutController.DefaultSpacing = 0;
LayoutController.Content = L.Column(
_providerWidgets.Select(x => C.Button(new ActionCommand(x.ClickAction)
_controller.GetWidgets().Select(x => C.Button(new ActionCommand(() =>
{
if (x.Choose())
{
Result = true;
Close();
}
})
{
Text = x.ProviderName,
Image = x.ProviderIcon,
@ -131,71 +41,4 @@ public class EmailProviderForm : EtoDialogBase
public bool Result { get; private set; }
private void ChooseSystem(string clientName)
{
var transact = Config.User.BeginTransaction();
transact.Remove(c => c.EmailSetup);
transact.Set(c => c.EmailSetup.SystemProviderName, clientName);
transact.Set(c => c.EmailSetup.ProviderType, EmailProviderType.System);
transact.Commit();
Result = true;
Close();
}
private void ChooseThunderbird()
{
var transact = Config.User.BeginTransaction();
transact.Remove(c => c.EmailSetup);
transact.Set(c => c.EmailSetup.ProviderType, EmailProviderType.Thunderbird);
transact.Commit();
Result = true;
Close();
}
private void ChooseOauth(OauthProvider provider)
{
var authForm = FormFactory.Create<AuthorizeForm>();
authForm.OauthProvider = provider;
authForm.ShowModal();
if (authForm.Result)
{
Result = true;
Close();
}
}
private EmailProviderWidget? GetDefaultWidget()
{
var emailSetup = Config.Get(c => c.EmailSetup);
foreach (var widget in _providerWidgets)
{
if (widget.ProviderType == emailSetup.ProviderType)
{
if (widget.ProviderType == EmailProviderType.System)
{
// System providers need additional logic since there may be more than one
if (widget.ProviderName == emailSetup.SystemProviderName
|| string.IsNullOrEmpty(emailSetup.SystemProviderName) &&
widget.ProviderName == _defaultSystemClientName)
{
return widget;
}
}
else
{
return widget;
}
}
}
return null;
}
public class EmailProviderWidget
{
public required EmailProviderType ProviderType { get; init; }
public required Bitmap ProviderIcon { get; init; }
public required string ProviderName { get; init; }
public required Action ClickAction { get; init; }
public bool Enabled { get; set; } = true;
}
}

View File

@ -0,0 +1,155 @@
using Eto.Drawing;
using NAPS2.EtoForms;
using NAPS2.EtoForms.Ui;
using NAPS2.ImportExport.Email.Mapi;
using NAPS2.ImportExport.Email.Oauth;
using NAPS2.Scan;
namespace NAPS2.ImportExport.Email;
public class EmailProviderController
{
private readonly IFormFactory _formFactory;
private readonly Naps2Config _config;
private readonly SystemEmailClients _systemEmailClients;
private readonly GmailOauthProvider _gmailOauthProvider;
private readonly OutlookWebOauthProvider _outlookWebOauthProvider;
private readonly ThunderbirdEmailProvider _thunderbirdProvider;
public EmailProviderController(IFormFactory formFactory, Naps2Config config, SystemEmailClients systemEmailClients,
GmailOauthProvider gmailOauthProvider, OutlookWebOauthProvider outlookWebOauthProvider,
ThunderbirdEmailProvider thunderbirdProvider)
{
_formFactory = formFactory;
_config = config;
_systemEmailClients = systemEmailClients;
_gmailOauthProvider = gmailOauthProvider;
_outlookWebOauthProvider = outlookWebOauthProvider;
_thunderbirdProvider = thunderbirdProvider;
}
public List<EmailProviderWidget> GetWidgets()
{
var providerWidgets = new List<EmailProviderWidget>();
var userSetup = _config.Get(c => c.EmailSetup);
#if NET6_0_OR_GREATER
if (OperatingSystem.IsWindowsVersionAtLeast(7))
{
#endif
var systemClientNames = _systemEmailClients.GetNames();
var defaultSystemClientName = _systemEmailClients.GetDefaultName();
foreach (var clientName in systemClientNames.OrderBy(x =>
x == userSetup.SystemProviderName ? 0 : x == defaultSystemClientName ? 1 : 2))
{
providerWidgets.Add(GetWidget(EmailProviderType.System, clientName));
}
#if NET6_0_OR_GREATER
}
#endif
void MaybeAddWidget(EmailProviderType type, bool condition)
{
if (condition)
{
providerWidgets.Add(GetWidget(type));
}
}
#if NET6_0_OR_GREATER
// For Windows we expect Thunderbird to be used through MAPI. For Linux we need to handle it specially.
MaybeAddWidget(EmailProviderType.Thunderbird, !OperatingSystem.IsWindows());
#endif
MaybeAddWidget(EmailProviderType.Gmail, _gmailOauthProvider.HasClientCreds);
MaybeAddWidget(EmailProviderType.OutlookWeb, _outlookWebOauthProvider.HasClientCreds);
// Sort the currently-selected provider to the top
return providerWidgets.OrderBy(widget => widget.ProviderType == userSetup.ProviderType ? 0 : 1).ToList();
}
private EmailProviderWidget GetWidget(EmailProviderType type, string? clientName = null)
{
return type switch
{
EmailProviderType.System => new EmailProviderWidget
{
ProviderType = EmailProviderType.System,
ProviderIcon = GetSystemIcon(clientName!) ?? Icons.mail_yellow.ToEtoImage(),
ProviderName = clientName!,
Choose = () => ChooseSystem(clientName!)
},
EmailProviderType.Thunderbird => new EmailProviderWidget
{
ProviderType = EmailProviderType.Thunderbird,
ProviderIcon = Icons.thunderbird.ToEtoImage(),
ProviderName = EmailProviderType.Thunderbird.Description(),
Choose = ChooseThunderbird,
// When Thunderbird isn't available, we disable it rather than hide it.
// The point is to give a hint to the user that Thunderbird support is present.
Enabled = _thunderbirdProvider.IsAvailable
},
EmailProviderType.Gmail => new EmailProviderWidget
{
ProviderType = EmailProviderType.Gmail,
ProviderIcon = Icons.gmail.ToEtoImage(),
ProviderName = EmailProviderType.Gmail.Description(),
Choose = () => ChooseOauth(_gmailOauthProvider)
},
EmailProviderType.OutlookWeb => new EmailProviderWidget
{
ProviderType = EmailProviderType.OutlookWeb,
ProviderIcon = Icons.outlookweb.ToEtoImage(),
ProviderName = EmailProviderType.OutlookWeb.Description(),
Choose = () => ChooseOauth(_outlookWebOauthProvider)
},
// EmailProviderType.CustomSmtp => new EmailProviderWidget
// {
// ProviderType = EmailProviderType.CustomSmtp,
// ProviderIcon = Icons.email_setting.ToEtoImage(),
// ProviderName = EmailProviderType.CustomSmtp.Description(),
// Choose = ChooseCustomSmtp
// },
_ => throw new ArgumentException()
};
}
private Bitmap? GetSystemIcon(string clientName)
{
#if NET6_0_OR_GREATER
if (!OperatingSystem.IsWindowsVersionAtLeast(7))
{
throw new InvalidOperationException();
}
#endif
var exePath = _systemEmailClients.GetExePath(clientName);
return exePath == null ? null : EtoPlatform.Current.ExtractAssociatedIcon(exePath);
}
private bool ChooseSystem(string clientName)
{
var transact = _config.User.BeginTransaction();
transact.Remove(c => c.EmailSetup);
transact.Set(c => c.EmailSetup.SystemProviderName, clientName);
transact.Set(c => c.EmailSetup.ProviderType, EmailProviderType.System);
transact.Commit();
return true;
}
private bool ChooseThunderbird()
{
var transact = _config.User.BeginTransaction();
transact.Remove(c => c.EmailSetup);
transact.Set(c => c.EmailSetup.ProviderType, EmailProviderType.Thunderbird);
transact.Commit();
return true;
}
private bool ChooseOauth(OauthProvider provider)
{
var authForm = _formFactory.Create<AuthorizeForm>();
authForm.OauthProvider = provider;
authForm.ShowModal();
return authForm.Result;
}
}

View File

@ -0,0 +1,12 @@
using Eto.Drawing;
namespace NAPS2.ImportExport.Email;
public class EmailProviderWidget
{
public required EmailProviderType ProviderType { get; init; }
public required Bitmap ProviderIcon { get; init; }
public required string ProviderName { get; init; }
public required Func<bool> Choose { get; init; }
public bool Enabled { get; set; } = true;
}