@@ -1,91 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.AppCenter.Crashes;
|
||||
using Serilog;
|
||||
using Wino.Core;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Entities;
|
||||
using Wino.Core.Domain.Entities.Mail;
|
||||
using Wino.Core.Domain.Entities.Shared;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Exceptions;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.Navigation;
|
||||
using Wino.Core.Domain.Models.Store;
|
||||
using Wino.Core.Domain.Models.Synchronization;
|
||||
using Wino.Core.ViewModels;
|
||||
using Wino.Core.ViewModels.Data;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
using Wino.Messaging.Client.Authorization;
|
||||
using Wino.Messaging.Client.Navigation;
|
||||
using Wino.Messaging.Server;
|
||||
using Wino.Messaging.UI;
|
||||
|
||||
namespace Wino.Mail.ViewModels
|
||||
{
|
||||
public partial class AccountManagementViewModel : BaseViewModel, IRecipient<ProtocolAuthorizationCallbackReceived>
|
||||
public partial class AccountManagementViewModel : AccountManagementPageViewModelBase
|
||||
{
|
||||
public int FREE_ACCOUNT_COUNT { get; } = 3;
|
||||
public IMailDialogService MailDialogService { get; }
|
||||
|
||||
private readonly IDialogService _dialogService;
|
||||
private readonly IAccountService _accountService;
|
||||
private readonly IProviderService _providerService;
|
||||
private readonly IFolderService _folderService;
|
||||
private readonly IStoreManagementService _storeManagementService;
|
||||
private readonly IPreferencesService _preferencesService;
|
||||
private readonly IAuthenticationProvider _authenticationProvider;
|
||||
private readonly IWinoServerConnectionManager _winoServerConnectionManager;
|
||||
|
||||
public ObservableCollection<IAccountProviderDetailViewModel> Accounts { get; set; } = [];
|
||||
|
||||
public bool IsPurchasePanelVisible => !HasUnlimitedAccountProduct;
|
||||
public bool IsAccountCreationAlmostOnLimit => Accounts != null && Accounts.Count == FREE_ACCOUNT_COUNT - 1;
|
||||
public bool HasAccountsDefined => Accounts != null && Accounts.Any();
|
||||
public bool CanReorderAccounts => Accounts?.Sum(a => a.HoldingAccountCount) > 1;
|
||||
|
||||
public string UsedAccountsString => string.Format(Translator.WinoUpgradeRemainingAccountsMessage, Accounts.Count, FREE_ACCOUNT_COUNT);
|
||||
|
||||
[ObservableProperty]
|
||||
private IAccountProviderDetailViewModel _startupAccount;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(IsPurchasePanelVisible))]
|
||||
private bool hasUnlimitedAccountProduct;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(IsAccountCreationAlmostOnLimit))]
|
||||
[NotifyPropertyChangedFor(nameof(IsPurchasePanelVisible))]
|
||||
private bool isAccountCreationBlocked;
|
||||
|
||||
public AccountManagementViewModel(IDialogService dialogService,
|
||||
IWinoNavigationService navigationService,
|
||||
public AccountManagementViewModel(IMailDialogService dialogService,
|
||||
IWinoServerConnectionManager winoServerConnectionManager,
|
||||
INavigationService navigationService,
|
||||
IAccountService accountService,
|
||||
IProviderService providerService,
|
||||
IFolderService folderService,
|
||||
IStoreManagementService storeManagementService,
|
||||
IPreferencesService preferencesService,
|
||||
IAuthenticationProvider authenticationProvider,
|
||||
IWinoServerConnectionManager winoServerConnectionManager) : base(dialogService)
|
||||
IPreferencesService preferencesService) : base(dialogService, winoServerConnectionManager, navigationService, accountService, providerService, storeManagementService, authenticationProvider, preferencesService)
|
||||
{
|
||||
_accountService = accountService;
|
||||
_dialogService = dialogService;
|
||||
_providerService = providerService;
|
||||
_folderService = folderService;
|
||||
_storeManagementService = storeManagementService;
|
||||
_preferencesService = preferencesService;
|
||||
_authenticationProvider = authenticationProvider;
|
||||
_winoServerConnectionManager = winoServerConnectionManager;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void NavigateAccountDetails(AccountProviderDetailViewModel accountDetails)
|
||||
{
|
||||
Messenger.Send(new BreadcrumbNavigationRequested(accountDetails.Account.Name,
|
||||
WinoPage.AccountDetailsPage,
|
||||
accountDetails.Account.Id));
|
||||
MailDialogService = dialogService;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
@@ -109,23 +62,7 @@ namespace Wino.Mail.ViewModels
|
||||
mergedAccountProviderDetailViewModel));
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task PurchaseUnlimitedAccountAsync()
|
||||
{
|
||||
var purchaseResult = await _storeManagementService.PurchaseAsync(StoreProductType.UnlimitedAccounts);
|
||||
|
||||
if (purchaseResult == StorePurchaseResult.Succeeded)
|
||||
DialogService.InfoBarMessage(Translator.Info_PurchaseThankYouTitle, Translator.Info_PurchaseThankYouMessage, InfoBarMessageType.Success);
|
||||
else if (purchaseResult == StorePurchaseResult.AlreadyPurchased)
|
||||
DialogService.InfoBarMessage(Translator.Info_PurchaseExistsTitle, Translator.Info_PurchaseExistsMessage, InfoBarMessageType.Warning);
|
||||
|
||||
bool shouldRefreshPurchasePanel = purchaseResult == StorePurchaseResult.Succeeded || purchaseResult == StorePurchaseResult.AlreadyPurchased;
|
||||
|
||||
if (shouldRefreshPurchasePanel)
|
||||
{
|
||||
await ManageStorePurchasesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task AddNewAccountAsync()
|
||||
@@ -146,16 +83,16 @@ namespace Wino.Mail.ViewModels
|
||||
|
||||
try
|
||||
{
|
||||
var providers = _providerService.GetProviderDetails();
|
||||
var providers = ProviderService.GetProviderDetails();
|
||||
|
||||
// Select provider.
|
||||
var accountCreationDialogResult = await _dialogService.ShowNewAccountMailProviderDialogAsync(providers);
|
||||
var accountCreationDialogResult = await MailDialogService.ShowNewAccountMailProviderDialogAsync(providers);
|
||||
|
||||
var accountCreationCancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
if (accountCreationDialogResult != null)
|
||||
{
|
||||
creationDialog = _dialogService.GetAccountCreationDialog(accountCreationDialogResult.ProviderType);
|
||||
creationDialog = MailDialogService.GetAccountCreationDialog(accountCreationDialogResult.ProviderType);
|
||||
|
||||
CustomServerInformation customServerInformation = null;
|
||||
|
||||
@@ -194,7 +131,7 @@ namespace Wino.Mail.ViewModels
|
||||
{
|
||||
// For OAuth authentications, we just generate token and assign it to the MailAccount.
|
||||
|
||||
var tokenInformationResponse = await _winoServerConnectionManager
|
||||
var tokenInformationResponse = await WinoServerConnectionManager
|
||||
.GetResponseAsync<TokenInformation, AuthorizationRequested>(new AuthorizationRequested(accountCreationDialogResult.ProviderType,
|
||||
createdAccount,
|
||||
createdAccount.ProviderType == MailProviderType.Gmail), accountCreationCancellationTokenSource.Token);
|
||||
@@ -209,7 +146,7 @@ namespace Wino.Mail.ViewModels
|
||||
tokenInformation.AccountId = createdAccount.Id;
|
||||
}
|
||||
|
||||
await _accountService.CreateAccountAsync(createdAccount, tokenInformation, customServerInformation);
|
||||
await AccountService.CreateAccountAsync(createdAccount, tokenInformation, customServerInformation);
|
||||
|
||||
// Local account has been created.
|
||||
|
||||
@@ -225,7 +162,7 @@ namespace Wino.Mail.ViewModels
|
||||
Type = SynchronizationType.UpdateProfile
|
||||
};
|
||||
|
||||
var profileSynchronizationResponse = await _winoServerConnectionManager.GetResponseAsync<SynchronizationResult, NewSynchronizationRequested>(new NewSynchronizationRequested(profileSyncOptions, SynchronizationSource.Client));
|
||||
var profileSynchronizationResponse = await WinoServerConnectionManager.GetResponseAsync<SynchronizationResult, NewSynchronizationRequested>(new NewSynchronizationRequested(profileSyncOptions, SynchronizationSource.Client));
|
||||
|
||||
var profileSynchronizationResult = profileSynchronizationResponse.Data;
|
||||
|
||||
@@ -235,7 +172,7 @@ namespace Wino.Mail.ViewModels
|
||||
createdAccount.SenderName = profileSynchronizationResult.ProfileInformation.SenderName;
|
||||
createdAccount.Base64ProfilePictureData = profileSynchronizationResult.ProfileInformation.Base64ProfilePictureData;
|
||||
|
||||
await _accountService.UpdateProfileInformationAsync(createdAccount.Id, profileSynchronizationResult.ProfileInformation);
|
||||
await AccountService.UpdateProfileInformationAsync(createdAccount.Id, profileSynchronizationResult.ProfileInformation);
|
||||
}
|
||||
|
||||
if (creationDialog is ICustomServerAccountCreationDialog customServerAccountCreationDialog)
|
||||
@@ -250,7 +187,7 @@ namespace Wino.Mail.ViewModels
|
||||
Type = SynchronizationType.FoldersOnly
|
||||
};
|
||||
|
||||
var folderSynchronizationResponse = await _winoServerConnectionManager.GetResponseAsync<SynchronizationResult, NewSynchronizationRequested>(new NewSynchronizationRequested(folderSyncOptions, SynchronizationSource.Client));
|
||||
var folderSynchronizationResponse = await WinoServerConnectionManager.GetResponseAsync<SynchronizationResult, NewSynchronizationRequested>(new NewSynchronizationRequested(folderSyncOptions, SynchronizationSource.Client));
|
||||
|
||||
var folderSynchronizationResult = folderSynchronizationResponse.Data;
|
||||
|
||||
@@ -268,7 +205,7 @@ namespace Wino.Mail.ViewModels
|
||||
Type = SynchronizationType.Alias
|
||||
};
|
||||
|
||||
var aliasSyncResponse = await _winoServerConnectionManager.GetResponseAsync<SynchronizationResult, NewSynchronizationRequested>(new NewSynchronizationRequested(aliasSyncOptions, SynchronizationSource.Client));
|
||||
var aliasSyncResponse = await WinoServerConnectionManager.GetResponseAsync<SynchronizationResult, NewSynchronizationRequested>(new NewSynchronizationRequested(aliasSyncOptions, SynchronizationSource.Client));
|
||||
var aliasSynchronizationResult = folderSynchronizationResponse.Data;
|
||||
|
||||
if (aliasSynchronizationResult.CompletedState != SynchronizationCompletedState.Success)
|
||||
@@ -279,7 +216,7 @@ namespace Wino.Mail.ViewModels
|
||||
// Create root primary alias for the account.
|
||||
// This is only available for accounts that do not support alias synchronization.
|
||||
|
||||
await _accountService.CreateRootAliasAsync(createdAccount.Id, createdAccount.Address);
|
||||
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.
|
||||
@@ -294,7 +231,7 @@ namespace Wino.Mail.ViewModels
|
||||
ReportUIChange(new AccountCreatedMessage(createdAccount));
|
||||
|
||||
// Notify success.
|
||||
_dialogService.InfoBarMessage(Translator.Info_AccountCreatedTitle, string.Format(Translator.Info_AccountCreatedMessage, createdAccount.Address), InfoBarMessageType.Success);
|
||||
DialogService.InfoBarMessage(Translator.Info_AccountCreatedTitle, string.Format(Translator.Info_AccountCreatedMessage, createdAccount.Address), InfoBarMessageType.Success);
|
||||
}
|
||||
}
|
||||
catch (AccountSetupCanceledException)
|
||||
@@ -310,12 +247,12 @@ namespace Wino.Mail.ViewModels
|
||||
Log.Error(ex, WinoErrors.AccountCreation);
|
||||
Crashes.TrackError(ex);
|
||||
|
||||
_dialogService.InfoBarMessage(Translator.Info_AccountCreationFailedTitle, ex.Message, InfoBarMessageType.Error);
|
||||
DialogService.InfoBarMessage(Translator.Info_AccountCreationFailedTitle, ex.Message, InfoBarMessageType.Error);
|
||||
|
||||
// Delete account in case of failure.
|
||||
if (createdAccount != null)
|
||||
{
|
||||
await _accountService.DeleteAccountAsync(createdAccount);
|
||||
await AccountService.DeleteAccountAsync(createdAccount);
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -333,7 +270,7 @@ namespace Wino.Mail.ViewModels
|
||||
}
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanReorderAccounts))]
|
||||
private Task ReorderAccountsAsync() => DialogService.ShowAccountReorderDialogAsync(availableAccounts: Accounts);
|
||||
private Task ReorderAccountsAsync() => MailDialogService.ShowAccountReorderDialogAsync(availableAccounts: Accounts);
|
||||
|
||||
public override void OnNavigatedFrom(NavigationMode mode, object parameters)
|
||||
{
|
||||
@@ -357,7 +294,7 @@ namespace Wino.Mail.ViewModels
|
||||
{
|
||||
if (e.PropertyName == nameof(StartupAccount) && StartupAccount != null)
|
||||
{
|
||||
_preferencesService.StartupEntityId = StartupAccount.StartupEntityId;
|
||||
PreferencesService.StartupEntityId = StartupAccount.StartupEntityId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,13 +311,13 @@ namespace Wino.Mail.ViewModels
|
||||
PropertyChanged += PagePropertyChanged;
|
||||
}
|
||||
|
||||
private async Task InitializeAccountsAsync()
|
||||
public override async Task InitializeAccountsAsync()
|
||||
{
|
||||
StartupAccount = null;
|
||||
|
||||
Accounts.Clear();
|
||||
|
||||
var accounts = await _accountService.GetAccountsAsync().ConfigureAwait(false);
|
||||
var accounts = await AccountService.GetAccountsAsync().ConfigureAwait(false);
|
||||
|
||||
// Group accounts and display merged ones at the top.
|
||||
var groupedAccounts = accounts.GroupBy(a => a.MergedInboxId);
|
||||
@@ -412,40 +349,14 @@ namespace Wino.Mail.ViewModels
|
||||
}
|
||||
|
||||
// Handle startup entity.
|
||||
if (_preferencesService.StartupEntityId != null)
|
||||
if (PreferencesService.StartupEntityId != null)
|
||||
{
|
||||
StartupAccount = Accounts.FirstOrDefault(a => a.StartupEntityId == _preferencesService.StartupEntityId);
|
||||
StartupAccount = Accounts.FirstOrDefault(a => a.StartupEntityId == PreferencesService.StartupEntityId);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
await ManageStorePurchasesAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task ManageStorePurchasesAsync()
|
||||
{
|
||||
await ExecuteUIThread(async () =>
|
||||
{
|
||||
HasUnlimitedAccountProduct = await _storeManagementService.HasProductAsync(StoreProductType.UnlimitedAccounts);
|
||||
|
||||
if (!HasUnlimitedAccountProduct)
|
||||
IsAccountCreationBlocked = Accounts.Sum(a => a.HoldingAccountCount) >= FREE_ACCOUNT_COUNT;
|
||||
else
|
||||
IsAccountCreationBlocked = false;
|
||||
});
|
||||
}
|
||||
|
||||
private AccountProviderDetailViewModel GetAccountProviderDetails(MailAccount account)
|
||||
{
|
||||
var provider = _providerService.GetProviderDetail(account.ProviderType);
|
||||
|
||||
return new AccountProviderDetailViewModel(provider, account);
|
||||
}
|
||||
|
||||
public async void Receive(ProtocolAuthorizationCallbackReceived message)
|
||||
{
|
||||
// Authorization must be completed in the server.
|
||||
await _winoServerConnectionManager.GetResponseAsync<bool, ProtocolAuthorizationCallbackReceived>(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user