Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
832b363da7 | ||
|
|
cf8f1ecd67 | ||
|
|
ee5129830c | ||
|
|
9facfaffa8 | ||
|
|
31b859ba1a | ||
|
|
b0f5a24c30 | ||
|
|
b60b594e44 | ||
|
|
a8cee1016b | ||
|
|
b551af01fa | ||
|
|
b178869a8e | ||
|
|
8e1c60d5f0 | ||
|
|
71ea49439e | ||
|
|
9d0a2f6535 | ||
|
|
c091fffe90 | ||
|
|
7e05d05f94 | ||
|
|
bd5b51c62f | ||
|
|
1d5eb2eced | ||
|
|
5073ead8fe | ||
|
|
f61bcb621b | ||
|
|
42b695854b | ||
|
|
496ae8b1b2 | ||
|
|
4215a2592f | ||
|
|
bca62033a1 | ||
|
|
18a91f9223 | ||
|
|
474d7c7a26 | ||
|
|
3f9a51ff46 | ||
|
|
df3b5c41f9 | ||
|
|
8800d11ab0 | ||
|
|
f021834ceb | ||
|
|
f54a39a549 | ||
|
|
c312ff3faf | ||
|
|
db833594f4 | ||
|
|
d36cf59829 | ||
|
|
caae751698 | ||
|
|
f7836eedce | ||
|
|
3ddc1a6229 | ||
|
|
cf9869b71e | ||
|
|
d31d8f574e | ||
|
|
c1336428dc | ||
|
|
f0e513bf0d | ||
|
|
ee9e41c5a7 | ||
|
|
30f1257983 | ||
|
|
f007cef208 | ||
|
|
19b5852098 | ||
|
|
2ec05ea7cc | ||
|
|
e8dd8bff44 | ||
|
|
ab3f65edfa |
@@ -149,7 +149,7 @@ csharp_preferred_modifier_order = public,private,protected,internal,static,exter
|
|||||||
# Code-block preferences
|
# Code-block preferences
|
||||||
csharp_prefer_braces = true:silent
|
csharp_prefer_braces = true:silent
|
||||||
csharp_prefer_simple_using_statement = true:suggestion
|
csharp_prefer_simple_using_statement = true:suggestion
|
||||||
csharp_style_namespace_declarations = block_scoped:silent
|
csharp_style_namespace_declarations = file_scoped:error
|
||||||
|
|
||||||
# Expression-level preferences
|
# Expression-level preferences
|
||||||
csharp_prefer_simple_default_expression = true:suggestion
|
csharp_prefer_simple_default_expression = true:suggestion
|
||||||
@@ -288,3 +288,5 @@ csharp_style_prefer_utf8_string_literals = true:suggestion
|
|||||||
csharp_style_prefer_readonly_struct = true:suggestion
|
csharp_style_prefer_readonly_struct = true:suggestion
|
||||||
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true:silent
|
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true:silent
|
||||||
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:silent
|
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:silent
|
||||||
|
csharp_style_prefer_primary_constructors = true:silent
|
||||||
|
csharp_prefer_system_threading_lock = true:suggestion
|
||||||
7
Directory.Build.Props
Normal file
7
Directory.Build.Props
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<LangVersion>preview</LangVersion>
|
||||||
|
<IsAotCompatible>true</IsAotCompatible>
|
||||||
|
<Configurations>Debug;Release</Configurations>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
65
Directory.Packages.props
Normal file
65
Directory.Packages.props
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageVersion Include="ColorHashSharp" Version="1.0.0" />
|
||||||
|
<PackageVersion Include="CommunityToolkit.Common" Version="8.4.0" />
|
||||||
|
<PackageVersion Include="CommunityToolkit.Diagnostics" Version="8.4.0" />
|
||||||
|
<PackageVersion Include="CommunityToolkit.Labs.Uwp.Controls.MarkdownTextBlock" Version="0.1.250206-build.2040" />
|
||||||
|
<PackageVersion Include="CommunityToolkit.Labs.Uwp.DependencyPropertyGenerator" Version="0.1.250206-build.2040" />
|
||||||
|
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||||
|
<PackageVersion Include="CommunityToolkit.Uwp.Animations" Version="8.2.250129-preview2" />
|
||||||
|
<PackageVersion Include="CommunityToolkit.Uwp.Behaviors" Version="8.2.250129-preview2" />
|
||||||
|
<PackageVersion Include="CommunityToolkit.Uwp.Controls.Segmented" Version="8.2.250129-preview2" />
|
||||||
|
<PackageVersion Include="CommunityToolkit.Uwp.Controls.SettingsControls" Version="8.2.250129-preview2" />
|
||||||
|
<PackageVersion Include="CommunityToolkit.Uwp.Controls.Sizers" Version="8.2.250129-preview2" />
|
||||||
|
<PackageVersion Include="CommunityToolkit.Uwp.Controls.TabbedCommandBar" Version="8.2.250129-preview2" />
|
||||||
|
<PackageVersion Include="CommunityToolkit.Uwp.Controls.TokenizingTextBox" Version="8.2.250129-preview2" />
|
||||||
|
<PackageVersion Include="CommunityToolkit.Uwp.Extensions" Version="8.2.250129-preview2" />
|
||||||
|
<PackageVersion Include="EmailValidation" Version="1.2.0" />
|
||||||
|
<PackageVersion Include="HtmlAgilityPack" Version="1.11.72" />
|
||||||
|
<PackageVersion Include="Ical.Net" Version="4.3.1" />
|
||||||
|
<PackageVersion Include="IsExternalInit" Version="1.0.3" />
|
||||||
|
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" />
|
||||||
|
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" />
|
||||||
|
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.2" />
|
||||||
|
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.2" />
|
||||||
|
<PackageVersion Include="Microsoft.Graph" Version="5.69.0" />
|
||||||
|
<PackageVersion Include="Microsoft.Identity.Client" Version="4.68.0" />
|
||||||
|
<PackageVersion Include="Microsoft.Identity.Client.Broker" Version="4.68.0" />
|
||||||
|
<PackageVersion Include="Microsoft.Identity.Client.Extensions.Msal" Version="4.68.0" />
|
||||||
|
<PackageVersion Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="6.2.14" />
|
||||||
|
<PackageVersion Include="Microsoft.UI.Xaml" Version="2.8.7" />
|
||||||
|
<PackageVersion Include="Microsoft.Xaml.Behaviors.Uwp.Managed" Version="3.0.0" />
|
||||||
|
<PackageVersion Include="MimeKit" Version="4.10.0" />
|
||||||
|
<PackageVersion Include="morelinq" Version="4.4.0" />
|
||||||
|
<PackageVersion Include="Nito.AsyncEx" Version="5.1.2" />
|
||||||
|
<PackageVersion Include="Nito.AsyncEx.Tasks" Version="5.1.2" />
|
||||||
|
<PackageVersion Include="NodaTime" Version="3.2.1" />
|
||||||
|
<PackageVersion Include="Serilog" Version="4.2.0" />
|
||||||
|
<PackageVersion Include="Serilog.Exceptions" Version="8.4.0" />
|
||||||
|
<PackageVersion Include="Serilog.Sinks.Debug" Version="3.0.0" />
|
||||||
|
<PackageVersion Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||||
|
<PackageVersion Include="Serilog.Sinks.ApplicationInsights" Version="4.0.0" />
|
||||||
|
<PackageVersion Include="SkiaSharp" Version="3.116.1" />
|
||||||
|
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
|
||||||
|
<PackageVersion Include="SqlKata" Version="4.0.1" />
|
||||||
|
<PackageVersion Include="System.Private.Uri" Version="4.3.2" />
|
||||||
|
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.2" />
|
||||||
|
<PackageVersion Include="System.Text.Json" Version="9.0.2" />
|
||||||
|
<PackageVersion Include="Win2D.uwp" Version="1.28.2" />
|
||||||
|
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.2.0" />
|
||||||
|
<PackageVersion Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" />
|
||||||
|
<PackageVersion Include="Google.Apis.Auth" Version="1.69.0" />
|
||||||
|
<PackageVersion Include="Google.Apis.Calendar.v3" Version="1.69.0.3667" />
|
||||||
|
<PackageVersion Include="Google.Apis.Gmail.v1" Version="1.68.0.3427" />
|
||||||
|
<PackageVersion Include="Google.Apis.PeopleService.v1" Version="1.68.0.3359" />
|
||||||
|
<PackageVersion Include="HtmlKit" Version="1.2.0" />
|
||||||
|
<PackageVersion Include="MailKit" Version="4.10.0" />
|
||||||
|
<PackageVersion Include="TimePeriodLibrary.NET" Version="2.1.5" />
|
||||||
|
<PackageVersion Include="System.Reactive" Version="6.0.1" />
|
||||||
|
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.2" />
|
||||||
|
<PackageVersion Include="System.Text.Encodings.Web" Version="9.0.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
|
||||||
namespace Wino.Authentication
|
namespace Wino.Authentication;
|
||||||
|
|
||||||
|
public abstract class BaseAuthenticator
|
||||||
{
|
{
|
||||||
public abstract class BaseAuthenticator
|
public abstract MailProviderType ProviderType { get; }
|
||||||
|
protected IAuthenticatorConfig AuthenticatorConfig { get; }
|
||||||
|
|
||||||
|
protected BaseAuthenticator(IAuthenticatorConfig authenticatorConfig)
|
||||||
{
|
{
|
||||||
public abstract MailProviderType ProviderType { get; }
|
|
||||||
protected IAuthenticatorConfig AuthenticatorConfig { get; }
|
|
||||||
|
|
||||||
protected BaseAuthenticator(IAuthenticatorConfig authenticatorConfig)
|
AuthenticatorConfig = authenticatorConfig;
|
||||||
{
|
|
||||||
|
|
||||||
AuthenticatorConfig = authenticatorConfig;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,45 +7,44 @@ using Wino.Core.Domain.Enums;
|
|||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
using Wino.Core.Domain.Models.Authentication;
|
using Wino.Core.Domain.Models.Authentication;
|
||||||
|
|
||||||
namespace Wino.Authentication
|
namespace Wino.Authentication;
|
||||||
|
|
||||||
|
public class GmailAuthenticator : BaseAuthenticator, IGmailAuthenticator
|
||||||
{
|
{
|
||||||
public class GmailAuthenticator : BaseAuthenticator, IGmailAuthenticator
|
public GmailAuthenticator(IAuthenticatorConfig authConfig) : base(authConfig)
|
||||||
{
|
{
|
||||||
public GmailAuthenticator(IAuthenticatorConfig authConfig) : base(authConfig)
|
}
|
||||||
|
|
||||||
|
public string ClientId => AuthenticatorConfig.GmailAuthenticatorClientId;
|
||||||
|
public bool ProposeCopyAuthURL { get; set; }
|
||||||
|
|
||||||
|
public override MailProviderType ProviderType => MailProviderType.Gmail;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates the token information for the given account.
|
||||||
|
/// For gmail, interactivity is automatically handled when you get the token.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="account">Account to get token for.</param>
|
||||||
|
public Task<TokenInformationEx> GenerateTokenInformationAsync(MailAccount account)
|
||||||
|
=> GetTokenInformationAsync(account);
|
||||||
|
|
||||||
|
public async Task<TokenInformationEx> GetTokenInformationAsync(MailAccount account)
|
||||||
|
{
|
||||||
|
var userCredential = await GetGoogleUserCredentialAsync(account);
|
||||||
|
|
||||||
|
if (userCredential.Token.IsStale)
|
||||||
{
|
{
|
||||||
|
await userCredential.RefreshTokenAsync(CancellationToken.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ClientId => AuthenticatorConfig.GmailAuthenticatorClientId;
|
return new TokenInformationEx(userCredential.Token.AccessToken, account.Address);
|
||||||
public bool ProposeCopyAuthURL { get; set; }
|
}
|
||||||
|
|
||||||
public override MailProviderType ProviderType => MailProviderType.Gmail;
|
private Task<UserCredential> GetGoogleUserCredentialAsync(MailAccount account)
|
||||||
|
{
|
||||||
/// <summary>
|
return GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets()
|
||||||
/// Generates the token information for the given account.
|
|
||||||
/// For gmail, interactivity is automatically handled when you get the token.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="account">Account to get token for.</param>
|
|
||||||
public Task<TokenInformationEx> GenerateTokenInformationAsync(MailAccount account)
|
|
||||||
=> GetTokenInformationAsync(account);
|
|
||||||
|
|
||||||
public async Task<TokenInformationEx> GetTokenInformationAsync(MailAccount account)
|
|
||||||
{
|
{
|
||||||
var userCredential = await GetGoogleUserCredentialAsync(account);
|
ClientId = ClientId
|
||||||
|
}, AuthenticatorConfig.GmailScope, account.Id.ToString(), CancellationToken.None, new FileDataStore(AuthenticatorConfig.GmailTokenStoreIdentifier));
|
||||||
if (userCredential.Token.IsStale)
|
|
||||||
{
|
|
||||||
await userCredential.RefreshTokenAsync(CancellationToken.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new TokenInformationEx(userCredential.Token.AccessToken, account.Address);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task<UserCredential> GetGoogleUserCredentialAsync(MailAccount account)
|
|
||||||
{
|
|
||||||
return GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets()
|
|
||||||
{
|
|
||||||
ClientId = ClientId
|
|
||||||
}, AuthenticatorConfig.GmailScope, account.Id.ToString(), CancellationToken.None, new FileDataStore(AuthenticatorConfig.GmailTokenStoreIdentifier));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
using Wino.Core.Domain.Enums;
|
|
||||||
using Wino.Core.Domain.Interfaces;
|
|
||||||
|
|
||||||
namespace Wino.Authentication
|
|
||||||
{
|
|
||||||
public class Office365Authenticator : OutlookAuthenticator
|
|
||||||
{
|
|
||||||
public Office365Authenticator(INativeAppService nativeAppService,
|
|
||||||
IApplicationConfiguration applicationConfiguration,
|
|
||||||
IAuthenticatorConfig authenticatorConfig) : base(nativeAppService, applicationConfiguration, authenticatorConfig)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override MailProviderType ProviderType => MailProviderType.Office365;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,116 +11,115 @@ using Wino.Core.Domain.Exceptions;
|
|||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
using Wino.Core.Domain.Models.Authentication;
|
using Wino.Core.Domain.Models.Authentication;
|
||||||
|
|
||||||
namespace Wino.Authentication
|
namespace Wino.Authentication;
|
||||||
|
|
||||||
|
public class OutlookAuthenticator : BaseAuthenticator, IOutlookAuthenticator
|
||||||
{
|
{
|
||||||
public class OutlookAuthenticator : BaseAuthenticator, IOutlookAuthenticator
|
private const string TokenCacheFileName = "OutlookCache.bin";
|
||||||
|
private bool isTokenCacheAttached = false;
|
||||||
|
|
||||||
|
// Outlook
|
||||||
|
private const string Authority = "https://login.microsoftonline.com/common";
|
||||||
|
|
||||||
|
public override MailProviderType ProviderType => MailProviderType.Outlook;
|
||||||
|
|
||||||
|
private readonly IPublicClientApplication _publicClientApplication;
|
||||||
|
private readonly IApplicationConfiguration _applicationConfiguration;
|
||||||
|
|
||||||
|
public OutlookAuthenticator(INativeAppService nativeAppService,
|
||||||
|
IApplicationConfiguration applicationConfiguration,
|
||||||
|
IAuthenticatorConfig authenticatorConfig) : base(authenticatorConfig)
|
||||||
{
|
{
|
||||||
private const string TokenCacheFileName = "OutlookCache.bin";
|
_applicationConfiguration = applicationConfiguration;
|
||||||
private bool isTokenCacheAttached = false;
|
|
||||||
|
|
||||||
// Outlook
|
var authenticationRedirectUri = nativeAppService.GetWebAuthenticationBrokerUri();
|
||||||
private const string Authority = "https://login.microsoftonline.com/common";
|
|
||||||
|
|
||||||
public override MailProviderType ProviderType => MailProviderType.Outlook;
|
var options = new BrokerOptions(BrokerOptions.OperatingSystems.Windows)
|
||||||
|
|
||||||
private readonly IPublicClientApplication _publicClientApplication;
|
|
||||||
private readonly IApplicationConfiguration _applicationConfiguration;
|
|
||||||
|
|
||||||
public OutlookAuthenticator(INativeAppService nativeAppService,
|
|
||||||
IApplicationConfiguration applicationConfiguration,
|
|
||||||
IAuthenticatorConfig authenticatorConfig) : base(authenticatorConfig)
|
|
||||||
{
|
{
|
||||||
_applicationConfiguration = applicationConfiguration;
|
Title = "Wino Mail",
|
||||||
|
ListOperatingSystemAccounts = true,
|
||||||
|
};
|
||||||
|
|
||||||
var authenticationRedirectUri = nativeAppService.GetWebAuthenticationBrokerUri();
|
var outlookAppBuilder = PublicClientApplicationBuilder.Create(AuthenticatorConfig.OutlookAuthenticatorClientId)
|
||||||
|
.WithParentActivityOrWindow(nativeAppService.GetCoreWindowHwnd)
|
||||||
|
.WithBroker(options)
|
||||||
|
.WithDefaultRedirectUri()
|
||||||
|
.WithAuthority(Authority);
|
||||||
|
|
||||||
var options = new BrokerOptions(BrokerOptions.OperatingSystems.Windows)
|
_publicClientApplication = outlookAppBuilder.Build();
|
||||||
{
|
}
|
||||||
Title = "Wino Mail",
|
|
||||||
ListOperatingSystemAccounts = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
var outlookAppBuilder = PublicClientApplicationBuilder.Create(AuthenticatorConfig.OutlookAuthenticatorClientId)
|
public string[] Scope => AuthenticatorConfig.OutlookScope;
|
||||||
.WithParentActivityOrWindow(nativeAppService.GetCoreWindowHwnd)
|
|
||||||
.WithBroker(options)
|
|
||||||
.WithDefaultRedirectUri()
|
|
||||||
.WithAuthority(Authority);
|
|
||||||
|
|
||||||
_publicClientApplication = outlookAppBuilder.Build();
|
private async Task EnsureTokenCacheAttachedAsync()
|
||||||
}
|
{
|
||||||
|
if (!isTokenCacheAttached)
|
||||||
public string[] Scope => AuthenticatorConfig.OutlookScope;
|
|
||||||
|
|
||||||
private async Task EnsureTokenCacheAttachedAsync()
|
|
||||||
{
|
{
|
||||||
if (!isTokenCacheAttached)
|
var storageProperties = new StorageCreationPropertiesBuilder(TokenCacheFileName, _applicationConfiguration.PublisherSharedFolderPath).Build();
|
||||||
{
|
var msalcachehelper = await MsalCacheHelper.CreateAsync(storageProperties);
|
||||||
var storageProperties = new StorageCreationPropertiesBuilder(TokenCacheFileName, _applicationConfiguration.PublisherSharedFolderPath).Build();
|
msalcachehelper.RegisterCache(_publicClientApplication.UserTokenCache);
|
||||||
var msalcachehelper = await MsalCacheHelper.CreateAsync(storageProperties);
|
|
||||||
msalcachehelper.RegisterCache(_publicClientApplication.UserTokenCache);
|
|
||||||
|
|
||||||
isTokenCacheAttached = true;
|
isTokenCacheAttached = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<TokenInformationEx> GetTokenInformationAsync(MailAccount account)
|
public async Task<TokenInformationEx> GetTokenInformationAsync(MailAccount account)
|
||||||
|
{
|
||||||
|
await EnsureTokenCacheAttachedAsync();
|
||||||
|
|
||||||
|
var storedAccount = (await _publicClientApplication.GetAccountsAsync()).FirstOrDefault(a => a.Username == account.Address);
|
||||||
|
|
||||||
|
if (storedAccount == null)
|
||||||
|
return await GenerateTokenInformationAsync(account);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var authResult = await _publicClientApplication.AcquireTokenSilent(Scope, storedAccount).ExecuteAsync();
|
||||||
|
|
||||||
|
return new TokenInformationEx(authResult.AccessToken, authResult.Account.Username);
|
||||||
|
}
|
||||||
|
catch (MsalUiRequiredException)
|
||||||
|
{
|
||||||
|
// Somehow MSAL is not able to refresh the token silently.
|
||||||
|
// Force interactive login.
|
||||||
|
|
||||||
|
return await GenerateTokenInformationAsync(account);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<TokenInformationEx> GenerateTokenInformationAsync(MailAccount account)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
await EnsureTokenCacheAttachedAsync();
|
await EnsureTokenCacheAttachedAsync();
|
||||||
|
|
||||||
var storedAccount = (await _publicClientApplication.GetAccountsAsync()).FirstOrDefault(a => a.Username == account.Address);
|
var authResult = await _publicClientApplication
|
||||||
|
.AcquireTokenInteractive(Scope)
|
||||||
|
.ExecuteAsync();
|
||||||
|
|
||||||
if (storedAccount == null)
|
// If the account is null, it means it's the initial creation of it.
|
||||||
return await GenerateTokenInformationAsync(account);
|
// If not, make sure the authenticated user address matches the username.
|
||||||
|
// When people refresh their token, accounts must match.
|
||||||
|
|
||||||
try
|
if (account?.Address != null && !account.Address.Equals(authResult.Account.Username, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var authResult = await _publicClientApplication.AcquireTokenSilent(Scope, storedAccount).ExecuteAsync();
|
throw new AuthenticationException("Authenticated address does not match with your account address.");
|
||||||
|
}
|
||||||
|
|
||||||
return new TokenInformationEx(authResult.AccessToken, authResult.Account.Username);
|
return new TokenInformationEx(authResult.AccessToken, authResult.Account.Username);
|
||||||
}
|
|
||||||
catch (MsalUiRequiredException)
|
|
||||||
{
|
|
||||||
// Somehow MSAL is not able to refresh the token silently.
|
|
||||||
// Force interactive login.
|
|
||||||
|
|
||||||
return await GenerateTokenInformationAsync(account);
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
catch (MsalClientException msalClientException)
|
||||||
public async Task<TokenInformationEx> GenerateTokenInformationAsync(MailAccount account)
|
|
||||||
{
|
{
|
||||||
try
|
if (msalClientException.ErrorCode == "authentication_canceled" || msalClientException.ErrorCode == "access_denied")
|
||||||
{
|
throw new AccountSetupCanceledException();
|
||||||
await EnsureTokenCacheAttachedAsync();
|
|
||||||
|
|
||||||
var authResult = await _publicClientApplication
|
throw;
|
||||||
.AcquireTokenInteractive(Scope)
|
|
||||||
.ExecuteAsync();
|
|
||||||
|
|
||||||
// If the account is null, it means it's the initial creation of it.
|
|
||||||
// If not, make sure the authenticated user address matches the username.
|
|
||||||
// When people refresh their token, accounts must match.
|
|
||||||
|
|
||||||
if (account?.Address != null && !account.Address.Equals(authResult.Account.Username, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
throw new AuthenticationException("Authenticated address does not match with your account address.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return new TokenInformationEx(authResult.AccessToken, authResult.Account.Username);
|
|
||||||
}
|
|
||||||
catch (MsalClientException msalClientException)
|
|
||||||
{
|
|
||||||
if (msalClientException.ErrorCode == "authentication_canceled" || msalClientException.ErrorCode == "access_denied")
|
|
||||||
throw new AccountSetupCanceledException();
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new AuthenticationException(Translator.Exception_UnknowErrorDuringAuthentication, new Exception(Translator.Exception_TokenGenerationFailed));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw new AuthenticationException(Translator.Exception_UnknowErrorDuringAuthentication, new Exception(Translator.Exception_TokenGenerationFailed));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,22 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
|
||||||
<RootNamespace>Wino.Authentication</RootNamespace>
|
<RootNamespace>Wino.Authentication</RootNamespace>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Platforms>x86;x64;arm64</Platforms>
|
||||||
<LangVersion>12</LangVersion>
|
|
||||||
<Platforms>AnyCPU;x64;x86</Platforms>
|
|
||||||
<AccelerateBuildsInVisualStudio>true</AccelerateBuildsInVisualStudio>
|
<AccelerateBuildsInVisualStudio>true</AccelerateBuildsInVisualStudio>
|
||||||
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
|
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CommunityToolkit.Diagnostics" Version="8.3.2" />
|
<PackageReference Include="CommunityToolkit.Diagnostics" />
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.3.2" />
|
<PackageReference Include="CommunityToolkit.Mvvm" />
|
||||||
<PackageReference Include="Google.Apis.Auth" Version="1.68.0" />
|
<PackageReference Include="Google.Apis.Auth" />
|
||||||
<PackageReference Include="Microsoft.Identity.Client" Version="4.66.2" />
|
<PackageReference Include="Microsoft.Identity.Client" />
|
||||||
<PackageReference Include="Microsoft.Identity.Client.Broker" Version="4.66.2" />
|
<PackageReference Include="Microsoft.Identity.Client.Broker" />
|
||||||
<PackageReference Include="Microsoft.Identity.Client.Extensions.Msal" Version="4.66.2" />
|
<PackageReference Include="Microsoft.Identity.Client.Extensions.Msal" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Wino.Core.Domain\Wino.Core.Domain.csproj" />
|
<ProjectReference Include="..\Wino.Core.Domain\Wino.Core.Domain.csproj" />
|
||||||
<ProjectReference Include="..\Wino.Messages\Wino.Messaging.csproj" />
|
<ProjectReference Include="..\Wino.Messages\Wino.Messaging.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -20,14 +20,6 @@
|
|||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
<Platform>x64</Platform>
|
<Platform>x64</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
<ProjectConfiguration Include="Debug|ARM">
|
|
||||||
<Configuration>Debug</Configuration>
|
|
||||||
<Platform>ARM</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
<ProjectConfiguration Include="Release|ARM">
|
|
||||||
<Configuration>Release</Configuration>
|
|
||||||
<Platform>ARM</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
<ProjectConfiguration Include="Debug|ARM64">
|
<ProjectConfiguration Include="Debug|ARM64">
|
||||||
<Configuration>Debug</Configuration>
|
<Configuration>Debug</Configuration>
|
||||||
<Platform>ARM64</Platform>
|
<Platform>ARM64</Platform>
|
||||||
@@ -76,7 +68,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.targets" />
|
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.targets" />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Identity.Client" Version="4.66.2" />
|
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.1742" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.1742" PrivateAssets="all" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ namespace Wino.Calendar.ViewModels
|
|||||||
if (accountCreationDialogResult == null) return;
|
if (accountCreationDialogResult == null) return;
|
||||||
|
|
||||||
var accountCreationCancellationTokenSource = new CancellationTokenSource();
|
var accountCreationCancellationTokenSource = new CancellationTokenSource();
|
||||||
var accountCreationDialog = CalendarDialogService.GetAccountCreationDialog(accountCreationDialogResult.ProviderType);
|
var accountCreationDialog = CalendarDialogService.GetAccountCreationDialog(accountCreationDialogResult);
|
||||||
|
|
||||||
accountCreationDialog.ShowDialog(accountCreationCancellationTokenSource);
|
accountCreationDialog.ShowDialog(accountCreationCancellationTokenSource);
|
||||||
accountCreationDialog.State = AccountCreationDialogState.SigningIn;
|
accountCreationDialog.State = AccountCreationDialogState.SigningIn;
|
||||||
@@ -92,7 +92,6 @@ namespace Wino.Calendar.ViewModels
|
|||||||
{
|
{
|
||||||
ProviderType = accountCreationDialogResult.ProviderType,
|
ProviderType = accountCreationDialogResult.ProviderType,
|
||||||
Name = accountCreationDialogResult.AccountName,
|
Name = accountCreationDialogResult.AccountName,
|
||||||
AccountColorHex = accountCreationDialogResult.AccountColorHex,
|
|
||||||
Id = Guid.NewGuid()
|
Id = Guid.NewGuid()
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -104,13 +103,8 @@ namespace Wino.Calendar.ViewModels
|
|||||||
if (accountCreationDialog.State == AccountCreationDialogState.Canceled)
|
if (accountCreationDialog.State == AccountCreationDialogState.Canceled)
|
||||||
throw new AccountSetupCanceledException();
|
throw new AccountSetupCanceledException();
|
||||||
|
|
||||||
|
|
||||||
tokenInformationResponse.ThrowIfFailed();
|
tokenInformationResponse.ThrowIfFailed();
|
||||||
|
|
||||||
//var tokenInformation = tokenInformationResponse.Data;
|
|
||||||
//createdAccount.Address = tokenInformation.Address;
|
|
||||||
//tokenInformation.AccountId = createdAccount.Id;
|
|
||||||
|
|
||||||
await AccountService.CreateAccountAsync(createdAccount, null);
|
await AccountService.CreateAccountAsync(createdAccount, null);
|
||||||
|
|
||||||
// Sync profile information if supported.
|
// Sync profile information if supported.
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Identity.Client" Version="4.66.2" />
|
|
||||||
<PackageReference Include="TimePeriodLibrary.NET" Version="2.1.5" />
|
<PackageReference Include="TimePeriodLibrary.NET" Version="2.1.5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -1,33 +1,32 @@
|
|||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
|
||||||
namespace Wino.Calendar.Services
|
namespace Wino.Calendar.Services;
|
||||||
|
|
||||||
|
public class CalendarAuthenticatorConfig : IAuthenticatorConfig
|
||||||
{
|
{
|
||||||
public class CalendarAuthenticatorConfig : IAuthenticatorConfig
|
public string OutlookAuthenticatorClientId => "b19c2035-d740-49ff-b297-de6ec561b208";
|
||||||
|
|
||||||
|
public string[] OutlookScope => new string[]
|
||||||
{
|
{
|
||||||
public string OutlookAuthenticatorClientId => "b19c2035-d740-49ff-b297-de6ec561b208";
|
"Calendars.Read",
|
||||||
|
"Calendars.Read.Shared",
|
||||||
|
"offline_access",
|
||||||
|
"Calendars.ReadBasic",
|
||||||
|
"Calendars.ReadWrite",
|
||||||
|
"Calendars.ReadWrite.Shared",
|
||||||
|
"User.Read"
|
||||||
|
};
|
||||||
|
|
||||||
public string[] OutlookScope => new string[]
|
public string GmailAuthenticatorClientId => "973025879644-s7b4ur9p3rlgop6a22u7iuptdc0brnrn.apps.googleusercontent.com";
|
||||||
{
|
|
||||||
"Calendars.Read",
|
|
||||||
"Calendars.Read.Shared",
|
|
||||||
"offline_access",
|
|
||||||
"Calendars.ReadBasic",
|
|
||||||
"Calendars.ReadWrite",
|
|
||||||
"Calendars.ReadWrite.Shared",
|
|
||||||
"User.Read"
|
|
||||||
};
|
|
||||||
|
|
||||||
public string GmailAuthenticatorClientId => "973025879644-s7b4ur9p3rlgop6a22u7iuptdc0brnrn.apps.googleusercontent.com";
|
public string[] GmailScope => new string[]
|
||||||
|
{
|
||||||
|
"https://www.googleapis.com/auth/calendar",
|
||||||
|
"https://www.googleapis.com/auth/calendar.events",
|
||||||
|
"https://www.googleapis.com/auth/calendar.settings.readonly",
|
||||||
|
"https://www.googleapis.com/auth/userinfo.profile",
|
||||||
|
"https://www.googleapis.com/auth/userinfo.email"
|
||||||
|
};
|
||||||
|
|
||||||
public string[] GmailScope => new string[]
|
public string GmailTokenStoreIdentifier => "WinoCalendarGmailTokenStore";
|
||||||
{
|
|
||||||
"https://www.googleapis.com/auth/calendar",
|
|
||||||
"https://www.googleapis.com/auth/calendar.events",
|
|
||||||
"https://www.googleapis.com/auth/calendar.settings.readonly",
|
|
||||||
"https://www.googleapis.com/auth/userinfo.profile",
|
|
||||||
"https://www.googleapis.com/auth/userinfo.email"
|
|
||||||
};
|
|
||||||
|
|
||||||
public string GmailTokenStoreIdentifier => "WinoCalendarGmailTokenStore";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace Wino.Calendar.Services
|
|||||||
|
|
||||||
foreach (var type in providers)
|
foreach (var type in providers)
|
||||||
{
|
{
|
||||||
providerList.Add(new ProviderDetail(type));
|
providerList.Add(new ProviderDetail(type, SpecialImapProvider.None));
|
||||||
}
|
}
|
||||||
|
|
||||||
return providerList;
|
return providerList;
|
||||||
|
|||||||
@@ -60,29 +60,6 @@
|
|||||||
<Prefer32Bit>true</Prefer32Bit>
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<OutputPath>bin\ARM\Debug\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
|
||||||
<NoWarn>;2008</NoWarn>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<PlatformTarget>ARM</PlatformTarget>
|
|
||||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<Prefer32Bit>true</Prefer32Bit>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
|
|
||||||
<OutputPath>bin\ARM\Release\</OutputPath>
|
|
||||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<NoWarn>;2008</NoWarn>
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<PlatformTarget>ARM</PlatformTarget>
|
|
||||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<Prefer32Bit>true</Prefer32Bit>
|
|
||||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM64'">
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
<OutputPath>bin\ARM64\Debug\</OutputPath>
|
<OutputPath>bin\ARM64\Debug\</OutputPath>
|
||||||
@@ -334,7 +311,7 @@
|
|||||||
<Version>6.2.14</Version>
|
<Version>6.2.14</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Win2D.uwp">
|
<PackageReference Include="Win2D.uwp">
|
||||||
<Version>1.28.0</Version>
|
<Version>1.28.1</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
11
Wino.Core.Domain/BasicTypesJsonContext.cs
Normal file
11
Wino.Core.Domain/BasicTypesJsonContext.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Wino.Core.Domain;
|
||||||
|
|
||||||
|
[JsonSerializable(typeof(Dictionary<string, string>))]
|
||||||
|
[JsonSerializable(typeof(string))]
|
||||||
|
[JsonSerializable(typeof(int))]
|
||||||
|
[JsonSerializable(typeof(List<string>))]
|
||||||
|
[JsonSerializable(typeof(bool))]
|
||||||
|
public partial class BasicTypesJsonContext : JsonSerializerContext;
|
||||||
@@ -7,150 +7,149 @@ using Wino.Core.Domain.Entities.Calendar;
|
|||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
using Wino.Core.Domain.Models.Calendar;
|
using Wino.Core.Domain.Models.Calendar;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Collections
|
namespace Wino.Core.Domain.Collections;
|
||||||
|
|
||||||
|
public class CalendarEventCollection
|
||||||
{
|
{
|
||||||
public class CalendarEventCollection
|
public event EventHandler<ICalendarItem> CalendarItemAdded;
|
||||||
|
public event EventHandler<ICalendarItem> CalendarItemRemoved;
|
||||||
|
|
||||||
|
public event EventHandler CalendarItemsCleared;
|
||||||
|
|
||||||
|
private ObservableRangeCollection<ICalendarItem> _internalRegularEvents = [];
|
||||||
|
private ObservableRangeCollection<ICalendarItem> _internalAllDayEvents = [];
|
||||||
|
|
||||||
|
public ReadOnlyObservableCollection<ICalendarItem> RegularEvents { get; }
|
||||||
|
public ReadOnlyObservableCollection<ICalendarItem> AllDayEvents { get; } // TODO: Rename this to include multi-day events.
|
||||||
|
public ITimePeriod Period { get; }
|
||||||
|
public CalendarSettings Settings { get; }
|
||||||
|
|
||||||
|
private readonly List<ICalendarItem> _allItems = new List<ICalendarItem>();
|
||||||
|
|
||||||
|
public CalendarEventCollection(ITimePeriod period, CalendarSettings settings)
|
||||||
{
|
{
|
||||||
public event EventHandler<ICalendarItem> CalendarItemAdded;
|
Period = period;
|
||||||
public event EventHandler<ICalendarItem> CalendarItemRemoved;
|
Settings = settings;
|
||||||
|
|
||||||
public event EventHandler CalendarItemsCleared;
|
RegularEvents = new ReadOnlyObservableCollection<ICalendarItem>(_internalRegularEvents);
|
||||||
|
AllDayEvents = new ReadOnlyObservableCollection<ICalendarItem>(_internalAllDayEvents);
|
||||||
|
}
|
||||||
|
|
||||||
private ObservableRangeCollection<ICalendarItem> _internalRegularEvents = [];
|
public bool HasCalendarEvent(AccountCalendar accountCalendar)
|
||||||
private ObservableRangeCollection<ICalendarItem> _internalAllDayEvents = [];
|
=> _allItems.Any(x => x.AssignedCalendar.Id == accountCalendar.Id);
|
||||||
|
|
||||||
public ReadOnlyObservableCollection<ICalendarItem> RegularEvents { get; }
|
public ICalendarItem GetCalendarItem(Guid calendarItemId)
|
||||||
public ReadOnlyObservableCollection<ICalendarItem> AllDayEvents { get; } // TODO: Rename this to include multi-day events.
|
{
|
||||||
public ITimePeriod Period { get; }
|
return _allItems.FirstOrDefault(x => x.Id == calendarItemId);
|
||||||
public CalendarSettings Settings { get; }
|
}
|
||||||
|
|
||||||
private readonly List<ICalendarItem> _allItems = new List<ICalendarItem>();
|
public void ClearSelectionStates()
|
||||||
|
{
|
||||||
public CalendarEventCollection(ITimePeriod period, CalendarSettings settings)
|
foreach (var item in _allItems)
|
||||||
{
|
{
|
||||||
Period = period;
|
if (item is ICalendarItemViewModel calendarItemViewModel)
|
||||||
Settings = settings;
|
|
||||||
|
|
||||||
RegularEvents = new ReadOnlyObservableCollection<ICalendarItem>(_internalRegularEvents);
|
|
||||||
AllDayEvents = new ReadOnlyObservableCollection<ICalendarItem>(_internalAllDayEvents);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasCalendarEvent(AccountCalendar accountCalendar)
|
|
||||||
=> _allItems.Any(x => x.AssignedCalendar.Id == accountCalendar.Id);
|
|
||||||
|
|
||||||
public ICalendarItem GetCalendarItem(Guid calendarItemId)
|
|
||||||
{
|
|
||||||
return _allItems.FirstOrDefault(x => x.Id == calendarItemId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearSelectionStates()
|
|
||||||
{
|
|
||||||
foreach (var item in _allItems)
|
|
||||||
{
|
{
|
||||||
if (item is ICalendarItemViewModel calendarItemViewModel)
|
calendarItemViewModel.IsSelected = false;
|
||||||
{
|
|
||||||
calendarItemViewModel.IsSelected = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public void FilterByCalendars(IEnumerable<Guid> visibleCalendarIds)
|
|
||||||
{
|
public void FilterByCalendars(IEnumerable<Guid> visibleCalendarIds)
|
||||||
foreach (var item in _allItems)
|
{
|
||||||
{
|
foreach (var item in _allItems)
|
||||||
var collections = GetProperCollectionsForCalendarItem(item);
|
{
|
||||||
|
var collections = GetProperCollectionsForCalendarItem(item);
|
||||||
foreach (var collection in collections)
|
|
||||||
{
|
foreach (var collection in collections)
|
||||||
if (!visibleCalendarIds.Contains(item.AssignedCalendar.Id) && collection.Contains(item))
|
{
|
||||||
{
|
if (!visibleCalendarIds.Contains(item.AssignedCalendar.Id) && collection.Contains(item))
|
||||||
RemoveCalendarItemInternal(collection, item, false);
|
{
|
||||||
}
|
RemoveCalendarItemInternal(collection, item, false);
|
||||||
else if (visibleCalendarIds.Contains(item.AssignedCalendar.Id) && !collection.Contains(item))
|
}
|
||||||
{
|
else if (visibleCalendarIds.Contains(item.AssignedCalendar.Id) && !collection.Contains(item))
|
||||||
AddCalendarItemInternal(collection, item, false);
|
{
|
||||||
}
|
AddCalendarItemInternal(collection, item, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private IEnumerable<ObservableRangeCollection<ICalendarItem>> GetProperCollectionsForCalendarItem(ICalendarItem calendarItem)
|
|
||||||
{
|
private IEnumerable<ObservableRangeCollection<ICalendarItem>> GetProperCollectionsForCalendarItem(ICalendarItem calendarItem)
|
||||||
// All-day events go to all days.
|
{
|
||||||
// Multi-day events go to both.
|
// All-day events go to all days.
|
||||||
// Anything else goes to regular.
|
// Multi-day events go to both.
|
||||||
|
// Anything else goes to regular.
|
||||||
if (calendarItem.IsAllDayEvent)
|
|
||||||
{
|
if (calendarItem.IsAllDayEvent)
|
||||||
return [_internalAllDayEvents];
|
{
|
||||||
}
|
return [_internalAllDayEvents];
|
||||||
else if (calendarItem.IsMultiDayEvent)
|
}
|
||||||
{
|
else if (calendarItem.IsMultiDayEvent)
|
||||||
return [_internalRegularEvents, _internalAllDayEvents];
|
{
|
||||||
}
|
return [_internalRegularEvents, _internalAllDayEvents];
|
||||||
else
|
}
|
||||||
{
|
else
|
||||||
return [_internalRegularEvents];
|
{
|
||||||
}
|
return [_internalRegularEvents];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public void AddCalendarItem(ICalendarItem calendarItem)
|
|
||||||
{
|
public void AddCalendarItem(ICalendarItem calendarItem)
|
||||||
var collections = GetProperCollectionsForCalendarItem(calendarItem);
|
{
|
||||||
|
var collections = GetProperCollectionsForCalendarItem(calendarItem);
|
||||||
foreach (var collection in collections)
|
|
||||||
{
|
foreach (var collection in collections)
|
||||||
AddCalendarItemInternal(collection, calendarItem);
|
{
|
||||||
}
|
AddCalendarItemInternal(collection, calendarItem);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public void RemoveCalendarItem(ICalendarItem calendarItem)
|
|
||||||
{
|
public void RemoveCalendarItem(ICalendarItem calendarItem)
|
||||||
var collections = GetProperCollectionsForCalendarItem(calendarItem);
|
{
|
||||||
|
var collections = GetProperCollectionsForCalendarItem(calendarItem);
|
||||||
foreach (var collection in collections)
|
|
||||||
{
|
foreach (var collection in collections)
|
||||||
RemoveCalendarItemInternal(collection, calendarItem);
|
{
|
||||||
}
|
RemoveCalendarItemInternal(collection, calendarItem);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private void AddCalendarItemInternal(ObservableRangeCollection<ICalendarItem> collection, ICalendarItem calendarItem, bool create = true)
|
|
||||||
{
|
private void AddCalendarItemInternal(ObservableRangeCollection<ICalendarItem> collection, ICalendarItem calendarItem, bool create = true)
|
||||||
if (calendarItem is not ICalendarItemViewModel)
|
{
|
||||||
throw new ArgumentException("CalendarItem must be of type ICalendarItemViewModel", nameof(calendarItem));
|
if (calendarItem is not ICalendarItemViewModel)
|
||||||
|
throw new ArgumentException("CalendarItem must be of type ICalendarItemViewModel", nameof(calendarItem));
|
||||||
collection.Add(calendarItem);
|
|
||||||
|
collection.Add(calendarItem);
|
||||||
if (create)
|
|
||||||
{
|
if (create)
|
||||||
_allItems.Add(calendarItem);
|
{
|
||||||
}
|
_allItems.Add(calendarItem);
|
||||||
|
}
|
||||||
CalendarItemAdded?.Invoke(this, calendarItem);
|
|
||||||
}
|
CalendarItemAdded?.Invoke(this, calendarItem);
|
||||||
|
}
|
||||||
private void RemoveCalendarItemInternal(ObservableRangeCollection<ICalendarItem> collection, ICalendarItem calendarItem, bool destroy = true)
|
|
||||||
{
|
private void RemoveCalendarItemInternal(ObservableRangeCollection<ICalendarItem> collection, ICalendarItem calendarItem, bool destroy = true)
|
||||||
if (calendarItem is not ICalendarItemViewModel)
|
{
|
||||||
throw new ArgumentException("CalendarItem must be of type ICalendarItemViewModel", nameof(calendarItem));
|
if (calendarItem is not ICalendarItemViewModel)
|
||||||
|
throw new ArgumentException("CalendarItem must be of type ICalendarItemViewModel", nameof(calendarItem));
|
||||||
collection.Remove(calendarItem);
|
|
||||||
|
collection.Remove(calendarItem);
|
||||||
if (destroy)
|
|
||||||
{
|
if (destroy)
|
||||||
_allItems.Remove(calendarItem);
|
{
|
||||||
}
|
_allItems.Remove(calendarItem);
|
||||||
|
}
|
||||||
CalendarItemRemoved?.Invoke(this, calendarItem);
|
|
||||||
}
|
CalendarItemRemoved?.Invoke(this, calendarItem);
|
||||||
|
}
|
||||||
public void Clear()
|
|
||||||
{
|
public void Clear()
|
||||||
_internalAllDayEvents.Clear();
|
{
|
||||||
_internalRegularEvents.Clear();
|
_internalAllDayEvents.Clear();
|
||||||
_allItems.Clear();
|
_internalRegularEvents.Clear();
|
||||||
|
_allItems.Clear();
|
||||||
CalendarItemsCleared?.Invoke(this, EventArgs.Empty);
|
|
||||||
}
|
CalendarItemsCleared?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,41 +2,40 @@
|
|||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
using Wino.Core.Domain.Models.Calendar;
|
using Wino.Core.Domain.Models.Calendar;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Collections
|
namespace Wino.Core.Domain.Collections;
|
||||||
|
|
||||||
|
public class DayRangeCollection : ObservableRangeCollection<DayRangeRenderModel>
|
||||||
{
|
{
|
||||||
public class DayRangeCollection : ObservableRangeCollection<DayRangeRenderModel>
|
/// <summary>
|
||||||
|
/// Gets the range of dates that are currently displayed in the collection.
|
||||||
|
/// </summary>
|
||||||
|
public DateRange DisplayRange
|
||||||
{
|
{
|
||||||
/// <summary>
|
get
|
||||||
/// Gets the range of dates that are currently displayed in the collection.
|
|
||||||
/// </summary>
|
|
||||||
public DateRange DisplayRange
|
|
||||||
{
|
{
|
||||||
get
|
if (Count == 0) return null;
|
||||||
{
|
|
||||||
if (Count == 0) return null;
|
|
||||||
|
|
||||||
var minimumLoadedDate = this[0].CalendarRenderOptions.DateRange.StartDate;
|
var minimumLoadedDate = this[0].CalendarRenderOptions.DateRange.StartDate;
|
||||||
var maximumLoadedDate = this[Count - 1].CalendarRenderOptions.DateRange.EndDate;
|
var maximumLoadedDate = this[Count - 1].CalendarRenderOptions.DateRange.EndDate;
|
||||||
|
|
||||||
return new DateRange(minimumLoadedDate, maximumLoadedDate);
|
return new DateRange(minimumLoadedDate, maximumLoadedDate);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void RemoveCalendarItem(ICalendarItem calendarItem)
|
public void RemoveCalendarItem(ICalendarItem calendarItem)
|
||||||
|
{
|
||||||
|
foreach (var dayRange in this)
|
||||||
{
|
{
|
||||||
foreach (var dayRange in this)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void AddCalendarItem(ICalendarItem calendarItem)
|
public void AddCalendarItem(ICalendarItem calendarItem)
|
||||||
|
{
|
||||||
|
foreach (var dayRange in this)
|
||||||
{
|
{
|
||||||
foreach (var dayRange in this)
|
var calendarDayModel = dayRange.CalendarDays.FirstOrDefault(x => x.Period.HasInside(calendarItem.Period.Start));
|
||||||
{
|
calendarDayModel?.EventsCollection.AddCalendarItem(calendarItem);
|
||||||
var calendarDayModel = dayRange.CalendarDays.FirstOrDefault(x => x.Period.HasInside(calendarItem.Period.Start));
|
|
||||||
calendarDayModel?.EventsCollection.AddCalendarItem(calendarItem);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,171 +4,170 @@ using System.Collections.ObjectModel;
|
|||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Collections
|
namespace Wino.Core.Domain.Collections;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
public class ObservableRangeCollection<T> : ObservableCollection<T>
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed.
|
/// Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T"></typeparam>
|
public ObservableRangeCollection()
|
||||||
public class ObservableRangeCollection<T> : ObservableCollection<T>
|
: base()
|
||||||
{
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class.
|
/// Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class that contains elements copied from the specified collection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ObservableRangeCollection()
|
/// <param name="collection">collection: The collection from which the elements are copied.</param>
|
||||||
: base()
|
/// <exception cref="ArgumentNullException">The collection parameter cannot be null.</exception>
|
||||||
|
public ObservableRangeCollection(IEnumerable<T> collection)
|
||||||
|
: base(collection)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the elements of the specified collection to the end of the ObservableCollection(Of T).
|
||||||
|
/// </summary>
|
||||||
|
public void AddRange(IEnumerable<T> collection, NotifyCollectionChangedAction notificationMode = NotifyCollectionChangedAction.Add)
|
||||||
|
{
|
||||||
|
if (notificationMode != NotifyCollectionChangedAction.Add && notificationMode != NotifyCollectionChangedAction.Reset)
|
||||||
|
throw new ArgumentException("Mode must be either Add or Reset for AddRange.", nameof(notificationMode));
|
||||||
|
if (collection == null)
|
||||||
|
throw new ArgumentNullException(nameof(collection));
|
||||||
|
|
||||||
|
CheckReentrancy();
|
||||||
|
|
||||||
|
var startIndex = Count;
|
||||||
|
|
||||||
|
var itemsAdded = AddArrangeCore(collection);
|
||||||
|
|
||||||
|
if (!itemsAdded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (notificationMode == NotifyCollectionChangedAction.Reset)
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class that contains elements copied from the specified collection.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="collection">collection: The collection from which the elements are copied.</param>
|
|
||||||
/// <exception cref="ArgumentNullException">The collection parameter cannot be null.</exception>
|
|
||||||
public ObservableRangeCollection(IEnumerable<T> collection)
|
|
||||||
: base(collection)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the elements of the specified collection to the end of the ObservableCollection(Of T).
|
|
||||||
/// </summary>
|
|
||||||
public void AddRange(IEnumerable<T> collection, NotifyCollectionChangedAction notificationMode = NotifyCollectionChangedAction.Add)
|
|
||||||
{
|
|
||||||
if (notificationMode != NotifyCollectionChangedAction.Add && notificationMode != NotifyCollectionChangedAction.Reset)
|
|
||||||
throw new ArgumentException("Mode must be either Add or Reset for AddRange.", nameof(notificationMode));
|
|
||||||
if (collection == null)
|
|
||||||
throw new ArgumentNullException(nameof(collection));
|
|
||||||
|
|
||||||
CheckReentrancy();
|
|
||||||
|
|
||||||
var startIndex = Count;
|
|
||||||
|
|
||||||
var itemsAdded = AddArrangeCore(collection);
|
|
||||||
|
|
||||||
if (!itemsAdded)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (notificationMode == NotifyCollectionChangedAction.Reset)
|
|
||||||
{
|
|
||||||
RaiseChangeNotificationEvents(action: NotifyCollectionChangedAction.Reset);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var changedItems = collection is List<T> ? (List<T>)collection : new List<T>(collection);
|
|
||||||
|
|
||||||
RaiseChangeNotificationEvents(
|
|
||||||
action: NotifyCollectionChangedAction.Add,
|
|
||||||
changedItems: changedItems,
|
|
||||||
startingIndex: startIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes the first occurence of each item in the specified collection from ObservableCollection(Of T). NOTE: with notificationMode = Remove, removed items starting index is not set because items are not guaranteed to be consecutive.
|
|
||||||
/// </summary>
|
|
||||||
public void RemoveRange(IEnumerable<T> collection, NotifyCollectionChangedAction notificationMode = NotifyCollectionChangedAction.Reset)
|
|
||||||
{
|
|
||||||
if (notificationMode != NotifyCollectionChangedAction.Remove && notificationMode != NotifyCollectionChangedAction.Reset)
|
|
||||||
throw new ArgumentException("Mode must be either Remove or Reset for RemoveRange.", nameof(notificationMode));
|
|
||||||
if (collection == null)
|
|
||||||
throw new ArgumentNullException(nameof(collection));
|
|
||||||
|
|
||||||
CheckReentrancy();
|
|
||||||
|
|
||||||
if (notificationMode == NotifyCollectionChangedAction.Reset)
|
|
||||||
{
|
|
||||||
var raiseEvents = false;
|
|
||||||
foreach (var item in collection)
|
|
||||||
{
|
|
||||||
Items.Remove(item);
|
|
||||||
raiseEvents = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (raiseEvents)
|
|
||||||
RaiseChangeNotificationEvents(action: NotifyCollectionChangedAction.Reset);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var changedItems = new List<T>(collection);
|
|
||||||
for (var i = 0; i < changedItems.Count; i++)
|
|
||||||
{
|
|
||||||
if (!Items.Remove(changedItems[i]))
|
|
||||||
{
|
|
||||||
changedItems.RemoveAt(i); //Can't use a foreach because changedItems is intended to be (carefully) modified
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changedItems.Count == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
RaiseChangeNotificationEvents(
|
|
||||||
action: NotifyCollectionChangedAction.Remove,
|
|
||||||
changedItems: changedItems);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clears the current collection and replaces it with the specified item.
|
|
||||||
/// </summary>
|
|
||||||
public void Replace(T item) => ReplaceRange(new T[] { item });
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clears the current collection and replaces it with the specified collection.
|
|
||||||
/// </summary>
|
|
||||||
public void ReplaceRange(IEnumerable<T> collection)
|
|
||||||
{
|
|
||||||
if (collection == null)
|
|
||||||
throw new ArgumentNullException(nameof(collection));
|
|
||||||
|
|
||||||
CheckReentrancy();
|
|
||||||
|
|
||||||
var previouslyEmpty = Items.Count == 0;
|
|
||||||
|
|
||||||
Items.Clear();
|
|
||||||
|
|
||||||
AddArrangeCore(collection);
|
|
||||||
|
|
||||||
var currentlyEmpty = Items.Count == 0;
|
|
||||||
|
|
||||||
if (previouslyEmpty && currentlyEmpty)
|
|
||||||
return;
|
|
||||||
|
|
||||||
RaiseChangeNotificationEvents(action: NotifyCollectionChangedAction.Reset);
|
RaiseChangeNotificationEvents(action: NotifyCollectionChangedAction.Reset);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InsertRange(IEnumerable<T> items)
|
var changedItems = collection is List<T> ? (List<T>)collection : new List<T>(collection);
|
||||||
|
|
||||||
|
RaiseChangeNotificationEvents(
|
||||||
|
action: NotifyCollectionChangedAction.Add,
|
||||||
|
changedItems: changedItems,
|
||||||
|
startingIndex: startIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the first occurence of each item in the specified collection from ObservableCollection(Of T). NOTE: with notificationMode = Remove, removed items starting index is not set because items are not guaranteed to be consecutive.
|
||||||
|
/// </summary>
|
||||||
|
public void RemoveRange(IEnumerable<T> collection, NotifyCollectionChangedAction notificationMode = NotifyCollectionChangedAction.Reset)
|
||||||
|
{
|
||||||
|
if (notificationMode != NotifyCollectionChangedAction.Remove && notificationMode != NotifyCollectionChangedAction.Reset)
|
||||||
|
throw new ArgumentException("Mode must be either Remove or Reset for RemoveRange.", nameof(notificationMode));
|
||||||
|
if (collection == null)
|
||||||
|
throw new ArgumentNullException(nameof(collection));
|
||||||
|
|
||||||
|
CheckReentrancy();
|
||||||
|
|
||||||
|
if (notificationMode == NotifyCollectionChangedAction.Reset)
|
||||||
{
|
{
|
||||||
CheckReentrancy();
|
var raiseEvents = false;
|
||||||
|
|
||||||
foreach (var item in items)
|
|
||||||
Items.Insert(0, item);
|
|
||||||
|
|
||||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool AddArrangeCore(IEnumerable<T> collection)
|
|
||||||
{
|
|
||||||
var itemAdded = false;
|
|
||||||
foreach (var item in collection)
|
foreach (var item in collection)
|
||||||
{
|
{
|
||||||
Items.Add(item);
|
Items.Remove(item);
|
||||||
itemAdded = true;
|
raiseEvents = true;
|
||||||
}
|
}
|
||||||
return itemAdded;
|
|
||||||
|
if (raiseEvents)
|
||||||
|
RaiseChangeNotificationEvents(action: NotifyCollectionChangedAction.Reset);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RaiseChangeNotificationEvents(NotifyCollectionChangedAction action, List<T> changedItems = null, int startingIndex = -1)
|
var changedItems = new List<T>(collection);
|
||||||
|
for (var i = 0; i < changedItems.Count; i++)
|
||||||
{
|
{
|
||||||
OnPropertyChanged(new PropertyChangedEventArgs(nameof(Count)));
|
if (!Items.Remove(changedItems[i]))
|
||||||
OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
|
{
|
||||||
|
changedItems.RemoveAt(i); //Can't use a foreach because changedItems is intended to be (carefully) modified
|
||||||
if (changedItems is null)
|
i--;
|
||||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(action));
|
}
|
||||||
else
|
|
||||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, changedItems: changedItems, startingIndex: startingIndex));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (changedItems.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RaiseChangeNotificationEvents(
|
||||||
|
action: NotifyCollectionChangedAction.Remove,
|
||||||
|
changedItems: changedItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears the current collection and replaces it with the specified item.
|
||||||
|
/// </summary>
|
||||||
|
public void Replace(T item) => ReplaceRange(new T[] { item });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears the current collection and replaces it with the specified collection.
|
||||||
|
/// </summary>
|
||||||
|
public void ReplaceRange(IEnumerable<T> collection)
|
||||||
|
{
|
||||||
|
if (collection == null)
|
||||||
|
throw new ArgumentNullException(nameof(collection));
|
||||||
|
|
||||||
|
CheckReentrancy();
|
||||||
|
|
||||||
|
var previouslyEmpty = Items.Count == 0;
|
||||||
|
|
||||||
|
Items.Clear();
|
||||||
|
|
||||||
|
AddArrangeCore(collection);
|
||||||
|
|
||||||
|
var currentlyEmpty = Items.Count == 0;
|
||||||
|
|
||||||
|
if (previouslyEmpty && currentlyEmpty)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RaiseChangeNotificationEvents(action: NotifyCollectionChangedAction.Reset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InsertRange(IEnumerable<T> items)
|
||||||
|
{
|
||||||
|
CheckReentrancy();
|
||||||
|
|
||||||
|
foreach (var item in items)
|
||||||
|
Items.Insert(0, item);
|
||||||
|
|
||||||
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool AddArrangeCore(IEnumerable<T> collection)
|
||||||
|
{
|
||||||
|
var itemAdded = false;
|
||||||
|
foreach (var item in collection)
|
||||||
|
{
|
||||||
|
Items.Add(item);
|
||||||
|
itemAdded = true;
|
||||||
|
}
|
||||||
|
return itemAdded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RaiseChangeNotificationEvents(NotifyCollectionChangedAction action, List<T> changedItems = null, int startingIndex = -1)
|
||||||
|
{
|
||||||
|
OnPropertyChanged(new PropertyChangedEventArgs(nameof(Count)));
|
||||||
|
OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
|
||||||
|
|
||||||
|
if (changedItems is null)
|
||||||
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(action));
|
||||||
|
else
|
||||||
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, changedItems: changedItems, startingIndex: startingIndex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,22 @@
|
|||||||
namespace Wino.Core.Domain
|
namespace Wino.Core.Domain;
|
||||||
|
|
||||||
|
public static class Constants
|
||||||
{
|
{
|
||||||
public static class Constants
|
/// <summary>
|
||||||
{
|
/// MIME header that exists in all the drafts created from Wino.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// MIME header that exists in all the drafts created from Wino.
|
public const string WinoLocalDraftHeader = "X-Wino-Draft-Id";
|
||||||
/// </summary>
|
public const string LocalDraftStartPrefix = "localDraft_";
|
||||||
public const string WinoLocalDraftHeader = "X-Wino-Draft-Id";
|
|
||||||
public const string LocalDraftStartPrefix = "localDraft_";
|
|
||||||
|
|
||||||
public const string CalendarEventRecurrenceRuleSeperator = "___";
|
public const string CalendarEventRecurrenceRuleSeperator = "___";
|
||||||
|
|
||||||
public const string ToastMailUniqueIdKey = nameof(ToastMailUniqueIdKey);
|
public const string ToastMailUniqueIdKey = nameof(ToastMailUniqueIdKey);
|
||||||
public const string ToastActionKey = nameof(ToastActionKey);
|
public const string ToastActionKey = nameof(ToastActionKey);
|
||||||
|
|
||||||
public const string ClientLogFile = "Client_.log";
|
public const string ClientLogFile = "Client_.log";
|
||||||
public const string ServerLogFile = "Server_.log";
|
public const string ServerLogFile = "Server_.log";
|
||||||
public const string LogArchiveFileName = "WinoLogs.zip";
|
public const string LogArchiveFileName = "WinoLogs.zip";
|
||||||
|
|
||||||
public const string WinoMailIdentiifer = nameof(WinoMailIdentiifer);
|
public const string WinoMailIdentiifer = nameof(WinoMailIdentiifer);
|
||||||
public const string WinoCalendarIdentifier = nameof(WinoCalendarIdentifier);
|
public const string WinoCalendarIdentifier = nameof(WinoCalendarIdentifier);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,24 +2,23 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Entities.Calendar
|
namespace Wino.Core.Domain.Entities.Calendar;
|
||||||
{
|
|
||||||
public class AccountCalendar : IAccountCalendar
|
|
||||||
{
|
|
||||||
[PrimaryKey]
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
public Guid AccountId { get; set; }
|
|
||||||
public string RemoteCalendarId { get; set; }
|
|
||||||
public string SynchronizationDeltaToken { get; set; }
|
|
||||||
public string Name { get; set; }
|
|
||||||
public bool IsPrimary { get; set; }
|
|
||||||
public bool IsExtended { get; set; } = true;
|
|
||||||
|
|
||||||
/// <summary>
|
public class AccountCalendar : IAccountCalendar
|
||||||
/// Unused for now.
|
{
|
||||||
/// </summary>
|
[PrimaryKey]
|
||||||
public string TextColorHex { get; set; }
|
public Guid Id { get; set; }
|
||||||
public string BackgroundColorHex { get; set; }
|
public Guid AccountId { get; set; }
|
||||||
public string TimeZone { get; set; }
|
public string RemoteCalendarId { get; set; }
|
||||||
}
|
public string SynchronizationDeltaToken { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public bool IsPrimary { get; set; }
|
||||||
|
public bool IsExtended { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unused for now.
|
||||||
|
/// </summary>
|
||||||
|
public string TextColorHex { get; set; }
|
||||||
|
public string BackgroundColorHex { get; set; }
|
||||||
|
public string TimeZone { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,19 +2,18 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Entities.Calendar
|
namespace Wino.Core.Domain.Entities.Calendar;
|
||||||
|
|
||||||
|
// TODO: Connect to Contact store with Wino People.
|
||||||
|
public class CalendarEventAttendee
|
||||||
{
|
{
|
||||||
// TODO: Connect to Contact store with Wino People.
|
[PrimaryKey]
|
||||||
public class CalendarEventAttendee
|
public Guid Id { get; set; }
|
||||||
{
|
public Guid CalendarItemId { get; set; }
|
||||||
[PrimaryKey]
|
public string Name { get; set; }
|
||||||
public Guid Id { get; set; }
|
public string Email { get; set; }
|
||||||
public Guid CalendarItemId { get; set; }
|
public AttendeeStatus AttendenceStatus { get; set; }
|
||||||
public string Name { get; set; }
|
public bool IsOrganizer { get; set; }
|
||||||
public string Email { get; set; }
|
public bool IsOptionalAttendee { get; set; }
|
||||||
public AttendeeStatus AttendenceStatus { get; set; }
|
public string Comment { get; set; }
|
||||||
public bool IsOrganizer { get; set; }
|
|
||||||
public bool IsOptionalAttendee { get; set; }
|
|
||||||
public string Comment { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,176 +5,175 @@ using SQLite;
|
|||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Entities.Calendar
|
namespace Wino.Core.Domain.Entities.Calendar;
|
||||||
|
|
||||||
|
[DebuggerDisplay("{Title} ({StartDate} - {EndDate})")]
|
||||||
|
public class CalendarItem : ICalendarItem
|
||||||
{
|
{
|
||||||
[DebuggerDisplay("{Title} ({StartDate} - {EndDate})")]
|
[PrimaryKey]
|
||||||
public class CalendarItem : ICalendarItem
|
public Guid Id { get; set; }
|
||||||
|
public string RemoteEventId { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public string Location { get; set; }
|
||||||
|
|
||||||
|
public DateTime StartDate { get; set; }
|
||||||
|
|
||||||
|
public DateTime EndDate
|
||||||
{
|
{
|
||||||
[PrimaryKey]
|
get
|
||||||
public Guid Id { get; set; }
|
|
||||||
public string RemoteEventId { get; set; }
|
|
||||||
public string Title { get; set; }
|
|
||||||
public string Description { get; set; }
|
|
||||||
public string Location { get; set; }
|
|
||||||
|
|
||||||
public DateTime StartDate { get; set; }
|
|
||||||
|
|
||||||
public DateTime EndDate
|
|
||||||
{
|
{
|
||||||
get
|
return StartDate.AddSeconds(DurationInSeconds);
|
||||||
{
|
|
||||||
return StartDate.AddSeconds(DurationInSeconds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public TimeSpan StartDateOffset { get; set; }
|
|
||||||
public TimeSpan EndDateOffset { get; set; }
|
|
||||||
|
|
||||||
private ITimePeriod _period;
|
|
||||||
public ITimePeriod Period
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
_period ??= new TimeRange(StartDate, EndDate);
|
|
||||||
|
|
||||||
return _period;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Events that starts at midnight and ends at midnight are considered all-day events.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsAllDayEvent
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return
|
|
||||||
StartDate.TimeOfDay == TimeSpan.Zero &&
|
|
||||||
EndDate.TimeOfDay == TimeSpan.Zero;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Events that are either an exceptional instance of a recurring event or occurrences.
|
|
||||||
/// IsOccurrence is used to display occurrence instances of parent recurring events.
|
|
||||||
/// IsOccurrence == false && IsRecurringChild == true => exceptional single instance.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsRecurringChild
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return RecurringCalendarItemId != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Events that are either an exceptional instance of a recurring event or occurrences.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsRecurringEvent => IsRecurringChild || IsRecurringParent;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Events that are the master event definition of recurrence events.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsRecurringParent
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return !string.IsNullOrEmpty(Recurrence) && RecurringCalendarItemId == null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Events that are not all-day events and last more than one day are considered multi-day events.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsMultiDayEvent
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Period.Duration.TotalDays >= 1 && !IsAllDayEvent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public double DurationInSeconds { get; set; }
|
|
||||||
public string Recurrence { get; set; }
|
|
||||||
|
|
||||||
public string OrganizerDisplayName { get; set; }
|
|
||||||
public string OrganizerEmail { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The id of the parent calendar item of the recurring event.
|
|
||||||
/// Exceptional instances are stored as a separate calendar item.
|
|
||||||
/// This makes the calendar item a child of the recurring event.
|
|
||||||
/// </summary>
|
|
||||||
public Guid? RecurringCalendarItemId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates read-only events. Default is false.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsLocked { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Hidden events must not be displayed to the user.
|
|
||||||
/// This usually happens when a child instance of recurring parent is cancelled after creation.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsHidden { get; set; }
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
public string CustomEventColorHex { get; set; }
|
|
||||||
public string HtmlLink { get; set; }
|
|
||||||
public CalendarItemStatus Status { get; set; }
|
|
||||||
public CalendarItemVisibility Visibility { get; set; }
|
|
||||||
public DateTimeOffset CreatedAt { get; set; }
|
|
||||||
public DateTimeOffset UpdatedAt { get; set; }
|
|
||||||
public Guid CalendarId { get; set; }
|
|
||||||
|
|
||||||
[Ignore]
|
|
||||||
public IAccountCalendar AssignedCalendar { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether this item does not really exist in the database or not.
|
|
||||||
/// These are used to display occurrence instances of parent recurring events.
|
|
||||||
/// </summary>
|
|
||||||
[Ignore]
|
|
||||||
public bool IsOccurrence { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Id to load information related to this event.
|
|
||||||
/// Occurrences tracked by the parent recurring event if they are not exceptional instances.
|
|
||||||
/// Recurring children here are exceptional instances. They have their own info in the database including Id.
|
|
||||||
/// </summary>
|
|
||||||
public Guid EventTrackingId => IsOccurrence ? RecurringCalendarItemId.Value : Id;
|
|
||||||
|
|
||||||
public CalendarItem CreateRecurrence(DateTime startDate, double durationInSeconds)
|
|
||||||
{
|
|
||||||
// Create a copy with the new start date and duration
|
|
||||||
|
|
||||||
return new CalendarItem
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid(),
|
|
||||||
Title = Title,
|
|
||||||
Description = Description,
|
|
||||||
Location = Location,
|
|
||||||
StartDate = startDate,
|
|
||||||
DurationInSeconds = durationInSeconds,
|
|
||||||
Recurrence = Recurrence,
|
|
||||||
OrganizerDisplayName = OrganizerDisplayName,
|
|
||||||
OrganizerEmail = OrganizerEmail,
|
|
||||||
RecurringCalendarItemId = Id,
|
|
||||||
AssignedCalendar = AssignedCalendar,
|
|
||||||
CalendarId = CalendarId,
|
|
||||||
CreatedAt = CreatedAt,
|
|
||||||
UpdatedAt = UpdatedAt,
|
|
||||||
Visibility = Visibility,
|
|
||||||
Status = Status,
|
|
||||||
CustomEventColorHex = CustomEventColorHex,
|
|
||||||
HtmlLink = HtmlLink,
|
|
||||||
StartDateOffset = StartDateOffset,
|
|
||||||
EndDateOffset = EndDateOffset,
|
|
||||||
RemoteEventId = RemoteEventId,
|
|
||||||
IsHidden = IsHidden,
|
|
||||||
IsLocked = IsLocked,
|
|
||||||
IsOccurrence = true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TimeSpan StartDateOffset { get; set; }
|
||||||
|
public TimeSpan EndDateOffset { get; set; }
|
||||||
|
|
||||||
|
private ITimePeriod _period;
|
||||||
|
public ITimePeriod Period
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
_period ??= new TimeRange(StartDate, EndDate);
|
||||||
|
|
||||||
|
return _period;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Events that starts at midnight and ends at midnight are considered all-day events.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsAllDayEvent
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return
|
||||||
|
StartDate.TimeOfDay == TimeSpan.Zero &&
|
||||||
|
EndDate.TimeOfDay == TimeSpan.Zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Events that are either an exceptional instance of a recurring event or occurrences.
|
||||||
|
/// IsOccurrence is used to display occurrence instances of parent recurring events.
|
||||||
|
/// IsOccurrence == false && IsRecurringChild == true => exceptional single instance.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsRecurringChild
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return RecurringCalendarItemId != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Events that are either an exceptional instance of a recurring event or occurrences.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsRecurringEvent => IsRecurringChild || IsRecurringParent;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Events that are the master event definition of recurrence events.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsRecurringParent
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return !string.IsNullOrEmpty(Recurrence) && RecurringCalendarItemId == null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Events that are not all-day events and last more than one day are considered multi-day events.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsMultiDayEvent
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Period.Duration.TotalDays >= 1 && !IsAllDayEvent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double DurationInSeconds { get; set; }
|
||||||
|
public string Recurrence { get; set; }
|
||||||
|
|
||||||
|
public string OrganizerDisplayName { get; set; }
|
||||||
|
public string OrganizerEmail { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The id of the parent calendar item of the recurring event.
|
||||||
|
/// Exceptional instances are stored as a separate calendar item.
|
||||||
|
/// This makes the calendar item a child of the recurring event.
|
||||||
|
/// </summary>
|
||||||
|
public Guid? RecurringCalendarItemId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates read-only events. Default is false.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsLocked { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hidden events must not be displayed to the user.
|
||||||
|
/// This usually happens when a child instance of recurring parent is cancelled after creation.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsHidden { get; set; }
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
public string CustomEventColorHex { get; set; }
|
||||||
|
public string HtmlLink { get; set; }
|
||||||
|
public CalendarItemStatus Status { get; set; }
|
||||||
|
public CalendarItemVisibility Visibility { get; set; }
|
||||||
|
public DateTimeOffset CreatedAt { get; set; }
|
||||||
|
public DateTimeOffset UpdatedAt { get; set; }
|
||||||
|
public Guid CalendarId { get; set; }
|
||||||
|
|
||||||
|
[Ignore]
|
||||||
|
public IAccountCalendar AssignedCalendar { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this item does not really exist in the database or not.
|
||||||
|
/// These are used to display occurrence instances of parent recurring events.
|
||||||
|
/// </summary>
|
||||||
|
[Ignore]
|
||||||
|
public bool IsOccurrence { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id to load information related to this event.
|
||||||
|
/// Occurrences tracked by the parent recurring event if they are not exceptional instances.
|
||||||
|
/// Recurring children here are exceptional instances. They have their own info in the database including Id.
|
||||||
|
/// </summary>
|
||||||
|
public Guid EventTrackingId => IsOccurrence ? RecurringCalendarItemId.Value : Id;
|
||||||
|
|
||||||
|
public CalendarItem CreateRecurrence(DateTime startDate, double durationInSeconds)
|
||||||
|
{
|
||||||
|
// Create a copy with the new start date and duration
|
||||||
|
|
||||||
|
return new CalendarItem
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Title = Title,
|
||||||
|
Description = Description,
|
||||||
|
Location = Location,
|
||||||
|
StartDate = startDate,
|
||||||
|
DurationInSeconds = durationInSeconds,
|
||||||
|
Recurrence = Recurrence,
|
||||||
|
OrganizerDisplayName = OrganizerDisplayName,
|
||||||
|
OrganizerEmail = OrganizerEmail,
|
||||||
|
RecurringCalendarItemId = Id,
|
||||||
|
AssignedCalendar = AssignedCalendar,
|
||||||
|
CalendarId = CalendarId,
|
||||||
|
CreatedAt = CreatedAt,
|
||||||
|
UpdatedAt = UpdatedAt,
|
||||||
|
Visibility = Visibility,
|
||||||
|
Status = Status,
|
||||||
|
CustomEventColorHex = CustomEventColorHex,
|
||||||
|
HtmlLink = HtmlLink,
|
||||||
|
StartDateOffset = StartDateOffset,
|
||||||
|
EndDateOffset = EndDateOffset,
|
||||||
|
RemoteEventId = RemoteEventId,
|
||||||
|
IsHidden = IsHidden,
|
||||||
|
IsLocked = IsLocked,
|
||||||
|
IsOccurrence = true
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,15 +2,14 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Entities.Calendar
|
namespace Wino.Core.Domain.Entities.Calendar;
|
||||||
{
|
|
||||||
public class Reminder
|
|
||||||
{
|
|
||||||
[PrimaryKey]
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
public Guid CalendarItemId { get; set; }
|
|
||||||
|
|
||||||
public DateTimeOffset ReminderTime { get; set; }
|
public class Reminder
|
||||||
public CalendarItemReminderType ReminderType { get; set; }
|
{
|
||||||
}
|
[PrimaryKey]
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public Guid CalendarItemId { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset ReminderTime { get; set; }
|
||||||
|
public CalendarItemReminderType ReminderType { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
using System;
|
using System;
|
||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Entities.Mail
|
namespace Wino.Core.Domain.Entities.Mail;
|
||||||
|
|
||||||
|
public class AccountSignature
|
||||||
{
|
{
|
||||||
public class AccountSignature
|
[PrimaryKey]
|
||||||
{
|
public Guid Id { get; set; }
|
||||||
[PrimaryKey]
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
|
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
public string HtmlBody { get; set; }
|
public string HtmlBody { get; set; }
|
||||||
|
|
||||||
public Guid MailAccountId { get; set; }
|
public Guid MailAccountId { get; set; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,63 +1,62 @@
|
|||||||
using System;
|
using System;
|
||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Entities.Mail
|
namespace Wino.Core.Domain.Entities.Mail;
|
||||||
|
|
||||||
|
public class RemoteAccountAlias
|
||||||
{
|
{
|
||||||
public class RemoteAccountAlias
|
/// <summary>
|
||||||
{
|
/// Display address of the alias.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Display address of the alias.
|
public string AliasAddress { get; set; }
|
||||||
/// </summary>
|
|
||||||
public string AliasAddress { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Address to be included in Reply-To header when alias is used for sending messages.
|
/// Address to be included in Reply-To header when alias is used for sending messages.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ReplyToAddress { get; set; }
|
public string ReplyToAddress { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this alias is the primary alias for the account.
|
/// Whether this alias is the primary alias for the account.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsPrimary { get; set; }
|
public bool IsPrimary { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the alias is verified by the server.
|
/// Whether the alias is verified by the server.
|
||||||
/// Only Gmail aliases are verified for now.
|
/// Only Gmail aliases are verified for now.
|
||||||
/// Non-verified alias messages might be rejected by SMTP server.
|
/// Non-verified alias messages might be rejected by SMTP server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsVerified { get; set; }
|
public bool IsVerified { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this alias is the root alias for the account.
|
/// Whether this alias is the root alias for the account.
|
||||||
/// Root alias means the first alias that was created for the account.
|
/// Root alias means the first alias that was created for the account.
|
||||||
/// It can't be deleted or changed.
|
/// It can't be deleted or changed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsRootAlias { get; set; }
|
public bool IsRootAlias { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Optional sender name for the alias.
|
/// Optional sender name for the alias.
|
||||||
/// Falls back to account's sender name if not set when preparing messages.
|
/// Falls back to account's sender name if not set when preparing messages.
|
||||||
/// Used for Gmail only.
|
/// Used for Gmail only.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string AliasSenderName { get; set; }
|
public string AliasSenderName { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MailAccountAlias : RemoteAccountAlias
|
public class MailAccountAlias : RemoteAccountAlias
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unique Id for the alias.
|
/// Unique Id for the alias.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PrimaryKey]
|
[PrimaryKey]
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Account id that this alias is attached to.
|
/// Account id that this alias is attached to.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid AccountId { get; set; }
|
public Guid AccountId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Root aliases can't be deleted.
|
/// Root aliases can't be deleted.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CanDelete => !IsRootAlias;
|
public bool CanDelete => !IsRootAlias;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,153 +5,152 @@ using Wino.Core.Domain.Entities.Shared;
|
|||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
using Wino.Core.Domain.Models.MailItem;
|
using Wino.Core.Domain.Models.MailItem;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Entities.Mail
|
namespace Wino.Core.Domain.Entities.Mail;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Summary of the parsed MIME messages.
|
||||||
|
/// Wino will do non-network operations on this table and others from the original MIME.
|
||||||
|
/// </summary>
|
||||||
|
public class MailCopy : IMailItem
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Summary of the parsed MIME messages.
|
/// Unique Id of the mail.
|
||||||
/// Wino will do non-network operations on this table and others from the original MIME.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MailCopy : IMailItem
|
[PrimaryKey]
|
||||||
{
|
public Guid UniqueId { get; set; }
|
||||||
/// <summary>
|
|
||||||
/// Unique Id of the mail.
|
|
||||||
/// </summary>
|
|
||||||
[PrimaryKey]
|
|
||||||
public Guid UniqueId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Not unique id of the item. Some operations held on this Id, some on the UniqueId.
|
/// Not unique id of the item. Some operations held on this Id, some on the UniqueId.
|
||||||
/// Same message can be in different folder. In that case UniqueId is used.
|
/// Same message can be in different folder. In that case UniqueId is used.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Folder that this mail belongs to.
|
/// Folder that this mail belongs to.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid FolderId { get; set; }
|
public Guid FolderId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Conversation id for the mail.
|
/// Conversation id for the mail.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ThreadId { get; set; }
|
public string ThreadId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// MIME MessageId if exists.
|
/// MIME MessageId if exists.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string MessageId { get; set; }
|
public string MessageId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// References header from MIME
|
/// References header from MIME
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string References { get; set; }
|
public string References { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// In-Reply-To header from MIME
|
/// In-Reply-To header from MIME
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string InReplyTo { get; set; }
|
public string InReplyTo { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Name for the sender.
|
/// Name for the sender.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string FromName { get; set; }
|
public string FromName { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Address of the sender.
|
/// Address of the sender.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string FromAddress { get; set; }
|
public string FromAddress { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Subject of the mail.
|
/// Subject of the mail.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Subject { get; set; }
|
public string Subject { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Short preview of the content.
|
/// Short preview of the content.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string PreviewText { get; set; }
|
public string PreviewText { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Date that represents this mail has been created in provider servers.
|
/// Date that represents this mail has been created in provider servers.
|
||||||
/// Stored always in UTC.
|
/// Stored always in UTC.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DateTime CreationDate { get; set; }
|
public DateTime CreationDate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Importance of the mail.
|
/// Importance of the mail.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MailImportance Importance { get; set; }
|
public MailImportance Importance { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Read status for the mail.
|
/// Read status for the mail.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsRead { get; set; }
|
public bool IsRead { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Flag status.
|
/// Flag status.
|
||||||
/// Flagged for Outlook.
|
/// Flagged for Outlook.
|
||||||
/// Important for Gmail.
|
/// Important for Gmail.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsFlagged { get; set; }
|
public bool IsFlagged { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// To support Outlook.
|
/// To support Outlook.
|
||||||
/// Gmail doesn't use it.
|
/// Gmail doesn't use it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsFocused { get; set; }
|
public bool IsFocused { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether mail has attachments included or not.
|
/// Whether mail has attachments included or not.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool HasAttachments { get; set; }
|
public bool HasAttachments { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Assigned draft id.
|
/// Assigned draft id.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string DraftId { get; set; }
|
public string DraftId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this mail is only created locally.
|
/// Whether this mail is only created locally.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Ignore]
|
[Ignore]
|
||||||
public bool IsLocalDraft => !string.IsNullOrEmpty(DraftId) && DraftId.StartsWith(Constants.LocalDraftStartPrefix);
|
public bool IsLocalDraft => !string.IsNullOrEmpty(DraftId) && DraftId.StartsWith(Constants.LocalDraftStartPrefix);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this copy is draft or not.
|
/// Whether this copy is draft or not.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsDraft { get; set; }
|
public bool IsDraft { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// File id that this mail is assigned to.
|
/// File id that this mail is assigned to.
|
||||||
/// This Id is immutable. It's used to find the file in the file system.
|
/// This Id is immutable. It's used to find the file in the file system.
|
||||||
/// Even after mapping local draft to remote draft, it will not change.
|
/// Even after mapping local draft to remote draft, it will not change.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid FileId { get; set; }
|
public Guid FileId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Folder that this mail is assigned to.
|
/// Folder that this mail is assigned to.
|
||||||
/// Warning: This field is not populated by queries.
|
/// Warning: This field is not populated by queries.
|
||||||
/// Services or View Models are responsible for populating this field.
|
/// Services or View Models are responsible for populating this field.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Ignore]
|
[Ignore]
|
||||||
public MailItemFolder AssignedFolder { get; set; }
|
public MailItemFolder AssignedFolder { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Account that this mail is assigned to.
|
/// Account that this mail is assigned to.
|
||||||
/// Warning: This field is not populated by queries.
|
/// Warning: This field is not populated by queries.
|
||||||
/// Services or View Models are responsible for populating this field.
|
/// Services or View Models are responsible for populating this field.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Ignore]
|
[Ignore]
|
||||||
public MailAccount AssignedAccount { get; set; }
|
public MailAccount AssignedAccount { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contact information of the sender if exists.
|
/// Contact information of the sender if exists.
|
||||||
/// Warning: This field is not populated by queries.
|
/// Warning: This field is not populated by queries.
|
||||||
/// Services or View Models are responsible for populating this field.
|
/// Services or View Models are responsible for populating this field.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Ignore]
|
[Ignore]
|
||||||
public AccountContact SenderContact { get; set; }
|
public AccountContact SenderContact { get; set; }
|
||||||
|
|
||||||
public IEnumerable<Guid> GetContainingIds() => [UniqueId];
|
public IEnumerable<Guid> GetContainingIds() => [UniqueId];
|
||||||
public override string ToString() => $"{Subject} <-> {Id}";
|
public override string ToString() => $"{Subject} <-> {Id}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,71 +5,70 @@ using SQLite;
|
|||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
using Wino.Core.Domain.Models.Folders;
|
using Wino.Core.Domain.Models.Folders;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Entities.Mail
|
namespace Wino.Core.Domain.Entities.Mail;
|
||||||
|
|
||||||
|
[DebuggerDisplay("{FolderName} - {SpecialFolderType}")]
|
||||||
|
public class MailItemFolder : IMailItemFolder
|
||||||
{
|
{
|
||||||
[DebuggerDisplay("{FolderName} - {SpecialFolderType}")]
|
[PrimaryKey]
|
||||||
public class MailItemFolder : IMailItemFolder
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public string RemoteFolderId { get; set; }
|
||||||
|
public string ParentRemoteFolderId { get; set; }
|
||||||
|
|
||||||
|
public Guid MailAccountId { get; set; }
|
||||||
|
public string FolderName { get; set; }
|
||||||
|
public SpecialFolderType SpecialFolderType { get; set; }
|
||||||
|
public bool IsSystemFolder { get; set; }
|
||||||
|
public bool IsSticky { get; set; }
|
||||||
|
public bool IsSynchronizationEnabled { get; set; }
|
||||||
|
public bool IsHidden { get; set; }
|
||||||
|
public bool ShowUnreadCount { get; set; }
|
||||||
|
public DateTime? LastSynchronizedDate { get; set; }
|
||||||
|
|
||||||
|
// For IMAP
|
||||||
|
public uint UidValidity { get; set; }
|
||||||
|
public long HighestModeSeq { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Outlook shares delta changes per-folder. Gmail is for per-account.
|
||||||
|
/// This is only used for Outlook provider.
|
||||||
|
/// </summary>
|
||||||
|
public string DeltaToken { get; set; }
|
||||||
|
|
||||||
|
// For GMail Labels
|
||||||
|
public string TextColorHex { get; set; }
|
||||||
|
public string BackgroundColorHex { get; set; }
|
||||||
|
|
||||||
|
[Ignore]
|
||||||
|
public List<IMailItemFolder> ChildFolders { get; set; } = [];
|
||||||
|
|
||||||
|
// Category and Move type folders are not valid move targets.
|
||||||
|
// These folders are virtual. They don't exist on the server.
|
||||||
|
public bool IsMoveTarget => !(SpecialFolderType == SpecialFolderType.More || SpecialFolderType == SpecialFolderType.Category);
|
||||||
|
|
||||||
|
public bool ContainsSpecialFolderType(SpecialFolderType type)
|
||||||
{
|
{
|
||||||
[PrimaryKey]
|
if (SpecialFolderType == type)
|
||||||
public Guid Id { get; set; }
|
return true;
|
||||||
|
|
||||||
public string RemoteFolderId { get; set; }
|
foreach (var child in ChildFolders)
|
||||||
public string ParentRemoteFolderId { get; set; }
|
|
||||||
|
|
||||||
public Guid MailAccountId { get; set; }
|
|
||||||
public string FolderName { get; set; }
|
|
||||||
public SpecialFolderType SpecialFolderType { get; set; }
|
|
||||||
public bool IsSystemFolder { get; set; }
|
|
||||||
public bool IsSticky { get; set; }
|
|
||||||
public bool IsSynchronizationEnabled { get; set; }
|
|
||||||
public bool IsHidden { get; set; }
|
|
||||||
public bool ShowUnreadCount { get; set; }
|
|
||||||
public DateTime? LastSynchronizedDate { get; set; }
|
|
||||||
|
|
||||||
// For IMAP
|
|
||||||
public uint UidValidity { get; set; }
|
|
||||||
public long HighestModeSeq { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Outlook shares delta changes per-folder. Gmail is for per-account.
|
|
||||||
/// This is only used for Outlook provider.
|
|
||||||
/// </summary>
|
|
||||||
public string DeltaToken { get; set; }
|
|
||||||
|
|
||||||
// For GMail Labels
|
|
||||||
public string TextColorHex { get; set; }
|
|
||||||
public string BackgroundColorHex { get; set; }
|
|
||||||
|
|
||||||
[Ignore]
|
|
||||||
public List<IMailItemFolder> ChildFolders { get; set; } = [];
|
|
||||||
|
|
||||||
// Category and Move type folders are not valid move targets.
|
|
||||||
// These folders are virtual. They don't exist on the server.
|
|
||||||
public bool IsMoveTarget => !(SpecialFolderType == SpecialFolderType.More || SpecialFolderType == SpecialFolderType.Category);
|
|
||||||
|
|
||||||
public bool ContainsSpecialFolderType(SpecialFolderType type)
|
|
||||||
{
|
{
|
||||||
if (SpecialFolderType == type)
|
if (child.SpecialFolderType == type)
|
||||||
return true;
|
|
||||||
|
|
||||||
foreach (var child in ChildFolders)
|
|
||||||
{
|
{
|
||||||
if (child.SpecialFolderType == type)
|
return true;
|
||||||
{
|
}
|
||||||
return true;
|
else
|
||||||
}
|
{
|
||||||
else
|
return child.ContainsSpecialFolderType(type);
|
||||||
{
|
|
||||||
return child.ContainsSpecialFolderType(type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MailItemFolder CreateMoreFolder() => new MailItemFolder() { IsSticky = true, SpecialFolderType = SpecialFolderType.More, FolderName = Translator.MoreFolderNameOverride };
|
return false;
|
||||||
public static MailItemFolder CreateCategoriesFolder() => new MailItemFolder() { IsSticky = true, SpecialFolderType = SpecialFolderType.Category, FolderName = Translator.CategoriesFolderNameOverride };
|
|
||||||
|
|
||||||
public override string ToString() => FolderName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MailItemFolder CreateMoreFolder() => new MailItemFolder() { IsSticky = true, SpecialFolderType = SpecialFolderType.More, FolderName = Translator.MoreFolderNameOverride };
|
||||||
|
public static MailItemFolder CreateCategoriesFolder() => new MailItemFolder() { IsSticky = true, SpecialFolderType = SpecialFolderType.Category, FolderName = Translator.CategoriesFolderNameOverride };
|
||||||
|
|
||||||
|
public override string ToString() => FolderName;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Entities.Mail
|
namespace Wino.Core.Domain.Entities.Mail;
|
||||||
{
|
|
||||||
public class MergedInbox
|
|
||||||
{
|
|
||||||
[PrimaryKey]
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
|
|
||||||
public string Name { get; set; }
|
public class MergedInbox
|
||||||
}
|
{
|
||||||
|
[PrimaryKey]
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,76 +2,64 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Entities.Shared
|
namespace Wino.Core.Domain.Entities.Shared;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Back storage for simple name-address book.
|
||||||
|
/// These values will be inserted during MIME fetch.
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
// TODO: This can easily evolve to Contact store, just like People app in Windows 10/11.
|
||||||
|
// Do it.
|
||||||
|
public class AccountContact : IEquatable<AccountContact>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Back storage for simple name-address book.
|
/// E-mail address of the contact.
|
||||||
/// These values will be inserted during MIME fetch.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[PrimaryKey]
|
||||||
|
public string Address { get; set; }
|
||||||
|
|
||||||
// TODO: This can easily evolve to Contact store, just like People app in Windows 10/11.
|
/// <summary>
|
||||||
// Do it.
|
/// Display name of the contact.
|
||||||
public class AccountContact : IEquatable<AccountContact>
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base64 encoded profile image of the contact.
|
||||||
|
/// </summary>
|
||||||
|
public string Base64ContactPicture { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// All registered accounts have their contacts registered as root.
|
||||||
|
/// Root contacts must not be overridden by any configuration.
|
||||||
|
/// They are created on account creation.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsRootContact { get; set; }
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
{
|
{
|
||||||
/// <summary>
|
return Equals(obj as AccountContact);
|
||||||
/// E-mail address of the contact.
|
}
|
||||||
/// </summary>
|
|
||||||
[PrimaryKey]
|
|
||||||
public string Address { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
public bool Equals(AccountContact other)
|
||||||
/// Display name of the contact.
|
{
|
||||||
/// </summary>
|
return other is not null &&
|
||||||
public string Name { get; set; }
|
Address == other.Address &&
|
||||||
|
Name == other.Name;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
public override int GetHashCode()
|
||||||
/// Base64 encoded profile image of the contact.
|
{
|
||||||
/// </summary>
|
return HashCode.Combine(Address, Name);
|
||||||
public string Base64ContactPicture { get; set; }
|
}
|
||||||
|
|
||||||
/// <summary>
|
public static bool operator ==(AccountContact left, AccountContact right)
|
||||||
/// All registered accounts have their contacts registered as root.
|
{
|
||||||
/// Root contacts must not be overridden by any configuration.
|
return EqualityComparer<AccountContact>.Default.Equals(left, right);
|
||||||
/// They are created on account creation.
|
}
|
||||||
/// </summary>
|
|
||||||
public bool IsRootContact { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
public static bool operator !=(AccountContact left, AccountContact right)
|
||||||
/// Short display name of the contact.
|
{
|
||||||
/// Eather Name or Address.
|
return !(left == right);
|
||||||
/// </summary>
|
|
||||||
public string ShortDisplayName => Address == Name || string.IsNullOrWhiteSpace(Name) ? $"{Address.ToLowerInvariant()};" : $"{Name};";
|
|
||||||
|
|
||||||
public string DisplayName => Address == Name || string.IsNullOrWhiteSpace(Name) ? Address.ToLowerInvariant() : $"{Name} <{Address.ToLowerInvariant()}>";
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
return Equals(obj as AccountContact);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Equals(AccountContact other)
|
|
||||||
{
|
|
||||||
return other is not null &&
|
|
||||||
Address == other.Address &&
|
|
||||||
Name == other.Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
int hashCode = -1717786383;
|
|
||||||
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Address);
|
|
||||||
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Name);
|
|
||||||
return hashCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator ==(AccountContact left, AccountContact right)
|
|
||||||
{
|
|
||||||
return EqualityComparer<AccountContact>.Default.Equals(left, right);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator !=(AccountContact left, AccountContact right)
|
|
||||||
{
|
|
||||||
return !(left == right);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,53 +1,74 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using SQLite;
|
using SQLite;
|
||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Entities.Shared
|
namespace Wino.Core.Domain.Entities.Shared;
|
||||||
|
|
||||||
|
public class CustomServerInformation
|
||||||
{
|
{
|
||||||
public class CustomServerInformation
|
[PrimaryKey]
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public Guid AccountId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This field is ignored. DisplayName is stored in MailAccount as SenderName from now.
|
||||||
|
/// </summary>
|
||||||
|
[Ignore]
|
||||||
|
public string DisplayName { get; set; }
|
||||||
|
public string Address { get; set; }
|
||||||
|
public string IncomingServer { get; set; }
|
||||||
|
public string IncomingServerUsername { get; set; }
|
||||||
|
public string IncomingServerPassword { get; set; }
|
||||||
|
public string IncomingServerPort { get; set; }
|
||||||
|
|
||||||
|
public CustomIncomingServerType IncomingServerType { get; set; }
|
||||||
|
|
||||||
|
public string OutgoingServer { get; set; }
|
||||||
|
public string OutgoingServerPort { get; set; }
|
||||||
|
public string OutgoingServerUsername { get; set; }
|
||||||
|
public string OutgoingServerPassword { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// useSSL True: SslOnConnect
|
||||||
|
/// useSSL False: StartTlsWhenAvailable
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
public ImapConnectionSecurity IncomingServerSocketOption { get; set; }
|
||||||
|
public ImapAuthenticationMethod IncomingAuthenticationMethod { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public ImapConnectionSecurity OutgoingServerSocketOption { get; set; }
|
||||||
|
public ImapAuthenticationMethod OutgoingAuthenticationMethod { get; set; }
|
||||||
|
|
||||||
|
public string ProxyServer { get; set; }
|
||||||
|
public string ProxyServerPort { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of concurrent clients that can connect to the server.
|
||||||
|
/// Default is 5.
|
||||||
|
/// </summary>
|
||||||
|
public int MaxConcurrentClients { get; set; }
|
||||||
|
|
||||||
|
public Dictionary<string, string> GetConnectionProperties()
|
||||||
{
|
{
|
||||||
[PrimaryKey]
|
// Printout the public connection properties.
|
||||||
public Guid Id { get; set; }
|
|
||||||
|
|
||||||
public Guid AccountId { get; set; }
|
var connectionProperties = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ "IncomingServer", IncomingServer },
|
||||||
|
{ "IncomingServerPort", IncomingServerPort },
|
||||||
|
{ "IncomingServerSocketOption", IncomingServerSocketOption.ToString() },
|
||||||
|
{ "IncomingAuthenticationMethod", IncomingAuthenticationMethod.ToString() },
|
||||||
|
{ "OutgoingServer", OutgoingServer },
|
||||||
|
{ "OutgoingServerPort", OutgoingServerPort },
|
||||||
|
{ "OutgoingServerSocketOption", OutgoingServerSocketOption.ToString() },
|
||||||
|
{ "OutgoingAuthenticationMethod", OutgoingAuthenticationMethod.ToString() },
|
||||||
|
{ "ProxyServer", ProxyServer },
|
||||||
|
{ "ProxyServerPort", ProxyServerPort }
|
||||||
|
};
|
||||||
|
|
||||||
/// <summary>
|
return connectionProperties;
|
||||||
/// This field is ignored. DisplayName is stored in MailAccount as SenderName from now.
|
|
||||||
/// </summary>
|
|
||||||
[Ignore]
|
|
||||||
public string DisplayName { get; set; }
|
|
||||||
public string Address { get; set; }
|
|
||||||
public string IncomingServer { get; set; }
|
|
||||||
public string IncomingServerUsername { get; set; }
|
|
||||||
public string IncomingServerPassword { get; set; }
|
|
||||||
public string IncomingServerPort { get; set; }
|
|
||||||
|
|
||||||
public CustomIncomingServerType IncomingServerType { get; set; }
|
|
||||||
|
|
||||||
public string OutgoingServer { get; set; }
|
|
||||||
public string OutgoingServerPort { get; set; }
|
|
||||||
public string OutgoingServerUsername { get; set; }
|
|
||||||
public string OutgoingServerPassword { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// useSSL True: SslOnConnect
|
|
||||||
/// useSSL False: StartTlsWhenAvailable
|
|
||||||
/// </summary>
|
|
||||||
|
|
||||||
public ImapConnectionSecurity IncomingServerSocketOption { get; set; }
|
|
||||||
public ImapAuthenticationMethod IncomingAuthenticationMethod { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public ImapConnectionSecurity OutgoingServerSocketOption { get; set; }
|
|
||||||
public ImapAuthenticationMethod OutgoingAuthenticationMethod { get; set; }
|
|
||||||
|
|
||||||
public string ProxyServer { get; set; }
|
|
||||||
public string ProxyServerPort { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Number of concurrent clients that can connect to the server.
|
|
||||||
/// Default is 5.
|
|
||||||
/// </summary>
|
|
||||||
public int MaxConcurrentClients { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,103 +3,108 @@ using SQLite;
|
|||||||
using Wino.Core.Domain.Entities.Mail;
|
using Wino.Core.Domain.Entities.Mail;
|
||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Entities.Shared
|
namespace Wino.Core.Domain.Entities.Shared;
|
||||||
|
|
||||||
|
public class MailAccount
|
||||||
{
|
{
|
||||||
public class MailAccount
|
[PrimaryKey]
|
||||||
{
|
public Guid Id { get; set; }
|
||||||
[PrimaryKey]
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Given name of the account in Wino.
|
/// Given name of the account in Wino.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// TODO: Display name of the authenticated user/account.
|
/// TODO: Display name of the authenticated user/account.
|
||||||
/// API integrations will query this value from the API.
|
/// API integrations will query this value from the API.
|
||||||
/// IMAP is populated by user on setup dialog.
|
/// IMAP is populated by user on setup dialog.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
public string SenderName { get; set; }
|
public string SenderName { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Account e-mail address.
|
/// Account e-mail address.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Address { get; set; }
|
public string Address { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provider type of the account. Outlook,Gmail etc...
|
/// Provider type of the account. Outlook,Gmail etc...
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MailProviderType ProviderType { get; set; }
|
public MailProviderType ProviderType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// For tracking mail change delta.
|
/// For tracking mail change delta.
|
||||||
/// Gmail : historyId
|
/// Gmail : historyId
|
||||||
/// Outlook: deltaToken
|
/// Outlook: deltaToken
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string SynchronizationDeltaIdentifier { get; set; }
|
public string SynchronizationDeltaIdentifier { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// For tracking calendar change delta.
|
/// For tracking calendar change delta.
|
||||||
/// Gmail: It's per-calendar, so unused.
|
/// Gmail: It's per-calendar, so unused.
|
||||||
/// Outlook: deltaLink
|
/// Outlook: deltaLink
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string CalendarSynchronizationDeltaIdentifier { get; set; }
|
public string CalendarSynchronizationDeltaIdentifier { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// TODO: Gets or sets the custom account identifier color in hex.
|
/// TODO: Gets or sets the custom account identifier color in hex.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string AccountColorHex { get; set; }
|
public string AccountColorHex { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base64 encoded profile picture of the account.
|
/// Base64 encoded profile picture of the account.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Base64ProfilePictureData { 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.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Order { get; set; }
|
public int Order { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets whether the account has any reason for an interactive user action to fix continue operating.
|
/// Gets or sets whether the account has any reason for an interactive user action to fix continue operating.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public AccountAttentionReason AttentionReason { get; set; }
|
public AccountAttentionReason AttentionReason { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the id of the merged inbox this account belongs to.
|
/// Gets or sets the id of the merged inbox this account belongs to.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid? MergedInboxId { get; set; }
|
public Guid? MergedInboxId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains the merged inbox this account belongs to.
|
/// Gets or sets the additional IMAP provider assignment for the account.
|
||||||
/// Ignored for all SQLite operations.
|
/// Providers that use IMAP as a synchronizer but have special requirements.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Ignore]
|
public SpecialImapProvider SpecialImapProvider { get; set; }
|
||||||
public MergedInbox MergedInbox { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Populated only when account has custom server information.
|
/// Contains the merged inbox this account belongs to.
|
||||||
/// </summary>
|
/// Ignored for all SQLite operations.
|
||||||
|
/// </summary>
|
||||||
|
[Ignore]
|
||||||
|
public MergedInbox MergedInbox { get; set; }
|
||||||
|
|
||||||
[Ignore]
|
/// <summary>
|
||||||
public CustomServerInformation ServerInformation { get; set; }
|
/// Populated only when account has custom server information.
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
/// <summary>
|
[Ignore]
|
||||||
/// Account preferences.
|
public CustomServerInformation ServerInformation { get; set; }
|
||||||
/// </summary>
|
|
||||||
[Ignore]
|
|
||||||
public MailAccountPreferences Preferences { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets whether the account can perform ProfileInformation sync type.
|
/// Account preferences.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsProfileInfoSyncSupported => ProviderType == MailProviderType.Outlook || ProviderType == MailProviderType.Office365 || ProviderType == MailProviderType.Gmail;
|
[Ignore]
|
||||||
|
public MailAccountPreferences Preferences { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets whether the account can perform AliasInformation sync type.
|
/// Gets whether the account can perform ProfileInformation sync type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsAliasSyncSupported => ProviderType == MailProviderType.Gmail;
|
public bool IsProfileInfoSyncSupported => ProviderType == MailProviderType.Outlook || ProviderType == MailProviderType.Gmail;
|
||||||
}
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets whether the account can perform AliasInformation sync type.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsAliasSyncSupported => ProviderType == MailProviderType.Gmail;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,54 +1,53 @@
|
|||||||
using System;
|
using System;
|
||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Entities.Shared
|
namespace Wino.Core.Domain.Entities.Shared;
|
||||||
|
|
||||||
|
public class MailAccountPreferences
|
||||||
{
|
{
|
||||||
public class MailAccountPreferences
|
[PrimaryKey]
|
||||||
{
|
public Guid Id { get; set; }
|
||||||
[PrimaryKey]
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Id of the account in MailAccount table.
|
/// Id of the account in MailAccount table.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid AccountId { get; set; }
|
public Guid AccountId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets whether sent draft messages should be appended to the sent folder.
|
/// Gets or sets whether sent draft messages should be appended to the sent folder.
|
||||||
/// Some IMAP servers do this automatically, some don't.
|
/// Some IMAP servers do this automatically, some don't.
|
||||||
/// It's disabled by default.
|
/// It's disabled by default.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool ShouldAppendMessagesToSentFolder { get; set; }
|
public bool ShouldAppendMessagesToSentFolder { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets whether the notifications are enabled for the account.
|
/// Gets or sets whether the notifications are enabled for the account.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsNotificationsEnabled { get; set; }
|
public bool IsNotificationsEnabled { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets whether the account has Focused inbox support.
|
/// Gets or sets whether the account has Focused inbox support.
|
||||||
/// Null if the account provider type doesn't support Focused inbox.
|
/// Null if the account provider type doesn't support Focused inbox.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool? IsFocusedInboxEnabled { get; set; }
|
public bool? IsFocusedInboxEnabled { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets whether signature should be appended automatically.
|
/// Gets or sets whether signature should be appended automatically.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsSignatureEnabled { get; set; }
|
public bool IsSignatureEnabled { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets whether this account's unread items should be included in taskbar badge.
|
/// Gets or sets whether this account's unread items should be included in taskbar badge.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsTaskbarBadgeEnabled { get; set; } = true;
|
public bool IsTaskbarBadgeEnabled { get; set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets signature for new messages. Null if signature is not needed.
|
/// Gets or sets signature for new messages. Null if signature is not needed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid? SignatureIdForNewMessages { get; set; }
|
public Guid? SignatureIdForNewMessages { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets signature for following messages. Null if signature is not needed.
|
/// Gets or sets signature for following messages. Null if signature is not needed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid? SignatureIdForFollowingMessages { get; set; }
|
public Guid? SignatureIdForFollowingMessages { get; set; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum AccountAttentionReason
|
||||||
{
|
{
|
||||||
public enum AccountAttentionReason
|
None,
|
||||||
{
|
InvalidCredentials,
|
||||||
None,
|
MissingSystemFolderConfiguration
|
||||||
InvalidCredentials,
|
|
||||||
MissingSystemFolderConfiguration
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
7
Wino.Core.Domain/Enums/AccountCacheResetReason.cs
Normal file
7
Wino.Core.Domain/Enums/AccountCacheResetReason.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum AccountCacheResetReason
|
||||||
|
{
|
||||||
|
AccountRemoval,
|
||||||
|
ExpiredCache
|
||||||
|
}
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum AccountCreationDialogState
|
||||||
{
|
{
|
||||||
public enum AccountCreationDialogState
|
Idle,
|
||||||
{
|
SigningIn,
|
||||||
Idle,
|
PreparingFolders,
|
||||||
SigningIn,
|
Completed,
|
||||||
PreparingFolders,
|
ManuelSetupWaiting,
|
||||||
Completed,
|
TestingConnection,
|
||||||
ManuelSetupWaiting,
|
AutoDiscoverySetup,
|
||||||
TestingConnection,
|
AutoDiscoveryInProgress,
|
||||||
AutoDiscoverySetup,
|
FetchingProfileInformation,
|
||||||
AutoDiscoveryInProgress,
|
Canceled,
|
||||||
FetchingProfileInformation,
|
FetchingEvents
|
||||||
Canceled,
|
|
||||||
FetchingEvents
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates the state of synchronizer.
|
||||||
|
/// </summary>
|
||||||
|
public enum AccountSynchronizerState
|
||||||
{
|
{
|
||||||
/// <summary>
|
Idle,
|
||||||
/// Indicates the state of synchronizer.
|
ExecutingRequests,
|
||||||
/// </summary>
|
Synchronizing
|
||||||
public enum AccountSynchronizerState
|
|
||||||
{
|
|
||||||
Idle,
|
|
||||||
ExecutingRequests,
|
|
||||||
Synchronizing
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,20 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum AppLanguage
|
||||||
{
|
{
|
||||||
public enum AppLanguage
|
None,
|
||||||
{
|
English,
|
||||||
None,
|
Deutsch,
|
||||||
English,
|
Russian,
|
||||||
Deutsch,
|
Turkish,
|
||||||
Russian,
|
Polish,
|
||||||
Turkish,
|
Czech,
|
||||||
Polish,
|
Chinese,
|
||||||
Czech,
|
Spanish,
|
||||||
Chinese,
|
French,
|
||||||
Spanish,
|
Indonesian,
|
||||||
French,
|
Greek,
|
||||||
Indonesian,
|
PortugeseBrazil,
|
||||||
Greek,
|
Italian,
|
||||||
PortugeseBrazil,
|
Romanian
|
||||||
Italian,
|
|
||||||
Romanian
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum AppThemeType
|
||||||
{
|
{
|
||||||
public enum AppThemeType
|
System,
|
||||||
{
|
PreDefined,
|
||||||
System,
|
Custom,
|
||||||
PreDefined,
|
|
||||||
Custom,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum ApplicationElementTheme
|
||||||
{
|
{
|
||||||
public enum ApplicationElementTheme
|
Default,
|
||||||
{
|
Light,
|
||||||
Default,
|
Dark
|
||||||
Light,
|
|
||||||
Dark
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum AttendeeStatus
|
||||||
{
|
{
|
||||||
public enum AttendeeStatus
|
NeedsAction,
|
||||||
{
|
Accepted,
|
||||||
NeedsAction,
|
Tentative,
|
||||||
Accepted,
|
Declined
|
||||||
Tentative,
|
|
||||||
Declined
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum BackgroundSynchronizationReason
|
||||||
{
|
{
|
||||||
public enum BackgroundSynchronizationReason
|
SessionConnected,
|
||||||
{
|
Timer
|
||||||
SessionConnected,
|
|
||||||
Timer
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum CalendarDisplayType
|
||||||
{
|
{
|
||||||
public enum CalendarDisplayType
|
Day,
|
||||||
{
|
Week,
|
||||||
Day,
|
WorkWeek,
|
||||||
Week,
|
Month,
|
||||||
WorkWeek,
|
Year
|
||||||
Month,
|
|
||||||
Year
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum CalendarEventTargetType
|
||||||
{
|
{
|
||||||
public enum CalendarEventTargetType
|
Single, // Show details for a single event.
|
||||||
{
|
Series // Show the series event. Parent of all recurring events.
|
||||||
Single, // Show details for a single event.
|
|
||||||
Series // Show the series event. Parent of all recurring events.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Trigger to load more data.
|
||||||
|
/// </summary>
|
||||||
|
public enum CalendarInitInitiative
|
||||||
{
|
{
|
||||||
/// <summary>
|
User,
|
||||||
/// Trigger to load more data.
|
App
|
||||||
/// </summary>
|
|
||||||
public enum CalendarInitInitiative
|
|
||||||
{
|
|
||||||
User,
|
|
||||||
App
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum CalendarItemRecurrenceFrequency
|
||||||
{
|
{
|
||||||
public enum CalendarItemRecurrenceFrequency
|
Daily,
|
||||||
{
|
Weekly,
|
||||||
Daily,
|
Monthly,
|
||||||
Weekly,
|
Yearly
|
||||||
Monthly,
|
|
||||||
Yearly
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum CalendarItemReminderType
|
||||||
{
|
{
|
||||||
public enum CalendarItemReminderType
|
Popup,
|
||||||
{
|
Email
|
||||||
Popup,
|
|
||||||
Email
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum CalendarItemStatus
|
||||||
{
|
{
|
||||||
public enum CalendarItemStatus
|
NotResponded,
|
||||||
{
|
Confirmed,
|
||||||
NotResponded,
|
Tentative,
|
||||||
Confirmed,
|
Cancelled,
|
||||||
Tentative,
|
|
||||||
Cancelled,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum CalendarItemVisibility
|
||||||
{
|
{
|
||||||
public enum CalendarItemVisibility
|
Default,
|
||||||
{
|
Public,
|
||||||
Default,
|
Private,
|
||||||
Public,
|
Confidential
|
||||||
Private,
|
|
||||||
Confidential
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Which way in time to load more data for calendar.
|
||||||
|
/// </summary>
|
||||||
|
public enum CalendarLoadDirection
|
||||||
{
|
{
|
||||||
/// <summary>
|
Replace,
|
||||||
/// Which way in time to load more data for calendar.
|
Previous,
|
||||||
/// </summary>
|
Next
|
||||||
public enum CalendarLoadDirection
|
|
||||||
{
|
|
||||||
Replace,
|
|
||||||
Previous,
|
|
||||||
Next
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum CalendarOrientation
|
||||||
{
|
{
|
||||||
public enum CalendarOrientation
|
Horizontal,
|
||||||
{
|
Vertical
|
||||||
Horizontal,
|
|
||||||
Vertical
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum CalendarSynchronizationType
|
||||||
{
|
{
|
||||||
public enum CalendarSynchronizationType
|
ExecuteRequests, // Execute all requests in the queue.
|
||||||
{
|
CalendarMetadata, // Sync calendar metadata.
|
||||||
ExecuteRequests, // Execute all requests in the queue.
|
CalendarEvents, // Sync all events for all calendars.
|
||||||
CalendarMetadata, // Sync calendar metadata.
|
SingleCalendar, // Sync events for only specified calendars.
|
||||||
CalendarEvents, // Sync all events for all calendars.
|
UpdateProfile // Update profile information only.
|
||||||
SingleCalendar, // Sync events for only specified calendars.
|
|
||||||
UpdateProfile // Update profile information only.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,23 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum ChangeRequestType
|
||||||
{
|
{
|
||||||
public enum ChangeRequestType
|
MailMarkAs,
|
||||||
{
|
MailChangeFlag,
|
||||||
MailMarkAs,
|
MailHardDelete,
|
||||||
MailChangeFlag,
|
MailMove,
|
||||||
MailHardDelete,
|
MailAlwaysMoveTo,
|
||||||
MailMove,
|
MailChangeFocused,
|
||||||
MailAlwaysMoveTo,
|
MailArchive,
|
||||||
MailChangeFocused,
|
MailUnarchive,
|
||||||
MailArchive,
|
FolderMarkAsRead,
|
||||||
MailUnarchive,
|
FolderDelete,
|
||||||
FolderMarkAsRead,
|
FolderEmpty,
|
||||||
FolderDelete,
|
FolderRename,
|
||||||
FolderEmpty,
|
CreateNewDraft,
|
||||||
FolderRename,
|
CreateReplyDraft,
|
||||||
CreateNewDraft,
|
CreateForwardDraft,
|
||||||
CreateReplyDraft,
|
DiscardDraft,
|
||||||
CreateForwardDraft,
|
SendDraft,
|
||||||
DiscardDraft,
|
FetchSingleItem
|
||||||
SendDraft,
|
|
||||||
FetchSingleItem
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum CustomIncomingServerType
|
||||||
{
|
{
|
||||||
public enum CustomIncomingServerType
|
POP3,
|
||||||
{
|
IMAP4
|
||||||
POP3,
|
|
||||||
IMAP4
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum DayHeaderDisplayType
|
||||||
{
|
{
|
||||||
public enum DayHeaderDisplayType
|
TwelveHour,
|
||||||
{
|
TwentyFourHour,
|
||||||
TwelveHour,
|
|
||||||
TwentyFourHour,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum DraftCreationReason
|
||||||
{
|
{
|
||||||
public enum DraftCreationReason
|
Empty,
|
||||||
{
|
Reply,
|
||||||
Empty,
|
ReplyAll,
|
||||||
Reply,
|
Forward
|
||||||
ReplyAll,
|
|
||||||
Forward
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum FilterOptionType
|
||||||
{
|
{
|
||||||
public enum FilterOptionType
|
All,
|
||||||
{
|
Unread,
|
||||||
All,
|
Flagged,
|
||||||
Unread,
|
Mentions,
|
||||||
Flagged,
|
Files
|
||||||
Mentions,
|
|
||||||
Files
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,22 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines all possible folder operations that can be done.
|
||||||
|
/// Available values for each folder is returned by IContextMenuProvider
|
||||||
|
/// that integrators hold.
|
||||||
|
/// </summary>
|
||||||
|
public enum FolderOperation
|
||||||
{
|
{
|
||||||
/// <summary>
|
None,
|
||||||
/// Defines all possible folder operations that can be done.
|
Pin,
|
||||||
/// Available values for each folder is returned by IContextMenuProvider
|
Unpin,
|
||||||
/// that integrators hold.
|
MarkAllAsRead,
|
||||||
/// </summary>
|
DontSync,
|
||||||
public enum FolderOperation
|
Empty,
|
||||||
{
|
Rename,
|
||||||
None,
|
Delete,
|
||||||
Pin,
|
Move,
|
||||||
Unpin,
|
TurnOffNotifications,
|
||||||
MarkAllAsRead,
|
CreateSubFolder,
|
||||||
DontSync,
|
Seperator
|
||||||
Empty,
|
|
||||||
Rename,
|
|
||||||
Delete,
|
|
||||||
Move,
|
|
||||||
TurnOffNotifications,
|
|
||||||
CreateSubFolder,
|
|
||||||
Seperator
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum ImapAuthenticationMethod
|
||||||
{
|
{
|
||||||
public enum ImapAuthenticationMethod
|
Auto,
|
||||||
{
|
None,
|
||||||
Auto,
|
NormalPassword,
|
||||||
None,
|
EncryptedPassword,
|
||||||
NormalPassword,
|
Ntlm,
|
||||||
EncryptedPassword,
|
CramMd5,
|
||||||
Ntlm,
|
DigestMd5
|
||||||
CramMd5,
|
|
||||||
DigestMd5
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum ImapConnectionSecurity
|
||||||
{
|
{
|
||||||
public enum ImapConnectionSecurity
|
Auto,
|
||||||
{
|
None,
|
||||||
Auto,
|
StartTls,
|
||||||
None,
|
SslTls
|
||||||
StartTls,
|
|
||||||
SslTls
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum InfoBarAnimationType
|
||||||
{
|
{
|
||||||
public enum InfoBarAnimationType
|
SlideFromRightToLeft,
|
||||||
{
|
SlideFromBottomToTop
|
||||||
SlideFromRightToLeft,
|
|
||||||
SlideFromBottomToTop
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum InfoBarMessageType
|
||||||
{
|
{
|
||||||
public enum InfoBarMessageType
|
Information,
|
||||||
{
|
Success,
|
||||||
Information,
|
Warning,
|
||||||
Success,
|
Error
|
||||||
Warning,
|
|
||||||
Error
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
7
Wino.Core.Domain/Enums/InvalidMoveTargetReason.cs
Normal file
7
Wino.Core.Domain/Enums/InvalidMoveTargetReason.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum InvalidMoveTargetReason
|
||||||
|
{
|
||||||
|
NonMoveTarget, // This folder does not allow moving mails.
|
||||||
|
MultipleAccounts // Multiple mails from different accounts cannot be moved.
|
||||||
|
}
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum MailAttachmentType
|
||||||
{
|
{
|
||||||
public enum MailAttachmentType
|
None,
|
||||||
{
|
Executable,
|
||||||
None,
|
Image,
|
||||||
Executable,
|
Audio,
|
||||||
Image,
|
Video,
|
||||||
Audio,
|
PDF,
|
||||||
Video,
|
HTML,
|
||||||
PDF,
|
RarArchive,
|
||||||
HTML,
|
Archive,
|
||||||
RarArchive,
|
Other
|
||||||
Archive,
|
|
||||||
Other
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum MailImportance
|
||||||
{
|
{
|
||||||
public enum MailImportance
|
Low,
|
||||||
{
|
Normal,
|
||||||
Low,
|
High
|
||||||
Normal,
|
|
||||||
High
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
|
||||||
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum MailListDisplayMode
|
||||||
{
|
{
|
||||||
public enum MailListDisplayMode
|
Spacious,
|
||||||
{
|
Medium,
|
||||||
Spacious,
|
Compact,
|
||||||
Medium,
|
|
||||||
Compact,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum MailMarkAsOption
|
||||||
{
|
{
|
||||||
public enum MailMarkAsOption
|
WhenSelected,
|
||||||
{
|
DontMark,
|
||||||
WhenSelected,
|
AfterDelay
|
||||||
DontMark,
|
|
||||||
AfterDelay
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,58 +1,57 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
// Synchronizer requests.
|
||||||
|
public enum MailSynchronizerOperation
|
||||||
{
|
{
|
||||||
// Synchronizer requests.
|
MarkRead,
|
||||||
public enum MailSynchronizerOperation
|
Move,
|
||||||
{
|
Delete, // Hard delete.
|
||||||
MarkRead,
|
CreateDraft,
|
||||||
Move,
|
Send,
|
||||||
Delete, // Hard delete.
|
ChangeFlag,
|
||||||
CreateDraft,
|
AlwaysMoveTo,
|
||||||
Send,
|
MoveToFocused,
|
||||||
ChangeFlag,
|
Archive,
|
||||||
AlwaysMoveTo,
|
}
|
||||||
MoveToFocused,
|
|
||||||
Archive,
|
public enum FolderSynchronizerOperation
|
||||||
}
|
{
|
||||||
|
RenameFolder,
|
||||||
public enum FolderSynchronizerOperation
|
EmptyFolder,
|
||||||
{
|
MarkFolderRead,
|
||||||
RenameFolder,
|
}
|
||||||
EmptyFolder,
|
|
||||||
MarkFolderRead,
|
// UI requests
|
||||||
}
|
public enum MailOperation
|
||||||
|
{
|
||||||
// UI requests
|
None,
|
||||||
public enum MailOperation
|
Archive,
|
||||||
{
|
UnArchive,
|
||||||
None,
|
SoftDelete,
|
||||||
Archive,
|
HardDelete,
|
||||||
UnArchive,
|
Move,
|
||||||
SoftDelete,
|
MoveToJunk,
|
||||||
HardDelete,
|
MoveToFocused,
|
||||||
Move,
|
MoveToOther,
|
||||||
MoveToJunk,
|
AlwaysMoveToOther,
|
||||||
MoveToFocused,
|
AlwaysMoveToFocused,
|
||||||
MoveToOther,
|
SetFlag,
|
||||||
AlwaysMoveToOther,
|
ClearFlag,
|
||||||
AlwaysMoveToFocused,
|
MarkAsRead,
|
||||||
SetFlag,
|
MarkAsUnread,
|
||||||
ClearFlag,
|
MarkAsNotJunk,
|
||||||
MarkAsRead,
|
Seperator,
|
||||||
MarkAsUnread,
|
Ignore,
|
||||||
MarkAsNotJunk,
|
Reply,
|
||||||
Seperator,
|
ReplyAll,
|
||||||
Ignore,
|
Zoom,
|
||||||
Reply,
|
SaveAs,
|
||||||
ReplyAll,
|
Find,
|
||||||
Zoom,
|
Forward,
|
||||||
SaveAs,
|
DarkEditor,
|
||||||
Find,
|
LightEditor,
|
||||||
Forward,
|
Print,
|
||||||
DarkEditor,
|
ViewMessageSource,
|
||||||
LightEditor,
|
DiscardLocalDraft,
|
||||||
Print,
|
Navigate // For toast activation
|
||||||
ViewMessageSource,
|
|
||||||
DiscardLocalDraft,
|
|
||||||
Navigate // For toast activation
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum MailProviderType
|
||||||
{
|
{
|
||||||
public enum MailProviderType
|
Outlook,
|
||||||
{
|
Gmail,
|
||||||
Outlook,
|
IMAP4 = 4 // 2-3 were removed after release. Don't change for backward compatibility.
|
||||||
Gmail,
|
|
||||||
Office365,
|
|
||||||
Yahoo,
|
|
||||||
IMAP4
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum MailSynchronizationType
|
||||||
{
|
{
|
||||||
public enum MailSynchronizationType
|
UpdateProfile, // Only update profile information
|
||||||
{
|
ExecuteRequests, // Run the queued requests, and then synchronize if needed.
|
||||||
// Shared
|
FoldersOnly, // Only synchronize folder metadata.
|
||||||
UpdateProfile, // Only update profile information
|
InboxOnly, // Only Inbox, Sent, Draft and Deleted folders.
|
||||||
ExecuteRequests, // Run the queued requests, and then synchronize if needed.
|
CustomFolders, // Only sync folders that are specified in the options.
|
||||||
FoldersOnly, // Only synchronize folder metadata.
|
FullFolders, // Synchronize all folders. This won't update profile or alias information.
|
||||||
InboxOnly, // Only Inbox, Sent and Draft folders.
|
Alias, // Only update alias information
|
||||||
CustomFolders, // Only sync folders that are specified in the options.
|
IMAPIdle // Idle client triggered synchronization.
|
||||||
FullFolders, // Synchronize all folders. This won't update profile or alias information.
|
|
||||||
Alias, // Only update alias information
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum NavigationReferenceFrame
|
||||||
{
|
{
|
||||||
public enum NavigationReferenceFrame
|
ShellFrame,
|
||||||
{
|
RenderingFrame
|
||||||
ShellFrame,
|
|
||||||
RenderingFrame
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the potential reasons for picking folder in the folder picking dialog.
|
||||||
|
/// </summary>
|
||||||
|
public enum PickFolderReason
|
||||||
{
|
{
|
||||||
/// <summary>
|
Move,
|
||||||
/// Defines the potential reasons for picking folder in the folder picking dialog.
|
SpecialFolder,
|
||||||
/// </summary>
|
Any
|
||||||
public enum PickFolderReason
|
|
||||||
{
|
|
||||||
Move,
|
|
||||||
SpecialFolder,
|
|
||||||
Any
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum PrintingResult
|
||||||
{
|
{
|
||||||
public enum PrintingResult
|
Abandoned,
|
||||||
{
|
Canceled,
|
||||||
Abandoned,
|
Failed,
|
||||||
Canceled,
|
Submitted
|
||||||
Failed,
|
|
||||||
Submitted
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
6
Wino.Core.Domain/Enums/SearchMode.cs
Normal file
6
Wino.Core.Domain/Enums/SearchMode.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
public enum SearchMode
|
||||||
|
{
|
||||||
|
Local,
|
||||||
|
Online
|
||||||
|
}
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// What should happen to server app when the client is terminated.
|
||||||
|
/// </summary>
|
||||||
|
public enum ServerBackgroundMode
|
||||||
{
|
{
|
||||||
/// <summary>
|
MinimizedTray, // Still runs, tray icon is visible.
|
||||||
/// What should happen to server app when the client is terminated.
|
Invisible, // Still runs, tray icon is invisible.
|
||||||
/// </summary>
|
Terminate // Server is terminated as Wino terminates.
|
||||||
public enum ServerBackgroundMode
|
|
||||||
{
|
|
||||||
MinimizedTray, // Still runs, tray icon is visible.
|
|
||||||
Invisible, // Still runs, tray icon is invisible.
|
|
||||||
Terminate // Server is terminated as Wino terminates.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum SortingOptionType
|
||||||
{
|
{
|
||||||
public enum SortingOptionType
|
ReceiveDate,
|
||||||
{
|
Sender
|
||||||
ReceiveDate,
|
|
||||||
Sender
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,23 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum SpecialFolderType
|
||||||
{
|
{
|
||||||
public enum SpecialFolderType
|
Inbox,
|
||||||
{
|
Starred,
|
||||||
Inbox,
|
Important,
|
||||||
Starred,
|
Sent,
|
||||||
Important,
|
Draft,
|
||||||
Sent,
|
Archive,
|
||||||
Draft,
|
Deleted,
|
||||||
Archive,
|
Junk,
|
||||||
Deleted,
|
Chat,
|
||||||
Junk,
|
Category,
|
||||||
Chat,
|
Unread,
|
||||||
Category,
|
Forums,
|
||||||
Unread,
|
Updates,
|
||||||
Forums,
|
Personal,
|
||||||
Updates,
|
Promotions,
|
||||||
Personal,
|
Social,
|
||||||
Promotions,
|
Other,
|
||||||
Social,
|
More
|
||||||
Other,
|
|
||||||
More
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
8
Wino.Core.Domain/Enums/SpecialImapProvider.cs
Normal file
8
Wino.Core.Domain/Enums/SpecialImapProvider.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum SpecialImapProvider
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
iCloud,
|
||||||
|
Yahoo
|
||||||
|
}
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum StartupBehaviorResult
|
||||||
{
|
{
|
||||||
public enum StartupBehaviorResult
|
Enabled,
|
||||||
{
|
Disabled,
|
||||||
Enabled,
|
DisabledByUser,
|
||||||
Disabled,
|
DisabledByPolicy,
|
||||||
DisabledByUser,
|
Fatal
|
||||||
DisabledByPolicy,
|
|
||||||
Fatal
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
// From the SDK.
|
||||||
|
public enum StorePurchaseResult
|
||||||
{
|
{
|
||||||
// From the SDK.
|
//
|
||||||
public enum StorePurchaseResult
|
// Summary:
|
||||||
{
|
// The purchase request succeeded.
|
||||||
//
|
Succeeded,
|
||||||
// Summary:
|
//
|
||||||
// The purchase request succeeded.
|
// Summary:
|
||||||
Succeeded,
|
// The current user has already purchased the specified app or add-on.
|
||||||
//
|
AlreadyPurchased,
|
||||||
// Summary:
|
//
|
||||||
// The current user has already purchased the specified app or add-on.
|
// Summary:
|
||||||
AlreadyPurchased,
|
// The purchase request did not succeed.
|
||||||
//
|
NotPurchased,
|
||||||
// Summary:
|
|
||||||
// The purchase request did not succeed.
|
|
||||||
NotPurchased,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum SynchronizationCompletedState
|
||||||
{
|
{
|
||||||
public enum SynchronizationCompletedState
|
Success, // All succeeded.
|
||||||
{
|
Canceled, // Canceled by user or HTTP call.
|
||||||
Success, // All succeeded.
|
Failed // Exception.
|
||||||
Canceled, // Canceled by user or HTTP call.
|
|
||||||
Failed // Exception.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enumeration for the source of synchronization.
|
||||||
|
/// Right now it can either be from the client or the server.
|
||||||
|
/// </summary>
|
||||||
|
public enum SynchronizationSource
|
||||||
{
|
{
|
||||||
/// <summary>
|
Client,
|
||||||
/// Enumeration for the source of synchronization.
|
Server
|
||||||
/// Right now it can either be from the client or the server.
|
|
||||||
/// </summary>
|
|
||||||
public enum SynchronizationSource
|
|
||||||
{
|
|
||||||
Client,
|
|
||||||
Server
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum WinoAppType
|
||||||
{
|
{
|
||||||
public enum WinoAppType
|
Unknown,
|
||||||
{
|
Mail,
|
||||||
Unknown,
|
Calendar
|
||||||
Mail,
|
|
||||||
Calendar
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum WinoCustomMessageDialogIcon
|
||||||
{
|
{
|
||||||
public enum WinoCustomMessageDialogIcon
|
Information,
|
||||||
{
|
Warning,
|
||||||
Information,
|
Error,
|
||||||
Warning,
|
Question
|
||||||
Error,
|
|
||||||
Question
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +1,33 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// All registered views.
|
|
||||||
/// </summary>
|
|
||||||
public enum WinoPage
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
IdlePage,
|
|
||||||
ComposePage,
|
|
||||||
SettingsPage,
|
|
||||||
MailRenderingPage,
|
|
||||||
WelcomePage,
|
|
||||||
AccountDetailsPage,
|
|
||||||
MergedAccountDetailsPage,
|
|
||||||
ManageAccountsPage,
|
|
||||||
AccountManagementPage,
|
|
||||||
SignatureManagementPage,
|
|
||||||
AboutPage,
|
|
||||||
PersonalizationPage,
|
|
||||||
MessageListPage,
|
|
||||||
MailListPage,
|
|
||||||
ReadComposePanePage,
|
|
||||||
LanguageTimePage,
|
|
||||||
AppPreferencesPage,
|
|
||||||
SettingOptionsPage,
|
|
||||||
AliasManagementPage,
|
|
||||||
|
|
||||||
// Calendar
|
/// <summary>
|
||||||
CalendarPage,
|
/// All registered views.
|
||||||
CalendarSettingsPage,
|
/// </summary>
|
||||||
EventDetailsPage
|
public enum WinoPage
|
||||||
}
|
{
|
||||||
|
None,
|
||||||
|
IdlePage,
|
||||||
|
ComposePage,
|
||||||
|
SettingsPage,
|
||||||
|
MailRenderingPage,
|
||||||
|
WelcomePage,
|
||||||
|
AccountDetailsPage,
|
||||||
|
MergedAccountDetailsPage,
|
||||||
|
ManageAccountsPage,
|
||||||
|
AccountManagementPage,
|
||||||
|
SignatureManagementPage,
|
||||||
|
AboutPage,
|
||||||
|
PersonalizationPage,
|
||||||
|
MessageListPage,
|
||||||
|
MailListPage,
|
||||||
|
ReadComposePanePage,
|
||||||
|
LanguageTimePage,
|
||||||
|
AppPreferencesPage,
|
||||||
|
SettingOptionsPage,
|
||||||
|
AliasManagementPage,
|
||||||
|
|
||||||
|
// Calendar
|
||||||
|
CalendarPage,
|
||||||
|
CalendarSettingsPage,
|
||||||
|
EventDetailsPage
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
namespace Wino.Core.Domain.Enums
|
namespace Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
|
public enum WinoServerConnectionStatus
|
||||||
{
|
{
|
||||||
public enum WinoServerConnectionStatus
|
None,
|
||||||
{
|
Connecting,
|
||||||
None,
|
Connected,
|
||||||
Connecting,
|
Disconnected,
|
||||||
Connected,
|
Failed
|
||||||
Disconnected,
|
|
||||||
Failed
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
namespace Wino.Core.Domain.Exceptions
|
namespace Wino.Core.Domain.Exceptions;
|
||||||
{
|
|
||||||
public class AccountSetupCanceledException : System.Exception
|
public class AccountSetupCanceledException : System.Exception
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
using System;
|
using System;
|
||||||
using Wino.Core.Domain.Entities.Shared;
|
using Wino.Core.Domain.Entities.Shared;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Exceptions
|
namespace Wino.Core.Domain.Exceptions;
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Thrown when IAuthenticator requires user interaction to fix authentication issues.
|
|
||||||
/// It can be expired and can't restorable token, or some stuff that requires re-authentication.
|
|
||||||
/// </summary>
|
|
||||||
public class AuthenticationAttentionException : Exception
|
|
||||||
{
|
|
||||||
public AuthenticationAttentionException(MailAccount account)
|
|
||||||
{
|
|
||||||
Account = account;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MailAccount Account { get; }
|
/// <summary>
|
||||||
|
/// Thrown when IAuthenticator requires user interaction to fix authentication issues.
|
||||||
|
/// It can be expired and can't restorable token, or some stuff that requires re-authentication.
|
||||||
|
/// </summary>
|
||||||
|
public class AuthenticationAttentionException : Exception
|
||||||
|
{
|
||||||
|
public AuthenticationAttentionException(MailAccount account)
|
||||||
|
{
|
||||||
|
Account = account;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MailAccount Account { get; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Exceptions
|
namespace Wino.Core.Domain.Exceptions;
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// All exceptions related to authentication.
|
|
||||||
/// </summary>
|
|
||||||
public class AuthenticationException : Exception
|
|
||||||
{
|
|
||||||
public AuthenticationException(string message) : base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public AuthenticationException(string message, Exception innerException) : base(message, innerException)
|
/// <summary>
|
||||||
{
|
/// All exceptions related to authentication.
|
||||||
}
|
/// </summary>
|
||||||
|
public class AuthenticationException : Exception
|
||||||
|
{
|
||||||
|
public AuthenticationException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthenticationException(string message, Exception innerException) : base(message, innerException)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Exceptions
|
namespace Wino.Core.Domain.Exceptions;
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An exception thrown when the background task registration is failed.
|
/// An exception thrown when the background task registration is failed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class BackgroundTaskRegistrationFailedException : Exception { }
|
public class BackgroundTaskRegistrationFailedException : Exception { }
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Exceptions
|
namespace Wino.Core.Domain.Exceptions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Thrown when composer cant find the mime to load.
|
||||||
|
/// </summary>
|
||||||
|
public class ComposerMimeNotFoundException : Exception
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Thrown when composer cant find the mime to load.
|
|
||||||
/// </summary>
|
|
||||||
public class ComposerMimeNotFoundException : Exception
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Exceptions
|
namespace Wino.Core.Domain.Exceptions;
|
||||||
|
|
||||||
|
public class CustomThemeCreationFailedException : Exception
|
||||||
{
|
{
|
||||||
public class CustomThemeCreationFailedException : Exception
|
public CustomThemeCreationFailedException(string message) : base(message)
|
||||||
{
|
{
|
||||||
public CustomThemeCreationFailedException(string message) : base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace Wino.Core.Domain.Exceptions;
|
||||||
|
|
||||||
|
public class GmailServiceDisabledException : System.Exception { }
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
namespace Wino.Core.Domain.Exceptions
|
namespace Wino.Core.Domain.Exceptions;
|
||||||
|
|
||||||
|
public class GoogleAuthenticationException : System.Exception
|
||||||
{
|
{
|
||||||
public class GoogleAuthenticationException : System.Exception
|
public GoogleAuthenticationException(string message) : base(message) { }
|
||||||
{
|
|
||||||
public GoogleAuthenticationException(string message) : base(message) { }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,30 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using Wino.Core.Domain.Entities.Shared;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Exceptions
|
namespace Wino.Core.Domain.Exceptions;
|
||||||
|
|
||||||
|
public class ImapClientPoolException : Exception
|
||||||
{
|
{
|
||||||
public class ImapClientPoolException : Exception
|
public ImapClientPoolException()
|
||||||
{
|
{
|
||||||
public ImapClientPoolException(Exception innerException, string protocolLog) : base(Translator.Exception_ImapClientPoolFailed, innerException)
|
|
||||||
{
|
|
||||||
ProtocolLog = protocolLog;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ProtocolLog { get; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ImapClientPoolException(string message, CustomServerInformation customServerInformation, string protocolLog) : base(message)
|
||||||
|
{
|
||||||
|
CustomServerInformation = customServerInformation;
|
||||||
|
ProtocolLog = protocolLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImapClientPoolException(string message, string protocolLog) : base(message)
|
||||||
|
{
|
||||||
|
ProtocolLog = protocolLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImapClientPoolException(Exception innerException, string protocolLog) : base(Translator.Exception_ImapClientPoolFailed, innerException)
|
||||||
|
{
|
||||||
|
ProtocolLog = protocolLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CustomServerInformation CustomServerInformation { get; }
|
||||||
|
public string ProtocolLog { get; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
using Wino.Core.Domain.Models.AutoDiscovery;
|
using Wino.Core.Domain.Models.AutoDiscovery;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Exceptions
|
namespace Wino.Core.Domain.Exceptions;
|
||||||
{
|
|
||||||
public class ImapConnectionFailedPackage
|
|
||||||
{
|
|
||||||
public ImapConnectionFailedPackage(string errorMessage, string protocolLog, AutoDiscoverySettings settings)
|
|
||||||
{
|
|
||||||
ErrorMessage = errorMessage;
|
|
||||||
ProtocolLog = protocolLog;
|
|
||||||
Settings = settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AutoDiscoverySettings Settings { get; }
|
public class ImapConnectionFailedPackage
|
||||||
public string ErrorMessage { get; set; }
|
{
|
||||||
public string ProtocolLog { get; }
|
public ImapConnectionFailedPackage(string errorMessage, string protocolLog, AutoDiscoverySettings settings)
|
||||||
|
{
|
||||||
|
ErrorMessage = errorMessage;
|
||||||
|
ProtocolLog = protocolLog;
|
||||||
|
Settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AutoDiscoverySettings Settings { get; }
|
||||||
|
public string ErrorMessage { get; set; }
|
||||||
|
public string ProtocolLog { get; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Wino.Core.Domain.Exceptions;
|
||||||
|
|
||||||
|
public class ImapSynchronizerStrategyException : System.Exception
|
||||||
|
{
|
||||||
|
public ImapSynchronizerStrategyException(string message) : base(message)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
namespace Wino.Core.Domain.Exceptions
|
namespace Wino.Core.Domain.Exceptions;
|
||||||
|
|
||||||
|
public class ImapTestSSLCertificateException : System.Exception
|
||||||
{
|
{
|
||||||
public class ImapTestSSLCertificateException : System.Exception
|
public ImapTestSSLCertificateException(string issuer, string expirationDateString, string validFromDateString)
|
||||||
{
|
{
|
||||||
public ImapTestSSLCertificateException(string issuer, string expirationDateString, string validFromDateString)
|
Issuer = issuer;
|
||||||
{
|
ExpirationDateString = expirationDateString;
|
||||||
Issuer = issuer;
|
ValidFromDateString = validFromDateString;
|
||||||
ExpirationDateString = expirationDateString;
|
|
||||||
ValidFromDateString = validFromDateString;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Issuer { get; set; }
|
|
||||||
public string ExpirationDateString { get; set; }
|
|
||||||
public string ValidFromDateString { get; set; }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string Issuer { get; set; }
|
||||||
|
public string ExpirationDateString { get; set; }
|
||||||
|
public string ValidFromDateString { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using Wino.Core.Domain.Enums;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Exceptions
|
namespace Wino.Core.Domain.Exceptions;
|
||||||
|
|
||||||
|
public class InvalidMoveTargetException(InvalidMoveTargetReason reason) : Exception
|
||||||
{
|
{
|
||||||
public class InvalidMoveTargetException : Exception { }
|
public InvalidMoveTargetReason Reason { get; } = reason;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
namespace Wino.Core.Domain.Exceptions
|
namespace Wino.Core.Domain.Exceptions;
|
||||||
|
|
||||||
|
public class MissingAliasException : System.Exception
|
||||||
{
|
{
|
||||||
public class MissingAliasException : System.Exception
|
public MissingAliasException() : base(Translator.Exception_MissingAlias) { }
|
||||||
{
|
|
||||||
public MissingAliasException() : base(Translator.Exception_MissingAlias) { }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Exceptions
|
namespace Wino.Core.Domain.Exceptions;
|
||||||
|
|
||||||
|
public class SynchronizerEntityNotFoundException : Exception
|
||||||
{
|
{
|
||||||
public class SynchronizerEntityNotFoundException : Exception
|
public SynchronizerEntityNotFoundException(string message) : base(message)
|
||||||
{
|
{
|
||||||
public SynchronizerEntityNotFoundException(string message) : base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user