Show "You" for active account in mail rendering page (#566)
* Added account contact view model to handle "You" case. * fix namespaces again
This commit is contained in:
@@ -36,14 +36,6 @@ public class AccountContact : IEquatable<AccountContact>
|
||||
/// </summary>
|
||||
public bool IsRootContact { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Short display name of the contact.
|
||||
/// Eather Name or Address.
|
||||
/// </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);
|
||||
@@ -58,10 +50,7 @@ public class AccountContact : IEquatable<AccountContact>
|
||||
|
||||
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;
|
||||
return HashCode.Combine(Address, Name);
|
||||
}
|
||||
|
||||
public static bool operator ==(AccountContact left, AccountContact right)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
"AccountSettingsDialog_AccountName": "Sender Display Name",
|
||||
"AccountSettingsDialog_AccountNamePlaceholder": "eg. John Doe",
|
||||
"AddHyperlink": "Add",
|
||||
"AccountContactNameYou": "You",
|
||||
"AutoDiscoveryProgressMessage": "Searching for mail settings...",
|
||||
"AppCloseBackgroundSynchronizationWarningTitle": "Background Synchronization",
|
||||
"AppCloseTerminateBehaviorWarningMessageFirstLine": "You are terminating Wino Mail and your app close behavior is set to 'Terminate'.",
|
||||
|
||||
@@ -22,228 +22,227 @@ using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Services;
|
||||
|
||||
namespace Wino.Core.UWP
|
||||
namespace Wino.Core.UWP;
|
||||
|
||||
public abstract class WinoApplication : Application
|
||||
{
|
||||
public abstract class WinoApplication : Application
|
||||
public new static WinoApplication Current => (WinoApplication)Application.Current;
|
||||
public const string WinoLaunchLogPrefix = "[Wino Launch] ";
|
||||
|
||||
public IServiceProvider Services { get; }
|
||||
protected IWinoLogger LogInitializer { get; }
|
||||
protected IApplicationConfiguration AppConfiguration { get; }
|
||||
protected IWinoServerConnectionManager<AppServiceConnection> AppServiceConnectionManager { get; }
|
||||
protected IThemeService ThemeService { get; }
|
||||
protected IDatabaseService DatabaseService { get; }
|
||||
protected ITranslationService TranslationService { get; }
|
||||
|
||||
protected WinoApplication()
|
||||
{
|
||||
public new static WinoApplication Current => (WinoApplication)Application.Current;
|
||||
public const string WinoLaunchLogPrefix = "[Wino Launch] ";
|
||||
ConfigurePrelaunch();
|
||||
|
||||
public IServiceProvider Services { get; }
|
||||
protected IWinoLogger LogInitializer { get; }
|
||||
protected IApplicationConfiguration AppConfiguration { get; }
|
||||
protected IWinoServerConnectionManager<AppServiceConnection> AppServiceConnectionManager { get; }
|
||||
protected IThemeService ThemeService { get; }
|
||||
protected IDatabaseService DatabaseService { get; }
|
||||
protected ITranslationService TranslationService { get; }
|
||||
Services = ConfigureServices();
|
||||
|
||||
protected WinoApplication()
|
||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
|
||||
UnhandledException += OnAppUnhandledException;
|
||||
|
||||
Resuming += OnResuming;
|
||||
Suspending += OnSuspending;
|
||||
|
||||
LogInitializer = Services.GetService<IWinoLogger>();
|
||||
AppConfiguration = Services.GetService<IApplicationConfiguration>();
|
||||
|
||||
AppServiceConnectionManager = Services.GetService<IWinoServerConnectionManager<AppServiceConnection>>();
|
||||
ThemeService = Services.GetService<IThemeService>();
|
||||
DatabaseService = Services.GetService<IDatabaseService>();
|
||||
TranslationService = Services.GetService<ITranslationService>();
|
||||
|
||||
// Make sure the paths are setup on app start.
|
||||
AppConfiguration.ApplicationDataFolderPath = ApplicationData.Current.LocalFolder.Path;
|
||||
AppConfiguration.PublisherSharedFolderPath = ApplicationData.Current.GetPublisherCacheFolder(ApplicationConfiguration.SharedFolderName).Path;
|
||||
AppConfiguration.ApplicationTempFolderPath = ApplicationData.Current.TemporaryFolder.Path;
|
||||
|
||||
ConfigureLogging();
|
||||
}
|
||||
|
||||
private void CurrentDomain_UnhandledException(object sender, System.UnhandledExceptionEventArgs e)
|
||||
=> Log.Fatal(e.ExceptionObject as Exception, "AppDomain Unhandled Exception");
|
||||
|
||||
private void OnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
|
||||
=> Log.Error(e.Exception, "Unobserved Task Exception");
|
||||
|
||||
private void OnAppUnhandledException(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e)
|
||||
{
|
||||
Log.Fatal(e.Exception, "Unhandled Exception");
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
protected abstract void OnApplicationCloseRequested(object sender, SystemNavigationCloseRequestedPreviewEventArgs e);
|
||||
protected abstract IEnumerable<ActivationHandler> GetActivationHandlers();
|
||||
protected abstract ActivationHandler<IActivatedEventArgs> GetDefaultActivationHandler();
|
||||
protected override void OnWindowCreated(WindowCreatedEventArgs args)
|
||||
{
|
||||
base.OnWindowCreated(args);
|
||||
|
||||
ConfigureTitleBar();
|
||||
|
||||
LogActivation($"OnWindowCreated -> IsWindowNull: {args.Window == null}");
|
||||
|
||||
TryRegisterAppCloseChange();
|
||||
}
|
||||
|
||||
public IEnumerable<IInitializeAsync> GetActivationServices()
|
||||
{
|
||||
yield return DatabaseService;
|
||||
yield return TranslationService;
|
||||
yield return ThemeService;
|
||||
}
|
||||
|
||||
public Task InitializeServicesAsync() => GetActivationServices().Select(a => a.InitializeAsync()).WhenAll();
|
||||
|
||||
public bool IsInteractiveLaunchArgs(object args) => args is IActivatedEventArgs;
|
||||
|
||||
public void LogActivation(string log) => Log.Information($"{WinoLaunchLogPrefix}{log}");
|
||||
|
||||
private void ConfigureTitleBar()
|
||||
{
|
||||
var coreTitleBar = CoreApplication.GetCurrentView().TitleBar;
|
||||
var applicationViewTitleBar = ApplicationView.GetForCurrentView().TitleBar;
|
||||
|
||||
// Extend shell content into core window to meet design requirements.
|
||||
coreTitleBar.ExtendViewIntoTitleBar = true;
|
||||
|
||||
// Change system buttons and background colors to meet design requirements.
|
||||
applicationViewTitleBar.ButtonBackgroundColor = Colors.Transparent;
|
||||
applicationViewTitleBar.BackgroundColor = Colors.Transparent;
|
||||
applicationViewTitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
|
||||
applicationViewTitleBar.ButtonForegroundColor = Colors.White;
|
||||
}
|
||||
|
||||
public async Task ActivateWinoAsync(object args)
|
||||
{
|
||||
await InitializeServicesAsync();
|
||||
|
||||
if (IsInteractiveLaunchArgs(args))
|
||||
{
|
||||
ConfigurePrelaunch();
|
||||
|
||||
Services = ConfigureServices();
|
||||
|
||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
|
||||
UnhandledException += OnAppUnhandledException;
|
||||
|
||||
Resuming += OnResuming;
|
||||
Suspending += OnSuspending;
|
||||
|
||||
LogInitializer = Services.GetService<IWinoLogger>();
|
||||
AppConfiguration = Services.GetService<IApplicationConfiguration>();
|
||||
|
||||
AppServiceConnectionManager = Services.GetService<IWinoServerConnectionManager<AppServiceConnection>>();
|
||||
ThemeService = Services.GetService<IThemeService>();
|
||||
DatabaseService = Services.GetService<IDatabaseService>();
|
||||
TranslationService = Services.GetService<ITranslationService>();
|
||||
|
||||
// Make sure the paths are setup on app start.
|
||||
AppConfiguration.ApplicationDataFolderPath = ApplicationData.Current.LocalFolder.Path;
|
||||
AppConfiguration.PublisherSharedFolderPath = ApplicationData.Current.GetPublisherCacheFolder(ApplicationConfiguration.SharedFolderName).Path;
|
||||
AppConfiguration.ApplicationTempFolderPath = ApplicationData.Current.TemporaryFolder.Path;
|
||||
|
||||
ConfigureLogging();
|
||||
}
|
||||
|
||||
private void CurrentDomain_UnhandledException(object sender, System.UnhandledExceptionEventArgs e)
|
||||
=> Log.Fatal(e.ExceptionObject as Exception, "AppDomain Unhandled Exception");
|
||||
|
||||
private void OnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
|
||||
=> Log.Error(e.Exception, "Unobserved Task Exception");
|
||||
|
||||
private void OnAppUnhandledException(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e)
|
||||
{
|
||||
Log.Fatal(e.Exception, "Unhandled Exception");
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
protected abstract void OnApplicationCloseRequested(object sender, SystemNavigationCloseRequestedPreviewEventArgs e);
|
||||
protected abstract IEnumerable<ActivationHandler> GetActivationHandlers();
|
||||
protected abstract ActivationHandler<IActivatedEventArgs> GetDefaultActivationHandler();
|
||||
protected override void OnWindowCreated(WindowCreatedEventArgs args)
|
||||
{
|
||||
base.OnWindowCreated(args);
|
||||
|
||||
ConfigureTitleBar();
|
||||
|
||||
LogActivation($"OnWindowCreated -> IsWindowNull: {args.Window == null}");
|
||||
|
||||
TryRegisterAppCloseChange();
|
||||
}
|
||||
|
||||
public IEnumerable<IInitializeAsync> GetActivationServices()
|
||||
{
|
||||
yield return DatabaseService;
|
||||
yield return TranslationService;
|
||||
yield return ThemeService;
|
||||
}
|
||||
|
||||
public Task InitializeServicesAsync() => GetActivationServices().Select(a => a.InitializeAsync()).WhenAll();
|
||||
|
||||
public bool IsInteractiveLaunchArgs(object args) => args is IActivatedEventArgs;
|
||||
|
||||
public void LogActivation(string log) => Log.Information($"{WinoLaunchLogPrefix}{log}");
|
||||
|
||||
private void ConfigureTitleBar()
|
||||
{
|
||||
var coreTitleBar = CoreApplication.GetCurrentView().TitleBar;
|
||||
var applicationViewTitleBar = ApplicationView.GetForCurrentView().TitleBar;
|
||||
|
||||
// Extend shell content into core window to meet design requirements.
|
||||
coreTitleBar.ExtendViewIntoTitleBar = true;
|
||||
|
||||
// Change system buttons and background colors to meet design requirements.
|
||||
applicationViewTitleBar.ButtonBackgroundColor = Colors.Transparent;
|
||||
applicationViewTitleBar.BackgroundColor = Colors.Transparent;
|
||||
applicationViewTitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
|
||||
applicationViewTitleBar.ButtonForegroundColor = Colors.White;
|
||||
}
|
||||
|
||||
public async Task ActivateWinoAsync(object args)
|
||||
{
|
||||
await InitializeServicesAsync();
|
||||
|
||||
if (IsInteractiveLaunchArgs(args))
|
||||
if (Window.Current.Content == null)
|
||||
{
|
||||
if (Window.Current.Content == null)
|
||||
{
|
||||
var mainFrame = new Frame();
|
||||
var mainFrame = new Frame();
|
||||
|
||||
Window.Current.Content = mainFrame;
|
||||
Window.Current.Content = mainFrame;
|
||||
|
||||
await ThemeService.InitializeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
await HandleActivationAsync(args);
|
||||
|
||||
if (IsInteractiveLaunchArgs(args))
|
||||
{
|
||||
Window.Current.Activate();
|
||||
|
||||
LogActivation("Window activated");
|
||||
await ThemeService.InitializeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task HandleActivationAsync(object activationArgs)
|
||||
await HandleActivationAsync(args);
|
||||
|
||||
if (IsInteractiveLaunchArgs(args))
|
||||
{
|
||||
if (GetActivationHandlers() != null)
|
||||
{
|
||||
var activationHandler = GetActivationHandlers().FirstOrDefault(h => h.CanHandle(activationArgs)) ?? null;
|
||||
Window.Current.Activate();
|
||||
|
||||
if (activationHandler != null)
|
||||
{
|
||||
await activationHandler.HandleAsync(activationArgs);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsInteractiveLaunchArgs(activationArgs))
|
||||
{
|
||||
var defaultHandler = GetDefaultActivationHandler();
|
||||
|
||||
if (defaultHandler.CanHandle(activationArgs))
|
||||
{
|
||||
await defaultHandler.HandleAsync(activationArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override async void OnLaunched(LaunchActivatedEventArgs args)
|
||||
{
|
||||
LogActivation($"OnLaunched -> {args.GetType().Name}, Kind -> {args.Kind}, PreviousExecutionState -> {args.PreviousExecutionState}, IsPrelaunch -> {args.PrelaunchActivated}");
|
||||
|
||||
if (!args.PrelaunchActivated)
|
||||
{
|
||||
await ActivateWinoAsync(args);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async void OnFileActivated(FileActivatedEventArgs args)
|
||||
{
|
||||
base.OnFileActivated(args);
|
||||
|
||||
LogActivation($"OnFileActivated -> ItemCount: {args.Files.Count}, Kind: {args.Kind}, PreviousExecutionState: {args.PreviousExecutionState}");
|
||||
|
||||
await ActivateWinoAsync(args);
|
||||
}
|
||||
|
||||
protected override async void OnActivated(IActivatedEventArgs args)
|
||||
{
|
||||
base.OnActivated(args);
|
||||
|
||||
Log.Information($"OnActivated -> {args.GetType().Name}, Kind -> {args.Kind}, Prev Execution State -> {args.PreviousExecutionState}");
|
||||
|
||||
await ActivateWinoAsync(args);
|
||||
}
|
||||
|
||||
private void TryRegisterAppCloseChange()
|
||||
{
|
||||
try
|
||||
{
|
||||
var systemNavigationManagerPreview = SystemNavigationManagerPreview.GetForCurrentView();
|
||||
|
||||
systemNavigationManagerPreview.CloseRequested -= OnApplicationCloseRequested;
|
||||
systemNavigationManagerPreview.CloseRequested += OnApplicationCloseRequested;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private void ConfigurePrelaunch()
|
||||
{
|
||||
if (ApiInformation.IsMethodPresent("Windows.ApplicationModel.Core.CoreApplication", "EnablePrelaunch"))
|
||||
CoreApplication.EnablePrelaunch(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public virtual async void OnResuming(object sender, object e)
|
||||
{
|
||||
// App Service connection was lost on suspension.
|
||||
// We must restore it.
|
||||
// Server might be running already, but re-launching it will trigger a new connection attempt.
|
||||
|
||||
try
|
||||
{
|
||||
await AppServiceConnectionManager.ConnectAsync();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Failed to connect to server after resuming the app.");
|
||||
}
|
||||
}
|
||||
public virtual void OnSuspending(object sender, SuspendingEventArgs e) { }
|
||||
|
||||
public abstract IServiceProvider ConfigureServices();
|
||||
|
||||
public void ConfigureLogging()
|
||||
{
|
||||
string logFilePath = Path.Combine(ApplicationData.Current.LocalFolder.Path, Constants.ClientLogFile);
|
||||
LogInitializer.SetupLogger(logFilePath);
|
||||
LogActivation("Window activated");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task HandleActivationAsync(object activationArgs)
|
||||
{
|
||||
if (GetActivationHandlers() != null)
|
||||
{
|
||||
var activationHandler = GetActivationHandlers().FirstOrDefault(h => h.CanHandle(activationArgs)) ?? null;
|
||||
|
||||
if (activationHandler != null)
|
||||
{
|
||||
await activationHandler.HandleAsync(activationArgs);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsInteractiveLaunchArgs(activationArgs))
|
||||
{
|
||||
var defaultHandler = GetDefaultActivationHandler();
|
||||
|
||||
if (defaultHandler.CanHandle(activationArgs))
|
||||
{
|
||||
await defaultHandler.HandleAsync(activationArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override async void OnLaunched(LaunchActivatedEventArgs args)
|
||||
{
|
||||
LogActivation($"OnLaunched -> {args.GetType().Name}, Kind -> {args.Kind}, PreviousExecutionState -> {args.PreviousExecutionState}, IsPrelaunch -> {args.PrelaunchActivated}");
|
||||
|
||||
if (!args.PrelaunchActivated)
|
||||
{
|
||||
await ActivateWinoAsync(args);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async void OnFileActivated(FileActivatedEventArgs args)
|
||||
{
|
||||
base.OnFileActivated(args);
|
||||
|
||||
LogActivation($"OnFileActivated -> ItemCount: {args.Files.Count}, Kind: {args.Kind}, PreviousExecutionState: {args.PreviousExecutionState}");
|
||||
|
||||
await ActivateWinoAsync(args);
|
||||
}
|
||||
|
||||
protected override async void OnActivated(IActivatedEventArgs args)
|
||||
{
|
||||
base.OnActivated(args);
|
||||
|
||||
Log.Information($"OnActivated -> {args.GetType().Name}, Kind -> {args.Kind}, Prev Execution State -> {args.PreviousExecutionState}");
|
||||
|
||||
await ActivateWinoAsync(args);
|
||||
}
|
||||
|
||||
private void TryRegisterAppCloseChange()
|
||||
{
|
||||
try
|
||||
{
|
||||
var systemNavigationManagerPreview = SystemNavigationManagerPreview.GetForCurrentView();
|
||||
|
||||
systemNavigationManagerPreview.CloseRequested -= OnApplicationCloseRequested;
|
||||
systemNavigationManagerPreview.CloseRequested += OnApplicationCloseRequested;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private void ConfigurePrelaunch()
|
||||
{
|
||||
if (ApiInformation.IsMethodPresent("Windows.ApplicationModel.Core.CoreApplication", "EnablePrelaunch"))
|
||||
CoreApplication.EnablePrelaunch(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public virtual async void OnResuming(object sender, object e)
|
||||
{
|
||||
// App Service connection was lost on suspension.
|
||||
// We must restore it.
|
||||
// Server might be running already, but re-launching it will trigger a new connection attempt.
|
||||
|
||||
try
|
||||
{
|
||||
await AppServiceConnectionManager.ConnectAsync();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Failed to connect to server after resuming the app.");
|
||||
}
|
||||
}
|
||||
public virtual void OnSuspending(object sender, SuspendingEventArgs e) { }
|
||||
|
||||
public abstract IServiceProvider ConfigureServices();
|
||||
|
||||
public void ConfigureLogging()
|
||||
{
|
||||
string logFilePath = Path.Combine(ApplicationData.Current.LocalFolder.Path, Constants.ClientLogFile);
|
||||
LogInitializer.SetupLogger(logFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,125 +6,124 @@ using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
|
||||
namespace Wino.Core.ViewModels
|
||||
namespace Wino.Core.ViewModels;
|
||||
|
||||
public partial class AboutPageViewModel : CoreBaseViewModel
|
||||
{
|
||||
public partial class AboutPageViewModel : CoreBaseViewModel
|
||||
private readonly IStoreRatingService _storeRatingService;
|
||||
private readonly IMailDialogService _dialogService;
|
||||
private readonly INativeAppService _nativeAppService;
|
||||
private readonly IApplicationConfiguration _appInitializerService;
|
||||
private readonly IClipboardService _clipboardService;
|
||||
private readonly IFileService _fileService;
|
||||
private readonly IWinoLogger _logInitializer;
|
||||
|
||||
public string VersionName => _nativeAppService.GetFullAppVersion();
|
||||
public string DiscordChannelUrl => "https://discord.gg/windows-apps-hub-714581497222398064";
|
||||
public string GitHubUrl => "https://github.com/bkaankose/Wino-Mail/";
|
||||
public string PrivacyPolicyUrl => "https://www.winomail.app/support/privacy";
|
||||
public string PaypalUrl => "https://paypal.me/bkaankose?country.x=PL&locale.x=en_US";
|
||||
|
||||
public IPreferencesService PreferencesService { get; }
|
||||
|
||||
public AboutPageViewModel(IStoreRatingService storeRatingService,
|
||||
IMailDialogService dialogService,
|
||||
INativeAppService nativeAppService,
|
||||
IPreferencesService preferencesService,
|
||||
IApplicationConfiguration appInitializerService,
|
||||
IClipboardService clipboardService,
|
||||
IFileService fileService,
|
||||
IWinoLogger logInitializer)
|
||||
{
|
||||
private readonly IStoreRatingService _storeRatingService;
|
||||
private readonly IMailDialogService _dialogService;
|
||||
private readonly INativeAppService _nativeAppService;
|
||||
private readonly IApplicationConfiguration _appInitializerService;
|
||||
private readonly IClipboardService _clipboardService;
|
||||
private readonly IFileService _fileService;
|
||||
private readonly IWinoLogger _logInitializer;
|
||||
_storeRatingService = storeRatingService;
|
||||
_dialogService = dialogService;
|
||||
_nativeAppService = nativeAppService;
|
||||
_logInitializer = logInitializer;
|
||||
_appInitializerService = appInitializerService;
|
||||
_clipboardService = clipboardService;
|
||||
_fileService = fileService;
|
||||
|
||||
public string VersionName => _nativeAppService.GetFullAppVersion();
|
||||
public string DiscordChannelUrl => "https://discord.gg/windows-apps-hub-714581497222398064";
|
||||
public string GitHubUrl => "https://github.com/bkaankose/Wino-Mail/";
|
||||
public string PrivacyPolicyUrl => "https://www.winomail.app/support/privacy";
|
||||
public string PaypalUrl => "https://paypal.me/bkaankose?country.x=PL&locale.x=en_US";
|
||||
PreferencesService = preferencesService;
|
||||
}
|
||||
|
||||
public IPreferencesService PreferencesService { get; }
|
||||
protected override void OnActivated()
|
||||
{
|
||||
base.OnActivated();
|
||||
|
||||
public AboutPageViewModel(IStoreRatingService storeRatingService,
|
||||
IMailDialogService dialogService,
|
||||
INativeAppService nativeAppService,
|
||||
IPreferencesService preferencesService,
|
||||
IApplicationConfiguration appInitializerService,
|
||||
IClipboardService clipboardService,
|
||||
IFileService fileService,
|
||||
IWinoLogger logInitializer)
|
||||
PreferencesService.PreferenceChanged -= PreferencesChanged;
|
||||
PreferencesService.PreferenceChanged += PreferencesChanged;
|
||||
}
|
||||
|
||||
protected override void OnDeactivated()
|
||||
{
|
||||
base.OnDeactivated();
|
||||
|
||||
PreferencesService.PreferenceChanged -= PreferencesChanged;
|
||||
}
|
||||
|
||||
private void PreferencesChanged(object sender, string e)
|
||||
{
|
||||
if (e == nameof(PreferencesService.IsLoggingEnabled))
|
||||
{
|
||||
_storeRatingService = storeRatingService;
|
||||
_dialogService = dialogService;
|
||||
_nativeAppService = nativeAppService;
|
||||
_logInitializer = logInitializer;
|
||||
_appInitializerService = appInitializerService;
|
||||
_clipboardService = clipboardService;
|
||||
_fileService = fileService;
|
||||
|
||||
PreferencesService = preferencesService;
|
||||
_logInitializer.RefreshLoggingLevel();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnActivated()
|
||||
[RelayCommand]
|
||||
private async Task CopyDiagnosticId()
|
||||
{
|
||||
try
|
||||
{
|
||||
base.OnActivated();
|
||||
|
||||
PreferencesService.PreferenceChanged -= PreferencesChanged;
|
||||
PreferencesService.PreferenceChanged += PreferencesChanged;
|
||||
await _clipboardService.CopyClipboardAsync(PreferencesService.DiagnosticId);
|
||||
_dialogService.InfoBarMessage(Translator.Buttons_Copy, string.Format(Translator.ClipboardTextCopied_Message, "Id"), InfoBarMessageType.Success);
|
||||
}
|
||||
|
||||
protected override void OnDeactivated()
|
||||
catch (Exception ex)
|
||||
{
|
||||
base.OnDeactivated();
|
||||
|
||||
PreferencesService.PreferenceChanged -= PreferencesChanged;
|
||||
_dialogService.InfoBarMessage(Translator.GeneralTitle_Error, string.Format(Translator.ClipboardTextCopyFailed_Message, "Id"), InfoBarMessageType.Error);
|
||||
Log.Error(ex, "Failed to copy diagnostic id to clipboard.");
|
||||
}
|
||||
}
|
||||
|
||||
private void PreferencesChanged(object sender, string e)
|
||||
[RelayCommand]
|
||||
private async Task ShareWinoLogAsync()
|
||||
{
|
||||
var appDataFolder = _appInitializerService.ApplicationDataFolderPath;
|
||||
|
||||
var selectedFolderPath = await _dialogService.PickWindowsFolderAsync();
|
||||
|
||||
if (string.IsNullOrEmpty(selectedFolderPath)) return;
|
||||
|
||||
var areLogsSaved = await _fileService.SaveLogsToFolderAsync(appDataFolder, selectedFolderPath).ConfigureAwait(false);
|
||||
|
||||
if (areLogsSaved)
|
||||
{
|
||||
if (e == nameof(PreferencesService.IsLoggingEnabled))
|
||||
{
|
||||
_logInitializer.RefreshLoggingLevel();
|
||||
}
|
||||
_dialogService.InfoBarMessage(Translator.Info_LogsSavedTitle, string.Format(Translator.Info_LogsSavedMessage, Constants.LogArchiveFileName), InfoBarMessageType.Success);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task CopyDiagnosticId()
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
await _clipboardService.CopyClipboardAsync(PreferencesService.DiagnosticId);
|
||||
_dialogService.InfoBarMessage(Translator.Buttons_Copy, string.Format(Translator.ClipboardTextCopied_Message, "Id"), InfoBarMessageType.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_dialogService.InfoBarMessage(Translator.GeneralTitle_Error, string.Format(Translator.ClipboardTextCopyFailed_Message, "Id"), InfoBarMessageType.Error);
|
||||
Log.Error(ex, "Failed to copy diagnostic id to clipboard.");
|
||||
}
|
||||
_dialogService.InfoBarMessage(Translator.Info_LogsNotFoundTitle, Translator.Info_LogsNotFoundMessage, InfoBarMessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task ShareWinoLogAsync()
|
||||
[RelayCommand]
|
||||
private async Task Navigate(object url)
|
||||
{
|
||||
if (url is string stringUrl)
|
||||
{
|
||||
var appDataFolder = _appInitializerService.ApplicationDataFolderPath;
|
||||
|
||||
var selectedFolderPath = await _dialogService.PickWindowsFolderAsync();
|
||||
|
||||
if (string.IsNullOrEmpty(selectedFolderPath)) return;
|
||||
|
||||
var areLogsSaved = await _fileService.SaveLogsToFolderAsync(appDataFolder, selectedFolderPath).ConfigureAwait(false);
|
||||
|
||||
if (areLogsSaved)
|
||||
{
|
||||
_dialogService.InfoBarMessage(Translator.Info_LogsSavedTitle, string.Format(Translator.Info_LogsSavedMessage, Constants.LogArchiveFileName), InfoBarMessageType.Success);
|
||||
}
|
||||
if (stringUrl == "Store")
|
||||
await ShowRateDialogAsync();
|
||||
else
|
||||
{
|
||||
_dialogService.InfoBarMessage(Translator.Info_LogsNotFoundTitle, Translator.Info_LogsNotFoundMessage, InfoBarMessageType.Error);
|
||||
// Discord disclaimer message about server.
|
||||
if (stringUrl == DiscordChannelUrl)
|
||||
await _dialogService.ShowMessageAsync(Translator.DiscordChannelDisclaimerMessage,
|
||||
Translator.DiscordChannelDisclaimerTitle,
|
||||
WinoCustomMessageDialogIcon.Warning);
|
||||
|
||||
await _nativeAppService.LaunchUriAsync(new Uri(stringUrl));
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task Navigate(object url)
|
||||
{
|
||||
if (url is string stringUrl)
|
||||
{
|
||||
if (stringUrl == "Store")
|
||||
await ShowRateDialogAsync();
|
||||
else
|
||||
{
|
||||
// Discord disclaimer message about server.
|
||||
if (stringUrl == DiscordChannelUrl)
|
||||
await _dialogService.ShowMessageAsync(Translator.DiscordChannelDisclaimerMessage,
|
||||
Translator.DiscordChannelDisclaimerTitle,
|
||||
WinoCustomMessageDialogIcon.Warning);
|
||||
|
||||
await _nativeAppService.LaunchUriAsync(new Uri(stringUrl));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Task ShowRateDialogAsync() => _storeRatingService.LaunchStorePageForReviewAsync();
|
||||
}
|
||||
|
||||
private Task ShowRateDialogAsync() => _storeRatingService.LaunchStorePageForReviewAsync();
|
||||
}
|
||||
|
||||
37
Wino.Mail.ViewModels/Data/AccountContactViewModel.cs
Normal file
37
Wino.Mail.ViewModels/Data/AccountContactViewModel.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Entities.Shared;
|
||||
|
||||
namespace Wino.Mail.ViewModels.Data;
|
||||
|
||||
public class AccountContactViewModel: AccountContact
|
||||
{
|
||||
public AccountContactViewModel(AccountContact contact)
|
||||
{
|
||||
Address = contact.Address;
|
||||
Name = contact.Name;
|
||||
Base64ContactPicture = contact.Base64ContactPicture;
|
||||
IsRootContact = contact.IsRootContact;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the contact is the current account.
|
||||
/// </summary>
|
||||
public bool IsMe { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Provides a short name of the contact.
|
||||
/// <see cref="ShortDisplayName"/> or "You"
|
||||
/// </summary>
|
||||
public string ShortNameOrYou => IsMe ? Translator.AccountContactNameYou : ShortDisplayName;
|
||||
|
||||
/// <summary>
|
||||
/// Short display name of the contact.
|
||||
/// Either Name or Address.
|
||||
/// </summary>
|
||||
public string ShortDisplayName => Address == Name || string.IsNullOrWhiteSpace(Name) ? $"{Address.ToLowerInvariant()};" : $"{Name};";
|
||||
|
||||
/// <summary>
|
||||
/// Display name of the contact in a format: Name <Address>.
|
||||
/// </summary>
|
||||
public string DisplayName => Address == Name || string.IsNullOrWhiteSpace(Name) ? Address.ToLowerInvariant() : $"{Name} <{Address.ToLowerInvariant()}>";
|
||||
}
|
||||
@@ -90,35 +90,33 @@ public partial class MailRenderingPageViewModel : MailBaseViewModel,
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(ShouldDisplayDownloadProgress))]
|
||||
private bool isIndetermineProgress;
|
||||
public partial bool IsIndetermineProgress { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(ShouldDisplayDownloadProgress))]
|
||||
private double currentDownloadPercentage;
|
||||
public partial double CurrentDownloadPercentage { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(CanUnsubscribe))]
|
||||
private MailRenderModel currentRenderModel;
|
||||
public partial MailRenderModel CurrentRenderModel { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
private string subject;
|
||||
public partial string Subject { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
private string fromAddress;
|
||||
public partial string FromAddress { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
private string fromName;
|
||||
public partial string FromName { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
private string contactPicture;
|
||||
public partial string ContactPicture { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
private DateTime creationDate;
|
||||
|
||||
|
||||
public ObservableCollection<AccountContact> ToItems { get; set; } = [];
|
||||
public ObservableCollection<AccountContact> CcItems { get; set; } = [];
|
||||
public ObservableCollection<AccountContact> BccItems { get; set; } = [];
|
||||
public partial DateTime CreationDate { get; set; }
|
||||
public ObservableCollection<AccountContactViewModel> ToItems { get; set; } = [];
|
||||
public ObservableCollection<AccountContactViewModel> CcItems { get; set; } = [];
|
||||
public ObservableCollection<AccountContactViewModel> BccItems { get; set; } = [];
|
||||
public ObservableCollection<MailAttachmentViewModel> Attachments { get; set; } = [];
|
||||
public ObservableCollection<MailOperationMenuItem> MenuItems { get; set; } = [];
|
||||
|
||||
@@ -467,9 +465,9 @@ public partial class MailRenderingPageViewModel : MailBaseViewModel,
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<List<AccountContact>> GetAccountContacts(InternetAddressList internetAddresses)
|
||||
private async Task<List<AccountContactViewModel>> GetAccountContacts(InternetAddressList internetAddresses)
|
||||
{
|
||||
var accounts = new List<AccountContact>();
|
||||
List<AccountContactViewModel> accounts = [];
|
||||
foreach (var item in internetAddresses)
|
||||
{
|
||||
if (item is MailboxAddress mailboxAddress)
|
||||
@@ -477,14 +475,17 @@ public partial class MailRenderingPageViewModel : MailBaseViewModel,
|
||||
var foundContact = await _contactService.GetAddressInformationByAddressAsync(mailboxAddress.Address).ConfigureAwait(false)
|
||||
?? new AccountContact() { Name = mailboxAddress.Name, Address = mailboxAddress.Address };
|
||||
|
||||
var contactViewModel = new AccountContactViewModel(foundContact);
|
||||
|
||||
// Make sure that user account first in the list.
|
||||
if (foundContact.Address == initializedMailItemViewModel?.AssignedAccount?.Address)
|
||||
if (string.Equals(contactViewModel.Address, initializedMailItemViewModel?.AssignedAccount?.Address, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
accounts.Insert(0, foundContact);
|
||||
contactViewModel.IsMe = true;
|
||||
accounts.Insert(0, contactViewModel);
|
||||
}
|
||||
else
|
||||
{
|
||||
accounts.Add(foundContact);
|
||||
accounts.Add(contactViewModel);
|
||||
}
|
||||
}
|
||||
else if (item is GroupAddress groupAddress)
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
<DataTemplate x:Key="InternetAddressTemplate" x:DataType="entities:AccountContact">
|
||||
<DataTemplate x:Key="InternetAddressTemplate" x:DataType="viewModelData:AccountContactViewModel">
|
||||
<HyperlinkButton
|
||||
Margin="-2,-2"
|
||||
Padding="4,2"
|
||||
Click="InternetAddressClicked"
|
||||
Content="{x:Bind ShortDisplayName}"
|
||||
Content="{x:Bind ShortNameOrYou}"
|
||||
ToolTipService.ToolTip="{x:Bind DisplayName}">
|
||||
<HyperlinkButton.ContextFlyout>
|
||||
<Flyout Placement="Bottom">
|
||||
|
||||
@@ -37,7 +37,7 @@ public class ContactService : BaseDatabaseService, IContactService
|
||||
}
|
||||
|
||||
public Task<AccountContact> GetAddressInformationByAddressAsync(string address)
|
||||
=> Connection.Table<AccountContact>().Where(a => a.Address == address).FirstOrDefaultAsync();
|
||||
=> Connection.Table<AccountContact>().FirstOrDefaultAsync(a => a.Address == address);
|
||||
|
||||
public async Task SaveAddressInformationAsync(MimeMessage message)
|
||||
{
|
||||
|
||||
@@ -2,35 +2,34 @@
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Services.Threading;
|
||||
|
||||
namespace Wino.Services
|
||||
namespace Wino.Services;
|
||||
|
||||
public static class ServicesContainerSetup
|
||||
{
|
||||
public static class ServicesContainerSetup
|
||||
public static void RegisterSharedServices(this IServiceCollection services)
|
||||
{
|
||||
public static void RegisterSharedServices(this IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<ITranslationService, TranslationService>();
|
||||
services.AddSingleton<IDatabaseService, DatabaseService>();
|
||||
services.AddSingleton<ITranslationService, TranslationService>();
|
||||
services.AddSingleton<IDatabaseService, DatabaseService>();
|
||||
|
||||
services.AddSingleton<IApplicationConfiguration, ApplicationConfiguration>();
|
||||
services.AddSingleton<IWinoLogger, WinoLogger>();
|
||||
services.AddSingleton<ILaunchProtocolService, LaunchProtocolService>();
|
||||
services.AddSingleton<IMimeFileService, MimeFileService>();
|
||||
services.AddSingleton<IApplicationConfiguration, ApplicationConfiguration>();
|
||||
services.AddSingleton<IWinoLogger, WinoLogger>();
|
||||
services.AddSingleton<ILaunchProtocolService, LaunchProtocolService>();
|
||||
services.AddSingleton<IMimeFileService, MimeFileService>();
|
||||
|
||||
services.AddTransient<ICalendarService, CalendarService>();
|
||||
services.AddTransient<IMailService, MailService>();
|
||||
services.AddTransient<IFolderService, FolderService>();
|
||||
services.AddTransient<IAccountService, AccountService>();
|
||||
services.AddTransient<IContactService, ContactService>();
|
||||
services.AddTransient<ISignatureService, SignatureService>();
|
||||
services.AddTransient<IContextMenuItemService, ContextMenuItemService>();
|
||||
services.AddTransient<ISpecialImapProviderConfigResolver, SpecialImapProviderConfigResolver>();
|
||||
services.AddTransient<ICalendarService, CalendarService>();
|
||||
services.AddTransient<IMailService, MailService>();
|
||||
services.AddTransient<IFolderService, FolderService>();
|
||||
services.AddTransient<IAccountService, AccountService>();
|
||||
services.AddTransient<IContactService, ContactService>();
|
||||
services.AddTransient<ISignatureService, SignatureService>();
|
||||
services.AddTransient<IContextMenuItemService, ContextMenuItemService>();
|
||||
services.AddTransient<ISpecialImapProviderConfigResolver, SpecialImapProviderConfigResolver>();
|
||||
|
||||
services.AddSingleton<IThreadingStrategyProvider, ThreadingStrategyProvider>();
|
||||
services.AddTransient<IOutlookThreadingStrategy, OutlookThreadingStrategy>();
|
||||
services.AddTransient<IGmailThreadingStrategy, GmailThreadingStrategy>();
|
||||
services.AddTransient<IImapThreadingStrategy, ImapThreadingStrategy>();
|
||||
services.AddSingleton<IThreadingStrategyProvider, ThreadingStrategyProvider>();
|
||||
services.AddTransient<IOutlookThreadingStrategy, OutlookThreadingStrategy>();
|
||||
services.AddTransient<IGmailThreadingStrategy, GmailThreadingStrategy>();
|
||||
services.AddTransient<IImapThreadingStrategy, ImapThreadingStrategy>();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user