Add Windows share target draft attachment flow
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
#nullable enable
|
||||||
|
using System;
|
||||||
|
using Wino.Core.Domain.Models.Launch;
|
||||||
|
|
||||||
|
namespace Wino.Core.Domain.Interfaces;
|
||||||
|
|
||||||
|
public interface IShareActivationService
|
||||||
|
{
|
||||||
|
MailShareRequest? PendingShareRequest { get; set; }
|
||||||
|
MailShareRequest? ConsumePendingShareRequest();
|
||||||
|
void ClearPendingShareRequest();
|
||||||
|
void StagePendingComposeShareRequest(Guid draftUniqueId, MailShareRequest shareRequest);
|
||||||
|
MailShareRequest? ConsumePendingComposeShareRequest(Guid draftUniqueId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Wino.Core.Domain.Models.Common;
|
||||||
|
|
||||||
|
namespace Wino.Core.Domain.Models.Launch;
|
||||||
|
|
||||||
|
public sealed class MailShareRequest
|
||||||
|
{
|
||||||
|
public MailShareRequest(IReadOnlyList<SharedFile> files)
|
||||||
|
{
|
||||||
|
Files = files ?? throw new ArgumentNullException(nameof(files));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<SharedFile> Files { get; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Wino.Core.Domain.Models.Launch;
|
||||||
|
|
||||||
|
public sealed class PendingComposeMailShareRequest
|
||||||
|
{
|
||||||
|
public PendingComposeMailShareRequest(Guid draftUniqueId, MailShareRequest shareRequest)
|
||||||
|
{
|
||||||
|
DraftUniqueId = draftUniqueId;
|
||||||
|
ShareRequest = shareRequest ?? throw new ArgumentNullException(nameof(shareRequest));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid DraftUniqueId { get; }
|
||||||
|
public MailShareRequest ShareRequest { get; }
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ 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;
|
using Wino.Core.Domain.Models;
|
||||||
|
using Wino.Core.Domain.Models.Launch;
|
||||||
using Wino.Core.Domain.Models.Navigation;
|
using Wino.Core.Domain.Models.Navigation;
|
||||||
using Wino.Core.Extensions;
|
using Wino.Core.Extensions;
|
||||||
using Wino.Core.Services;
|
using Wino.Core.Services;
|
||||||
@@ -159,6 +160,7 @@ public partial class ComposePageViewModel : MailBaseViewModel,
|
|||||||
public readonly IPreferencesService PreferencesService;
|
public readonly IPreferencesService PreferencesService;
|
||||||
public readonly IContactService ContactService;
|
public readonly IContactService ContactService;
|
||||||
public readonly ISmimeCertificateService _smimeCertificateService;
|
public readonly ISmimeCertificateService _smimeCertificateService;
|
||||||
|
private readonly IShareActivationService _shareActivationService;
|
||||||
|
|
||||||
public ComposePageViewModel(IMailDialogService dialogService,
|
public ComposePageViewModel(IMailDialogService dialogService,
|
||||||
IMailService mailService,
|
IMailService mailService,
|
||||||
@@ -172,7 +174,8 @@ public partial class ComposePageViewModel : MailBaseViewModel,
|
|||||||
IContactService contactService,
|
IContactService contactService,
|
||||||
IFontService fontService,
|
IFontService fontService,
|
||||||
IPreferencesService preferencesService,
|
IPreferencesService preferencesService,
|
||||||
ISmimeCertificateService smimeCertificateService)
|
ISmimeCertificateService smimeCertificateService,
|
||||||
|
IShareActivationService shareActivationService)
|
||||||
{
|
{
|
||||||
NativeAppService = nativeAppService;
|
NativeAppService = nativeAppService;
|
||||||
ContactService = contactService;
|
ContactService = contactService;
|
||||||
@@ -188,6 +191,7 @@ public partial class ComposePageViewModel : MailBaseViewModel,
|
|||||||
_emailTemplateService = emailTemplateService;
|
_emailTemplateService = emailTemplateService;
|
||||||
_worker = worker;
|
_worker = worker;
|
||||||
_smimeCertificateService = smimeCertificateService;
|
_smimeCertificateService = smimeCertificateService;
|
||||||
|
_shareActivationService = shareActivationService;
|
||||||
|
|
||||||
foreach (var cert in _smimeCertificateService.GetCertificates(emailAddress: SelectedAlias?.AliasAddress))
|
foreach (var cert in _smimeCertificateService.GetCertificates(emailAddress: SelectedAlias?.AliasAddress))
|
||||||
{
|
{
|
||||||
@@ -752,6 +756,7 @@ public partial class ComposePageViewModel : MailBaseViewModel,
|
|||||||
await LoadAddressInfoAsync(replyingMime.Bcc, BCCItems);
|
await LoadAddressInfoAsync(replyingMime.Bcc, BCCItems);
|
||||||
|
|
||||||
LoadAttachments();
|
LoadAttachments();
|
||||||
|
ApplyPendingSharedAttachments();
|
||||||
|
|
||||||
if (replyingMime.Cc.Any() || replyingMime.Bcc.Any())
|
if (replyingMime.Cc.Any() || replyingMime.Bcc.Any())
|
||||||
IsCCBCCVisible = true;
|
IsCCBCCVisible = true;
|
||||||
@@ -783,6 +788,24 @@ public partial class ComposePageViewModel : MailBaseViewModel,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ApplyPendingSharedAttachments()
|
||||||
|
{
|
||||||
|
var draftUniqueId = CurrentMailDraftItem?.MailCopy?.UniqueId ?? Guid.Empty;
|
||||||
|
|
||||||
|
if (draftUniqueId == Guid.Empty)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var shareRequest = _shareActivationService.ConsumePendingComposeShareRequest(draftUniqueId);
|
||||||
|
|
||||||
|
if (shareRequest?.Files == null || shareRequest.Files.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var sharedFile in shareRequest.Files)
|
||||||
|
{
|
||||||
|
IncludedAttachments.Add(new MailAttachmentViewModel(sharedFile));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task LoadAddressInfoAsync(InternetAddressList list, ObservableCollection<AccountContact> collection)
|
private async Task LoadAddressInfoAsync(InternetAddressList list, ObservableCollection<AccountContact> collection)
|
||||||
{
|
{
|
||||||
foreach (var item in list)
|
foreach (var item in list)
|
||||||
|
|||||||
@@ -15,8 +15,9 @@ using Wino.Core.Domain.Entities.Shared;
|
|||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
using Wino.Core.Domain.MenuItems;
|
using Wino.Core.Domain.MenuItems;
|
||||||
using Wino.Core.Domain.Models.Folders;
|
|
||||||
using Wino.Core.Domain.Models;
|
using Wino.Core.Domain.Models;
|
||||||
|
using Wino.Core.Domain.Models.Folders;
|
||||||
|
using Wino.Core.Domain.Models.Launch;
|
||||||
using Wino.Core.Domain.Models.MailItem;
|
using Wino.Core.Domain.Models.MailItem;
|
||||||
using Wino.Core.Domain.Models.Navigation;
|
using Wino.Core.Domain.Models.Navigation;
|
||||||
using Wino.Core.Domain.Models.Synchronization;
|
using Wino.Core.Domain.Models.Synchronization;
|
||||||
@@ -84,6 +85,7 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
private readonly IMimeFileService _mimeFileService;
|
private readonly IMimeFileService _mimeFileService;
|
||||||
private readonly IWebView2RuntimeValidatorService _webView2RuntimeValidatorService;
|
private readonly IWebView2RuntimeValidatorService _webView2RuntimeValidatorService;
|
||||||
private readonly IStoreUpdateService _storeUpdateService;
|
private readonly IStoreUpdateService _storeUpdateService;
|
||||||
|
private readonly IShareActivationService _shareActivationService;
|
||||||
|
|
||||||
private readonly INativeAppService _nativeAppService;
|
private readonly INativeAppService _nativeAppService;
|
||||||
private readonly IMailService _mailService;
|
private readonly IMailService _mailService;
|
||||||
@@ -109,7 +111,8 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
IConfigurationService configurationService,
|
IConfigurationService configurationService,
|
||||||
IStartupBehaviorService startupBehaviorService,
|
IStartupBehaviorService startupBehaviorService,
|
||||||
IWebView2RuntimeValidatorService webView2RuntimeValidatorService,
|
IWebView2RuntimeValidatorService webView2RuntimeValidatorService,
|
||||||
IStoreUpdateService storeUpdateService)
|
IStoreUpdateService storeUpdateService,
|
||||||
|
IShareActivationService shareActivationService)
|
||||||
{
|
{
|
||||||
StatePersistenceService = statePersistanceService;
|
StatePersistenceService = statePersistanceService;
|
||||||
|
|
||||||
@@ -131,6 +134,7 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
_winoRequestDelegator = winoRequestDelegator;
|
_winoRequestDelegator = winoRequestDelegator;
|
||||||
_webView2RuntimeValidatorService = webView2RuntimeValidatorService;
|
_webView2RuntimeValidatorService = webView2RuntimeValidatorService;
|
||||||
_storeUpdateService = storeUpdateService;
|
_storeUpdateService = storeUpdateService;
|
||||||
|
_shareActivationService = shareActivationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDispatcherAssigned()
|
protected override void OnDispatcherAssigned()
|
||||||
@@ -274,6 +278,7 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
}
|
}
|
||||||
|
|
||||||
await ProcessLaunchOptionsAsync();
|
await ProcessLaunchOptionsAsync();
|
||||||
|
await HandlePendingShareRequestAsync();
|
||||||
await ValidateWebView2RuntimeAsync();
|
await ValidateWebView2RuntimeAsync();
|
||||||
|
|
||||||
if (shouldRunStartupFlows && !Debugger.IsAttached)
|
if (shouldRunStartupFlows && !Debugger.IsAttached)
|
||||||
@@ -943,6 +948,9 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async Task CreateNewMailForAsync(MailAccount account)
|
public async Task CreateNewMailForAsync(MailAccount account)
|
||||||
|
=> await CreateNewMailForAsync(account, null);
|
||||||
|
|
||||||
|
public async Task CreateNewMailForAsync(MailAccount account, MailShareRequest shareRequest)
|
||||||
{
|
{
|
||||||
if (account == null) return;
|
if (account == null) return;
|
||||||
|
|
||||||
@@ -974,6 +982,11 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
|
|
||||||
var (draftMailCopy, draftBase64MimeMessage) = await _mailService.CreateDraftAsync(account.Id, draftOptions).ConfigureAwait(false);
|
var (draftMailCopy, draftBase64MimeMessage) = await _mailService.CreateDraftAsync(account.Id, draftOptions).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (shareRequest?.Files?.Count > 0)
|
||||||
|
{
|
||||||
|
_shareActivationService.StagePendingComposeShareRequest(draftMailCopy.UniqueId, shareRequest);
|
||||||
|
}
|
||||||
|
|
||||||
var draftPreparationRequest = new DraftPreparationRequest(account, draftMailCopy, draftBase64MimeMessage, draftOptions.Reason);
|
var draftPreparationRequest = new DraftPreparationRequest(account, draftMailCopy, draftBase64MimeMessage, draftOptions.Reason);
|
||||||
await _winoRequestDelegator.ExecuteAsync(draftPreparationRequest);
|
await _winoRequestDelegator.ExecuteAsync(draftPreparationRequest);
|
||||||
}
|
}
|
||||||
@@ -1034,6 +1047,35 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
await CreateNewMailForAsync(targetAccount);
|
await CreateNewMailForAsync(targetAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task HandlePendingShareRequestAsync()
|
||||||
|
{
|
||||||
|
var shareRequest = _shareActivationService.ConsumePendingShareRequest();
|
||||||
|
|
||||||
|
if (shareRequest?.Files == null || shareRequest.Files.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var accounts = await _accountService.GetAccountsAsync();
|
||||||
|
|
||||||
|
if (!accounts.Any())
|
||||||
|
return;
|
||||||
|
|
||||||
|
MailAccount targetAccount = null;
|
||||||
|
|
||||||
|
if (accounts.Count == 1)
|
||||||
|
{
|
||||||
|
targetAccount = accounts[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
targetAccount = await _dialogService.ShowAccountPickerDialogAsync(accounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetAccount == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
await CreateNewMailForAsync(targetAccount, shareRequest);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task RecreateMenuItemsAsync()
|
private async Task RecreateMenuItemsAsync()
|
||||||
{
|
{
|
||||||
await _menuRefreshSemaphore.WaitAsync().ConfigureAwait(false);
|
await _menuRefreshSemaphore.WaitAsync().ConfigureAwait(false);
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ using Microsoft.Windows.AppLifecycle;
|
|||||||
using Microsoft.Windows.AppNotifications;
|
using Microsoft.Windows.AppNotifications;
|
||||||
using MimeKit.Cryptography;
|
using MimeKit.Cryptography;
|
||||||
using Windows.ApplicationModel.Activation;
|
using Windows.ApplicationModel.Activation;
|
||||||
|
using Windows.ApplicationModel.DataTransfer;
|
||||||
|
using Windows.ApplicationModel.DataTransfer.ShareTarget;
|
||||||
|
using Windows.Storage;
|
||||||
using Wino.Calendar.ViewModels;
|
using Wino.Calendar.ViewModels;
|
||||||
using Wino.Calendar.ViewModels.Interfaces;
|
using Wino.Calendar.ViewModels.Interfaces;
|
||||||
using Wino.Core;
|
using Wino.Core;
|
||||||
@@ -22,6 +25,8 @@ using Wino.Core.Domain;
|
|||||||
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.Calendar;
|
using Wino.Core.Domain.Models.Calendar;
|
||||||
|
using Wino.Core.Domain.Models.Common;
|
||||||
|
using Wino.Core.Domain.Models.Launch;
|
||||||
using Wino.Core.Domain.Models.MailItem;
|
using Wino.Core.Domain.Models.MailItem;
|
||||||
using Wino.Core.Domain.Models.Navigation;
|
using Wino.Core.Domain.Models.Navigation;
|
||||||
using Wino.Core.Domain.Models.Synchronization;
|
using Wino.Core.Domain.Models.Synchronization;
|
||||||
@@ -30,6 +35,7 @@ using Wino.Mail.Services;
|
|||||||
using Wino.Mail.ViewModels;
|
using Wino.Mail.ViewModels;
|
||||||
using Wino.Mail.ViewModels.Data;
|
using Wino.Mail.ViewModels.Data;
|
||||||
using Wino.Mail.WinUI.Activation;
|
using Wino.Mail.WinUI.Activation;
|
||||||
|
using Wino.Mail.WinUI.Extensions;
|
||||||
using Wino.Mail.WinUI.Interfaces;
|
using Wino.Mail.WinUI.Interfaces;
|
||||||
using Wino.Mail.WinUI.Models;
|
using Wino.Mail.WinUI.Models;
|
||||||
using Wino.Mail.WinUI.Services;
|
using Wino.Mail.WinUI.Services;
|
||||||
@@ -61,6 +67,7 @@ public partial class App : WinoApplication,
|
|||||||
private bool _isExiting;
|
private bool _isExiting;
|
||||||
private bool _activationInfrastructureInitialized;
|
private bool _activationInfrastructureInitialized;
|
||||||
private int _initialNotificationActivationHandled;
|
private int _initialNotificationActivationHandled;
|
||||||
|
private int _initialShareActivationHandled;
|
||||||
private CancellationTokenSource? _autoSynchronizationLoopCts;
|
private CancellationTokenSource? _autoSynchronizationLoopCts;
|
||||||
private readonly SemaphoreSlim _autoSynchronizationSemaphore = new(1, 1);
|
private readonly SemaphoreSlim _autoSynchronizationSemaphore = new(1, 1);
|
||||||
private readonly SemaphoreSlim _activationInfrastructureSemaphore = new(1, 1);
|
private readonly SemaphoreSlim _activationInfrastructureSemaphore = new(1, 1);
|
||||||
@@ -446,12 +453,26 @@ public partial class App : WinoApplication,
|
|||||||
private bool TryMarkInitialNotificationActivationHandled()
|
private bool TryMarkInitialNotificationActivationHandled()
|
||||||
=> Interlocked.Exchange(ref _initialNotificationActivationHandled, 1) == 0;
|
=> Interlocked.Exchange(ref _initialNotificationActivationHandled, 1) == 0;
|
||||||
|
|
||||||
|
private bool TryMarkInitialShareActivationHandled()
|
||||||
|
=> Interlocked.Exchange(ref _initialShareActivationHandled, 1) == 0;
|
||||||
|
|
||||||
protected override async void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
|
protected override async void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
|
||||||
{
|
{
|
||||||
base.OnLaunched(args);
|
base.OnLaunched(args);
|
||||||
|
|
||||||
await EnsureActivationInfrastructureAsync();
|
await EnsureActivationInfrastructureAsync();
|
||||||
|
|
||||||
|
var activationArgs = AppInstance.GetCurrent().GetActivatedEventArgs();
|
||||||
|
|
||||||
|
if (activationArgs.Kind == ExtendedActivationKind.ShareTarget &&
|
||||||
|
TryMarkInitialShareActivationHandled())
|
||||||
|
{
|
||||||
|
LogActivation("Processing share target activation from OnLaunched.");
|
||||||
|
|
||||||
|
if (await HandleShareTargetActivationAsync(activationArgs, activateWindow: true))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var hasAnyAccount = _hasConfiguredAccounts;
|
var hasAnyAccount = _hasConfiguredAccounts;
|
||||||
if (!IsStartupTaskLaunch() && !hasAnyAccount)
|
if (!IsStartupTaskLaunch() && !hasAnyAccount)
|
||||||
{
|
{
|
||||||
@@ -635,6 +656,89 @@ public partial class App : WinoApplication,
|
|||||||
return HandleToastActivationAsync(toastArguments, userInput);
|
return HandleToastActivationAsync(toastArguments, userInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<bool> HandleShareTargetActivationAsync(AppActivationArguments activationArgs, bool activateWindow)
|
||||||
|
{
|
||||||
|
if (activationArgs.Kind != ExtendedActivationKind.ShareTarget ||
|
||||||
|
activationArgs.Data is not ShareTargetActivatedEventArgs shareTargetArgs)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var shareRequest = await ExtractMailShareRequestAsync(shareTargetArgs);
|
||||||
|
|
||||||
|
if (shareRequest?.Files == null || shareRequest.Files.Count == 0)
|
||||||
|
{
|
||||||
|
Services.GetRequiredService<IShareActivationService>().ClearPendingShareRequest();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var shareActivationService = Services.GetRequiredService<IShareActivationService>();
|
||||||
|
shareActivationService.PendingShareRequest = shareRequest;
|
||||||
|
|
||||||
|
if (!_hasConfiguredAccounts)
|
||||||
|
{
|
||||||
|
shareActivationService.ClearPendingShareRequest();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var shellWindowAlreadyExists = HasShellWindow();
|
||||||
|
|
||||||
|
await EnsureShellWindowAsync(WinoApplicationMode.Mail, activateWindow, suppressStartupFlows: true);
|
||||||
|
|
||||||
|
if (shellWindowAlreadyExists)
|
||||||
|
{
|
||||||
|
await Services.GetRequiredService<MailAppShellViewModel>().HandlePendingShareRequestAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<MailShareRequest?> ExtractMailShareRequestAsync(ShareTargetActivatedEventArgs shareTargetArgs)
|
||||||
|
{
|
||||||
|
var shareOperation = shareTargetArgs.ShareOperation;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
shareOperation.ReportStarted();
|
||||||
|
|
||||||
|
if (!shareOperation.Data.Contains(StandardDataFormats.StorageItems))
|
||||||
|
{
|
||||||
|
shareOperation.ReportCompleted();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var storageItems = await shareOperation.Data.GetStorageItemsAsync();
|
||||||
|
List<SharedFile> sharedFiles = [];
|
||||||
|
|
||||||
|
foreach (var storageFile in storageItems.OfType<StorageFile>())
|
||||||
|
{
|
||||||
|
sharedFiles.Add(await storageFile.ToSharedFileAsync());
|
||||||
|
}
|
||||||
|
|
||||||
|
shareOperation.ReportDataRetrieved();
|
||||||
|
shareOperation.ReportCompleted();
|
||||||
|
|
||||||
|
return sharedFiles.Count == 0
|
||||||
|
? null
|
||||||
|
: new MailShareRequest(sharedFiles);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogActivation($"Failed to extract share target payload: {ex.GetType().Name} - {ex.Message}");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
shareOperation.ReportError(ex.Message);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Ignore share reporting failures and fall back to normal launch flow.
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<IWinoShellWindow?> EnsureShellWindowAsync(WinoApplicationMode mode, bool activateWindow, bool suppressStartupFlows = true)
|
private async Task<IWinoShellWindow?> EnsureShellWindowAsync(WinoApplicationMode mode, bool activateWindow, bool suppressStartupFlows = true)
|
||||||
{
|
{
|
||||||
var windowManager = Services.GetRequiredService<IWinoWindowManager>();
|
var windowManager = Services.GetRequiredService<IWinoWindowManager>();
|
||||||
@@ -1446,6 +1550,11 @@ public partial class App : WinoApplication,
|
|||||||
LogActivation($"Processing redirected notification activation. Arguments: {toastArgs.Argument}");
|
LogActivation($"Processing redirected notification activation. Arguments: {toastArgs.Argument}");
|
||||||
_ = HandleToastActivationAsync(toastArgs.Argument, toastArgs.UserInput);
|
_ = HandleToastActivationAsync(toastArgs.Argument, toastArgs.UserInput);
|
||||||
}
|
}
|
||||||
|
else if (args.Kind == ExtendedActivationKind.ShareTarget)
|
||||||
|
{
|
||||||
|
LogActivation("Processing redirected share target activation.");
|
||||||
|
await HandleShareTargetActivationAsync(args, activateWindow: true);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var shouldActivateWindow = true;
|
var shouldActivateWindow = true;
|
||||||
@@ -1527,6 +1636,12 @@ public partial class App : WinoApplication,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (activationArgs.Kind == ExtendedActivationKind.ShareTarget)
|
||||||
|
{
|
||||||
|
mode = WinoApplicationMode.Mail;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (activationArgs.Kind == ExtendedActivationKind.File &&
|
if (activationArgs.Kind == ExtendedActivationKind.File &&
|
||||||
activationArgs.Data is IFileActivatedEventArgs fileArgs)
|
activationArgs.Data is IFileActivatedEventArgs fileArgs)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -97,6 +97,15 @@
|
|||||||
</uap:Protocol>
|
</uap:Protocol>
|
||||||
</uap:Extension>
|
</uap:Extension>
|
||||||
|
|
||||||
|
<!-- Share target activation -->
|
||||||
|
<uap:Extension Category="windows.shareTarget">
|
||||||
|
<uap:ShareTarget>
|
||||||
|
<uap:SupportedFileTypes>
|
||||||
|
<uap:SupportsAnyFileType />
|
||||||
|
</uap:SupportedFileTypes>
|
||||||
|
</uap:ShareTarget>
|
||||||
|
</uap:Extension>
|
||||||
|
|
||||||
<!-- File Assosication: EML -->
|
<!-- File Assosication: EML -->
|
||||||
<uap:Extension Category="windows.fileTypeAssociation">
|
<uap:Extension Category="windows.fileTypeAssociation">
|
||||||
<uap:FileTypeAssociation Name="eml">
|
<uap:FileTypeAssociation Name="eml">
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ public static class ServicesContainerSetup
|
|||||||
services.AddSingleton<IApplicationConfiguration, ApplicationConfiguration>();
|
services.AddSingleton<IApplicationConfiguration, ApplicationConfiguration>();
|
||||||
services.AddSingleton<IWinoLogger, WinoLogger>();
|
services.AddSingleton<IWinoLogger, WinoLogger>();
|
||||||
services.AddSingleton<ILaunchProtocolService, LaunchProtocolService>();
|
services.AddSingleton<ILaunchProtocolService, LaunchProtocolService>();
|
||||||
|
services.AddSingleton<IShareActivationService, ShareActivationService>();
|
||||||
services.AddSingleton<IMimeFileService, MimeFileService>();
|
services.AddSingleton<IMimeFileService, MimeFileService>();
|
||||||
services.AddSingleton<ICalendarIcsFileService, CalendarIcsFileService>();
|
services.AddSingleton<ICalendarIcsFileService, CalendarIcsFileService>();
|
||||||
services.AddTransient<IMimeStorageService, MimeStorageService>();
|
services.AddTransient<IMimeStorageService, MimeStorageService>();
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
#nullable enable
|
||||||
|
using System;
|
||||||
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
using Wino.Core.Domain.Models.Launch;
|
||||||
|
|
||||||
|
namespace Wino.Services;
|
||||||
|
|
||||||
|
public class ShareActivationService : IShareActivationService
|
||||||
|
{
|
||||||
|
private readonly object _syncRoot = new();
|
||||||
|
private MailShareRequest? _pendingShareRequest;
|
||||||
|
private PendingComposeMailShareRequest? _pendingComposeShareRequest;
|
||||||
|
|
||||||
|
public MailShareRequest? PendingShareRequest
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (_syncRoot)
|
||||||
|
{
|
||||||
|
return _pendingShareRequest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
lock (_syncRoot)
|
||||||
|
{
|
||||||
|
_pendingShareRequest = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MailShareRequest? ConsumePendingShareRequest()
|
||||||
|
{
|
||||||
|
lock (_syncRoot)
|
||||||
|
{
|
||||||
|
var pendingRequest = _pendingShareRequest;
|
||||||
|
_pendingShareRequest = null;
|
||||||
|
return pendingRequest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearPendingShareRequest()
|
||||||
|
{
|
||||||
|
lock (_syncRoot)
|
||||||
|
{
|
||||||
|
_pendingShareRequest = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StagePendingComposeShareRequest(Guid draftUniqueId, MailShareRequest shareRequest)
|
||||||
|
{
|
||||||
|
lock (_syncRoot)
|
||||||
|
{
|
||||||
|
_pendingComposeShareRequest = new PendingComposeMailShareRequest(draftUniqueId, shareRequest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MailShareRequest? ConsumePendingComposeShareRequest(Guid draftUniqueId)
|
||||||
|
{
|
||||||
|
lock (_syncRoot)
|
||||||
|
{
|
||||||
|
if (_pendingComposeShareRequest?.DraftUniqueId != draftUniqueId)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var pendingRequest = _pendingComposeShareRequest.ShareRequest;
|
||||||
|
_pendingComposeShareRequest = null;
|
||||||
|
return pendingRequest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user