Ground work for Wino Calendar. (#475)

Wino Calendar abstractions.
This commit is contained in:
Burak Kaan Köse
2024-11-10 23:28:25 +01:00
committed by GitHub
parent a979e8430f
commit d1d6f12f05
486 changed files with 7969 additions and 2708 deletions

View File

@@ -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);
}
}
}