Local draft resent and default app mode settings.
This commit is contained in:
@@ -52,6 +52,11 @@ public interface IPreferencesService : INotifyPropertyChanged
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
int EmailSyncIntervalMinutes { get; set; }
|
int EmailSyncIntervalMinutes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Setting: Default application mode to open when activation does not specify one.
|
||||||
|
/// </summary>
|
||||||
|
WinoApplicationMode DefaultApplicationMode { get; set; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Mail
|
#region Mail
|
||||||
|
|||||||
@@ -77,6 +77,7 @@
|
|||||||
"Buttons_Save": "Save",
|
"Buttons_Save": "Save",
|
||||||
"Buttons_SaveConfiguration": "Save Configuration",
|
"Buttons_SaveConfiguration": "Save Configuration",
|
||||||
"Buttons_Send": "Send",
|
"Buttons_Send": "Send",
|
||||||
|
"Buttons_SendToServer": "Send to server",
|
||||||
"Buttons_Share": "Share",
|
"Buttons_Share": "Share",
|
||||||
"Buttons_SignIn": "Sign In",
|
"Buttons_SignIn": "Sign In",
|
||||||
"Buttons_Sync": "Synchronize",
|
"Buttons_Sync": "Synchronize",
|
||||||
@@ -619,6 +620,10 @@
|
|||||||
"SettingsAppPreferences_SearchMode_Local": "Local",
|
"SettingsAppPreferences_SearchMode_Local": "Local",
|
||||||
"SettingsAppPreferences_SearchMode_Online": "Online",
|
"SettingsAppPreferences_SearchMode_Online": "Online",
|
||||||
"SettingsAppPreferences_SearchMode_Title": "Default search mode",
|
"SettingsAppPreferences_SearchMode_Title": "Default search mode",
|
||||||
|
"SettingsAppPreferences_ApplicationMode_Title": "Default application mode",
|
||||||
|
"SettingsAppPreferences_ApplicationMode_Description": "Choose which mode Wino opens in when no activation type explicitly sets it.",
|
||||||
|
"SettingsAppPreferences_ApplicationMode_Mail": "Mail",
|
||||||
|
"SettingsAppPreferences_ApplicationMode_Calendar": "Calendar",
|
||||||
"SettingsAppPreferences_ServerBackgroundingMode_Invisible_Description": "Wino Mail will keep running in the background. You will be notified as new mails arrive.",
|
"SettingsAppPreferences_ServerBackgroundingMode_Invisible_Description": "Wino Mail will keep running in the background. You will be notified as new mails arrive.",
|
||||||
"SettingsAppPreferences_ServerBackgroundingMode_Invisible_Title": "Run in the background",
|
"SettingsAppPreferences_ServerBackgroundingMode_Invisible_Title": "Run in the background",
|
||||||
"SettingsAppPreferences_ServerBackgroundingMode_MinimizeTray_Description": "Wino Mail will keep running on the system tray. Available to launch by clicking on an icon. You will be notified as new mails arrive.",
|
"SettingsAppPreferences_ServerBackgroundingMode_MinimizeTray_Description": "Wino Mail will keep running on the system tray. Available to launch by clicking on an icon. You will be notified as new mails arrive.",
|
||||||
@@ -915,6 +920,7 @@
|
|||||||
"Composer_CcBcc": "Cc & Bcc",
|
"Composer_CcBcc": "Cc & Bcc",
|
||||||
"Composer_EnableSmimeSignature": "Enable/disable S/MIME signature",
|
"Composer_EnableSmimeSignature": "Enable/disable S/MIME signature",
|
||||||
"Composer_EnableSmimeEncryption": "Enable/disable S/MIME encryption",
|
"Composer_EnableSmimeEncryption": "Enable/disable S/MIME encryption",
|
||||||
|
"Composer_LocalDraftSyncInfo": "This draft is local only. Wino failed to send it to your mail server. Click to retry sending it to the server.",
|
||||||
"Composer_CertificateExpires": "Expires on: ",
|
"Composer_CertificateExpires": "Expires on: ",
|
||||||
"Composer_SmimeSignature": "S/MIME Signature",
|
"Composer_SmimeSignature": "S/MIME Signature",
|
||||||
"Composer_SmimeEncryption": "S/MIME Encryption",
|
"Composer_SmimeEncryption": "S/MIME Encryption",
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using CommunityToolkit.Mvvm.Messaging;
|
|
||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
using Wino.Core.Domain.Models.MailItem;
|
using Wino.Core.Domain.Models.MailItem;
|
||||||
using Wino.Core.Domain.Models.Requests;
|
using Wino.Core.Domain.Models.Requests;
|
||||||
using Wino.Messaging.UI;
|
|
||||||
|
|
||||||
namespace Wino.Core.Requests.Mail;
|
namespace Wino.Core.Requests.Mail;
|
||||||
|
|
||||||
@@ -24,6 +22,7 @@ public record CreateDraftRequest(DraftPreparationRequest DraftPreperationRequest
|
|||||||
|
|
||||||
public override void RevertUIChanges()
|
public override void RevertUIChanges()
|
||||||
{
|
{
|
||||||
WeakReferenceMessenger.Default.Send(new MailRemovedMessage(Item));
|
// Keep local draft intact when create-draft synchronization fails.
|
||||||
|
// This allows users to retry sending the local draft to the server.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ public partial class AppPreferencesPageViewModel : MailBaseViewModel
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public partial List<string> SearchModes { get; set; }
|
public partial List<string> SearchModes { get; set; }
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public partial List<string> ApplicationModes { get; set; }
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
[NotifyPropertyChangedFor(nameof(IsStartupBehaviorDisabled))]
|
[NotifyPropertyChangedFor(nameof(IsStartupBehaviorDisabled))]
|
||||||
[NotifyPropertyChangedFor(nameof(IsStartupBehaviorEnabled))]
|
[NotifyPropertyChangedFor(nameof(IsStartupBehaviorEnabled))]
|
||||||
@@ -48,6 +51,18 @@ public partial class AppPreferencesPageViewModel : MailBaseViewModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string _selectedDefaultApplicationMode;
|
||||||
|
public string SelectedDefaultApplicationMode
|
||||||
|
{
|
||||||
|
get => _selectedDefaultApplicationMode;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetProperty(ref _selectedDefaultApplicationMode, value);
|
||||||
|
|
||||||
|
PreferencesService.DefaultApplicationMode = (WinoApplicationMode)ApplicationModes.IndexOf(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private readonly IMailDialogService _dialogService;
|
private readonly IMailDialogService _dialogService;
|
||||||
private readonly IStartupBehaviorService _startupBehaviorService;
|
private readonly IStartupBehaviorService _startupBehaviorService;
|
||||||
|
|
||||||
@@ -65,7 +80,14 @@ public partial class AppPreferencesPageViewModel : MailBaseViewModel
|
|||||||
Translator.SettingsAppPreferences_SearchMode_Online
|
Translator.SettingsAppPreferences_SearchMode_Online
|
||||||
];
|
];
|
||||||
|
|
||||||
|
ApplicationModes =
|
||||||
|
[
|
||||||
|
Translator.SettingsAppPreferences_ApplicationMode_Mail,
|
||||||
|
Translator.SettingsAppPreferences_ApplicationMode_Calendar
|
||||||
|
];
|
||||||
|
|
||||||
SelectedDefaultSearchMode = SearchModes[(int)PreferencesService.DefaultSearchMode];
|
SelectedDefaultSearchMode = SearchModes[(int)PreferencesService.DefaultSearchMode];
|
||||||
|
SelectedDefaultApplicationMode = ApplicationModes[(int)PreferencesService.DefaultApplicationMode];
|
||||||
EmailSyncIntervalMinutes = PreferencesService.EmailSyncIntervalMinutes;
|
EmailSyncIntervalMinutes = PreferencesService.EmailSyncIntervalMinutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ using Wino.Core.Domain.Entities.Mail;
|
|||||||
using Wino.Core.Domain.Entities.Shared;
|
using Wino.Core.Domain.Entities.Shared;
|
||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
using Wino.Core.Domain.Exceptions;
|
using Wino.Core.Domain.Exceptions;
|
||||||
|
using Wino.Core.Domain.Extensions;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
using Wino.Core.Domain.Models.MailItem;
|
using Wino.Core.Domain.Models.MailItem;
|
||||||
using Wino.Core.Domain.Models.Navigation;
|
using Wino.Core.Domain.Models.Navigation;
|
||||||
@@ -23,11 +24,15 @@ using Wino.Core.Services;
|
|||||||
using Wino.Mail.ViewModels.Data;
|
using Wino.Mail.ViewModels.Data;
|
||||||
using Wino.Mail.ViewModels.Messages;
|
using Wino.Mail.ViewModels.Messages;
|
||||||
using Wino.Messaging.Client.Mails;
|
using Wino.Messaging.Client.Mails;
|
||||||
|
using Wino.Messaging.UI;
|
||||||
|
|
||||||
namespace Wino.Mail.ViewModels;
|
namespace Wino.Mail.ViewModels;
|
||||||
|
|
||||||
public partial class ComposePageViewModel : MailBaseViewModel,
|
public partial class ComposePageViewModel : MailBaseViewModel,
|
||||||
IRecipient<NewComposeDraftItemRequestedEvent>
|
IRecipient<NewComposeDraftItemRequestedEvent>,
|
||||||
|
IRecipient<SynchronizationActionsAdded>,
|
||||||
|
IRecipient<SynchronizationActionsCompleted>,
|
||||||
|
IRecipient<AccountSynchronizerStateChanged>
|
||||||
{
|
{
|
||||||
public Func<Task<string>> GetHTMLBodyFunction;
|
public Func<Task<string>> GetHTMLBodyFunction;
|
||||||
|
|
||||||
@@ -36,9 +41,11 @@ public partial class ComposePageViewModel : MailBaseViewModel,
|
|||||||
private bool isUpdatingMimeBlocked = false;
|
private bool isUpdatingMimeBlocked = false;
|
||||||
|
|
||||||
private bool canSendMail => ComposingAccount != null && !IsLocalDraft && CurrentMimeMessage != null && !IsDraftBusy;
|
private bool canSendMail => ComposingAccount != null && !IsLocalDraft && CurrentMimeMessage != null && !IsDraftBusy;
|
||||||
|
private bool canSendLocalDraftToServer => ComposingAccount != null && IsLocalDraft && CurrentMimeMessage != null && !IsDraftBusy && !IsRetryingSendToServer;
|
||||||
|
|
||||||
[NotifyCanExecuteChangedFor(nameof(DiscardCommand))]
|
[NotifyCanExecuteChangedFor(nameof(DiscardCommand))]
|
||||||
[NotifyCanExecuteChangedFor(nameof(SendCommand))]
|
[NotifyCanExecuteChangedFor(nameof(SendCommand))]
|
||||||
|
[NotifyCanExecuteChangedFor(nameof(SendToServerCommand))]
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private MimeMessage currentMimeMessage = null;
|
private MimeMessage currentMimeMessage = null;
|
||||||
|
|
||||||
@@ -50,15 +57,24 @@ public partial class ComposePageViewModel : MailBaseViewModel,
|
|||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
[NotifyPropertyChangedFor(nameof(IsLocalDraft))]
|
[NotifyPropertyChangedFor(nameof(IsLocalDraft))]
|
||||||
|
[NotifyPropertyChangedFor(nameof(ShouldShowSendToServerButton))]
|
||||||
|
[NotifyPropertyChangedFor(nameof(ShouldShowSendButton))]
|
||||||
[NotifyCanExecuteChangedFor(nameof(DiscardCommand))]
|
[NotifyCanExecuteChangedFor(nameof(DiscardCommand))]
|
||||||
[NotifyCanExecuteChangedFor(nameof(SendCommand))]
|
[NotifyCanExecuteChangedFor(nameof(SendCommand))]
|
||||||
|
[NotifyCanExecuteChangedFor(nameof(SendToServerCommand))]
|
||||||
public partial MailItemViewModel CurrentMailDraftItem { get; set; }
|
public partial MailItemViewModel CurrentMailDraftItem { get; set; }
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
|
[NotifyPropertyChangedFor(nameof(ShouldShowSendToServerButton))]
|
||||||
[NotifyCanExecuteChangedFor(nameof(DiscardCommand))]
|
[NotifyCanExecuteChangedFor(nameof(DiscardCommand))]
|
||||||
[NotifyCanExecuteChangedFor(nameof(SendCommand))]
|
[NotifyCanExecuteChangedFor(nameof(SendCommand))]
|
||||||
|
[NotifyCanExecuteChangedFor(nameof(SendToServerCommand))]
|
||||||
public partial bool IsDraftBusy { get; set; }
|
public partial bool IsDraftBusy { get; set; }
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[NotifyCanExecuteChangedFor(nameof(SendToServerCommand))]
|
||||||
|
public partial bool IsRetryingSendToServer { get; set; }
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public partial bool IsImportanceSelected { get; set; }
|
public partial bool IsImportanceSelected { get; set; }
|
||||||
|
|
||||||
@@ -74,6 +90,7 @@ public partial class ComposePageViewModel : MailBaseViewModel,
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
[NotifyCanExecuteChangedFor(nameof(DiscardCommand))]
|
[NotifyCanExecuteChangedFor(nameof(DiscardCommand))]
|
||||||
[NotifyCanExecuteChangedFor(nameof(SendCommand))]
|
[NotifyCanExecuteChangedFor(nameof(SendCommand))]
|
||||||
|
[NotifyCanExecuteChangedFor(nameof(SendToServerCommand))]
|
||||||
public partial MailAccount ComposingAccount { get; set; }
|
public partial MailAccount ComposingAccount { get; set; }
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
@@ -103,6 +120,8 @@ public partial class ComposePageViewModel : MailBaseViewModel,
|
|||||||
public ObservableCollection<AccountContact> ToItems { get; set; } = [];
|
public ObservableCollection<AccountContact> ToItems { get; set; } = [];
|
||||||
public ObservableCollection<AccountContact> CCItems { get; set; } = [];
|
public ObservableCollection<AccountContact> CCItems { get; set; } = [];
|
||||||
public ObservableCollection<AccountContact> BCCItems { get; set; } = [];
|
public ObservableCollection<AccountContact> BCCItems { get; set; } = [];
|
||||||
|
public bool ShouldShowSendToServerButton => IsLocalDraft && !IsDraftBusy;
|
||||||
|
public bool ShouldShowSendButton => !IsLocalDraft;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -325,6 +344,48 @@ public partial class ComposePageViewModel : MailBaseViewModel,
|
|||||||
await _worker.ExecuteAsync(draftSendPreparationRequest);
|
await _worker.ExecuteAsync(draftSendPreparationRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RelayCommand(CanExecute = nameof(canSendLocalDraftToServer))]
|
||||||
|
private async Task SendToServerAsync()
|
||||||
|
{
|
||||||
|
if (CurrentMailDraftItem?.MailCopy == null || ComposingAccount == null || CurrentMimeMessage == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await ExecuteUIThread(() =>
|
||||||
|
{
|
||||||
|
IsRetryingSendToServer = true;
|
||||||
|
IsDraftBusy = true;
|
||||||
|
NotifyComposeActionStateChanged();
|
||||||
|
});
|
||||||
|
|
||||||
|
await UpdateMimeChangesAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
var localDraftCopy = CurrentMailDraftItem.MailCopy;
|
||||||
|
var draftPreparationRequest = new DraftPreparationRequest(
|
||||||
|
localDraftCopy.AssignedAccount ?? ComposingAccount,
|
||||||
|
localDraftCopy,
|
||||||
|
CurrentMimeMessage.GetBase64MimeMessage(),
|
||||||
|
DraftCreationReason.Empty);
|
||||||
|
|
||||||
|
await _worker.ExecuteAsync(draftPreparationRequest).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_dialogService.InfoBarMessage(Translator.Info_RequestCreationFailedTitle, ex.Message, InfoBarMessageType.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await ExecuteUIThread(() =>
|
||||||
|
{
|
||||||
|
IsRetryingSendToServer = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
await UpdatePendingOperationStateAsync().ConfigureAwait(false);
|
||||||
|
NotifyComposeActionStateChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task UpdateMimeChangesAsync()
|
public async Task UpdateMimeChangesAsync()
|
||||||
{
|
{
|
||||||
if (isUpdatingMimeBlocked || CurrentMimeMessage == null || ComposingAccount == null || CurrentMailDraftItem == null) return;
|
if (isUpdatingMimeBlocked || CurrentMimeMessage == null || ComposingAccount == null || CurrentMailDraftItem == null) return;
|
||||||
@@ -424,13 +485,13 @@ public partial class ComposePageViewModel : MailBaseViewModel,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnNavigatedFrom(NavigationMode mode, object parameters)
|
//public override void OnNavigatedFrom(NavigationMode mode, object parameters)
|
||||||
{
|
//{
|
||||||
base.OnNavigatedFrom(mode, parameters);
|
// base.OnNavigatedFrom(mode, parameters);
|
||||||
|
|
||||||
/// Do not put any code here.
|
// /// Do not put any code here.
|
||||||
/// Make sure to use Page's OnNavigatedTo instead.
|
// /// Make sure to use Page's OnNavigatedTo instead.
|
||||||
}
|
//}
|
||||||
|
|
||||||
public override async void OnNavigatedTo(NavigationMode mode, object parameters)
|
public override async void OnNavigatedTo(NavigationMode mode, object parameters)
|
||||||
{
|
{
|
||||||
@@ -461,11 +522,38 @@ public partial class ComposePageViewModel : MailBaseViewModel,
|
|||||||
await TryPrepareComposeAsync(true);
|
await TryPrepareComposeAsync(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async void Receive(SynchronizationActionsAdded message)
|
||||||
|
{
|
||||||
|
if (!ShouldTrackDraftSynchronizationState(message.AccountId))
|
||||||
|
return;
|
||||||
|
|
||||||
|
await UpdatePendingOperationStateAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void Receive(SynchronizationActionsCompleted message)
|
||||||
|
{
|
||||||
|
if (!ShouldTrackDraftSynchronizationState(message.AccountId))
|
||||||
|
return;
|
||||||
|
|
||||||
|
await UpdatePendingOperationStateAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void Receive(AccountSynchronizerStateChanged message)
|
||||||
|
{
|
||||||
|
if (message.NewState != AccountSynchronizerState.Idle || !ShouldTrackDraftSynchronizationState(message.AccountId))
|
||||||
|
return;
|
||||||
|
|
||||||
|
await UpdatePendingOperationStateAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
protected override void RegisterRecipients()
|
protected override void RegisterRecipients()
|
||||||
{
|
{
|
||||||
base.RegisterRecipients();
|
base.RegisterRecipients();
|
||||||
|
|
||||||
Messenger.Register<NewComposeDraftItemRequestedEvent>(this);
|
Messenger.Register<NewComposeDraftItemRequestedEvent>(this);
|
||||||
|
Messenger.Register<SynchronizationActionsAdded>(this);
|
||||||
|
Messenger.Register<SynchronizationActionsCompleted>(this);
|
||||||
|
Messenger.Register<AccountSynchronizerStateChanged>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UnregisterRecipients()
|
protected override void UnregisterRecipients()
|
||||||
@@ -473,6 +561,9 @@ public partial class ComposePageViewModel : MailBaseViewModel,
|
|||||||
base.UnregisterRecipients();
|
base.UnregisterRecipients();
|
||||||
|
|
||||||
Messenger.Unregister<NewComposeDraftItemRequestedEvent>(this);
|
Messenger.Unregister<NewComposeDraftItemRequestedEvent>(this);
|
||||||
|
Messenger.Unregister<SynchronizationActionsAdded>(this);
|
||||||
|
Messenger.Unregister<SynchronizationActionsCompleted>(this);
|
||||||
|
Messenger.Unregister<AccountSynchronizerStateChanged>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> InitializeComposerAccountAsync()
|
private async Task<bool> InitializeComposerAccountAsync()
|
||||||
@@ -514,19 +605,31 @@ public partial class ComposePageViewModel : MailBaseViewModel,
|
|||||||
|
|
||||||
private async Task UpdatePendingOperationStateAsync()
|
private async Task UpdatePendingOperationStateAsync()
|
||||||
{
|
{
|
||||||
IsDraftBusy = false;
|
var hasPendingOperation = false;
|
||||||
|
|
||||||
if (CurrentMailDraftItem?.MailCopy == null || !CurrentMailDraftItem.MailCopy.IsDraft)
|
if (CurrentMailDraftItem?.MailCopy == null || !CurrentMailDraftItem.MailCopy.IsDraft)
|
||||||
|
{
|
||||||
|
await ExecuteUIThread(() =>
|
||||||
|
{
|
||||||
|
IsDraftBusy = false;
|
||||||
|
NotifyComposeActionStateChanged();
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var accountId = CurrentMailDraftItem.MailCopy.AssignedAccount?.Id ?? Guid.Empty;
|
var accountId = CurrentMailDraftItem.MailCopy.AssignedAccount?.Id ?? Guid.Empty;
|
||||||
|
|
||||||
if (accountId == Guid.Empty)
|
if (accountId != Guid.Empty)
|
||||||
return;
|
{
|
||||||
|
var synchronizer = await SynchronizationManager.Instance.GetSynchronizerAsync(accountId).ConfigureAwait(false);
|
||||||
|
hasPendingOperation = synchronizer?.HasPendingOperation(CurrentMailDraftItem.MailCopy.UniqueId) ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
var synchronizer = await SynchronizationManager.Instance.GetSynchronizerAsync(accountId).ConfigureAwait(false);
|
await ExecuteUIThread(() =>
|
||||||
|
{
|
||||||
IsDraftBusy = synchronizer?.HasPendingOperation(CurrentMailDraftItem.MailCopy.UniqueId) ?? false;
|
IsDraftBusy = hasPendingOperation;
|
||||||
|
NotifyComposeActionStateChanged();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task TryPrepareComposeAsync(bool downloadIfNeeded)
|
private async Task TryPrepareComposeAsync(bool downloadIfNeeded)
|
||||||
@@ -706,11 +809,32 @@ public partial class ComposePageViewModel : MailBaseViewModel,
|
|||||||
await ExecuteUIThread(async () =>
|
await ExecuteUIThread(async () =>
|
||||||
{
|
{
|
||||||
CurrentMailDraftItem.UpdateFrom(updatedMail);
|
CurrentMailDraftItem.UpdateFrom(updatedMail);
|
||||||
DiscardCommand.NotifyCanExecuteChanged();
|
|
||||||
SendCommand.NotifyCanExecuteChanged();
|
|
||||||
|
|
||||||
await UpdatePendingOperationStateAsync();
|
await UpdatePendingOperationStateAsync();
|
||||||
|
NotifyComposeActionStateChanged();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void NotifyComposeActionStateChanged()
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(IsLocalDraft));
|
||||||
|
OnPropertyChanged(nameof(ShouldShowSendToServerButton));
|
||||||
|
OnPropertyChanged(nameof(ShouldShowSendButton));
|
||||||
|
|
||||||
|
DiscardCommand.NotifyCanExecuteChanged();
|
||||||
|
SendCommand.NotifyCanExecuteChanged();
|
||||||
|
SendToServerCommand.NotifyCanExecuteChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ShouldTrackDraftSynchronizationState(Guid accountId)
|
||||||
|
{
|
||||||
|
if (accountId == Guid.Empty)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var currentDraftAccountId = CurrentMailDraftItem?.MailCopy?.AssignedAccount?.Id
|
||||||
|
?? ComposingAccount?.Id
|
||||||
|
?? Guid.Empty;
|
||||||
|
|
||||||
|
return currentDraftAccountId != Guid.Empty && currentDraftAccountId == accountId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace Wino.Mail.WinUI.Activation;
|
|||||||
|
|
||||||
internal static class AppModeActivationResolver
|
internal static class AppModeActivationResolver
|
||||||
{
|
{
|
||||||
public static WinoApplicationMode Resolve(string? launchArguments, string? tileId, string? appId)
|
public static WinoApplicationMode Resolve(string? launchArguments, string? tileId, string? appId, WinoApplicationMode defaultMode = WinoApplicationMode.Mail)
|
||||||
{
|
{
|
||||||
if (TryResolveFromText(launchArguments, out var mode))
|
if (TryResolveFromText(launchArguments, out var mode))
|
||||||
return mode;
|
return mode;
|
||||||
@@ -16,7 +16,7 @@ internal static class AppModeActivationResolver
|
|||||||
if (TryResolveFromText(appId, out mode))
|
if (TryResolveFromText(appId, out mode))
|
||||||
return mode;
|
return mode;
|
||||||
|
|
||||||
return WinoApplicationMode.Mail;
|
return defaultMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryResolveFromText(string? value, out WinoApplicationMode mode)
|
private static bool TryResolveFromText(string? value, out WinoApplicationMode mode)
|
||||||
|
|||||||
@@ -198,7 +198,10 @@ public partial class App : WinoApplication,
|
|||||||
if (activationArgs.Kind == ExtendedActivationKind.AppNotification)
|
if (activationArgs.Kind == ExtendedActivationKind.AppNotification)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
var launchMode = AppModeActivationResolver.Resolve(args?.Arguments, GetCurrentLaunchTileId(), Environment.CommandLine);
|
var launchMode = AppModeActivationResolver.Resolve(args?.Arguments,
|
||||||
|
GetCurrentLaunchTileId(),
|
||||||
|
Environment.CommandLine,
|
||||||
|
_preferencesService?.DefaultApplicationMode ?? WinoApplicationMode.Mail);
|
||||||
bool shouldRegister = launchMode == WinoApplicationMode.Mail;
|
bool shouldRegister = launchMode == WinoApplicationMode.Mail;
|
||||||
|
|
||||||
if (!shouldRegister)
|
if (!shouldRegister)
|
||||||
@@ -313,6 +316,7 @@ public partial class App : WinoApplication,
|
|||||||
{
|
{
|
||||||
// Pass null for args since we're handling toast navigation
|
// Pass null for args since we're handling toast navigation
|
||||||
await CreateAndActivateWindow(null!);
|
await CreateAndActivateWindow(null!);
|
||||||
|
navigationService.ChangeApplicationMode(Core.Domain.Enums.WinoApplicationMode.Mail);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -453,7 +457,7 @@ public partial class App : WinoApplication,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryResolveActivationMode(activationArgs, out var activationMode))
|
if (TryResolveActivationMode(activationArgs, _preferencesService?.DefaultApplicationMode ?? WinoApplicationMode.Mail, out var activationMode))
|
||||||
{
|
{
|
||||||
shellWindow.HandleAppActivation(GetModeLaunchArgument(activationMode));
|
shellWindow.HandleAppActivation(GetModeLaunchArgument(activationMode));
|
||||||
return;
|
return;
|
||||||
@@ -684,7 +688,7 @@ public partial class App : WinoApplication,
|
|||||||
{
|
{
|
||||||
shellWindow.HandleAppActivation(launchArgs.Arguments, launchArgs.TileId);
|
shellWindow.HandleAppActivation(launchArgs.Arguments, launchArgs.TileId);
|
||||||
}
|
}
|
||||||
else if (TryResolveActivationMode(args, out var redirectedMode))
|
else if (TryResolveActivationMode(args, _preferencesService?.DefaultApplicationMode ?? WinoApplicationMode.Mail, out var redirectedMode))
|
||||||
{
|
{
|
||||||
shellWindow.HandleAppActivation(GetModeLaunchArgument(redirectedMode));
|
shellWindow.HandleAppActivation(GetModeLaunchArgument(redirectedMode));
|
||||||
}
|
}
|
||||||
@@ -700,9 +704,9 @@ public partial class App : WinoApplication,
|
|||||||
private static string GetModeLaunchArgument(WinoApplicationMode mode)
|
private static string GetModeLaunchArgument(WinoApplicationMode mode)
|
||||||
=> mode == WinoApplicationMode.Calendar ? "--mode=calendar" : "--mode=mail";
|
=> mode == WinoApplicationMode.Calendar ? "--mode=calendar" : "--mode=mail";
|
||||||
|
|
||||||
private static bool TryResolveActivationMode(AppActivationArguments activationArgs, out WinoApplicationMode mode)
|
private static bool TryResolveActivationMode(AppActivationArguments activationArgs, WinoApplicationMode defaultMode, out WinoApplicationMode mode)
|
||||||
{
|
{
|
||||||
mode = WinoApplicationMode.Mail;
|
mode = defaultMode;
|
||||||
|
|
||||||
if (activationArgs.Kind == ExtendedActivationKind.Protocol &&
|
if (activationArgs.Kind == ExtendedActivationKind.Protocol &&
|
||||||
activationArgs.Data is IProtocolActivatedEventArgs protocolArgs)
|
activationArgs.Data is IProtocolActivatedEventArgs protocolArgs)
|
||||||
@@ -746,7 +750,7 @@ public partial class App : WinoApplication,
|
|||||||
if (activationArgs.Kind == ExtendedActivationKind.Launch &&
|
if (activationArgs.Kind == ExtendedActivationKind.Launch &&
|
||||||
activationArgs.Data is ILaunchActivatedEventArgs launchArgs)
|
activationArgs.Data is ILaunchActivatedEventArgs launchArgs)
|
||||||
{
|
{
|
||||||
mode = AppModeActivationResolver.Resolve(launchArgs.Arguments, launchArgs.TileId, null);
|
mode = AppModeActivationResolver.Resolve(launchArgs.Arguments, launchArgs.TileId, null, defaultMode);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -290,6 +290,19 @@ public class PreferencesService(IConfigurationService configurationService) : Ob
|
|||||||
set => SetPropertyAndSave(nameof(EmailSyncIntervalMinutes), value);
|
set => SetPropertyAndSave(nameof(EmailSyncIntervalMinutes), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public WinoApplicationMode DefaultApplicationMode
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var configuredMode = _configurationService.Get(nameof(DefaultApplicationMode), WinoApplicationMode.Mail);
|
||||||
|
|
||||||
|
return Enum.IsDefined(typeof(WinoApplicationMode), configuredMode)
|
||||||
|
? configuredMode
|
||||||
|
: WinoApplicationMode.Mail;
|
||||||
|
}
|
||||||
|
set => SaveProperty(propertyName: nameof(DefaultApplicationMode), value);
|
||||||
|
}
|
||||||
|
|
||||||
public CalendarSettings GetCurrentCalendarSettings()
|
public CalendarSettings GetCurrentCalendarSettings()
|
||||||
{
|
{
|
||||||
var workingDays = GetDaysBetween(WorkingDayStart, WorkingDayEnd);
|
var workingDays = GetDaysBetween(WorkingDayStart, WorkingDayEnd);
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow,
|
|||||||
|
|
||||||
public void HandleAppActivation(string? launchArguments, string? tileId = null, string? appId = null)
|
public void HandleAppActivation(string? launchArguments, string? tileId = null, string? appId = null)
|
||||||
{
|
{
|
||||||
var targetMode = AppModeActivationResolver.Resolve(launchArguments, tileId, appId);
|
var targetMode = AppModeActivationResolver.Resolve(launchArguments, tileId, appId, PreferencesService.DefaultApplicationMode);
|
||||||
_currentMode = targetMode;
|
_currentMode = targetMode;
|
||||||
|
|
||||||
_isApplyingActivationMode = true;
|
_isApplyingActivationMode = true;
|
||||||
|
|||||||
@@ -227,11 +227,23 @@
|
|||||||
<coreControls:WinoFontIcon Icon="Delete" />
|
<coreControls:WinoFontIcon Icon="Delete" />
|
||||||
</AppBarButton.Icon>
|
</AppBarButton.Icon>
|
||||||
</AppBarButton>
|
</AppBarButton>
|
||||||
<AppBarButton Command="{x:Bind ViewModel.SendCommand}" Label="{x:Bind domain:Translator.Buttons_Send}">
|
<AppBarButton
|
||||||
|
Command="{x:Bind ViewModel.SendCommand}"
|
||||||
|
Label="{x:Bind domain:Translator.Buttons_Send}"
|
||||||
|
Visibility="{x:Bind ViewModel.ShouldShowSendButton, Mode=OneWay}">
|
||||||
<AppBarButton.Icon>
|
<AppBarButton.Icon>
|
||||||
<coreControls:WinoFontIcon Icon="Send" />
|
<coreControls:WinoFontIcon Icon="Send" />
|
||||||
</AppBarButton.Icon>
|
</AppBarButton.Icon>
|
||||||
</AppBarButton>
|
</AppBarButton>
|
||||||
|
<AppBarButton
|
||||||
|
Command="{x:Bind ViewModel.SendToServerCommand}"
|
||||||
|
Label="{x:Bind domain:Translator.Buttons_SendToServer}"
|
||||||
|
ToolTipService.ToolTip="{x:Bind domain:Translator.Composer_LocalDraftSyncInfo}"
|
||||||
|
Visibility="{x:Bind ViewModel.ShouldShowSendToServerButton, Mode=OneWay}">
|
||||||
|
<AppBarButton.Icon>
|
||||||
|
<coreControls:WinoFontIcon Icon="SendNew" />
|
||||||
|
</AppBarButton.Icon>
|
||||||
|
</AppBarButton>
|
||||||
</toolkit:TabbedCommandBarItem>
|
</toolkit:TabbedCommandBarItem>
|
||||||
</toolkit:TabbedCommandBar.PaneCustomContent>
|
</toolkit:TabbedCommandBar.PaneCustomContent>
|
||||||
<toolkit:TabbedCommandBar.MenuItems>
|
<toolkit:TabbedCommandBar.MenuItems>
|
||||||
|
|||||||
@@ -280,7 +280,14 @@ public sealed partial class MailListPage : MailListPageAbstract,
|
|||||||
// No active mail item. Go to empty page.
|
// No active mail item. Go to empty page.
|
||||||
if (message.SelectedMailItemViewModel == null)
|
if (message.SelectedMailItemViewModel == null)
|
||||||
{
|
{
|
||||||
WeakReferenceMessenger.Default.Send(new CancelRenderingContentRequested());
|
if (IsRenderingPageActive())
|
||||||
|
{
|
||||||
|
WeakReferenceMessenger.Default.Send(new CancelRenderingContentRequested());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure rendering frame actually navigates away from Compose/Rendering pages.
|
||||||
|
// Otherwise those pages keep their messenger registrations alive.
|
||||||
|
ViewModel.NavigationService.Navigate(WinoPage.IdlePage, null, NavigationReferenceFrame.RenderingFrame, NavigationTransitionType.DrillIn);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -30,6 +30,13 @@
|
|||||||
</controls:SettingsCard.HeaderIcon>
|
</controls:SettingsCard.HeaderIcon>
|
||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
|
||||||
|
<controls:SettingsCard Description="{x:Bind domain:Translator.SettingsAppPreferences_ApplicationMode_Description}" Header="{x:Bind domain:Translator.SettingsAppPreferences_ApplicationMode_Title}">
|
||||||
|
<ComboBox ItemsSource="{x:Bind ViewModel.ApplicationModes, Mode=OneWay}" SelectedItem="{x:Bind ViewModel.SelectedDefaultApplicationMode, Mode=TwoWay}" />
|
||||||
|
<controls:SettingsCard.HeaderIcon>
|
||||||
|
<PathIcon Data="F1 M 2.5 3.125 C 2.5 2.955729 2.561849 2.809245 2.685547 2.685547 C 2.809244 2.56185 2.955729 2.5 3.125 2.5 L 16.875 2.5 C 17.044271 2.5 17.190756 2.56185 17.314453 2.685547 C 17.43815 2.809245 17.5 2.955729 17.5 3.125 L 17.5 16.875 C 17.5 17.044271 17.43815 17.190756 17.314453 17.314453 C 17.190756 17.43815 17.044271 17.5 16.875 17.5 L 3.125 17.5 C 2.955729 17.5 2.809244 17.43815 2.685547 17.314453 C 2.561849 17.190756 2.5 17.044271 2.5 16.875 Z M 3.75 3.75 L 3.75 16.25 L 16.25 16.25 L 16.25 3.75 Z M 9.375 5 C 9.375 4.830729 9.436849 4.684245 9.560547 4.560547 C 9.684244 4.43685 9.830729 4.375 10 4.375 C 10.169271 4.375 10.315755 4.43685 10.439453 4.560547 C 10.56315 4.684245 10.625 4.830729 10.625 5 L 10.625 15 C 10.625 15.169271 10.56315 15.315756 10.439453 15.439453 C 10.315755 15.56315 10.169271 15.625 10 15.625 C 9.830729 15.625 9.684244 15.56315 9.560547 15.439453 C 9.436849 15.315756 9.375 15.169271 9.375 15 Z " />
|
||||||
|
</controls:SettingsCard.HeaderIcon>
|
||||||
|
</controls:SettingsCard>
|
||||||
|
|
||||||
<controls:SettingsCard Description="{x:Bind domain:Translator.SettingsAppPreferences_EmailSyncInterval_Description}" Header="{x:Bind domain:Translator.SettingsAppPreferences_EmailSyncInterval_Title}">
|
<controls:SettingsCard Description="{x:Bind domain:Translator.SettingsAppPreferences_EmailSyncInterval_Description}" Header="{x:Bind domain:Translator.SettingsAppPreferences_EmailSyncInterval_Title}">
|
||||||
<NumberBox
|
<NumberBox
|
||||||
Minimum="1"
|
Minimum="1"
|
||||||
|
|||||||
Reference in New Issue
Block a user