Managing account aliases and profile synchronization for outlook and gmail.
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using SQLite;
|
using SQLite;
|
||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
@@ -48,7 +47,7 @@ namespace Wino.Core.Domain.Entities
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base64 encoded profile picture of the account.
|
/// Base64 encoded profile picture of the account.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ProfilePictureBase64 { get; set; }
|
public string Base64ProfilePictureData { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the listing order of the account in the accounts list.
|
/// Gets or sets the listing order of the account in the accounts list.
|
||||||
@@ -84,8 +83,8 @@ namespace Wino.Core.Domain.Entities
|
|||||||
/// It's only synchronized for Gmail right now.
|
/// It's only synchronized for Gmail right now.
|
||||||
/// Other provider types are manually added by users and not verified.
|
/// Other provider types are manually added by users and not verified.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Ignore]
|
//[Ignore]
|
||||||
public List<MailAccountAlias> Aliases { get; set; }
|
//public List<MailAccountAlias> Aliases { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Account preferences.
|
/// Account preferences.
|
||||||
|
|||||||
@@ -32,6 +32,13 @@ namespace Wino.Core.Domain.Entities
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsPrimary { get; set; }
|
public bool IsPrimary { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this alias is the root alias for the account.
|
||||||
|
/// Root alias means the first alias that was created for the account.
|
||||||
|
/// It can't be deleted or changed.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsRootAlias { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the alias is verified by the server.
|
/// Whether the alias is verified by the server.
|
||||||
/// Non-verified aliases will show an info tip to users during sending.
|
/// Non-verified aliases will show an info tip to users during sending.
|
||||||
@@ -40,6 +47,11 @@ namespace Wino.Core.Domain.Entities
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsVerified { get; set; }
|
public bool IsVerified { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Root aliases can't be deleted.
|
||||||
|
/// </summary>
|
||||||
|
public bool CanDelete => !IsRootAlias;
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
{
|
{
|
||||||
if (obj == null || GetType() != obj.GetType())
|
if (obj == null || GetType() != obj.GetType())
|
||||||
@@ -51,17 +63,20 @@ namespace Wino.Core.Domain.Entities
|
|||||||
AliasAddress == other.AliasAddress &&
|
AliasAddress == other.AliasAddress &&
|
||||||
ReplyToAddress == other.ReplyToAddress &&
|
ReplyToAddress == other.ReplyToAddress &&
|
||||||
IsPrimary == other.IsPrimary &&
|
IsPrimary == other.IsPrimary &&
|
||||||
IsVerified == other.IsVerified;
|
IsVerified == other.IsVerified &&
|
||||||
|
IsRootAlias == other.IsRootAlias;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
int hashCode = -753829106;
|
int hashCode = 59052167;
|
||||||
hashCode = hashCode * -1521134295 + AccountId.GetHashCode();
|
hashCode = hashCode * -1521134295 + AccountId.GetHashCode();
|
||||||
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(AliasAddress);
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(AliasAddress);
|
||||||
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(ReplyToAddress);
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(ReplyToAddress);
|
||||||
hashCode = hashCode * -1521134295 + IsPrimary.GetHashCode();
|
hashCode = hashCode * -1521134295 + IsPrimary.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + IsRootAlias.GetHashCode();
|
||||||
hashCode = hashCode * -1521134295 + IsVerified.GetHashCode();
|
hashCode = hashCode * -1521134295 + IsVerified.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + CanDelete.GetHashCode();
|
||||||
return hashCode;
|
return hashCode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
ManuelSetupWaiting,
|
ManuelSetupWaiting,
|
||||||
TestingConnection,
|
TestingConnection,
|
||||||
AutoDiscoverySetup,
|
AutoDiscoverySetup,
|
||||||
AutoDiscoveryInProgress
|
AutoDiscoveryInProgress,
|
||||||
|
FetchingProfileInformation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,5 +7,6 @@
|
|||||||
Inbox, // Only Inbox
|
Inbox, // Only Inbox
|
||||||
Custom, // Only sync folders that are specified in the options.
|
Custom, // Only sync folders that are specified in the options.
|
||||||
Full, // Synchronize everything
|
Full, // Synchronize everything
|
||||||
|
UpdateProfile, // Only update profile information
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,5 +23,6 @@
|
|||||||
LanguageTimePage,
|
LanguageTimePage,
|
||||||
AppPreferencesPage,
|
AppPreferencesPage,
|
||||||
SettingOptionsPage,
|
SettingOptionsPage,
|
||||||
|
AliasManagementPage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Wino.Core.Domain.Entities;
|
using Wino.Core.Domain.Entities;
|
||||||
|
using Wino.Core.Domain.Models.Accounts;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Interfaces
|
namespace Wino.Core.Domain.Interfaces
|
||||||
{
|
{
|
||||||
@@ -101,12 +102,42 @@ namespace Wino.Core.Domain.Interfaces
|
|||||||
/// <param name="accountIdOrderPair">AccountId-OrderNumber pair for all accounts.</param>
|
/// <param name="accountIdOrderPair">AccountId-OrderNumber pair for all accounts.</param>
|
||||||
Task UpdateAccountOrdersAsync(Dictionary<Guid, int> accountIdOrderPair);
|
Task UpdateAccountOrdersAsync(Dictionary<Guid, int> accountIdOrderPair);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the account aliases.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="accountId">Account id.</param>
|
||||||
|
/// <returns>A list of MailAccountAlias that has e-mail aliases.</returns>
|
||||||
|
Task<List<MailAccountAlias>> GetAccountAliasesAsync(Guid accountId);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updated account's aliases.
|
/// Updated account's aliases.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="accountId">Account id to update aliases for.</param>
|
/// <param name="accountId">Account id to update aliases for.</param>
|
||||||
/// <param name="aliases">Full list of updated aliases.</param>
|
/// <param name="aliases">Full list of updated aliases.</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task UpdateAccountAliases(Guid accountId, List<MailAccountAlias> aliases);
|
Task UpdateAccountAliasesAsync(Guid accountId, List<MailAccountAlias> aliases);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delete account alias.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="aliasId">Alias to remove.</param>
|
||||||
|
Task DeleteAccountAliasAsync(Guid aliasId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updated profile information of the account.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="accountId">Account id to update info for.</param>
|
||||||
|
/// <param name="profileInformation">Info data.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task UpdateProfileInformationAsync(Guid accountId, ProfileInformation profileInformation);
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a root + primary alias for the account.
|
||||||
|
/// This is only called when the account is created.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="accountId">Account id.</param>
|
||||||
|
/// <param name="address">Address to create root primary alias from.</param>
|
||||||
|
Task CreateRootAliasAsync(Guid accountId, string address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Threading.Tasks;
|
|||||||
using MailKit;
|
using MailKit;
|
||||||
using Wino.Core.Domain.Entities;
|
using Wino.Core.Domain.Entities;
|
||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
|
using Wino.Core.Domain.Models.Accounts;
|
||||||
using Wino.Core.Domain.Models.MailItem;
|
using Wino.Core.Domain.Models.MailItem;
|
||||||
using Wino.Core.Domain.Models.Synchronization;
|
using Wino.Core.Domain.Models.Synchronization;
|
||||||
|
|
||||||
@@ -43,6 +44,13 @@ namespace Wino.Core.Domain.Interfaces
|
|||||||
/// <returns>Result summary of synchronization.</returns>
|
/// <returns>Result summary of synchronization.</returns>
|
||||||
Task<SynchronizationResult> SynchronizeAsync(SynchronizationOptions options, CancellationToken cancellationToken = default);
|
Task<SynchronizationResult> SynchronizeAsync(SynchronizationOptions options, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Synchronizes profile information with the server.
|
||||||
|
/// Sender name and
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<ProfileInformation> SynchronizeProfileInformationAsync();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Downloads a single MIME message from the server and saves it to disk.
|
/// Downloads a single MIME message from the server and saves it to disk.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
9
Wino.Core.Domain/Interfaces/ICreateAccountAliasDialog.cs
Normal file
9
Wino.Core.Domain/Interfaces/ICreateAccountAliasDialog.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using Wino.Core.Domain.Entities;
|
||||||
|
|
||||||
|
namespace Wino.Core.Domain.Interfaces
|
||||||
|
{
|
||||||
|
public interface ICreateAccountAliasDialog
|
||||||
|
{
|
||||||
|
public MailAccountAlias CreatedAccountAlias { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -53,5 +53,6 @@ namespace Wino.Core.Domain.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Signature information. Null if canceled.</returns>
|
/// <returns>Signature information. Null if canceled.</returns>
|
||||||
Task<AccountSignature> ShowSignatureEditorDialog(AccountSignature signatureModel = null);
|
Task<AccountSignature> ShowSignatureEditorDialog(AccountSignature signatureModel = null);
|
||||||
|
Task<ICreateAccountAliasDialog> ShowCreateAccountAliasDialogAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,5 +2,5 @@
|
|||||||
|
|
||||||
namespace Wino.Core.Domain.Models.Accounts
|
namespace Wino.Core.Domain.Models.Accounts
|
||||||
{
|
{
|
||||||
public record AccountCreationDialogResult(MailProviderType ProviderType, string AccountName, string SenderName, string AccountColorHex = "");
|
public record AccountCreationDialogResult(MailProviderType ProviderType, string AccountName, string AccountColorHex = "");
|
||||||
}
|
}
|
||||||
|
|||||||
9
Wino.Core.Domain/Models/Accounts/ProfileInformation.cs
Normal file
9
Wino.Core.Domain/Models/Accounts/ProfileInformation.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Wino.Core.Domain.Models.Accounts
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Encapsulates the profile information of an account.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="SenderName">Display sender name for the account.</param>
|
||||||
|
/// <param name="Base64ProfilePictureData">Base 64 encoded profile picture data of the account. Thumbnail size.</param>
|
||||||
|
public record ProfileInformation(string SenderName, string Base64ProfilePictureData);
|
||||||
|
}
|
||||||
@@ -14,7 +14,6 @@ namespace Wino.Core.Domain.Models.Accounts
|
|||||||
public string ProviderImage => $"ms-appx:///Assets/Providers/{Type}.png";
|
public string ProviderImage => $"ms-appx:///Assets/Providers/{Type}.png";
|
||||||
|
|
||||||
public bool IsSupported => Type == MailProviderType.Outlook || Type == MailProviderType.Gmail || Type == MailProviderType.IMAP4;
|
public bool IsSupported => Type == MailProviderType.Outlook || Type == MailProviderType.Gmail || Type == MailProviderType.IMAP4;
|
||||||
public bool RequireSenderNameOnCreationDialog => Type != MailProviderType.IMAP4;
|
|
||||||
|
|
||||||
public ProviderDetail(MailProviderType type)
|
public ProviderDetail(MailProviderType type)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
|
using Wino.Core.Domain.Models.Accounts;
|
||||||
using Wino.Core.Domain.Models.MailItem;
|
using Wino.Core.Domain.Models.MailItem;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Models.Synchronization
|
namespace Wino.Core.Domain.Models.Synchronization
|
||||||
@@ -15,14 +16,18 @@ namespace Wino.Core.Domain.Models.Synchronization
|
|||||||
/// It's ignored in serialization. Client should not react to this.
|
/// It's ignored in serialization. Client should not react to this.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public IEnumerable<IMailItem> DownloadedMessages { get; set; } = new List<IMailItem>();
|
public IEnumerable<IMailItem> DownloadedMessages { get; set; } = [];
|
||||||
|
|
||||||
|
public ProfileInformation ProfileInformation { get; set; }
|
||||||
|
|
||||||
public SynchronizationCompletedState CompletedState { get; set; }
|
public SynchronizationCompletedState CompletedState { get; set; }
|
||||||
|
|
||||||
public static SynchronizationResult Empty => new() { CompletedState = SynchronizationCompletedState.Success };
|
public static SynchronizationResult Empty => new() { CompletedState = SynchronizationCompletedState.Success };
|
||||||
|
|
||||||
public static SynchronizationResult Completed(IEnumerable<IMailItem> downloadedMessages)
|
public static SynchronizationResult Completed(IEnumerable<IMailItem> downloadedMessages, ProfileInformation profileInformation = null)
|
||||||
=> new() { DownloadedMessages = downloadedMessages, CompletedState = SynchronizationCompletedState.Success };
|
=> new() { DownloadedMessages = downloadedMessages, ProfileInformation = profileInformation, CompletedState = SynchronizationCompletedState.Success };
|
||||||
|
|
||||||
public static SynchronizationResult Canceled => new() { CompletedState = SynchronizationCompletedState.Canceled };
|
public static SynchronizationResult Canceled => new() { CompletedState = SynchronizationCompletedState.Canceled };
|
||||||
|
public static SynchronizationResult Failed => new() { CompletedState = SynchronizationCompletedState.Failed };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
"AccountCreationDialog_Initializing": "initializing",
|
"AccountCreationDialog_Initializing": "initializing",
|
||||||
"AccountCreationDialog_PreparingFolders": "We are getting folder information at the moment.",
|
"AccountCreationDialog_PreparingFolders": "We are getting folder information at the moment.",
|
||||||
"AccountCreationDialog_SigninIn": "Account information is being saved.",
|
"AccountCreationDialog_SigninIn": "Account information is being saved.",
|
||||||
|
"AccountCreationDialog_FetchingProfileInformation": "Fetching profile details.",
|
||||||
"AccountEditDialog_Message": "Account Name",
|
"AccountEditDialog_Message": "Account Name",
|
||||||
"AccountEditDialog_Title": "Edit Account",
|
"AccountEditDialog_Title": "Edit Account",
|
||||||
"AccountPickerDialog_Title": "Pick an account",
|
"AccountPickerDialog_Title": "Pick an account",
|
||||||
@@ -64,6 +65,14 @@
|
|||||||
"CustomThemeBuilder_WallpaperTitle": "Set custom wallpaper",
|
"CustomThemeBuilder_WallpaperTitle": "Set custom wallpaper",
|
||||||
"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_AliasExistsTitle": "Existing Alias",
|
||||||
|
"DialogMessage_AliasExistsMessage": "This alias is already in use.",
|
||||||
|
"DialogMessage_InvalidAliasTitle": "Invalid Alias",
|
||||||
|
"DialogMessage_InvalidAliasMessage": "This alias is not valid. Make sure all addresses of the alias are valid e-mail addresses.",
|
||||||
|
"DialogMessage_CantDeleteRootAliasTitle": "Can't Delete Alias",
|
||||||
|
"DialogMessage_CantDeleteRootAliasMessage": "Root alias can't be deleted. This is your main identity associated with your account setup.",
|
||||||
|
"DialogMessage_AliasCreatedTitle": "Created New Alias",
|
||||||
|
"DialogMessage_AliasCreatedMessage": "New alias is succesfully created.",
|
||||||
"DialogMessage_CleanupFolderMessage": "Do you want to permanently delete all the mails in this folder?",
|
"DialogMessage_CleanupFolderMessage": "Do you want to permanently delete all the mails in this folder?",
|
||||||
"DialogMessage_CleanupFolderTitle": "Cleanup Folder",
|
"DialogMessage_CleanupFolderTitle": "Cleanup Folder",
|
||||||
"DialogMessage_ComposerMissingRecipientMessage": "Message has no recipient.",
|
"DialogMessage_ComposerMissingRecipientMessage": "Message has no recipient.",
|
||||||
@@ -92,6 +101,12 @@
|
|||||||
"DialogMessage_UnsubscribeConfirmationGoToWebsiteConfirmButton": "Go to website",
|
"DialogMessage_UnsubscribeConfirmationGoToWebsiteConfirmButton": "Go to website",
|
||||||
"DialogMessage_UnsubscribeConfirmationMailtoMessage": "Do you want to stop getting messages from {0}? Wino will unsubscribe for you by sending an email from your email account to {1}.",
|
"DialogMessage_UnsubscribeConfirmationMailtoMessage": "Do you want to stop getting messages from {0}? Wino will unsubscribe for you by sending an email from your email account to {1}.",
|
||||||
"Dialog_DontAskAgain": "Don't ask again",
|
"Dialog_DontAskAgain": "Don't ask again",
|
||||||
|
"CreateAccountAliasDialog_Title": "Create Account Alias",
|
||||||
|
"CreateAccountAliasDialog_Description": "Make sure your outgoing server allows sending mails from this alias.",
|
||||||
|
"CreateAccountAliasDialog_AliasAddress": "Address",
|
||||||
|
"CreateAccountAliasDialog_AliasAddressPlaceholder": "eg. support@mydomain.com",
|
||||||
|
"CreateAccountAliasDialog_ReplyToAddress": "Reply-To Address",
|
||||||
|
"CreateAccountAliasDialog_ReplyToAddressPlaceholder": "admin@mydomain.com",
|
||||||
"DiscordChannelDisclaimerMessage": "Wino doesn't have it's own Discord server, but special 'wino-mail' channel is hosted at 'Developer Sanctuary' server.\nTo get the updates about Wino please join Developer Sanctuary server and follow 'wino-mail' channel under 'Community Projects'\n\nYou will be directed to server URL since Discord doesn't support channel invites.",
|
"DiscordChannelDisclaimerMessage": "Wino doesn't have it's own Discord server, but special 'wino-mail' channel is hosted at 'Developer Sanctuary' server.\nTo get the updates about Wino please join Developer Sanctuary server and follow 'wino-mail' channel under 'Community Projects'\n\nYou will be directed to server URL since Discord doesn't support channel invites.",
|
||||||
"DiscordChannelDisclaimerTitle": "Important Discord Information",
|
"DiscordChannelDisclaimerTitle": "Important Discord Information",
|
||||||
"Draft": "Draft",
|
"Draft": "Draft",
|
||||||
@@ -113,6 +128,7 @@
|
|||||||
"Exception_CustomThemeMissingName": "You must provide a name.",
|
"Exception_CustomThemeMissingName": "You must provide a name.",
|
||||||
"Exception_CustomThemeMissingWallpaper": "You must provide a custom background image.",
|
"Exception_CustomThemeMissingWallpaper": "You must provide a custom background image.",
|
||||||
"Exception_FailedToSynchronizeFolders": "Failed to synchronize folders",
|
"Exception_FailedToSynchronizeFolders": "Failed to synchronize folders",
|
||||||
|
"Exception_FailedToSynchronizeProfileInformation": "Failed to synchronize profile information",
|
||||||
"Exception_GoogleAuthCallbackNull": "Callback uri is null on activation.",
|
"Exception_GoogleAuthCallbackNull": "Callback uri is null on activation.",
|
||||||
"Exception_GoogleAuthCorruptedCode": "Corrupted authorization response.",
|
"Exception_GoogleAuthCorruptedCode": "Corrupted authorization response.",
|
||||||
"Exception_GoogleAuthError": "OAuth authorization error: {0}",
|
"Exception_GoogleAuthError": "OAuth authorization error: {0}",
|
||||||
@@ -253,6 +269,7 @@
|
|||||||
"Info_UnsubscribeLinkInvalidMessage": "This unsubscribe link is invalid. Failed to unsubscribe from the list.",
|
"Info_UnsubscribeLinkInvalidMessage": "This unsubscribe link is invalid. Failed to unsubscribe from the list.",
|
||||||
"Info_UnsubscribeSuccessMessage": "Successfully unsubscribed from {0}.",
|
"Info_UnsubscribeSuccessMessage": "Successfully unsubscribed from {0}.",
|
||||||
"Info_UnsubscribeErrorMessage": "Failed to unsubscribe",
|
"Info_UnsubscribeErrorMessage": "Failed to unsubscribe",
|
||||||
|
"Info_CantDeletePrimaryAliasMessage": "Primary alias can't be deleted. Please change your alias before deleting this one",
|
||||||
"ImapAdvancedSetupDialog_AuthenticationMethod": "Authentication method",
|
"ImapAdvancedSetupDialog_AuthenticationMethod": "Authentication method",
|
||||||
"ImapAdvancedSetupDialog_ConnectionSecurity": "Connection security",
|
"ImapAdvancedSetupDialog_ConnectionSecurity": "Connection security",
|
||||||
"ImapAuthenticationMethod_Auto": "Auto",
|
"ImapAuthenticationMethod_Auto": "Auto",
|
||||||
@@ -396,6 +413,8 @@
|
|||||||
"SettingsFolderSync_Title": "Folder Synchronization",
|
"SettingsFolderSync_Title": "Folder Synchronization",
|
||||||
"SettingsFolderOptions_Title": "Folder Configuration",
|
"SettingsFolderOptions_Title": "Folder Configuration",
|
||||||
"SettingsFolderOptions_Description": "Change individual folder settings like enable/disable sync or show/hide unread badge.",
|
"SettingsFolderOptions_Description": "Change individual folder settings like enable/disable sync or show/hide unread badge.",
|
||||||
|
"SettingsManageAliases_Title": "Aliases",
|
||||||
|
"SettingsManageAliases_Description": "See e-mail aliases assigned for this account, update or delete them.",
|
||||||
"SettingsHoverActionCenter": "Center Action",
|
"SettingsHoverActionCenter": "Center Action",
|
||||||
"SettingsHoverActionLeft": "Left Action",
|
"SettingsHoverActionLeft": "Left Action",
|
||||||
"SettingsHoverActionRight": "Right Action",
|
"SettingsHoverActionRight": "Right Action",
|
||||||
@@ -406,6 +425,11 @@
|
|||||||
"SettingsLanguageTime_Title": "Language & Time",
|
"SettingsLanguageTime_Title": "Language & Time",
|
||||||
"SettingsLanguageTime_Description": "Wino display language, preferred time format.",
|
"SettingsLanguageTime_Description": "Wino display language, preferred time format.",
|
||||||
"CategoriesFolderNameOverride": "Categories",
|
"CategoriesFolderNameOverride": "Categories",
|
||||||
|
"AccountAlias_Column_Verified": "Verified",
|
||||||
|
"AccountAlias_Column_Alias": "Alias",
|
||||||
|
"AccountAlias_Column_IsPrimaryAlias": "Primary",
|
||||||
|
"AccountAlias_Disclaimer_FirstLine": "Wino can only import aliases for your Gmail accounts.",
|
||||||
|
"AccountAlias_Disclaimer_SecondLine": "If you want to use aliases for your Outlook or IMAP account, please add them yourself.",
|
||||||
"MoreFolderNameOverride": "More",
|
"MoreFolderNameOverride": "More",
|
||||||
"SettingsOptions_Title": "Settings",
|
"SettingsOptions_Title": "Settings",
|
||||||
"SettingsLinkAccounts_Description": "Merge multiple accounts into one. See mails from one Inbox together.",
|
"SettingsLinkAccounts_Description": "Merge multiple accounts into one. See mails from one Inbox together.",
|
||||||
|
|||||||
122
Wino.Core.Domain/Translator.Designer.cs
generated
122
Wino.Core.Domain/Translator.Designer.cs
generated
@@ -38,6 +38,11 @@ namespace Wino.Core.Domain
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static string AccountCreationDialog_SigninIn => Resources.GetTranslatedString(@"AccountCreationDialog_SigninIn");
|
public static string AccountCreationDialog_SigninIn => Resources.GetTranslatedString(@"AccountCreationDialog_SigninIn");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetching profile details.
|
||||||
|
/// </summary>
|
||||||
|
public static string AccountCreationDialog_FetchingProfileInformation => Resources.GetTranslatedString(@"AccountCreationDialog_FetchingProfileInformation");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Account Name
|
/// Account Name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -343,6 +348,46 @@ namespace Wino.Core.Domain
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static string DialogMessage_AccountLimitTitle => Resources.GetTranslatedString(@"DialogMessage_AccountLimitTitle");
|
public static string DialogMessage_AccountLimitTitle => Resources.GetTranslatedString(@"DialogMessage_AccountLimitTitle");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Existing Alias
|
||||||
|
/// </summary>
|
||||||
|
public static string DialogMessage_AliasExistsTitle => Resources.GetTranslatedString(@"DialogMessage_AliasExistsTitle");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This alias is already in use.
|
||||||
|
/// </summary>
|
||||||
|
public static string DialogMessage_AliasExistsMessage => Resources.GetTranslatedString(@"DialogMessage_AliasExistsMessage");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invalid Alias
|
||||||
|
/// </summary>
|
||||||
|
public static string DialogMessage_InvalidAliasTitle => Resources.GetTranslatedString(@"DialogMessage_InvalidAliasTitle");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This alias is not valid. Make sure all addresses of the alias are valid e-mail addresses.
|
||||||
|
/// </summary>
|
||||||
|
public static string DialogMessage_InvalidAliasMessage => Resources.GetTranslatedString(@"DialogMessage_InvalidAliasMessage");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Can't Delete Alias
|
||||||
|
/// </summary>
|
||||||
|
public static string DialogMessage_CantDeleteRootAliasTitle => Resources.GetTranslatedString(@"DialogMessage_CantDeleteRootAliasTitle");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Root alias can't be deleted. This is your main identity associated with your account setup.
|
||||||
|
/// </summary>
|
||||||
|
public static string DialogMessage_CantDeleteRootAliasMessage => Resources.GetTranslatedString(@"DialogMessage_CantDeleteRootAliasMessage");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Created New Alias
|
||||||
|
/// </summary>
|
||||||
|
public static string DialogMessage_AliasCreatedTitle => Resources.GetTranslatedString(@"DialogMessage_AliasCreatedTitle");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// New alias is succesfully created.
|
||||||
|
/// </summary>
|
||||||
|
public static string DialogMessage_AliasCreatedMessage => Resources.GetTranslatedString(@"DialogMessage_AliasCreatedMessage");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Do you want to permanently delete all the mails in this folder?
|
/// Do you want to permanently delete all the mails in this folder?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -434,7 +479,7 @@ namespace Wino.Core.Domain
|
|||||||
public static string DialogMessage_UnlinkAccountsConfirmationTitle => Resources.GetTranslatedString(@"DialogMessage_UnlinkAccountsConfirmationTitle");
|
public static string DialogMessage_UnlinkAccountsConfirmationTitle => Resources.GetTranslatedString(@"DialogMessage_UnlinkAccountsConfirmationTitle");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Missin Subject
|
/// Missing Subject
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string DialogMessage_EmptySubjectConfirmation => Resources.GetTranslatedString(@"DialogMessage_EmptySubjectConfirmation");
|
public static string DialogMessage_EmptySubjectConfirmation => Resources.GetTranslatedString(@"DialogMessage_EmptySubjectConfirmation");
|
||||||
|
|
||||||
@@ -483,6 +528,36 @@ namespace Wino.Core.Domain
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static string Dialog_DontAskAgain => Resources.GetTranslatedString(@"Dialog_DontAskAgain");
|
public static string Dialog_DontAskAgain => Resources.GetTranslatedString(@"Dialog_DontAskAgain");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create Account Alias
|
||||||
|
/// </summary>
|
||||||
|
public static string CreateAccountAliasDialog_Title => Resources.GetTranslatedString(@"CreateAccountAliasDialog_Title");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Make sure your outgoing server allows sending mails from this alias.
|
||||||
|
/// </summary>
|
||||||
|
public static string CreateAccountAliasDialog_Description => Resources.GetTranslatedString(@"CreateAccountAliasDialog_Description");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Address
|
||||||
|
/// </summary>
|
||||||
|
public static string CreateAccountAliasDialog_AliasAddress => Resources.GetTranslatedString(@"CreateAccountAliasDialog_AliasAddress");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// eg. support@mydomain.com
|
||||||
|
/// </summary>
|
||||||
|
public static string CreateAccountAliasDialog_AliasAddressPlaceholder => Resources.GetTranslatedString(@"CreateAccountAliasDialog_AliasAddressPlaceholder");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reply-To Address
|
||||||
|
/// </summary>
|
||||||
|
public static string CreateAccountAliasDialog_ReplyToAddress => Resources.GetTranslatedString(@"CreateAccountAliasDialog_ReplyToAddress");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// admin@mydomain.com
|
||||||
|
/// </summary>
|
||||||
|
public static string CreateAccountAliasDialog_ReplyToAddressPlaceholder => Resources.GetTranslatedString(@"CreateAccountAliasDialog_ReplyToAddressPlaceholder");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Wino doesn't have it's own Discord server, but special 'wino-mail' channel is hosted at 'Developer Sanctuary' server. To get the updates about Wino please join Developer Sanctuary server and follow 'wino-mail' channel under 'Community Projects' You will be directed to server URL since Discord doesn't support channel invites.
|
/// Wino doesn't have it's own Discord server, but special 'wino-mail' channel is hosted at 'Developer Sanctuary' server. To get the updates about Wino please join Developer Sanctuary server and follow 'wino-mail' channel under 'Community Projects' You will be directed to server URL since Discord doesn't support channel invites.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -588,6 +663,11 @@ namespace Wino.Core.Domain
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static string Exception_FailedToSynchronizeFolders => Resources.GetTranslatedString(@"Exception_FailedToSynchronizeFolders");
|
public static string Exception_FailedToSynchronizeFolders => Resources.GetTranslatedString(@"Exception_FailedToSynchronizeFolders");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Failed to synchronize profile information
|
||||||
|
/// </summary>
|
||||||
|
public static string Exception_FailedToSynchronizeProfileInformation => Resources.GetTranslatedString(@"Exception_FailedToSynchronizeProfileInformation");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Callback uri is null on activation.
|
/// Callback uri is null on activation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1288,6 +1368,11 @@ namespace Wino.Core.Domain
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static string Info_UnsubscribeErrorMessage => Resources.GetTranslatedString(@"Info_UnsubscribeErrorMessage");
|
public static string Info_UnsubscribeErrorMessage => Resources.GetTranslatedString(@"Info_UnsubscribeErrorMessage");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Primary alias can't be deleted. Please change your alias before deleting this one
|
||||||
|
/// </summary>
|
||||||
|
public static string Info_CantDeletePrimaryAliasMessage => Resources.GetTranslatedString(@"Info_CantDeletePrimaryAliasMessage");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Authentication method
|
/// Authentication method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2003,6 +2088,16 @@ namespace Wino.Core.Domain
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static string SettingsFolderOptions_Description => Resources.GetTranslatedString(@"SettingsFolderOptions_Description");
|
public static string SettingsFolderOptions_Description => Resources.GetTranslatedString(@"SettingsFolderOptions_Description");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Aliases
|
||||||
|
/// </summary>
|
||||||
|
public static string SettingsManageAliases_Title => Resources.GetTranslatedString(@"SettingsManageAliases_Title");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// See e-mail aliases assigned for this account, update or delete them.
|
||||||
|
/// </summary>
|
||||||
|
public static string SettingsManageAliases_Description => Resources.GetTranslatedString(@"SettingsManageAliases_Description");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Center Action
|
/// Center Action
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2053,6 +2148,31 @@ namespace Wino.Core.Domain
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static string CategoriesFolderNameOverride => Resources.GetTranslatedString(@"CategoriesFolderNameOverride");
|
public static string CategoriesFolderNameOverride => Resources.GetTranslatedString(@"CategoriesFolderNameOverride");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verified
|
||||||
|
/// </summary>
|
||||||
|
public static string AccountAlias_Column_Verified => Resources.GetTranslatedString(@"AccountAlias_Column_Verified");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Alias
|
||||||
|
/// </summary>
|
||||||
|
public static string AccountAlias_Column_Alias => Resources.GetTranslatedString(@"AccountAlias_Column_Alias");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Primary
|
||||||
|
/// </summary>
|
||||||
|
public static string AccountAlias_Column_IsPrimaryAlias => Resources.GetTranslatedString(@"AccountAlias_Column_IsPrimaryAlias");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wino can only import aliases for your Gmail accounts.
|
||||||
|
/// </summary>
|
||||||
|
public static string AccountAlias_Disclaimer_FirstLine => Resources.GetTranslatedString(@"AccountAlias_Disclaimer_FirstLine");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If you want to use aliases for your Outlook or IMAP account, please add them yourself.
|
||||||
|
/// </summary>
|
||||||
|
public static string AccountAlias_Disclaimer_SecondLine => Resources.GetTranslatedString(@"AccountAlias_Disclaimer_SecondLine");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// More
|
/// More
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -205,21 +205,22 @@ namespace Wino.Core.Extensions
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<MailAccountAlias> GetMailAliases(this ListSendAsResponse response, MailAccount currentAccount)
|
public static List<MailAccountAlias> GetMailAliases(this ListSendAsResponse response, List<MailAccountAlias> currentAliases, MailAccount account)
|
||||||
{
|
{
|
||||||
if (response == null || response.SendAs == null) return currentAccount.Aliases;
|
if (response == null || response.SendAs == null) return currentAliases;
|
||||||
|
|
||||||
var remoteAliases = response.SendAs.Select(a => new MailAccountAlias()
|
var remoteAliases = response.SendAs.Select(a => new MailAccountAlias()
|
||||||
{
|
{
|
||||||
AccountId = currentAccount.Id,
|
AccountId = account.Id,
|
||||||
AliasAddress = a.SendAsEmail,
|
AliasAddress = a.SendAsEmail,
|
||||||
IsPrimary = a.IsPrimary.GetValueOrDefault(),
|
IsPrimary = a.IsPrimary.GetValueOrDefault(),
|
||||||
ReplyToAddress = string.IsNullOrEmpty(a.ReplyToAddress) ? currentAccount.Address : a.ReplyToAddress,
|
ReplyToAddress = string.IsNullOrEmpty(a.ReplyToAddress) ? account.Address : a.ReplyToAddress,
|
||||||
IsVerified = string.IsNullOrEmpty(a.VerificationStatus) ? true : a.VerificationStatus == "accepted",
|
IsVerified = string.IsNullOrEmpty(a.VerificationStatus) ? true : a.VerificationStatus == "accepted",
|
||||||
|
IsRootAlias = account.Address == a.SendAsEmail,
|
||||||
Id = Guid.NewGuid()
|
Id = Guid.NewGuid()
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
return EntityExtensions.GetFinalAliasList(currentAccount.Aliases, remoteAliases);
|
return EntityExtensions.GetFinalAliasList(currentAliases, remoteAliases);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ namespace Wino.Core.Integration.Processors
|
|||||||
/// <returns>All folders.</returns>
|
/// <returns>All folders.</returns>
|
||||||
Task<List<MailItemFolder>> GetLocalFoldersAsync(Guid accountId);
|
Task<List<MailItemFolder>> GetLocalFoldersAsync(Guid accountId);
|
||||||
|
|
||||||
|
Task<List<MailAccountAlias>> GetAccountAliasesAsync(Guid accountId);
|
||||||
|
|
||||||
Task<List<MailItemFolder>> GetSynchronizationFoldersAsync(SynchronizationOptions options);
|
Task<List<MailItemFolder>> GetSynchronizationFoldersAsync(SynchronizationOptions options);
|
||||||
|
|
||||||
Task<bool> MapLocalDraftAsync(Guid accountId, Guid localDraftCopyUniqueId, string newMailCopyId, string newDraftId, string newThreadId);
|
Task<bool> MapLocalDraftAsync(Guid accountId, Guid localDraftCopyUniqueId, string newMailCopyId, string newDraftId, string newThreadId);
|
||||||
@@ -179,6 +181,9 @@ namespace Wino.Core.Integration.Processors
|
|||||||
=> AccountService.UpdateAccountAsync(account);
|
=> AccountService.UpdateAccountAsync(account);
|
||||||
|
|
||||||
public Task UpdateAccountAliasesAsync(Guid accountId, List<MailAccountAlias> aliases)
|
public Task UpdateAccountAliasesAsync(Guid accountId, List<MailAccountAlias> aliases)
|
||||||
=> AccountService.UpdateAccountAliases(accountId, aliases);
|
=> AccountService.UpdateAccountAliasesAsync(accountId, aliases);
|
||||||
|
|
||||||
|
public Task<List<MailAccountAlias>> GetAccountAliasesAsync(Guid accountId)
|
||||||
|
=> AccountService.GetAccountAliasesAsync(accountId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ namespace Wino.Core.MenuItems
|
|||||||
public string Base64ProfilePicture
|
public string Base64ProfilePicture
|
||||||
{
|
{
|
||||||
get => Parameter.Name;
|
get => Parameter.Name;
|
||||||
set => SetProperty(Parameter.ProfilePictureBase64, value, Parameter, (u, n) => u.ProfilePictureBase64 = n);
|
set => SetProperty(Parameter.Base64ProfilePictureData, value, Parameter, (u, n) => u.Base64ProfilePictureData = n);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<MailAccount> HoldingAccounts => new List<MailAccount> { Parameter };
|
public IEnumerable<MailAccount> HoldingAccounts => new List<MailAccount> { Parameter };
|
||||||
@@ -65,7 +65,7 @@ namespace Wino.Core.MenuItems
|
|||||||
Parameter = account;
|
Parameter = account;
|
||||||
AccountName = account.Name;
|
AccountName = account.Name;
|
||||||
AttentionReason = account.AttentionReason;
|
AttentionReason = account.AttentionReason;
|
||||||
Base64ProfilePicture = account.ProfilePictureBase64;
|
Base64ProfilePicture = account.Base64ProfilePictureData;
|
||||||
|
|
||||||
if (SubMenuItems == null) return;
|
if (SubMenuItems == null) return;
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using SqlKata;
|
|||||||
using Wino.Core.Domain.Entities;
|
using Wino.Core.Domain.Entities;
|
||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
using Wino.Core.Domain.Models.Accounts;
|
||||||
using Wino.Core.Extensions;
|
using Wino.Core.Extensions;
|
||||||
using Wino.Messaging.Client.Accounts;
|
using Wino.Messaging.Client.Accounts;
|
||||||
using Wino.Messaging.UI;
|
using Wino.Messaging.UI;
|
||||||
@@ -226,43 +227,37 @@ namespace Wino.Core.Services
|
|||||||
if (account.MergedInboxId != null)
|
if (account.MergedInboxId != null)
|
||||||
account.MergedInbox = await GetMergedInboxInformationAsync(account.MergedInboxId.Value);
|
account.MergedInbox = await GetMergedInboxInformationAsync(account.MergedInboxId.Value);
|
||||||
|
|
||||||
// Load aliases
|
|
||||||
account.Aliases = await GetAccountAliases(account.Id, account.Address);
|
|
||||||
|
|
||||||
account.Preferences = await GetAccountPreferencesAsync(account.Id);
|
account.Preferences = await GetAccountPreferencesAsync(account.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return accounts;
|
return accounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<List<MailAccountAlias>> GetAccountAliases(Guid accountId, string primaryAccountAddress)
|
public async Task CreateRootAliasAsync(Guid accountId, string address)
|
||||||
{
|
{
|
||||||
// By default all accounts must have at least 1 primary alias to create drafts for.
|
var rootAlias = new MailAccountAlias()
|
||||||
// If there's no alias, create one from the existing account address. Migration doesn't exists to create one for older messages.
|
|
||||||
|
|
||||||
var aliases = await Connection
|
|
||||||
.Table<MailAccountAlias>()
|
|
||||||
.Where(a => a.AccountId == accountId)
|
|
||||||
.ToListAsync()
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (!aliases.Any())
|
|
||||||
{
|
{
|
||||||
var primaryAccountAlias = new MailAccountAlias()
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid(),
|
|
||||||
AccountId = accountId,
|
AccountId = accountId,
|
||||||
|
AliasAddress = address,
|
||||||
IsPrimary = true,
|
IsPrimary = true,
|
||||||
AliasAddress = primaryAccountAddress,
|
IsRootAlias = true,
|
||||||
ReplyToAddress = primaryAccountAddress,
|
|
||||||
IsVerified = true,
|
IsVerified = true,
|
||||||
|
ReplyToAddress = address,
|
||||||
|
Id = Guid.NewGuid()
|
||||||
};
|
};
|
||||||
|
|
||||||
await Connection.InsertAsync(primaryAccountAlias).ConfigureAwait(false);
|
await Connection.InsertAsync(rootAlias).ConfigureAwait(false);
|
||||||
aliases.Add(primaryAccountAlias);
|
|
||||||
|
Log.Information("Created root alias for the account {AccountId}", accountId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return aliases;
|
public async Task<List<MailAccountAlias>> GetAccountAliasesAsync(Guid accountId)
|
||||||
|
{
|
||||||
|
var query = new Query(nameof(MailAccountAlias))
|
||||||
|
.Where(nameof(MailAccountAlias.AccountId), accountId)
|
||||||
|
.OrderByDesc(nameof(MailAccountAlias.IsRootAlias));
|
||||||
|
|
||||||
|
return await Connection.QueryAsync<MailAccountAlias>(query.GetRawQuery()).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task<MergedInbox> GetMergedInboxInformationAsync(Guid mergedInboxId)
|
private Task<MergedInbox> GetMergedInboxInformationAsync(Guid mergedInboxId)
|
||||||
@@ -277,6 +272,7 @@ namespace Wino.Core.Services
|
|||||||
await Connection.Table<TokenInformation>().Where(a => a.AccountId == account.Id).DeleteAsync();
|
await Connection.Table<TokenInformation>().Where(a => a.AccountId == account.Id).DeleteAsync();
|
||||||
await Connection.Table<MailItemFolder>().DeleteAsync(a => a.MailAccountId == account.Id);
|
await Connection.Table<MailItemFolder>().DeleteAsync(a => a.MailAccountId == account.Id);
|
||||||
await Connection.Table<AccountSignature>().DeleteAsync(a => a.MailAccountId == account.Id);
|
await Connection.Table<AccountSignature>().DeleteAsync(a => a.MailAccountId == account.Id);
|
||||||
|
await Connection.Table<MailAccountAlias>().DeleteAsync(a => a.AccountId == account.Id);
|
||||||
|
|
||||||
// Account belongs to a merged inbox.
|
// Account belongs to a merged inbox.
|
||||||
// In case of there'll be a single account in the merged inbox, remove the merged inbox as well.
|
// In case of there'll be a single account in the merged inbox, remove the merged inbox as well.
|
||||||
@@ -327,6 +323,19 @@ namespace Wino.Core.Services
|
|||||||
ReportUIChange(new AccountRemovedMessage(account));
|
ReportUIChange(new AccountRemovedMessage(account));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task UpdateProfileInformationAsync(Guid accountId, ProfileInformation profileInformation)
|
||||||
|
{
|
||||||
|
var account = await GetAccountAsync(accountId).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (account != null)
|
||||||
|
{
|
||||||
|
account.SenderName = profileInformation.SenderName;
|
||||||
|
account.Base64ProfilePictureData = profileInformation.Base64ProfilePictureData;
|
||||||
|
|
||||||
|
await UpdateAccountAsync(account).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<MailAccount> GetAccountAsync(Guid accountId)
|
public async Task<MailAccount> GetAccountAsync(Guid accountId)
|
||||||
{
|
{
|
||||||
var account = await Connection.Table<MailAccount>().FirstOrDefaultAsync(a => a.Id == accountId);
|
var account = await Connection.Table<MailAccount>().FirstOrDefaultAsync(a => a.Id == accountId);
|
||||||
@@ -359,7 +368,7 @@ namespace Wino.Core.Services
|
|||||||
ReportUIChange(new AccountUpdatedMessage(account));
|
ReportUIChange(new AccountUpdatedMessage(account));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateAccountAliases(Guid accountId, List<MailAccountAlias> aliases)
|
public async Task UpdateAccountAliasesAsync(Guid accountId, List<MailAccountAlias> aliases)
|
||||||
{
|
{
|
||||||
// Delete existing ones.
|
// Delete existing ones.
|
||||||
await Connection.Table<MailAccountAlias>().DeleteAsync(a => a.AccountId == accountId).ConfigureAwait(false);
|
await Connection.Table<MailAccountAlias>().DeleteAsync(a => a.AccountId == accountId).ConfigureAwait(false);
|
||||||
@@ -371,6 +380,17 @@ namespace Wino.Core.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task DeleteAccountAliasAsync(Guid aliasId)
|
||||||
|
{
|
||||||
|
// Create query to delete alias.
|
||||||
|
|
||||||
|
var query = new Query("MailAccountAlias")
|
||||||
|
.Where("Id", aliasId)
|
||||||
|
.AsDelete();
|
||||||
|
|
||||||
|
await Connection.ExecuteAsync(query.GetRawQuery()).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task CreateAccountAsync(MailAccount account, TokenInformation tokenInformation, CustomServerInformation customServerInformation)
|
public async Task CreateAccountAsync(MailAccount account, TokenInformation tokenInformation, CustomServerInformation customServerInformation)
|
||||||
{
|
{
|
||||||
Guard.IsNotNull(account);
|
Guard.IsNotNull(account);
|
||||||
@@ -424,7 +444,7 @@ namespace Wino.Core.Services
|
|||||||
// Outlook token cache is managed by MSAL.
|
// Outlook token cache is managed by MSAL.
|
||||||
// Don't save it to database.
|
// Don't save it to database.
|
||||||
|
|
||||||
if (tokenInformation != null && account.ProviderType != MailProviderType.Outlook)
|
if (tokenInformation != null && (account.ProviderType != MailProviderType.Outlook || account.ProviderType == MailProviderType.Office365))
|
||||||
await Connection.InsertAsync(tokenInformation);
|
await Connection.InsertAsync(tokenInformation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ using Wino.Core.Domain;
|
|||||||
using Wino.Core.Domain.Entities;
|
using Wino.Core.Domain.Entities;
|
||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
using Wino.Core.Domain.Models.Accounts;
|
||||||
using Wino.Core.Domain.Models.MailItem;
|
using Wino.Core.Domain.Models.MailItem;
|
||||||
using Wino.Core.Domain.Models.Synchronization;
|
using Wino.Core.Domain.Models.Synchronization;
|
||||||
using Wino.Core.Integration;
|
using Wino.Core.Integration;
|
||||||
@@ -71,10 +72,16 @@ namespace Wino.Core.Synchronizers
|
|||||||
public abstract Task ExecuteNativeRequestsAsync(IEnumerable<IRequestBundle<TBaseRequest>> batchedRequests, CancellationToken cancellationToken = default);
|
public abstract Task ExecuteNativeRequestsAsync(IEnumerable<IRequestBundle<TBaseRequest>> batchedRequests, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Refreshed remote mail account profile if possible.
|
/// Refreshes remote mail account profile if possible.
|
||||||
/// Aliases, profile pictures, mailbox settings will be handled in this step.
|
/// Profile picture, sender name and mailbox settings (todo) will be handled in this step.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual Task SynchronizeProfileInformationAsync() => Task.CompletedTask;
|
public virtual Task<ProfileInformation> SynchronizeProfileInformationAsync() => default;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Refreshes the aliases of the account.
|
||||||
|
/// Only available for Gmail right now.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual Task SynchronizeAliasesAsync() => Task.CompletedTask;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the base64 encoded profile picture of the account from the given URL.
|
/// Returns the base64 encoded profile picture of the account from the given URL.
|
||||||
@@ -100,6 +107,33 @@ namespace Wino.Core.Synchronizers
|
|||||||
/// <returns>Synchronization result that contains summary of the sync.</returns>
|
/// <returns>Synchronization result that contains summary of the sync.</returns>
|
||||||
protected abstract Task<SynchronizationResult> SynchronizeInternalAsync(SynchronizationOptions options, CancellationToken cancellationToken = default);
|
protected abstract Task<SynchronizationResult> SynchronizeInternalAsync(SynchronizationOptions options, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Safely updates account's profile information.
|
||||||
|
/// Database changes are reflected after this call.
|
||||||
|
/// Null returns mean that the operation failed.
|
||||||
|
/// </summary>
|
||||||
|
private async Task<ProfileInformation> SynchronizeProfileInformationInternalAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var profileInformation = await SynchronizeProfileInformationAsync();
|
||||||
|
|
||||||
|
if (profileInformation != null)
|
||||||
|
{
|
||||||
|
Account.SenderName = profileInformation.SenderName;
|
||||||
|
Account.Base64ProfilePictureData = profileInformation.Base64ProfilePictureData;
|
||||||
|
}
|
||||||
|
|
||||||
|
return profileInformation;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failed to update profile information for account '{Name}'", Account.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Batches network requests, executes them, and does the needed synchronization after the batch request execution.
|
/// Batches network requests, executes them, and does the needed synchronization after the batch request execution.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -139,12 +173,16 @@ namespace Wino.Core.Synchronizers
|
|||||||
|
|
||||||
await synchronizationSemaphore.WaitAsync(activeSynchronizationCancellationToken);
|
await synchronizationSemaphore.WaitAsync(activeSynchronizationCancellationToken);
|
||||||
|
|
||||||
if (options.Type == SynchronizationType.Full)
|
if (options.Type == SynchronizationType.UpdateProfile)
|
||||||
{
|
{
|
||||||
// Refresh profile information and mailbox settings on full synchronization.
|
// Refresh profile information on full synchronization.
|
||||||
// Exceptions here is not critical. Therefore, they are ignored.
|
// Exceptions here is not critical. Therefore, they are ignored.
|
||||||
|
|
||||||
await SynchronizeProfileInformationAsync();
|
var newprofileInformation = await SynchronizeProfileInformationInternalAsync();
|
||||||
|
|
||||||
|
if (newprofileInformation == null) return SynchronizationResult.Failed;
|
||||||
|
|
||||||
|
return SynchronizationResult.Completed(null, newprofileInformation);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let servers to finish their job. Sometimes the servers doesn't respond immediately.
|
// Let servers to finish their job. Sometimes the servers doesn't respond immediately.
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ using Wino.Core.Domain.Entities;
|
|||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
using Wino.Core.Domain.Exceptions;
|
using Wino.Core.Domain.Exceptions;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
using Wino.Core.Domain.Models.Accounts;
|
||||||
using Wino.Core.Domain.Models.MailItem;
|
using Wino.Core.Domain.Models.MailItem;
|
||||||
using Wino.Core.Domain.Models.Requests;
|
using Wino.Core.Domain.Models.Requests;
|
||||||
using Wino.Core.Domain.Models.Synchronization;
|
using Wino.Core.Domain.Models.Synchronization;
|
||||||
@@ -68,16 +69,12 @@ namespace Wino.Core.Synchronizers
|
|||||||
|
|
||||||
public ConfigurableHttpClient CreateHttpClient(CreateHttpClientArgs args) => _googleHttpClient;
|
public ConfigurableHttpClient CreateHttpClient(CreateHttpClientArgs args) => _googleHttpClient;
|
||||||
|
|
||||||
protected override async Task SynchronizeProfileInformationAsync()
|
public override async Task<ProfileInformation> SynchronizeProfileInformationAsync()
|
||||||
{
|
|
||||||
// Gmail profile info synchronizes Sender Name, Alias and Profile Picture.
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
var profileRequest = _peopleService.People.Get("people/me");
|
var profileRequest = _peopleService.People.Get("people/me");
|
||||||
profileRequest.PersonFields = "names,photos";
|
profileRequest.PersonFields = "names,photos";
|
||||||
|
|
||||||
string senderName = Account.SenderName, base64ProfilePicture = Account.ProfilePictureBase64;
|
string senderName = string.Empty, base64ProfilePicture = string.Empty;
|
||||||
|
|
||||||
var userProfile = await profileRequest.ExecuteAsync();
|
var userProfile = await profileRequest.ExecuteAsync();
|
||||||
|
|
||||||
@@ -90,46 +87,28 @@ namespace Wino.Core.Synchronizers
|
|||||||
base64ProfilePicture = await GetProfilePictureBase64EncodedAsync(profilePicture).ConfigureAwait(false);
|
base64ProfilePicture = await GetProfilePictureBase64EncodedAsync(profilePicture).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool shouldUpdateAccountProfile = (!string.IsNullOrEmpty(senderName) && Account.SenderName != senderName)
|
return new ProfileInformation(senderName, base64ProfilePicture);
|
||||||
|| (!string.IsNullOrEmpty(profilePicture) && Account.ProfilePictureBase64 != base64ProfilePicture);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(senderName) && Account.SenderName != senderName)
|
|
||||||
{
|
|
||||||
Account.SenderName = senderName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(profilePicture) && Account.ProfilePictureBase64 != base64ProfilePicture)
|
protected override async Task SynchronizeAliasesAsync()
|
||||||
{
|
{
|
||||||
Account.ProfilePictureBase64 = base64ProfilePicture;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync aliases
|
// Sync aliases
|
||||||
|
|
||||||
var sendAsListRequest = _gmailService.Users.Settings.SendAs.List("me");
|
var sendAsListRequest = _gmailService.Users.Settings.SendAs.List("me");
|
||||||
var sendAsListResponse = await sendAsListRequest.ExecuteAsync();
|
var sendAsListResponse = await sendAsListRequest.ExecuteAsync();
|
||||||
|
|
||||||
var updatedAliases = sendAsListResponse.GetMailAliases(Account);
|
var localAliases = await _gmailChangeProcessor.GetAccountAliasesAsync(Account.Id).ConfigureAwait(false);
|
||||||
|
|
||||||
|
var updatedAliases = sendAsListResponse.GetMailAliases(localAliases, Account);
|
||||||
|
|
||||||
bool shouldUpdateAliases =
|
bool shouldUpdateAliases =
|
||||||
Account.Aliases.Any(a => updatedAliases.Any(b => a.Id == b.Id) == false) ||
|
localAliases.Any(a => updatedAliases.Any(b => a.Id == b.Id) == false) ||
|
||||||
updatedAliases.Any(a => Account.Aliases.Any(b => a.Id == b.Id) == false);
|
updatedAliases.Any(a => localAliases.Any(b => a.Id == b.Id) == false);
|
||||||
|
|
||||||
if (shouldUpdateAliases)
|
if (shouldUpdateAliases)
|
||||||
{
|
{
|
||||||
Account.Aliases = updatedAliases;
|
|
||||||
|
|
||||||
await _gmailChangeProcessor.UpdateAccountAliasesAsync(Account.Id, updatedAliases);
|
await _gmailChangeProcessor.UpdateAccountAliasesAsync(Account.Id, updatedAliases);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldUpdateAccountProfile)
|
|
||||||
{
|
|
||||||
await _gmailChangeProcessor.UpdateAccountAsync(Account).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.Error(ex, "Error while synchronizing profile information for {Name}", Account.Name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task<SynchronizationResult> SynchronizeInternalAsync(SynchronizationOptions options, CancellationToken cancellationToken = default)
|
protected override async Task<SynchronizationResult> SynchronizeInternalAsync(SynchronizationOptions options, CancellationToken cancellationToken = default)
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ using Wino.Core.Domain.Entities;
|
|||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
using Wino.Core.Domain.Exceptions;
|
using Wino.Core.Domain.Exceptions;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
using Wino.Core.Domain.Models.Accounts;
|
||||||
using Wino.Core.Domain.Models.MailItem;
|
using Wino.Core.Domain.Models.MailItem;
|
||||||
using Wino.Core.Domain.Models.Requests;
|
using Wino.Core.Domain.Models.Requests;
|
||||||
using Wino.Core.Domain.Models.Synchronization;
|
using Wino.Core.Domain.Models.Synchronization;
|
||||||
@@ -478,8 +479,6 @@ namespace Wino.Core.Synchronizers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Base64 encoded profile picture.</returns>
|
/// <returns>Base64 encoded profile picture.</returns>
|
||||||
private async Task<string> GetUserProfilePictureAsync()
|
private async Task<string> GetUserProfilePictureAsync()
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
var photoStream = await _graphClient.Me.Photos["48x48"].Content.GetAsync();
|
var photoStream = await _graphClient.Me.Photos["48x48"].Content.GetAsync();
|
||||||
|
|
||||||
@@ -489,60 +488,20 @@ namespace Wino.Core.Synchronizers
|
|||||||
|
|
||||||
return Convert.ToBase64String(byteArray);
|
return Convert.ToBase64String(byteArray);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Log.Error(ex, "Error occurred while getting user profile picture.");
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> GetSenderNameAsync()
|
private async Task<string> GetSenderNameAsync()
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
var userInfo = await _graphClient.Users["me"].GetAsync();
|
var userInfo = await _graphClient.Users["me"].GetAsync();
|
||||||
|
|
||||||
return userInfo.DisplayName;
|
return userInfo.DisplayName;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Log.Error(ex, "Failed to get sender name.");
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override async Task SynchronizeProfileInformationAsync()
|
public override async Task<ProfileInformation> SynchronizeProfileInformationAsync()
|
||||||
{
|
{
|
||||||
try
|
|
||||||
{
|
|
||||||
// Outlook profile info synchronizes Sender Name and Profile Picture.
|
|
||||||
string senderName = Account.SenderName, base64ProfilePicture = Account.ProfilePictureBase64;
|
|
||||||
|
|
||||||
var profilePictureData = await GetUserProfilePictureAsync().ConfigureAwait(false);
|
var profilePictureData = await GetUserProfilePictureAsync().ConfigureAwait(false);
|
||||||
senderName = await GetSenderNameAsync().ConfigureAwait(false);
|
var senderName = await GetSenderNameAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
bool shouldUpdateAccountProfile = (!string.IsNullOrEmpty(senderName) && Account.SenderName != senderName)
|
return new ProfileInformation(senderName, profilePictureData);
|
||||||
|| (!string.IsNullOrEmpty(profilePictureData) && Account.ProfilePictureBase64 != base64ProfilePicture);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(profilePictureData) && Account.ProfilePictureBase64 != profilePictureData)
|
|
||||||
{
|
|
||||||
Account.ProfilePictureBase64 = profilePictureData;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(senderName) && Account.SenderName != senderName)
|
|
||||||
{
|
|
||||||
Account.SenderName = senderName;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldUpdateAccountProfile)
|
|
||||||
{
|
|
||||||
await _outlookChangeProcessor.UpdateAccountAsync(Account).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Log.Error(ex, "Failed to synchronize profile information for {Name}", Account.Name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Mail Integration
|
#region Mail Integration
|
||||||
|
|||||||
@@ -56,7 +56,11 @@ namespace Wino.Mail.ViewModels
|
|||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void EditSignature()
|
private void EditSignature()
|
||||||
=> Messenger.Send(new BreadcrumbNavigationRequested("Signature", WinoPage.SignatureManagementPage, Account.Id));
|
=> Messenger.Send(new BreadcrumbNavigationRequested(Translator.SettingsSignature_Title, WinoPage.SignatureManagementPage, Account.Id));
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void EditAliases()
|
||||||
|
=> Messenger.Send(new BreadcrumbNavigationRequested(Translator.SettingsManageAliases_Title, WinoPage.AliasManagementPage, Account.Id));
|
||||||
|
|
||||||
public Task FolderSyncToggledAsync(IMailItemFolder folderStructure, bool isEnabled)
|
public Task FolderSyncToggledAsync(IMailItemFolder folderStructure, bool isEnabled)
|
||||||
=> _folderService.ChangeFolderSynchronizationStateAsync(folderStructure.Id, isEnabled);
|
=> _folderService.ChangeFolderSynchronizationStateAsync(folderStructure.Id, isEnabled);
|
||||||
|
|||||||
@@ -154,15 +154,12 @@ namespace Wino.Mail.ViewModels
|
|||||||
{
|
{
|
||||||
creationDialog = _dialogService.GetAccountCreationDialog(accountCreationDialogResult.ProviderType);
|
creationDialog = _dialogService.GetAccountCreationDialog(accountCreationDialogResult.ProviderType);
|
||||||
|
|
||||||
// _accountService.ExternalAuthenticationAuthenticator = _authenticationProvider.GetAuthenticator(accountCreationDialogResult.ProviderType);
|
|
||||||
|
|
||||||
CustomServerInformation customServerInformation = null;
|
CustomServerInformation customServerInformation = null;
|
||||||
|
|
||||||
createdAccount = new MailAccount()
|
createdAccount = new MailAccount()
|
||||||
{
|
{
|
||||||
ProviderType = accountCreationDialogResult.ProviderType,
|
ProviderType = accountCreationDialogResult.ProviderType,
|
||||||
Name = accountCreationDialogResult.AccountName,
|
Name = accountCreationDialogResult.AccountName,
|
||||||
SenderName = accountCreationDialogResult.SenderName,
|
|
||||||
AccountColorHex = accountCreationDialogResult.AccountColorHex,
|
AccountColorHex = accountCreationDialogResult.AccountColorHex,
|
||||||
Id = Guid.NewGuid()
|
Id = Guid.NewGuid()
|
||||||
};
|
};
|
||||||
@@ -208,30 +205,59 @@ namespace Wino.Mail.ViewModels
|
|||||||
await _accountService.CreateAccountAsync(createdAccount, tokenInformation, customServerInformation);
|
await _accountService.CreateAccountAsync(createdAccount, tokenInformation, customServerInformation);
|
||||||
|
|
||||||
// Local account has been created.
|
// Local account has been created.
|
||||||
// Create new synchronizer and start synchronization.
|
|
||||||
|
// Start profile information synchronization.
|
||||||
|
// Profile info is not updated in the database yet.
|
||||||
|
|
||||||
|
var profileSyncOptions = new SynchronizationOptions()
|
||||||
|
{
|
||||||
|
AccountId = createdAccount.Id,
|
||||||
|
Type = SynchronizationType.UpdateProfile
|
||||||
|
};
|
||||||
|
|
||||||
|
var profileSynchronizationResponse = await _winoServerConnectionManager.GetResponseAsync<SynchronizationResult, NewSynchronizationRequested>(new NewSynchronizationRequested(profileSyncOptions, SynchronizationSource.Client));
|
||||||
|
|
||||||
|
var profileSynchronizationResult = profileSynchronizationResponse.Data;
|
||||||
|
|
||||||
|
if (profileSynchronizationResult.CompletedState != SynchronizationCompletedState.Success)
|
||||||
|
throw new Exception(Translator.Exception_FailedToSynchronizeProfileInformation);
|
||||||
|
|
||||||
|
createdAccount.SenderName = profileSynchronizationResult.ProfileInformation.SenderName;
|
||||||
|
createdAccount.Base64ProfilePictureData = profileSynchronizationResult.ProfileInformation.Base64ProfilePictureData;
|
||||||
|
|
||||||
|
await _accountService.UpdateProfileInformationAsync(createdAccount.Id, profileSynchronizationResult.ProfileInformation);
|
||||||
|
|
||||||
if (creationDialog is ICustomServerAccountCreationDialog customServerAccountCreationDialog)
|
if (creationDialog is ICustomServerAccountCreationDialog customServerAccountCreationDialog)
|
||||||
customServerAccountCreationDialog.ShowPreparingFolders();
|
customServerAccountCreationDialog.ShowPreparingFolders();
|
||||||
else
|
else
|
||||||
creationDialog.State = AccountCreationDialogState.PreparingFolders;
|
creationDialog.State = AccountCreationDialogState.PreparingFolders;
|
||||||
|
|
||||||
var options = new SynchronizationOptions()
|
// Start synchronizing folders.
|
||||||
|
var folderSyncOptions = new SynchronizationOptions()
|
||||||
{
|
{
|
||||||
AccountId = createdAccount.Id,
|
AccountId = createdAccount.Id,
|
||||||
Type = SynchronizationType.FoldersOnly
|
Type = SynchronizationType.FoldersOnly
|
||||||
};
|
};
|
||||||
|
|
||||||
var synchronizationResultResponse = await _winoServerConnectionManager.GetResponseAsync<SynchronizationResult, NewSynchronizationRequested>(new NewSynchronizationRequested(options, SynchronizationSource.Client));
|
var folderSynchronizationResponse = await _winoServerConnectionManager.GetResponseAsync<SynchronizationResult, NewSynchronizationRequested>(new NewSynchronizationRequested(folderSyncOptions, SynchronizationSource.Client));
|
||||||
|
|
||||||
var synchronizationResult = synchronizationResultResponse.Data;
|
var folderSynchronizationResult = folderSynchronizationResponse.Data;
|
||||||
if (synchronizationResult.CompletedState != SynchronizationCompletedState.Success)
|
|
||||||
|
if (folderSynchronizationResult.CompletedState != SynchronizationCompletedState.Success)
|
||||||
throw new Exception(Translator.Exception_FailedToSynchronizeFolders);
|
throw new Exception(Translator.Exception_FailedToSynchronizeFolders);
|
||||||
|
|
||||||
// Check if Inbox folder is available for the account after synchronization.
|
// Create root primary alias for the account.
|
||||||
var isInboxAvailable = await _folderService.IsInboxAvailableForAccountAsync(createdAccount.Id);
|
// This is the first alias for the account and it's primary.
|
||||||
|
|
||||||
if (!isInboxAvailable)
|
await _accountService.CreateRootAliasAsync(createdAccount.Id, createdAccount.Address);
|
||||||
throw new Exception(Translator.Exception_InboxNotAvailable);
|
|
||||||
|
// 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.
|
// Send changes to listeners.
|
||||||
ReportUIChange(new AccountCreatedMessage(createdAccount));
|
ReportUIChange(new AccountCreatedMessage(createdAccount));
|
||||||
|
|||||||
115
Wino.Mail.ViewModels/AliasManagementPageViewModel.cs
Normal file
115
Wino.Mail.ViewModels/AliasManagementPageViewModel.cs
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using EmailValidation;
|
||||||
|
using Wino.Core.Domain;
|
||||||
|
using Wino.Core.Domain.Entities;
|
||||||
|
using Wino.Core.Domain.Enums;
|
||||||
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
using Wino.Core.Domain.Models.Navigation;
|
||||||
|
|
||||||
|
namespace Wino.Mail.ViewModels
|
||||||
|
{
|
||||||
|
public partial class AliasManagementPageViewModel : BaseViewModel
|
||||||
|
{
|
||||||
|
private readonly IAccountService _accountService;
|
||||||
|
|
||||||
|
public MailAccount Account { get; set; }
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private List<MailAccountAlias> accountAliases = [];
|
||||||
|
|
||||||
|
public AliasManagementPageViewModel(IDialogService dialogService, IAccountService accountService) : base(dialogService)
|
||||||
|
{
|
||||||
|
_accountService = accountService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async void OnNavigatedTo(NavigationMode mode, object parameters)
|
||||||
|
{
|
||||||
|
base.OnNavigatedTo(mode, parameters);
|
||||||
|
|
||||||
|
if (parameters is Guid accountId)
|
||||||
|
Account = await _accountService.GetAccountAsync(accountId);
|
||||||
|
|
||||||
|
if (Account == null) return;
|
||||||
|
|
||||||
|
await LoadAliasesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadAliasesAsync()
|
||||||
|
{
|
||||||
|
AccountAliases = await _accountService.GetAccountAliasesAsync(Account.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task SetAliasPrimaryAsync(MailAccountAlias alias)
|
||||||
|
{
|
||||||
|
if (alias.IsPrimary) return;
|
||||||
|
|
||||||
|
AccountAliases.ForEach(a =>
|
||||||
|
{
|
||||||
|
a.IsPrimary = a == alias;
|
||||||
|
});
|
||||||
|
|
||||||
|
await _accountService.UpdateAccountAliasesAsync(Account.Id, AccountAliases);
|
||||||
|
await LoadAliasesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task AddNewAliasAsync()
|
||||||
|
{
|
||||||
|
var createdAliasDialog = await DialogService.ShowCreateAccountAliasDialogAsync();
|
||||||
|
|
||||||
|
if (createdAliasDialog.CreatedAccountAlias == null) return;
|
||||||
|
|
||||||
|
var newAlias = createdAliasDialog.CreatedAccountAlias;
|
||||||
|
|
||||||
|
// Check existence.
|
||||||
|
if (AccountAliases.Any(a => a.AliasAddress == newAlias.AliasAddress))
|
||||||
|
{
|
||||||
|
await DialogService.ShowMessageAsync(Translator.DialogMessage_AliasExistsTitle, Translator.DialogMessage_AliasExistsMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate all addresses.
|
||||||
|
if (!EmailValidator.Validate(newAlias.ReplyToAddress) || !EmailValidator.Validate(newAlias.AliasAddress))
|
||||||
|
{
|
||||||
|
await DialogService.ShowMessageAsync(Translator.DialogMessage_InvalidAliasMessage, Translator.DialogMessage_InvalidAliasTitle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
newAlias.AccountId = Account.Id;
|
||||||
|
|
||||||
|
AccountAliases.Add(newAlias);
|
||||||
|
|
||||||
|
await _accountService.UpdateAccountAliasesAsync(Account.Id, AccountAliases);
|
||||||
|
DialogService.InfoBarMessage(Translator.DialogMessage_AliasCreatedTitle, Translator.DialogMessage_AliasCreatedMessage, InfoBarMessageType.Success);
|
||||||
|
|
||||||
|
await LoadAliasesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task DeleteAliasAsync(MailAccountAlias alias)
|
||||||
|
{
|
||||||
|
// Primary aliases can't be deleted.
|
||||||
|
if (alias.IsPrimary)
|
||||||
|
{
|
||||||
|
await DialogService.ShowMessageAsync(Translator.Info_CantDeletePrimaryAliasMessage, Translator.GeneralTitle_Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Root aliases can't be deleted.
|
||||||
|
if (alias.IsRootAlias)
|
||||||
|
{
|
||||||
|
await DialogService.ShowMessageAsync(Translator.DialogMessage_CantDeleteRootAliasTitle, Translator.DialogMessage_CantDeleteRootAliasMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _accountService.DeleteAccountAliasAsync(alias.Id);
|
||||||
|
await LoadAliasesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,31 +3,21 @@ using Wino.Messaging.Client.Navigation;
|
|||||||
|
|
||||||
namespace Wino.Mail.ViewModels.Data
|
namespace Wino.Mail.ViewModels.Data
|
||||||
{
|
{
|
||||||
public class BreadcrumbNavigationItemViewModel : ObservableObject
|
public partial class BreadcrumbNavigationItemViewModel : ObservableObject
|
||||||
{
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private string title;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool isActive;
|
||||||
|
|
||||||
public BreadcrumbNavigationRequested Request { get; set; }
|
public BreadcrumbNavigationRequested Request { get; set; }
|
||||||
|
|
||||||
public BreadcrumbNavigationItemViewModel(BreadcrumbNavigationRequested request, bool isActive)
|
public BreadcrumbNavigationItemViewModel(BreadcrumbNavigationRequested request, bool isActive)
|
||||||
{
|
{
|
||||||
Request = request;
|
Request = request;
|
||||||
Title = request.PageTitle;
|
Title = request.PageTitle;
|
||||||
|
IsActive = isActive;
|
||||||
this.isActive = isActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string title;
|
|
||||||
public string Title
|
|
||||||
{
|
|
||||||
get => title;
|
|
||||||
set => SetProperty(ref title, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool isActive;
|
|
||||||
|
|
||||||
public bool IsActive
|
|
||||||
{
|
|
||||||
get => isActive;
|
|
||||||
set => SetProperty(ref isActive, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="EmailValidation" Version="1.2.0" />
|
||||||
<PackageReference Include="IsExternalInit" Version="1.0.3">
|
<PackageReference Include="IsExternalInit" Version="1.0.3">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<Application x:Class="Wino.App"
|
<Application
|
||||||
|
x:Class="Wino.App"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:controls="using:Wino.Controls"
|
xmlns:controls="using:Wino.Controls"
|
||||||
@@ -48,6 +49,14 @@
|
|||||||
<Setter Property="BorderThickness" Value="1" />
|
<Setter Property="BorderThickness" Value="1" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<!-- Custom Grid style for info panels. -->
|
||||||
|
<Style TargetType="Grid" x:Key="InformationAreaGridStyle">
|
||||||
|
<Setter Property="Background" Value="{ThemeResource CardBackgroundFillColorDefaultBrush}" />
|
||||||
|
<Setter Property="BorderBrush" Value="{ThemeResource DividerStrokeColorDefaultBrush}" />
|
||||||
|
<Setter Property="CornerRadius" Value="8" />
|
||||||
|
<Setter Property="Padding" Value="16" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
<!-- Default StackPanel animation. -->
|
<!-- Default StackPanel animation. -->
|
||||||
<Style TargetType="StackPanel">
|
<Style TargetType="StackPanel">
|
||||||
<Setter Property="ChildrenTransitions">
|
<Setter Property="ChildrenTransitions">
|
||||||
@@ -60,7 +69,8 @@
|
|||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<!-- Default Style for ContentDialog -->
|
<!-- Default Style for ContentDialog -->
|
||||||
<Style x:Key="WinoDialogStyle"
|
<Style
|
||||||
|
x:Key="WinoDialogStyle"
|
||||||
BasedOn="{StaticResource DefaultContentDialogStyle}"
|
BasedOn="{StaticResource DefaultContentDialogStyle}"
|
||||||
TargetType="ContentDialog" />
|
TargetType="ContentDialog" />
|
||||||
|
|
||||||
@@ -74,14 +84,16 @@
|
|||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<ControlTemplate TargetType="controls:SettingsMenuItemControl">
|
<ControlTemplate TargetType="controls:SettingsMenuItemControl">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Button Padding="0"
|
<Button
|
||||||
|
Padding="0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
HorizontalContentAlignment="Stretch"
|
HorizontalContentAlignment="Stretch"
|
||||||
Command="{TemplateBinding Command}"
|
Command="{TemplateBinding Command}"
|
||||||
CommandParameter="{TemplateBinding CommandParameter}"
|
CommandParameter="{TemplateBinding CommandParameter}"
|
||||||
IsEnabled="{TemplateBinding IsEnabled}"
|
IsEnabled="{TemplateBinding IsEnabled}"
|
||||||
IsHitTestVisible="{TemplateBinding IsClickable}">
|
IsHitTestVisible="{TemplateBinding IsClickable}">
|
||||||
<Grid Height="70"
|
<Grid
|
||||||
|
Height="70"
|
||||||
Padding="0,6,12,6"
|
Padding="0,6,12,6"
|
||||||
CornerRadius="4">
|
CornerRadius="4">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
@@ -89,11 +101,13 @@
|
|||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<ContentControl HorizontalAlignment="Center"
|
<ContentControl
|
||||||
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Content="{TemplateBinding Icon}" />
|
Content="{TemplateBinding Icon}" />
|
||||||
|
|
||||||
<Grid Grid.Column="1"
|
<Grid
|
||||||
|
Grid.Column="1"
|
||||||
Margin="4,0"
|
Margin="4,0"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
RowSpacing="3">
|
RowSpacing="3">
|
||||||
@@ -102,17 +116,20 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<TextBlock VerticalAlignment="Center"
|
<TextBlock
|
||||||
|
VerticalAlignment="Center"
|
||||||
FontWeight="SemiBold"
|
FontWeight="SemiBold"
|
||||||
Style="{StaticResource BodyTextBlockStyle}"
|
Style="{StaticResource BodyTextBlockStyle}"
|
||||||
Text="{TemplateBinding Title}" />
|
Text="{TemplateBinding Title}" />
|
||||||
<TextBlock Grid.Row="1"
|
<TextBlock
|
||||||
|
Grid.Row="1"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource CaptionTextBlockStyle}"
|
Style="{StaticResource CaptionTextBlockStyle}"
|
||||||
Text="{TemplateBinding Description}" />
|
Text="{TemplateBinding Description}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Viewbox Grid.Column="0"
|
<Viewbox
|
||||||
|
Grid.Column="0"
|
||||||
Grid.ColumnSpan="2"
|
Grid.ColumnSpan="2"
|
||||||
Width="16"
|
Width="16"
|
||||||
Height="16"
|
Height="16"
|
||||||
@@ -124,7 +141,8 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<ContentControl Grid.RowSpan="2"
|
<ContentControl
|
||||||
|
Grid.RowSpan="2"
|
||||||
Margin="0,0,16,0"
|
Margin="0,0,16,0"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
@@ -188,7 +206,8 @@
|
|||||||
<Image Source="/Assets/FileTypes/type_other.png" />
|
<Image Source="/Assets/FileTypes/type_other.png" />
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
<selectors:FileAttachmentTypeSelector x:Key="FileTypeIconSelector"
|
<selectors:FileAttachmentTypeSelector
|
||||||
|
x:Key="FileTypeIconSelector"
|
||||||
Archive="{StaticResource ArchiveTemplate}"
|
Archive="{StaticResource ArchiveTemplate}"
|
||||||
Executable="{StaticResource ExecutableTemplate}"
|
Executable="{StaticResource ExecutableTemplate}"
|
||||||
HTML="{StaticResource HTMLTemplate}"
|
HTML="{StaticResource HTMLTemplate}"
|
||||||
|
|||||||
@@ -179,6 +179,7 @@ namespace Wino
|
|||||||
services.AddTransient(typeof(MergedAccountDetailsPageViewModel));
|
services.AddTransient(typeof(MergedAccountDetailsPageViewModel));
|
||||||
services.AddTransient(typeof(LanguageTimePageViewModel));
|
services.AddTransient(typeof(LanguageTimePageViewModel));
|
||||||
services.AddTransient(typeof(AppPreferencesPageViewModel));
|
services.AddTransient(typeof(AppPreferencesPageViewModel));
|
||||||
|
services.AddTransient(typeof(AliasManagementPageViewModel));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
<ResourceDictionary
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:xaml="using:Windows.UI.Xaml">
|
xmlns:xaml="using:Windows.UI.Xaml">
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,13 @@
|
|||||||
</VisualState.Setters>
|
</VisualState.Setters>
|
||||||
</VisualState>
|
</VisualState>
|
||||||
|
|
||||||
|
<VisualState x:Name="FetchingProfileInformation">
|
||||||
|
<VisualState.Setters>
|
||||||
|
<Setter Target="StatusText.Text" Value="{x:Bind domain:Translator.AccountCreationDialog_FetchingProfileInformation}" />
|
||||||
|
<Setter Target="DialogIcon.Glyph" Value="F1 M 1.875 17.5 C 1.621094 17.5 1.380208 17.451172 1.152344 17.353516 C 0.924479 17.255859 0.724284 17.120768 0.551758 16.948242 C 0.379232 16.775717 0.244141 16.575521 0.146484 16.347656 C 0.048828 16.119791 0 15.878906 0 15.625 L 0 4.375 C 0 4.121094 0.048828 3.880209 0.146484 3.652344 C 0.244141 3.42448 0.379232 3.224285 0.551758 3.051758 C 0.724284 2.879232 0.924479 2.744141 1.152344 2.646484 C 1.380208 2.548828 1.621094 2.5 1.875 2.5 L 18.125 2.5 C 18.378906 2.5 18.619791 2.548828 18.847656 2.646484 C 19.07552 2.744141 19.275715 2.879232 19.448242 3.051758 C 19.620768 3.224285 19.755859 3.42448 19.853516 3.652344 C 19.951172 3.880209 20 4.121094 20 4.375 L 20 15.625 C 20 15.878906 19.951172 16.119791 19.853516 16.347656 C 19.755859 16.575521 19.620768 16.775717 19.448242 16.948242 C 19.275715 17.120768 19.07552 17.255859 18.847656 17.353516 C 18.619791 17.451172 18.378906 17.5 18.125 17.5 Z M 5 16.25 L 5 14.375 C 5 14.121094 5.048828 13.880209 5.146484 13.652344 C 5.244141 13.424479 5.379231 13.224284 5.551758 13.051758 C 5.724284 12.879232 5.924479 12.744141 6.152344 12.646484 C 6.380208 12.548828 6.621094 12.5 6.875 12.5 L 13.125 12.5 C 13.378905 12.5 13.619791 12.548828 13.847656 12.646484 C 14.075521 12.744141 14.275716 12.879232 14.448242 13.051758 C 14.620768 13.224284 14.755858 13.424479 14.853516 13.652344 C 14.951171 13.880209 14.999999 14.121094 15 14.375 L 15 16.25 L 18.125 16.25 C 18.29427 16.25 18.440754 16.188152 18.564453 16.064453 C 18.68815 15.940756 18.75 15.794271 18.75 15.625 L 18.75 4.375 C 18.75 4.20573 18.68815 4.059246 18.564453 3.935547 C 18.440754 3.81185 18.29427 3.75 18.125 3.75 L 1.875 3.75 C 1.705729 3.75 1.559245 3.81185 1.435547 3.935547 C 1.311849 4.059246 1.25 4.20573 1.25 4.375 L 1.25 15.625 C 1.25 15.794271 1.311849 15.940756 1.435547 16.064453 C 1.559245 16.188152 1.705729 16.25 1.875 16.25 Z M 6.875 8.056641 C 6.875 7.633464 6.959635 7.236328 7.128906 6.865234 C 7.298177 6.494141 7.526041 6.170248 7.8125 5.893555 C 8.098958 5.616862 8.430989 5.398764 8.808594 5.239258 C 9.186197 5.079754 9.583333 5.000001 10 5 C 10.436197 5.000001 10.843099 5.081381 11.220703 5.244141 C 11.598307 5.406901 11.928711 5.629883 12.211914 5.913086 C 12.495117 6.196289 12.718099 6.526693 12.880859 6.904297 C 13.043619 7.281901 13.124999 7.688803 13.125 8.125 C 13.124999 8.561198 13.043619 8.9681 12.880859 9.345703 C 12.718099 9.723308 12.495117 10.053711 12.211914 10.336914 C 11.928711 10.620117 11.598307 10.8431 11.220703 11.005859 C 10.843099 11.16862 10.436197 11.25 10 11.25 C 9.550781 11.25 9.135742 11.166992 8.754883 11.000977 C 8.374023 10.834961 8.043619 10.607097 7.763672 10.317383 C 7.483724 10.02767 7.265625 9.689128 7.109375 9.301758 C 6.953125 8.914389 6.875 8.49935 6.875 8.056641 Z M 11.875 8.125 C 11.875 7.871094 11.826172 7.630209 11.728516 7.402344 C 11.630859 7.174479 11.495768 6.974284 11.323242 6.801758 C 11.150716 6.629232 10.950521 6.494141 10.722656 6.396484 C 10.494791 6.298828 10.253906 6.25 10 6.25 C 9.746094 6.25 9.505208 6.298828 9.277344 6.396484 C 9.049479 6.494141 8.849283 6.629232 8.676758 6.801758 C 8.504231 6.974284 8.369141 7.174479 8.271484 7.402344 C 8.173828 7.630209 8.125 7.871094 8.125 8.125 C 8.125 8.378906 8.173828 8.619792 8.271484 8.847656 C 8.369141 9.075521 8.504231 9.275717 8.676758 9.448242 C 8.849283 9.620769 9.049479 9.755859 9.277344 9.853516 C 9.505208 9.951172 9.746094 10 10 10 C 10.253906 10 10.494791 9.951172 10.722656 9.853516 C 10.950521 9.755859 11.150716 9.620769 11.323242 9.448242 C 11.495768 9.275717 11.630859 9.075521 11.728516 8.847656 C 11.826172 8.619792 11.875 8.378906 11.875 8.125 Z M 6.25 16.25 L 13.75 16.25 L 13.75 14.375 C 13.75 14.205729 13.68815 14.059245 13.564453 13.935547 C 13.440755 13.81185 13.294271 13.75 13.125 13.75 L 6.875 13.75 C 6.705729 13.75 6.559244 13.81185 6.435547 13.935547 C 6.311849 14.059245 6.25 14.205729 6.25 14.375 Z " />
|
||||||
|
</VisualState.Setters>
|
||||||
|
</VisualState>
|
||||||
|
|
||||||
<VisualState x:Name="Completed">
|
<VisualState x:Name="Completed">
|
||||||
<VisualState.Setters>
|
<VisualState.Setters>
|
||||||
<Setter Target="StatusText.Text" Value="{x:Bind domain:Translator.AccountCreationDialog_Completed}" />
|
<Setter Target="StatusText.Text" Value="{x:Bind domain:Translator.AccountCreationDialog_Completed}" />
|
||||||
|
|||||||
40
Wino.Mail/Dialogs/CreateAccountAliasDialog.xaml
Normal file
40
Wino.Mail/Dialogs/CreateAccountAliasDialog.xaml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<ContentDialog
|
||||||
|
x:Class="Wino.Dialogs.CreateAccountAliasDialog"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="using:Wino.Dialogs"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
xmlns:domain="using:Wino.Core.Domain"
|
||||||
|
PrimaryButtonText="{x:Bind domain:Translator.Buttons_Create}"
|
||||||
|
SecondaryButtonText="{x:Bind domain:Translator.Buttons_Cancel}"
|
||||||
|
DefaultButton="Primary"
|
||||||
|
PrimaryButtonClick="CreateClicked"
|
||||||
|
Title="{x:Bind domain:Translator.CreateAccountAliasDialog_Title}"
|
||||||
|
Style="{StaticResource WinoDialogStyle}">
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<TextBlock Text="{x:Bind domain:Translator.CreateAccountAliasDialog_Description}" Style="{StaticResource CaptionTextBlockStyle}" />
|
||||||
|
|
||||||
|
<StackPanel
|
||||||
|
Grid.Row="1"
|
||||||
|
Margin="0,20"
|
||||||
|
Spacing="8">
|
||||||
|
<TextBox
|
||||||
|
x:Name="AliasTextBox"
|
||||||
|
PlaceholderText="{x:Bind domain:Translator.CreateAccountAliasDialog_AliasAddressPlaceholder}"
|
||||||
|
Header="{x:Bind domain:Translator.CreateAccountAliasDialog_AliasAddress}" />
|
||||||
|
|
||||||
|
<TextBox
|
||||||
|
x:Name="ReplyToTextBox"
|
||||||
|
PlaceholderText="{x:Bind domain:Translator.CreateAccountAliasDialog_ReplyToAddressPlaceholder}"
|
||||||
|
Header="{x:Bind domain:Translator.CreateAccountAliasDialog_ReplyToAddress}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</ContentDialog>
|
||||||
|
|
||||||
30
Wino.Mail/Dialogs/CreateAccountAliasDialog.xaml.cs
Normal file
30
Wino.Mail/Dialogs/CreateAccountAliasDialog.xaml.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using System;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
|
using Wino.Core.Domain.Entities;
|
||||||
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
|
||||||
|
namespace Wino.Dialogs
|
||||||
|
{
|
||||||
|
public sealed partial class CreateAccountAliasDialog : ContentDialog, ICreateAccountAliasDialog
|
||||||
|
{
|
||||||
|
public MailAccountAlias CreatedAccountAlias { get; set; }
|
||||||
|
public CreateAccountAliasDialog()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args)
|
||||||
|
{
|
||||||
|
CreatedAccountAlias = new MailAccountAlias
|
||||||
|
{
|
||||||
|
AliasAddress = AliasTextBox.Text.Trim(),
|
||||||
|
ReplyToAddress = ReplyToTextBox.Text.Trim(),
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
IsPrimary = false,
|
||||||
|
IsVerified = false
|
||||||
|
};
|
||||||
|
|
||||||
|
Hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -56,14 +56,6 @@
|
|||||||
PlaceholderText="{x:Bind domain:Translator.NewAccountDialog_AccountNamePlaceholder}"
|
PlaceholderText="{x:Bind domain:Translator.NewAccountDialog_AccountNamePlaceholder}"
|
||||||
TextChanged="AccountNameChanged" />
|
TextChanged="AccountNameChanged" />
|
||||||
|
|
||||||
<!-- Sender Name -->
|
|
||||||
<TextBox
|
|
||||||
x:Name="SenderNameTextbox"
|
|
||||||
Grid.Row="1"
|
|
||||||
Header="{x:Bind domain:Translator.AccountSettingsDialog_AccountName}"
|
|
||||||
PlaceholderText="{x:Bind domain:Translator.AccountSettingsDialog_AccountNamePlaceholder}"
|
|
||||||
TextChanged="SenderNameChanged" />
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
TODO: Move Name, Sender Name and Color Picker to another Frame.
|
TODO: Move Name, Sender Name and Color Picker to another Frame.
|
||||||
Provider selection should be first, then account details.
|
Provider selection should be first, then account details.
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ namespace Wino.Dialogs
|
|||||||
|
|
||||||
if (IsSecondaryButtonEnabled)
|
if (IsSecondaryButtonEnabled)
|
||||||
{
|
{
|
||||||
Result = new AccountCreationDialogResult(SelectedMailProvider.Type, AccountNameTextbox.Text.Trim(), SenderNameTextbox.Text.Trim());
|
Result = new AccountCreationDialogResult(SelectedMailProvider.Type, AccountNameTextbox.Text.Trim());
|
||||||
Hide();
|
Hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,8 +68,7 @@ namespace Wino.Dialogs
|
|||||||
{
|
{
|
||||||
bool shouldEnable = SelectedMailProvider != null
|
bool shouldEnable = SelectedMailProvider != null
|
||||||
&& SelectedMailProvider.IsSupported
|
&& SelectedMailProvider.IsSupported
|
||||||
&& !string.IsNullOrEmpty(AccountNameTextbox.Text)
|
&& !string.IsNullOrEmpty(AccountNameTextbox.Text);
|
||||||
&& (SelectedMailProvider.RequireSenderNameOnCreationDialog ? !string.IsNullOrEmpty(SenderNameTextbox.Text) : true);
|
|
||||||
|
|
||||||
IsPrimaryButtonEnabled = shouldEnable;
|
IsPrimaryButtonEnabled = shouldEnable;
|
||||||
}
|
}
|
||||||
@@ -77,7 +76,6 @@ namespace Wino.Dialogs
|
|||||||
private void ValidateNames()
|
private void ValidateNames()
|
||||||
{
|
{
|
||||||
AccountNameTextbox.IsEnabled = SelectedMailProvider != null;
|
AccountNameTextbox.IsEnabled = SelectedMailProvider != null;
|
||||||
SenderNameTextbox.IsEnabled = SelectedMailProvider != null && SelectedMailProvider.Type != Core.Domain.Enums.MailProviderType.IMAP4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DialogOpened(ContentDialog sender, ContentDialogOpenedEventArgs args) => Validate();
|
private void DialogOpened(ContentDialog sender, ContentDialogOpenedEventArgs args) => Validate();
|
||||||
|
|||||||
@@ -216,6 +216,18 @@ namespace Wino.Services
|
|||||||
return storeDialog;
|
return storeDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ICreateAccountAliasDialog> ShowCreateAccountAliasDialogAsync()
|
||||||
|
{
|
||||||
|
var createAccountAliasDialog = new CreateAccountAliasDialog()
|
||||||
|
{
|
||||||
|
RequestedTheme = _themeService.RootTheme.ToWindowsElementTheme()
|
||||||
|
};
|
||||||
|
|
||||||
|
await HandleDialogPresentationAsync(createAccountAliasDialog);
|
||||||
|
|
||||||
|
return createAccountAliasDialog;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task HandleSystemFolderConfigurationDialogAsync(Guid accountId, IFolderService folderService)
|
public async Task HandleSystemFolderConfigurationDialogAsync(Guid accountId, IFolderService folderService)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -88,6 +88,8 @@ namespace Wino.Services
|
|||||||
return typeof(SettingOptionsPage);
|
return typeof(SettingOptionsPage);
|
||||||
case WinoPage.AppPreferencesPage:
|
case WinoPage.AppPreferencesPage:
|
||||||
return typeof(AppPreferencesPage);
|
return typeof(AppPreferencesPage);
|
||||||
|
case WinoPage.AliasManagementPage:
|
||||||
|
return typeof(AliasManagementPage);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
|
|
||||||
<SolidColorBrush x:Key="FolderSyncBrush">#1abc9c</SolidColorBrush>
|
<SolidColorBrush x:Key="FolderSyncBrush">#1abc9c</SolidColorBrush>
|
||||||
|
|
||||||
|
<SolidColorBrush x:Key="AliasUnverifiedBrush">#ff7675</SolidColorBrush>
|
||||||
|
<SolidColorBrush x:Key="AliasVerifiedBrush">#1abc9c</SolidColorBrush>
|
||||||
|
|
||||||
<ResourceDictionary.ThemeDictionaries>
|
<ResourceDictionary.ThemeDictionaries>
|
||||||
<ResourceDictionary x:Name="Light">
|
<ResourceDictionary x:Name="Light">
|
||||||
<SolidColorBrush x:Key="AttachmentBrush">#fdcb6e</SolidColorBrush>
|
<SolidColorBrush x:Key="AttachmentBrush">#fdcb6e</SolidColorBrush>
|
||||||
|
|||||||
6
Wino.Mail/Views/Abstract/AliasManagementPageAbstract.cs
Normal file
6
Wino.Mail/Views/Abstract/AliasManagementPageAbstract.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
using Wino.Mail.ViewModels;
|
||||||
|
|
||||||
|
namespace Wino.Views.Abstract
|
||||||
|
{
|
||||||
|
public abstract class AliasManagementPageAbstract : BasePage<AliasManagementPageViewModel> { }
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -443,7 +443,6 @@
|
|||||||
x:Name="AccountsComboBox"
|
x:Name="AccountsComboBox"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
IsEditable="False"
|
IsEditable="False"
|
||||||
IsEnabled="False"
|
|
||||||
ItemsSource="{x:Bind ViewModel.Accounts}"
|
ItemsSource="{x:Bind ViewModel.Accounts}"
|
||||||
SelectedItem="{x:Bind ViewModel.ComposingAccount, Mode=TwoWay}">
|
SelectedItem="{x:Bind ViewModel.ComposingAccount, Mode=TwoWay}">
|
||||||
<ComboBox.ItemTemplate>
|
<ComboBox.ItemTemplate>
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ namespace Wino.Views
|
|||||||
WinoPage.SignatureManagementPage => typeof(SignatureManagementPage),
|
WinoPage.SignatureManagementPage => typeof(SignatureManagementPage),
|
||||||
WinoPage.AccountDetailsPage => typeof(AccountDetailsPage),
|
WinoPage.AccountDetailsPage => typeof(AccountDetailsPage),
|
||||||
WinoPage.MergedAccountDetailsPage => typeof(MergedAccountDetailsPage),
|
WinoPage.MergedAccountDetailsPage => typeof(MergedAccountDetailsPage),
|
||||||
|
WinoPage.AliasManagementPage => typeof(AliasManagementPage),
|
||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
163
Wino.Mail/Views/Settings/AliasManagementPage.xaml
Normal file
163
Wino.Mail/Views/Settings/AliasManagementPage.xaml
Normal file
File diff suppressed because one or more lines are too long
12
Wino.Mail/Views/Settings/AliasManagementPage.xaml.cs
Normal file
12
Wino.Mail/Views/Settings/AliasManagementPage.xaml.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Wino.Views.Abstract;
|
||||||
|
|
||||||
|
namespace Wino.Views.Settings
|
||||||
|
{
|
||||||
|
public sealed partial class AliasManagementPage : AliasManagementPageAbstract
|
||||||
|
{
|
||||||
|
public AliasManagementPage()
|
||||||
|
{
|
||||||
|
this.InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -169,6 +169,9 @@
|
|||||||
<PackageReference Include="CommunityToolkit.Uwp.Animations">
|
<PackageReference Include="CommunityToolkit.Uwp.Animations">
|
||||||
<Version>8.0.240109</Version>
|
<Version>8.0.240109</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
<PackageReference Include="CommunityToolkit.Uwp.Behaviors">
|
||||||
|
<Version>8.0.240109</Version>
|
||||||
|
</PackageReference>
|
||||||
<PackageReference Include="CommunityToolkit.Uwp.Controls.SettingsControls">
|
<PackageReference Include="CommunityToolkit.Uwp.Controls.SettingsControls">
|
||||||
<Version>8.0.240109</Version>
|
<Version>8.0.240109</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
@@ -268,6 +271,9 @@
|
|||||||
<Compile Include="Dialogs\NewImapSetupDialog.xaml.cs">
|
<Compile Include="Dialogs\NewImapSetupDialog.xaml.cs">
|
||||||
<DependentUpon>NewImapSetupDialog.xaml</DependentUpon>
|
<DependentUpon>NewImapSetupDialog.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Dialogs\CreateAccountAliasDialog.xaml.cs">
|
||||||
|
<DependentUpon>CreateAccountAliasDialog.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Dialogs\StoreRatingDialog.xaml.cs">
|
<Compile Include="Dialogs\StoreRatingDialog.xaml.cs">
|
||||||
<DependentUpon>StoreRatingDialog.xaml</DependentUpon>
|
<DependentUpon>StoreRatingDialog.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
@@ -340,6 +346,7 @@
|
|||||||
<Compile Include="Views\Abstract\AboutPageAbstract.cs" />
|
<Compile Include="Views\Abstract\AboutPageAbstract.cs" />
|
||||||
<Compile Include="Views\Abstract\AccountDetailsPageAbstract.cs" />
|
<Compile Include="Views\Abstract\AccountDetailsPageAbstract.cs" />
|
||||||
<Compile Include="Views\Abstract\AccountManagementPageAbstract.cs" />
|
<Compile Include="Views\Abstract\AccountManagementPageAbstract.cs" />
|
||||||
|
<Compile Include="Views\Abstract\AliasManagementPageAbstract.cs" />
|
||||||
<Compile Include="Views\Abstract\AppPreferencesPageAbstract.cs" />
|
<Compile Include="Views\Abstract\AppPreferencesPageAbstract.cs" />
|
||||||
<Compile Include="Views\Abstract\AppShellAbstract.cs" />
|
<Compile Include="Views\Abstract\AppShellAbstract.cs" />
|
||||||
<Compile Include="Views\Abstract\ComposePageAbstract.cs" />
|
<Compile Include="Views\Abstract\ComposePageAbstract.cs" />
|
||||||
@@ -423,6 +430,9 @@
|
|||||||
<Compile Include="Views\Settings\SettingOptionsPage.xaml.cs">
|
<Compile Include="Views\Settings\SettingOptionsPage.xaml.cs">
|
||||||
<DependentUpon>SettingOptionsPage.xaml</DependentUpon>
|
<DependentUpon>SettingOptionsPage.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Views\Settings\AliasManagementPage.xaml.cs">
|
||||||
|
<DependentUpon>AliasManagementPage.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Views\Settings\SignatureManagementPage.xaml.cs">
|
<Compile Include="Views\Settings\SignatureManagementPage.xaml.cs">
|
||||||
<DependentUpon>SignatureManagementPage.xaml</DependentUpon>
|
<DependentUpon>SignatureManagementPage.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
@@ -509,6 +519,10 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="Dialogs\CreateAccountAliasDialog.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
<Page Include="Dialogs\StoreRatingDialog.xaml">
|
<Page Include="Dialogs\StoreRatingDialog.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
@@ -657,6 +671,10 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="Views\Settings\AliasManagementPage.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
<Page Include="Views\Settings\SignatureManagementPage.xaml">
|
<Page Include="Views\Settings\SignatureManagementPage.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ namespace Wino.Server.MessageHandlers
|
|||||||
{
|
{
|
||||||
var synchronizationResult = await synchronizer.SynchronizeAsync(message.Options, cancellationToken).ConfigureAwait(false);
|
var synchronizationResult = await synchronizer.SynchronizeAsync(message.Options, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
if (synchronizationResult.DownloadedMessages.Any())
|
if (synchronizationResult.DownloadedMessages?.Any() ?? false || !synchronizer.Account.Preferences.IsNotificationsEnabled)
|
||||||
{
|
{
|
||||||
var accountInboxFolder = await _folderService.GetSpecialFolderByAccountIdAsync(message.Options.AccountId, SpecialFolderType.Inbox);
|
var accountInboxFolder = await _folderService.GetSpecialFolderByAccountIdAsync(message.Options.AccountId, SpecialFolderType.Inbox);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user