IMAP Improvements (#558)
* Fixing an issue where scrollviewer overrides a part of template in mail list. Adjusted zoomed out header grid's corner radius. * IDLE implementation, imap synchronization strategies basics and condstore synchronization. * Adding iCloud and Yahoo as special IMAP handling scenario. * iCloud special imap handling. * Support for killing synchronizers. * Update privacy policy url. * Batching condstore downloads into 50, using SORT extension for searches if supported. * Bumping some nugets. More on the imap synchronizers. * Delegating idle synchronizations to server to post-sync operations. * Update mailkit to resolve qresync bug with iCloud. * Fixing remote highest mode seq checks for qresync and condstore synchronizers. * Yahoo custom settings. * Bump google sdk package. * Fixing the build issue.... * NRE on canceled token accounts during setup. * Server crash handlers. * Remove ARM32. Upgrade server to .NET 9. * Fix icons for yahoo and apple. * Fixed an issue where disabled folders causing an exception on forced sync. * Remove smtp encoding constraint. * Remove commented code. * Fixing merge conflict * Addressing double registrations for mailkit remote folder events in synchronizers. * Making sure idle canceled result is not reported. * Fixing custom imap server dialog opening. * Fixing the issue with account creation making the previously selected account as selected as well. * Fixing app close behavior and logging app close.
This commit is contained in:
@@ -12,6 +12,7 @@ using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.Folders;
|
||||
using Wino.Core.Domain.Models.Navigation;
|
||||
using Wino.Messaging.Client.Navigation;
|
||||
using Wino.Messaging.Server;
|
||||
using Wino.Messaging.UI;
|
||||
|
||||
namespace Wino.Mail.ViewModels
|
||||
@@ -20,6 +21,7 @@ namespace Wino.Mail.ViewModels
|
||||
{
|
||||
private readonly IMailDialogService _dialogService;
|
||||
private readonly IAccountService _accountService;
|
||||
private readonly IWinoServerConnectionManager _serverConnectionManager;
|
||||
private readonly IFolderService _folderService;
|
||||
|
||||
public MailAccount Account { get; set; }
|
||||
@@ -48,10 +50,12 @@ namespace Wino.Mail.ViewModels
|
||||
|
||||
public AccountDetailsPageViewModel(IMailDialogService dialogService,
|
||||
IAccountService accountService,
|
||||
IWinoServerConnectionManager serverConnectionManager,
|
||||
IFolderService folderService)
|
||||
{
|
||||
_dialogService = dialogService;
|
||||
_accountService = accountService;
|
||||
_serverConnectionManager = serverConnectionManager;
|
||||
_folderService = folderService;
|
||||
}
|
||||
|
||||
@@ -102,13 +106,17 @@ namespace Wino.Mail.ViewModels
|
||||
if (!confirmation)
|
||||
return;
|
||||
|
||||
await _accountService.DeleteAccountAsync(Account);
|
||||
|
||||
// TODO: Server: Cancel ongoing calls from server for this account.
|
||||
var isSynchronizerKilledResponse = await _serverConnectionManager.GetResponseAsync<bool, KillAccountSynchronizerRequested>(new KillAccountSynchronizerRequested(Account.Id));
|
||||
|
||||
_dialogService.InfoBarMessage(Translator.Info_AccountDeletedTitle, string.Format(Translator.Info_AccountDeletedMessage, Account.Name), InfoBarMessageType.Success);
|
||||
if (isSynchronizerKilledResponse.IsSuccess)
|
||||
{
|
||||
await _accountService.DeleteAccountAsync(Account);
|
||||
|
||||
Messenger.Send(new BackBreadcrumNavigationRequested());
|
||||
_dialogService.InfoBarMessage(Translator.Info_AccountDeletedTitle, string.Format(Translator.Info_AccountDeletedMessage, Account.Name), InfoBarMessageType.Success);
|
||||
|
||||
Messenger.Send(new BackBreadcrumNavigationRequested());
|
||||
}
|
||||
}
|
||||
|
||||
public override async void OnNavigatedTo(NavigationMode mode, object parameters)
|
||||
|
||||
@@ -28,18 +28,25 @@ namespace Wino.Mail.ViewModels
|
||||
{
|
||||
public partial class AccountManagementViewModel : AccountManagementPageViewModelBase
|
||||
{
|
||||
private readonly ISpecialImapProviderConfigResolver _specialImapProviderConfigResolver;
|
||||
private readonly IImapTestService _imapTestService;
|
||||
|
||||
public IMailDialogService MailDialogService { get; }
|
||||
|
||||
public AccountManagementViewModel(IMailDialogService dialogService,
|
||||
IWinoServerConnectionManager winoServerConnectionManager,
|
||||
INavigationService navigationService,
|
||||
IAccountService accountService,
|
||||
ISpecialImapProviderConfigResolver specialImapProviderConfigResolver,
|
||||
IProviderService providerService,
|
||||
IImapTestService imapTestService,
|
||||
IStoreManagementService storeManagementService,
|
||||
IAuthenticationProvider authenticationProvider,
|
||||
IPreferencesService preferencesService) : base(dialogService, winoServerConnectionManager, navigationService, accountService, providerService, storeManagementService, authenticationProvider, preferencesService)
|
||||
{
|
||||
MailDialogService = dialogService;
|
||||
_specialImapProviderConfigResolver = specialImapProviderConfigResolver;
|
||||
_imapTestService = imapTestService;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
@@ -93,7 +100,7 @@ namespace Wino.Mail.ViewModels
|
||||
|
||||
if (accountCreationDialogResult != null)
|
||||
{
|
||||
creationDialog = MailDialogService.GetAccountCreationDialog(accountCreationDialogResult.ProviderType);
|
||||
creationDialog = MailDialogService.GetAccountCreationDialog(accountCreationDialogResult);
|
||||
|
||||
CustomServerInformation customServerInformation = null;
|
||||
|
||||
@@ -101,17 +108,17 @@ namespace Wino.Mail.ViewModels
|
||||
{
|
||||
ProviderType = accountCreationDialogResult.ProviderType,
|
||||
Name = accountCreationDialogResult.AccountName,
|
||||
AccountColorHex = accountCreationDialogResult.AccountColorHex,
|
||||
SpecialImapProvider = accountCreationDialogResult.SpecialImapProviderDetails?.SpecialImapProvider ?? SpecialImapProvider.None,
|
||||
Id = Guid.NewGuid()
|
||||
};
|
||||
|
||||
creationDialog.ShowDialog(accountCreationCancellationTokenSource);
|
||||
await creationDialog.ShowDialogAsync(accountCreationCancellationTokenSource);
|
||||
creationDialog.State = AccountCreationDialogState.SigningIn;
|
||||
|
||||
string tokenInformation = string.Empty;
|
||||
|
||||
// Custom server implementation requires more async waiting.
|
||||
if (creationDialog is ICustomServerAccountCreationDialog customServerDialog)
|
||||
if (creationDialog is IImapAccountCreationDialog customServerDialog)
|
||||
{
|
||||
// Pass along the account properties and perform initial navigation on the imap frame.
|
||||
customServerDialog.StartImapConnectionSetup(createdAccount);
|
||||
@@ -130,20 +137,39 @@ namespace Wino.Mail.ViewModels
|
||||
}
|
||||
else
|
||||
{
|
||||
// OAuth authentication is handled here.
|
||||
// Server authenticates, returns the token info here.
|
||||
// Hanle special imap providers like iCloud and Yahoo.
|
||||
if (accountCreationDialogResult.SpecialImapProviderDetails != null)
|
||||
{
|
||||
// Special imap provider testing dialog. This is only available for iCloud and Yahoo.
|
||||
customServerInformation = _specialImapProviderConfigResolver.GetServerInformation(createdAccount, accountCreationDialogResult);
|
||||
customServerInformation.Id = Guid.NewGuid();
|
||||
customServerInformation.AccountId = createdAccount.Id;
|
||||
|
||||
var tokenInformationResponse = await WinoServerConnectionManager
|
||||
.GetResponseAsync<TokenInformationEx, AuthorizationRequested>(new AuthorizationRequested(accountCreationDialogResult.ProviderType,
|
||||
createdAccount,
|
||||
createdAccount.ProviderType == MailProviderType.Gmail), accountCreationCancellationTokenSource.Token);
|
||||
createdAccount.SenderName = accountCreationDialogResult.SpecialImapProviderDetails.SenderName;
|
||||
createdAccount.Address = customServerInformation.Address;
|
||||
|
||||
if (creationDialog.State == AccountCreationDialogState.Canceled)
|
||||
throw new AccountSetupCanceledException();
|
||||
await _imapTestService.TestImapConnectionAsync(customServerInformation, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// OAuth authentication is handled here.
|
||||
// Server authenticates, returns the token info here.
|
||||
|
||||
createdAccount.Address = tokenInformationResponse.Data.AccountAddress;
|
||||
var tokenInformationResponse = await WinoServerConnectionManager
|
||||
.GetResponseAsync<TokenInformationEx, AuthorizationRequested>(new AuthorizationRequested(accountCreationDialogResult.ProviderType,
|
||||
createdAccount,
|
||||
createdAccount.ProviderType == MailProviderType.Gmail), accountCreationCancellationTokenSource.Token);
|
||||
|
||||
tokenInformationResponse.ThrowIfFailed();
|
||||
if (creationDialog.State == AccountCreationDialogState.Canceled)
|
||||
throw new AccountSetupCanceledException();
|
||||
|
||||
if (!tokenInformationResponse.IsSuccess)
|
||||
throw new Exception(tokenInformationResponse.Message);
|
||||
|
||||
createdAccount.Address = tokenInformationResponse.Data.AccountAddress;
|
||||
|
||||
tokenInformationResponse.ThrowIfFailed();
|
||||
}
|
||||
}
|
||||
|
||||
// Address is still doesn't have a value for API synchronizers.
|
||||
@@ -183,7 +209,7 @@ namespace Wino.Mail.ViewModels
|
||||
await AccountService.UpdateProfileInformationAsync(createdAccount.Id, profileSynchronizationResult.ProfileInformation);
|
||||
}
|
||||
|
||||
if (creationDialog is ICustomServerAccountCreationDialog customServerAccountCreationDialog)
|
||||
if (creationDialog is IImapAccountCreationDialog customServerAccountCreationDialog)
|
||||
customServerAccountCreationDialog.ShowPreparingFolders();
|
||||
else
|
||||
creationDialog.State = AccountCreationDialogState.PreparingFolders;
|
||||
@@ -227,14 +253,6 @@ namespace Wino.Mail.ViewModels
|
||||
await AccountService.CreateRootAliasAsync(createdAccount.Id, createdAccount.Address);
|
||||
}
|
||||
|
||||
// TODO: Temporary disabled. Is this even needed? Users can configure special folders manually later on if discovery fails.
|
||||
// Check if Inbox folder is available for the account after synchronization.
|
||||
|
||||
//var isInboxAvailable = await _folderService.IsInboxAvailableForAccountAsync(createdAccount.Id);
|
||||
|
||||
//if (!isInboxAvailable)
|
||||
// throw new Exception(Translator.Exception_InboxNotAvailable);
|
||||
|
||||
// Send changes to listeners.
|
||||
ReportUIChange(new AccountCreatedMessage(createdAccount));
|
||||
|
||||
@@ -250,6 +268,10 @@ namespace Wino.Mail.ViewModels
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
catch (ImapClientPoolException clientPoolException)
|
||||
{
|
||||
DialogService.InfoBarMessage(Translator.Info_AccountCreationFailedTitle, clientPoolException.InnerException.Message, InfoBarMessageType.Error);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, WinoErrors.AccountCreation);
|
||||
|
||||
@@ -243,7 +243,9 @@ namespace Wino.Mail.ViewModels
|
||||
await RecreateMenuItemsAsync();
|
||||
await ProcessLaunchOptionsAsync();
|
||||
|
||||
#if !DEBUG
|
||||
await ForceAllAccountSynchronizationsAsync();
|
||||
#endif
|
||||
await MakeSureEnableStartupLaunchAsync();
|
||||
await ConfigureBackgroundTasksAsync();
|
||||
}
|
||||
@@ -878,6 +880,8 @@ namespace Wino.Mail.ViewModels
|
||||
|
||||
protected override async void OnAccountCreated(MailAccount createdAccount)
|
||||
{
|
||||
latestSelectedAccountMenuItem = null;
|
||||
|
||||
await RecreateMenuItemsAsync();
|
||||
|
||||
if (!MenuItems.TryGetAccountMenuItem(createdAccount.Id, out IAccountMenuItem createdMenuItem)) return;
|
||||
|
||||
Reference in New Issue
Block a user