Couple fixes for beta.
This commit is contained in:
@@ -23,6 +23,20 @@ public interface IAccountService
|
|||||||
/// <returns>All local accounts</returns>
|
/// <returns>All local accounts</returns>
|
||||||
Task<List<MailAccount>> GetAccountsAsync();
|
Task<List<MailAccount>> GetAccountsAsync();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks whether an account with the same display name already exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Account display name.</param>
|
||||||
|
/// <param name="excludedAccountId">Optional account id to exclude from the check.</param>
|
||||||
|
Task<bool> AccountNameExistsAsync(string name, Guid? excludedAccountId = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks whether an account with the same primary address already exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="address">Primary e-mail address.</param>
|
||||||
|
/// <param name="excludedAccountId">Optional account id to exclude from the check.</param>
|
||||||
|
Task<bool> AccountAddressExistsAsync(string address, Guid? excludedAccountId = null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns single MailAccount
|
/// Returns single MailAccount
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -274,10 +274,13 @@
|
|||||||
"Dialog_DontAskAgain": "Don't ask again",
|
"Dialog_DontAskAgain": "Don't ask again",
|
||||||
"DialogMessage_AccountLimitMessage": "You have reached the account creation limit.\nWould you like to purchase 'Unlimited Account' add-on to continue?",
|
"DialogMessage_AccountLimitMessage": "You have reached the account creation limit.\nWould you like to purchase 'Unlimited Account' add-on to continue?",
|
||||||
"DialogMessage_AccountLimitTitle": "Account Limit Reached",
|
"DialogMessage_AccountLimitTitle": "Account Limit Reached",
|
||||||
|
"DialogMessage_AccountAddressExistsMessage": "An account with the same e-mail address already exists.",
|
||||||
|
"DialogMessage_AccountExistsTitle": "Existing Account",
|
||||||
"DialogMessage_AliasCreatedMessage": "New alias is succesfully created.",
|
"DialogMessage_AliasCreatedMessage": "New alias is succesfully created.",
|
||||||
"DialogMessage_AliasCreatedTitle": "Created New Alias",
|
"DialogMessage_AliasCreatedTitle": "Created New Alias",
|
||||||
"DialogMessage_AliasExistsMessage": "This alias is already in use.",
|
"DialogMessage_AliasExistsMessage": "This alias is already in use.",
|
||||||
"DialogMessage_AliasExistsTitle": "Existing Alias",
|
"DialogMessage_AliasExistsTitle": "Existing Alias",
|
||||||
|
"DialogMessage_AccountNameExistsMessage": "An account with the same name already exists.",
|
||||||
"DialogMessage_AliasNotSelectedMessage": "You must select an alias before sending a message.",
|
"DialogMessage_AliasNotSelectedMessage": "You must select an alias before sending a message.",
|
||||||
"DialogMessage_AliasNotSelectedTitle": "Missing Alias",
|
"DialogMessage_AliasNotSelectedTitle": "Missing Alias",
|
||||||
"DialogMessage_CantDeleteRootAliasMessage": "Root alias can't be deleted. This is your main identity associated with your account setup.",
|
"DialogMessage_CantDeleteRootAliasMessage": "Root alias can't be deleted. This is your main identity associated with your account setup.",
|
||||||
@@ -883,6 +886,7 @@
|
|||||||
"SettingsMailCategories_Title": "Categories",
|
"SettingsMailCategories_Title": "Categories",
|
||||||
"SettingsEditAccountDetails_Title": "Edit Account Details",
|
"SettingsEditAccountDetails_Title": "Edit Account Details",
|
||||||
"SettingsEditAccountDetails_Description": "Change account name, sender name and assign a new color if you like.",
|
"SettingsEditAccountDetails_Description": "Change account name, sender name and assign a new color if you like.",
|
||||||
|
"SettingsAccountDetails_NavigationTitle": "{0} details",
|
||||||
"EditAccountDetailsPage_SaveSuccess_Title": "Changes Saved",
|
"EditAccountDetailsPage_SaveSuccess_Title": "Changes Saved",
|
||||||
"EditAccountDetailsPage_SaveSuccess_Message": "Your account details have been updated successfully.",
|
"EditAccountDetailsPage_SaveSuccess_Message": "Your account details have been updated successfully.",
|
||||||
"MailCategoryManagementPage_Title": "Categories",
|
"MailCategoryManagementPage_Title": "Categories",
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public abstract partial class AccountManagementPageViewModelBase : CoreBaseViewM
|
|||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void NavigateAccountDetails(AccountProviderDetailViewModel accountDetails)
|
private void NavigateAccountDetails(AccountProviderDetailViewModel accountDetails)
|
||||||
{
|
{
|
||||||
Messenger.Send(new BreadcrumbNavigationRequested(accountDetails.Account.Name,
|
Messenger.Send(new BreadcrumbNavigationRequested(GetAccountDetailsTitle(accountDetails.Account),
|
||||||
WinoPage.AccountDetailsPage,
|
WinoPage.AccountDetailsPage,
|
||||||
accountDetails.Account.Id));
|
accountDetails.Account.Id));
|
||||||
}
|
}
|
||||||
@@ -131,4 +131,9 @@ public abstract partial class AccountManagementPageViewModelBase : CoreBaseViewM
|
|||||||
{
|
{
|
||||||
OnPropertyChanged(nameof(HasAccountsDefined));
|
OnPropertyChanged(nameof(HasAccountsDefined));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GetAccountDetailsTitle(MailAccount account)
|
||||||
|
=> !string.IsNullOrWhiteSpace(account?.Address)
|
||||||
|
? string.Format(Translator.SettingsAccountDetails_NavigationTitle, account.Address)
|
||||||
|
: account?.Name ?? Translator.AccountDetailsPage_Title;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ public partial class SettingOptionsPageViewModel : CoreBaseViewModel
|
|||||||
switch (account)
|
switch (account)
|
||||||
{
|
{
|
||||||
case AccountProviderDetailViewModel accountDetails:
|
case AccountProviderDetailViewModel accountDetails:
|
||||||
Messenger.Send(new BreadcrumbNavigationRequested(accountDetails.Account.Name, WinoPage.AccountDetailsPage, accountDetails.Account.Id));
|
Messenger.Send(new BreadcrumbNavigationRequested(GetAccountDetailsTitle(accountDetails.Account), WinoPage.AccountDetailsPage, accountDetails.Account.Id));
|
||||||
break;
|
break;
|
||||||
case MergedAccountProviderDetailViewModel mergedAccount:
|
case MergedAccountProviderDetailViewModel mergedAccount:
|
||||||
Messenger.Send(new BreadcrumbNavigationRequested(mergedAccount.MergedInbox.Name, WinoPage.MergedAccountDetailsPage, mergedAccount));
|
Messenger.Send(new BreadcrumbNavigationRequested(mergedAccount.MergedInbox.Name, WinoPage.MergedAccountDetailsPage, mergedAccount));
|
||||||
@@ -201,6 +201,11 @@ public partial class SettingOptionsPageViewModel : CoreBaseViewModel
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GetAccountDetailsTitle(MailAccount account)
|
||||||
|
=> !string.IsNullOrWhiteSpace(account?.Address)
|
||||||
|
? string.Format(Translator.SettingsAccountDetails_NavigationTitle, account.Address)
|
||||||
|
: account?.Name ?? Translator.AccountDetailsPage_Title;
|
||||||
|
|
||||||
private void InitializeQuickSettings()
|
private void InitializeQuickSettings()
|
||||||
{
|
{
|
||||||
_isInitializingSettings = true;
|
_isInitializingSettings = true;
|
||||||
|
|||||||
@@ -220,7 +220,12 @@ public partial class AccountSetupProgressPageViewModel : MailBaseViewModel
|
|||||||
_createdAccount.Base64ProfilePictureData = profileResult.ProfileInformation.Base64ProfilePictureData;
|
_createdAccount.Base64ProfilePictureData = profileResult.ProfileInformation.Base64ProfilePictureData;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(profileResult.ProfileInformation.AccountAddress))
|
if (!string.IsNullOrEmpty(profileResult.ProfileInformation.AccountAddress))
|
||||||
|
{
|
||||||
|
if (await _accountService.AccountAddressExistsAsync(profileResult.ProfileInformation.AccountAddress, _createdAccount.Id).ConfigureAwait(false))
|
||||||
|
throw new InvalidOperationException(Translator.DialogMessage_AccountAddressExistsMessage);
|
||||||
|
|
||||||
_createdAccount.Address = profileResult.ProfileInformation.AccountAddress;
|
_createdAccount.Address = profileResult.ProfileInformation.AccountAddress;
|
||||||
|
}
|
||||||
|
|
||||||
await _accountService.UpdateProfileInformationAsync(_createdAccount.Id, profileResult.ProfileInformation);
|
await _accountService.UpdateProfileInformationAsync(_createdAccount.Id, profileResult.ProfileInformation);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ public partial class ImapCalDavSettingsPageViewModel : MailBaseViewModel
|
|||||||
private Guid _editingAccountId;
|
private Guid _editingAccountId;
|
||||||
private SpecialImapProvider _editingSpecialImapProvider;
|
private SpecialImapProvider _editingSpecialImapProvider;
|
||||||
private TaskCompletionSource<ImapCalDavSetupResult> _completionSource;
|
private TaskCompletionSource<ImapCalDavSetupResult> _completionSource;
|
||||||
|
private AccountCreationDialogResult _accountCreationContext;
|
||||||
private bool _isCompletionFinalized;
|
private bool _isCompletionFinalized;
|
||||||
private bool _localOnlyInfoShown;
|
private bool _localOnlyInfoShown;
|
||||||
|
|
||||||
@@ -283,6 +284,7 @@ public partial class ImapCalDavSettingsPageViewModel : MailBaseViewModel
|
|||||||
_pageMode = context.Mode;
|
_pageMode = context.Mode;
|
||||||
_editingAccountId = context.AccountId;
|
_editingAccountId = context.AccountId;
|
||||||
_completionSource = context.CompletionSource;
|
_completionSource = context.CompletionSource;
|
||||||
|
_accountCreationContext = context.AccountCreationDialogResult;
|
||||||
_isCompletionFinalized = false;
|
_isCompletionFinalized = false;
|
||||||
_localOnlyInfoShown = false;
|
_localOnlyInfoShown = false;
|
||||||
SelectedSetupTabIndex = 0;
|
SelectedSetupTabIndex = 0;
|
||||||
@@ -406,6 +408,13 @@ public partial class ImapCalDavSettingsPageViewModel : MailBaseViewModel
|
|||||||
ValidateImapSettings(serverInformation);
|
ValidateImapSettings(serverInformation);
|
||||||
ValidateCalendarModeSpecificSettings(serverInformation);
|
ValidateCalendarModeSpecificSettings(serverInformation);
|
||||||
|
|
||||||
|
var excludedAccountId = _pageMode == ImapCalDavSettingsPageMode.Edit
|
||||||
|
? _editingAccountId
|
||||||
|
: (Guid?)null;
|
||||||
|
|
||||||
|
if (!await ValidateAccountUniquenessAsync(excludedAccountId).ConfigureAwait(false))
|
||||||
|
return;
|
||||||
|
|
||||||
await ValidateImapConnectivityAsync(serverInformation);
|
await ValidateImapConnectivityAsync(serverInformation);
|
||||||
IsImapValidationSucceeded = true;
|
IsImapValidationSucceeded = true;
|
||||||
|
|
||||||
@@ -770,6 +779,34 @@ public partial class ImapCalDavSettingsPageViewModel : MailBaseViewModel
|
|||||||
Messenger.Send(new BackBreadcrumNavigationRequested());
|
Messenger.Send(new BackBreadcrumNavigationRequested());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<bool> ValidateAccountUniquenessAsync(Guid? excludedAccountId)
|
||||||
|
{
|
||||||
|
var accountName = (_pageMode == ImapCalDavSettingsPageMode.Create || _pageMode == ImapCalDavSettingsPageMode.Wizard)
|
||||||
|
? _accountCreationContext?.AccountName
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(accountName) &&
|
||||||
|
await _accountService.AccountNameExistsAsync(accountName, excludedAccountId).ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
_mailDialogService.InfoBarMessage(
|
||||||
|
Translator.DialogMessage_AccountExistsTitle,
|
||||||
|
Translator.DialogMessage_AccountNameExistsMessage,
|
||||||
|
InfoBarMessageType.Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await _accountService.AccountAddressExistsAsync(EmailAddress, excludedAccountId).ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
_mailDialogService.InfoBarMessage(
|
||||||
|
Translator.DialogMessage_AccountExistsTitle,
|
||||||
|
Translator.DialogMessage_AccountAddressExistsMessage,
|
||||||
|
InfoBarMessageType.Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task SaveEditFlowAsync(CustomServerInformation serverInformation)
|
private async Task SaveEditFlowAsync(CustomServerInformation serverInformation)
|
||||||
{
|
{
|
||||||
var account = await _accountService.GetAccountAsync(_editingAccountId).ConfigureAwait(false);
|
var account = await _accountService.GetAccountAsync(_editingAccountId).ConfigureAwait(false);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using CommunityToolkit.Mvvm.Messaging;
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
@@ -16,6 +17,8 @@ namespace Wino.Mail.ViewModels;
|
|||||||
|
|
||||||
public partial class ProviderSelectionPageViewModel : MailBaseViewModel
|
public partial class ProviderSelectionPageViewModel : MailBaseViewModel
|
||||||
{
|
{
|
||||||
|
private readonly IAccountService _accountService;
|
||||||
|
private readonly IDialogServiceBase _dialogService;
|
||||||
private readonly IProviderService _providerService;
|
private readonly IProviderService _providerService;
|
||||||
private readonly INewThemeService _themeService;
|
private readonly INewThemeService _themeService;
|
||||||
|
|
||||||
@@ -53,10 +56,14 @@ public partial class ProviderSelectionPageViewModel : MailBaseViewModel
|
|||||||
public bool IsInitialSynchronizationWarningVisible => SelectedInitialSynchronizationRange?.IsEverything == true;
|
public bool IsInitialSynchronizationWarningVisible => SelectedInitialSynchronizationRange?.IsEverything == true;
|
||||||
|
|
||||||
public ProviderSelectionPageViewModel(
|
public ProviderSelectionPageViewModel(
|
||||||
|
IAccountService accountService,
|
||||||
|
IDialogServiceBase dialogService,
|
||||||
IProviderService providerService,
|
IProviderService providerService,
|
||||||
INewThemeService themeService,
|
INewThemeService themeService,
|
||||||
WelcomeWizardContext wizardContext)
|
WelcomeWizardContext wizardContext)
|
||||||
{
|
{
|
||||||
|
_accountService = accountService;
|
||||||
|
_dialogService = dialogService;
|
||||||
_providerService = providerService;
|
_providerService = providerService;
|
||||||
_themeService = themeService;
|
_themeService = themeService;
|
||||||
WizardContext = wizardContext;
|
WizardContext = wizardContext;
|
||||||
@@ -107,10 +114,19 @@ public partial class ProviderSelectionPageViewModel : MailBaseViewModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void Proceed()
|
private async Task ProceedAsync()
|
||||||
{
|
{
|
||||||
if (!CanProceed) return;
|
if (!CanProceed) return;
|
||||||
|
|
||||||
|
if (await _accountService.AccountNameExistsAsync(AccountName).ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
await _dialogService.ShowMessageAsync(
|
||||||
|
Translator.DialogMessage_AccountNameExistsMessage,
|
||||||
|
Translator.DialogMessage_AccountExistsTitle,
|
||||||
|
WinoCustomMessageDialogIcon.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Persist to wizard context
|
// Persist to wizard context
|
||||||
WizardContext.SelectedProvider = SelectedProvider;
|
WizardContext.SelectedProvider = SelectedProvider;
|
||||||
WizardContext.AccountName = AccountName?.Trim();
|
WizardContext.AccountName = AccountName?.Trim();
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ namespace Wino.Mail.ViewModels;
|
|||||||
|
|
||||||
public partial class SpecialImapCredentialsPageViewModel : MailBaseViewModel
|
public partial class SpecialImapCredentialsPageViewModel : MailBaseViewModel
|
||||||
{
|
{
|
||||||
|
private readonly IAccountService _accountService;
|
||||||
|
private readonly IDialogServiceBase _dialogService;
|
||||||
private static readonly Dictionary<SpecialImapProvider, string> AppPasswordHelpLinks = new()
|
private static readonly Dictionary<SpecialImapProvider, string> AppPasswordHelpLinks = new()
|
||||||
{
|
{
|
||||||
{ SpecialImapProvider.iCloud, "https://support.apple.com/en-us/102654" },
|
{ SpecialImapProvider.iCloud, "https://support.apple.com/en-us/102654" },
|
||||||
@@ -56,9 +58,13 @@ public partial class SpecialImapCredentialsPageViewModel : MailBaseViewModel
|
|||||||
: Translator.ProviderSelection_CalendarMode_CalDavDescription_Yahoo;
|
: Translator.ProviderSelection_CalendarMode_CalDavDescription_Yahoo;
|
||||||
|
|
||||||
public SpecialImapCredentialsPageViewModel(
|
public SpecialImapCredentialsPageViewModel(
|
||||||
|
IAccountService accountService,
|
||||||
|
IDialogServiceBase dialogService,
|
||||||
INativeAppService nativeAppService,
|
INativeAppService nativeAppService,
|
||||||
WelcomeWizardContext wizardContext)
|
WelcomeWizardContext wizardContext)
|
||||||
{
|
{
|
||||||
|
_accountService = accountService;
|
||||||
|
_dialogService = dialogService;
|
||||||
_nativeAppService = nativeAppService;
|
_nativeAppService = nativeAppService;
|
||||||
WizardContext = wizardContext;
|
WizardContext = wizardContext;
|
||||||
}
|
}
|
||||||
@@ -98,10 +104,19 @@ public partial class SpecialImapCredentialsPageViewModel : MailBaseViewModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void Proceed()
|
private async Task ProceedAsync()
|
||||||
{
|
{
|
||||||
if (!CanProceed) return;
|
if (!CanProceed) return;
|
||||||
|
|
||||||
|
if (await _accountService.AccountAddressExistsAsync(EmailAddress).ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
await _dialogService.ShowMessageAsync(
|
||||||
|
Translator.DialogMessage_AccountAddressExistsMessage,
|
||||||
|
Translator.DialogMessage_AccountExistsTitle,
|
||||||
|
WinoCustomMessageDialogIcon.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
WizardContext.DisplayName = DisplayName?.Trim();
|
WizardContext.DisplayName = DisplayName?.Trim();
|
||||||
WizardContext.EmailAddress = EmailAddress?.Trim();
|
WizardContext.EmailAddress = EmailAddress?.Trim();
|
||||||
WizardContext.AppSpecificPassword = AppSpecificPassword?.Trim();
|
WizardContext.AppSpecificPassword = AppSpecificPassword?.Trim();
|
||||||
|
|||||||
@@ -127,6 +127,16 @@
|
|||||||
Text="{x:Bind ViewModel.SenderName, Mode=TwoWay}" />
|
Text="{x:Bind ViewModel.SenderName, Mode=TwoWay}" />
|
||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
|
||||||
|
<controls:SettingsCard Header="{x:Bind domain:Translator.IMAPSetupDialog_MailAddress}">
|
||||||
|
<controls:SettingsCard.HeaderIcon>
|
||||||
|
<SymbolIcon Symbol="Mail" />
|
||||||
|
</controls:SettingsCard.HeaderIcon>
|
||||||
|
<TextBox
|
||||||
|
Width="250"
|
||||||
|
IsReadOnly="True"
|
||||||
|
Text="{x:Bind ViewModel.Address, Mode=OneWay}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
|
|
||||||
<controls:SettingsCard
|
<controls:SettingsCard
|
||||||
HorizontalContentAlignment="Stretch"
|
HorizontalContentAlignment="Stretch"
|
||||||
VerticalContentAlignment="Stretch"
|
VerticalContentAlignment="Stretch"
|
||||||
|
|||||||
@@ -22,12 +22,10 @@ using Wino.Core.Domain.Entities.Mail;
|
|||||||
using Wino.Core.Domain.Entities.Shared;
|
using Wino.Core.Domain.Entities.Shared;
|
||||||
using Wino.Core.Domain.Models.Reader;
|
using Wino.Core.Domain.Models.Reader;
|
||||||
using Wino.Mail.ViewModels.Data;
|
using Wino.Mail.ViewModels.Data;
|
||||||
using Wino.Mail.ViewModels.Messages;
|
|
||||||
using Wino.Mail.WinUI.Controls;
|
using Wino.Mail.WinUI.Controls;
|
||||||
using Wino.Mail.WinUI.Extensions;
|
using Wino.Mail.WinUI.Extensions;
|
||||||
using Wino.Mail.WinUI.Interfaces;
|
using Wino.Mail.WinUI.Interfaces;
|
||||||
using Wino.Mail.WinUI.Models;
|
using Wino.Mail.WinUI.Models;
|
||||||
using Wino.Messaging.Client.Mails;
|
|
||||||
using Wino.Messaging.Client.Shell;
|
using Wino.Messaging.Client.Shell;
|
||||||
using Wino.Views.Abstract;
|
using Wino.Views.Abstract;
|
||||||
|
|
||||||
@@ -42,6 +40,7 @@ public sealed partial class ComposePage : ComposePageAbstract,
|
|||||||
|
|
||||||
private bool _isPoppedOut;
|
private bool _isPoppedOut;
|
||||||
private bool _isInitialFocusHandled;
|
private bool _isInitialFocusHandled;
|
||||||
|
private readonly Dictionary<TokenizingTextBox, List<AccountContact>> _recipientSuggestions = [];
|
||||||
|
|
||||||
public bool SupportsPopOut => !_isPoppedOut;
|
public bool SupportsPopOut => !_isPoppedOut;
|
||||||
public event EventHandler<PopOutRequestedEventArgs>? PopOutRequested;
|
public event EventHandler<PopOutRequestedEventArgs>? PopOutRequested;
|
||||||
@@ -132,12 +131,17 @@ public sealed partial class ComposePage : ComposePageAbstract,
|
|||||||
{
|
{
|
||||||
_ = ViewModel.ExecuteUIThread(() =>
|
_ = ViewModel.ExecuteUIThread(() =>
|
||||||
{
|
{
|
||||||
var addresses = x.Result;
|
var addresses = x.Result ?? [];
|
||||||
|
|
||||||
|
_recipientSuggestions[box] = addresses;
|
||||||
senderBox.ItemsSource = addresses;
|
senderBox.ItemsSource = addresses;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_recipientSuggestions[box] = [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -293,7 +297,7 @@ public sealed partial class ComposePage : ComposePageAbstract,
|
|||||||
{
|
{
|
||||||
base.OnNavigatedTo(e);
|
base.OnNavigatedTo(e);
|
||||||
|
|
||||||
FocusManager.GotFocus += GlobalFocusManagerGotFocus;
|
// FocusManager.GotFocus += GlobalFocusManagerGotFocus;
|
||||||
|
|
||||||
var webView = GetWebView();
|
var webView = GetWebView();
|
||||||
|
|
||||||
@@ -335,36 +339,60 @@ public sealed partial class ComposePage : ComposePageAbstract,
|
|||||||
|
|
||||||
private async void TokenItemAdding(TokenizingTextBox sender, TokenItemAddingEventArgs args)
|
private async void TokenItemAdding(TokenizingTextBox sender, TokenItemAddingEventArgs args)
|
||||||
{
|
{
|
||||||
// Check is valid email.
|
|
||||||
if (!EmailValidator.Validate(args.TokenText))
|
|
||||||
{
|
|
||||||
args.Cancel = true;
|
|
||||||
ViewModel.NotifyInvalidEmail(args.TokenText);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var deferral = args.GetDeferral();
|
var deferral = args.GetDeferral();
|
||||||
|
try
|
||||||
var addedItem = (sender.Tag?.ToString()) switch
|
|
||||||
{
|
{
|
||||||
"ToBox" => await ViewModel.GetAddressInformationAsync(args.TokenText, ViewModel.ToItems),
|
var suggestedContact = GetFirstSuggestedContact(sender);
|
||||||
"CCBox" => await ViewModel.GetAddressInformationAsync(args.TokenText, ViewModel.CCItems),
|
var tokenText = suggestedContact?.Address ?? args.TokenText;
|
||||||
"BCCBox" => await ViewModel.GetAddressInformationAsync(args.TokenText, ViewModel.BCCItems),
|
var addressCollection = sender.Tag?.ToString() switch
|
||||||
_ => null
|
{
|
||||||
};
|
"ToBox" => ViewModel.ToItems,
|
||||||
|
"CCBox" => ViewModel.CCItems,
|
||||||
|
"BCCBox" => ViewModel.BCCItems,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
|
||||||
if (addedItem == null)
|
if (suggestedContact == null && !EmailValidator.Validate(tokenText))
|
||||||
{
|
{
|
||||||
args.Cancel = true;
|
args.Cancel = true;
|
||||||
ViewModel.NotifyAddressExists();
|
ViewModel.NotifyInvalidEmail(args.TokenText);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccountContact? addedItem = null;
|
||||||
|
|
||||||
|
if (suggestedContact != null)
|
||||||
|
{
|
||||||
|
addedItem = addressCollection?.Any(a => string.Equals(a.Address, suggestedContact.Address, StringComparison.OrdinalIgnoreCase)) == true
|
||||||
|
? null
|
||||||
|
: suggestedContact;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
addedItem = sender.Tag?.ToString() switch
|
||||||
|
{
|
||||||
|
"ToBox" => await ViewModel.GetAddressInformationAsync(tokenText, ViewModel.ToItems),
|
||||||
|
"CCBox" => await ViewModel.GetAddressInformationAsync(tokenText, ViewModel.CCItems),
|
||||||
|
"BCCBox" => await ViewModel.GetAddressInformationAsync(tokenText, ViewModel.BCCItems),
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addedItem == null)
|
||||||
|
{
|
||||||
|
args.Cancel = true;
|
||||||
|
ViewModel.NotifyAddressExists();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
args.Item = addedItem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
finally
|
||||||
{
|
{
|
||||||
args.Item = addedItem;
|
_recipientSuggestions[sender] = [];
|
||||||
|
deferral.Complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
deferral.Complete();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRecipient<ApplicationThemeChanged>.Receive(ApplicationThemeChanged message)
|
void IRecipient<ApplicationThemeChanged>.Receive(ApplicationThemeChanged message)
|
||||||
@@ -438,6 +466,11 @@ public sealed partial class ComposePage : ComposePageAbstract,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AccountContact? GetFirstSuggestedContact(TokenizingTextBox box)
|
||||||
|
=> _recipientSuggestions.TryGetValue(box, out var suggestions)
|
||||||
|
? suggestions.FirstOrDefault()
|
||||||
|
: null;
|
||||||
|
|
||||||
private void ComposerLoaded(object sender, RoutedEventArgs e)
|
private void ComposerLoaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (ShouldFocusRecipients())
|
if (ShouldFocusRecipients())
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using CommunityToolkit.Mvvm.Messaging;
|
|||||||
using Microsoft.UI.Xaml.Media.Animation;
|
using Microsoft.UI.Xaml.Media.Animation;
|
||||||
using Microsoft.UI.Xaml.Navigation;
|
using Microsoft.UI.Xaml.Navigation;
|
||||||
using Wino.Core.Domain;
|
using Wino.Core.Domain;
|
||||||
|
using Wino.Core.Domain.Entities.Shared;
|
||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
using Wino.Core.Domain.Models.Settings;
|
using Wino.Core.Domain.Models.Settings;
|
||||||
using Wino.Helpers;
|
using Wino.Helpers;
|
||||||
@@ -162,7 +163,7 @@ public sealed partial class SettingsPage : SettingsPageAbstract,
|
|||||||
|
|
||||||
DispatcherQueue.TryEnqueue(() =>
|
DispatcherQueue.TryEnqueue(() =>
|
||||||
{
|
{
|
||||||
activePage.Title = message.Account.Name;
|
activePage.Title = GetAccountDetailsTitle(message.Account);
|
||||||
_ = RefreshCurrentPageStateAsync();
|
_ = RefreshCurrentPageStateAsync();
|
||||||
UpdateWindowTitle();
|
UpdateWindowTitle();
|
||||||
});
|
});
|
||||||
@@ -249,6 +250,11 @@ public sealed partial class SettingsPage : SettingsPageAbstract,
|
|||||||
: activeTitle;
|
: activeTitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GetAccountDetailsTitle(MailAccount account)
|
||||||
|
=> !string.IsNullOrWhiteSpace(account?.Address)
|
||||||
|
? string.Format(Translator.SettingsAccountDetails_NavigationTitle, account.Address)
|
||||||
|
: account?.Name ?? Translator.AccountDetailsPage_Title;
|
||||||
|
|
||||||
public Task OnTitleBarSearchTextChangedAsync()
|
public Task OnTitleBarSearchTextChangedAsync()
|
||||||
{
|
{
|
||||||
SearchSuggestions.Clear();
|
SearchSuggestions.Clear();
|
||||||
|
|||||||
@@ -240,6 +240,34 @@ public class AccountService : BaseDatabaseService, IAccountService
|
|||||||
return accounts;
|
return accounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<bool> AccountNameExistsAsync(string name, Guid? excludedAccountId = null)
|
||||||
|
{
|
||||||
|
var normalizedName = name?.Trim();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(normalizedName))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var accounts = await Connection.Table<MailAccount>().ToListAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
return accounts.Any(account =>
|
||||||
|
account.Id != excludedAccountId &&
|
||||||
|
string.Equals(account.Name?.Trim(), normalizedName, StringComparison.OrdinalIgnoreCase));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> AccountAddressExistsAsync(string address, Guid? excludedAccountId = null)
|
||||||
|
{
|
||||||
|
var normalizedAddress = address?.Trim();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(normalizedAddress))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var accounts = await Connection.Table<MailAccount>().ToListAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
return accounts.Any(account =>
|
||||||
|
account.Id != excludedAccountId &&
|
||||||
|
string.Equals(account.Address?.Trim(), normalizedAddress, StringComparison.OrdinalIgnoreCase));
|
||||||
|
}
|
||||||
|
|
||||||
public async Task CreateRootAliasAsync(Guid accountId, string address)
|
public async Task CreateRootAliasAsync(Guid accountId, string address)
|
||||||
{
|
{
|
||||||
var rootAlias = new MailAccountAlias()
|
var rootAlias = new MailAccountAlias()
|
||||||
@@ -610,6 +638,12 @@ public class AccountService : BaseDatabaseService, IAccountService
|
|||||||
{
|
{
|
||||||
Guard.IsNotNull(account);
|
Guard.IsNotNull(account);
|
||||||
|
|
||||||
|
if (await AccountNameExistsAsync(account.Name).ConfigureAwait(false))
|
||||||
|
throw new InvalidOperationException(Translator.DialogMessage_AccountNameExistsMessage);
|
||||||
|
|
||||||
|
if (await AccountAddressExistsAsync(account.Address).ConfigureAwait(false))
|
||||||
|
throw new InvalidOperationException(Translator.DialogMessage_AccountAddressExistsMessage);
|
||||||
|
|
||||||
if (!account.CreatedAt.HasValue)
|
if (!account.CreatedAt.HasValue)
|
||||||
{
|
{
|
||||||
account.CreatedAt = DateTime.UtcNow;
|
account.CreatedAt = DateTime.UtcNow;
|
||||||
|
|||||||
Reference in New Issue
Block a user