Remove single entry and mode launch on ctrl press.
This commit is contained in:
@@ -7,25 +7,32 @@ internal static class AppModeActivationResolver
|
||||
{
|
||||
public static WinoApplicationMode Resolve(string? launchArguments, string? tileId, string? appId, WinoApplicationMode defaultMode = WinoApplicationMode.Mail)
|
||||
{
|
||||
if (TryResolveFromText(launchArguments, out var mode))
|
||||
if (TryResolveFromText(launchArguments, defaultMode, out var mode))
|
||||
return mode;
|
||||
|
||||
if (TryResolveFromText(tileId, out mode))
|
||||
if (TryResolveFromText(tileId, defaultMode, out mode))
|
||||
return mode;
|
||||
|
||||
if (TryResolveFromText(appId, out mode))
|
||||
if (TryResolveFromText(appId, defaultMode, out mode))
|
||||
return mode;
|
||||
|
||||
return defaultMode;
|
||||
}
|
||||
|
||||
private static bool TryResolveFromText(string? value, out WinoApplicationMode mode)
|
||||
private static bool TryResolveFromText(string? value, WinoApplicationMode defaultMode, out WinoApplicationMode mode)
|
||||
{
|
||||
mode = WinoApplicationMode.Mail;
|
||||
mode = defaultMode;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
return false;
|
||||
|
||||
if (Contains(value, "--mode=toggle-default") ||
|
||||
Contains(value, "mode=toggle-default"))
|
||||
{
|
||||
mode = GetOpposite(defaultMode);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Contains(value, "wino-calendar") ||
|
||||
Contains(value, "--mode=calendar") ||
|
||||
Contains(value, "mode=calendar") ||
|
||||
@@ -54,4 +61,9 @@ internal static class AppModeActivationResolver
|
||||
|
||||
private static bool EqualsToken(string source, string token)
|
||||
=> string.Equals(source.Trim(), token, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
private static WinoApplicationMode GetOpposite(WinoApplicationMode defaultMode)
|
||||
=> defaultMode == WinoApplicationMode.Mail
|
||||
? WinoApplicationMode.Calendar
|
||||
: WinoApplicationMode.Mail;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ public partial class App : WinoApplication,
|
||||
IRecipient<NewCalendarSynchronizationRequested>
|
||||
{
|
||||
private const int InboxSyncsPerFullSync = 20;
|
||||
private const string ToggleDefaultModeLaunchArgument = "--mode=toggle-default";
|
||||
private ISynchronizationManager? _synchronizationManager;
|
||||
private IPreferencesService? _preferencesService;
|
||||
private IAccountService? _accountService;
|
||||
@@ -136,7 +137,7 @@ public partial class App : WinoApplication,
|
||||
{
|
||||
base.OnLaunched(args);
|
||||
|
||||
// Always register notification callbacks for both app entries (Mail and Calendar).
|
||||
// Always register notification callbacks.
|
||||
TryRegisterAppNotifications();
|
||||
|
||||
// Initialize required services regardless of launch activation type.
|
||||
@@ -429,7 +430,14 @@ public partial class App : WinoApplication,
|
||||
if (activationArgs.Kind == ExtendedActivationKind.Launch &&
|
||||
activationArgs.Data is ILaunchActivatedEventArgs launchArgs)
|
||||
{
|
||||
shellWindow.HandleAppActivation(launchArgs.Arguments, launchArgs.TileId, Environment.CommandLine);
|
||||
var launchArguments = launchArgs.Arguments;
|
||||
|
||||
if (Program.TryConsumeCurrentProcessAlternateModeOverride())
|
||||
{
|
||||
launchArguments = AppendLaunchArgument(launchArguments, ToggleDefaultModeLaunchArgument);
|
||||
}
|
||||
|
||||
shellWindow.HandleAppActivation(launchArguments, launchArgs.TileId, Environment.CommandLine);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -662,7 +670,14 @@ public partial class App : WinoApplication,
|
||||
if (args.Kind == ExtendedActivationKind.Launch &&
|
||||
args.Data is ILaunchActivatedEventArgs launchArgs)
|
||||
{
|
||||
shellWindow.HandleAppActivation(launchArgs.Arguments, launchArgs.TileId);
|
||||
var launchArguments = launchArgs.Arguments;
|
||||
|
||||
if (Program.TryConsumeRedirectedAlternateModeOverride())
|
||||
{
|
||||
launchArguments = AppendLaunchArgument(launchArguments, ToggleDefaultModeLaunchArgument);
|
||||
}
|
||||
|
||||
shellWindow.HandleAppActivation(launchArguments, launchArgs.TileId);
|
||||
}
|
||||
else if (TryResolveActivationMode(args, _preferencesService?.DefaultApplicationMode ?? WinoApplicationMode.Mail, out var redirectedMode))
|
||||
{
|
||||
@@ -680,6 +695,13 @@ public partial class App : WinoApplication,
|
||||
private static string GetModeLaunchArgument(WinoApplicationMode mode)
|
||||
=> mode == WinoApplicationMode.Calendar ? "--mode=calendar" : "--mode=mail";
|
||||
|
||||
private static string AppendLaunchArgument(string? launchArguments, string launchArgument)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(launchArguments)
|
||||
? launchArgument
|
||||
: $"{launchArguments} {launchArgument}";
|
||||
}
|
||||
|
||||
private static bool TryResolveActivationMode(AppActivationArguments activationArgs, WinoApplicationMode defaultMode, out WinoApplicationMode mode)
|
||||
{
|
||||
mode = defaultMode;
|
||||
|
||||
@@ -90,33 +90,6 @@
|
||||
</uap:Protocol>
|
||||
</uap:Extension>
|
||||
|
||||
<!-- File Assosication: EML -->
|
||||
<uap:Extension Category="windows.fileTypeAssociation">
|
||||
<uap:FileTypeAssociation Name="eml">
|
||||
<uap:Logo>EML\eml.png</uap:Logo>
|
||||
<uap:SupportedFileTypes>
|
||||
<uap:FileType>.eml</uap:FileType>
|
||||
</uap:SupportedFileTypes>
|
||||
</uap:FileTypeAssociation>
|
||||
</uap:Extension>
|
||||
</Extensions>
|
||||
</Application>
|
||||
|
||||
<Application Id="CalendarApp"
|
||||
Executable="$targetnametoken$.exe"
|
||||
EntryPoint="$targetentrypoint$"
|
||||
uap10:Parameters="--mode=calendar">
|
||||
<uap:VisualElements
|
||||
DisplayName="Wino Calendar"
|
||||
Description="Wino.Mail.WinUI.Calendar"
|
||||
BackgroundColor="transparent"
|
||||
Square150x150Logo="Assets\AppEntries\CalendarAssets\Square150x150Logo.png"
|
||||
Square44x44Logo="Assets\AppEntries\CalendarAssets\Square44x44Logo.png">
|
||||
<uap:DefaultTile Wide310x150Logo="Assets\AppEntries\CalendarAssets\Wide310x150Logo.png" Square71x71Logo="Assets\AppEntries\CalendarAssets\SmallTile.png" Square310x310Logo="Assets\AppEntries\CalendarAssets\LargeTile.png"/>
|
||||
<uap:SplashScreen Image="Assets\AppEntries\CalendarAssets\SplashScreen.png" />
|
||||
</uap:VisualElements>
|
||||
|
||||
<Extensions>
|
||||
<!-- Protocol activation: webcal -->
|
||||
<uap:Extension Category="windows.protocol">
|
||||
<uap:Protocol Name="webcal">
|
||||
@@ -130,6 +103,16 @@
|
||||
</uap:Protocol>
|
||||
</uap:Extension>
|
||||
|
||||
<!-- File Assosication: EML -->
|
||||
<uap:Extension Category="windows.fileTypeAssociation">
|
||||
<uap:FileTypeAssociation Name="eml">
|
||||
<uap:Logo>EML\eml.png</uap:Logo>
|
||||
<uap:SupportedFileTypes>
|
||||
<uap:FileType>.eml</uap:FileType>
|
||||
</uap:SupportedFileTypes>
|
||||
</uap:FileTypeAssociation>
|
||||
</uap:Extension>
|
||||
|
||||
<!-- File Association: ICS -->
|
||||
<uap:Extension Category="windows.fileTypeAssociation">
|
||||
<uap:FileTypeAssociation Name="ics">
|
||||
|
||||
@@ -11,6 +11,13 @@ namespace Wino.Mail.WinUI;
|
||||
|
||||
public class Program
|
||||
{
|
||||
private const string SingleInstanceKey = "WinoMailSingleInstance";
|
||||
private const string ForceAlternateModeSignalEventName = "Local\\WinoMailForceAlternateMode";
|
||||
private const int VkControl = 0x11;
|
||||
|
||||
private static bool _forceAlternateModeOnLaunch;
|
||||
private static EventWaitHandle? _forceAlternateModeSignalHandle;
|
||||
|
||||
[STAThread]
|
||||
static int Main(string[] args)
|
||||
{
|
||||
@@ -35,15 +42,24 @@ public class Program
|
||||
{
|
||||
bool isRedirect = false;
|
||||
AppActivationArguments args = AppInstance.GetCurrent().GetActivatedEventArgs();
|
||||
AppInstance keyInstance = AppInstance.FindOrRegisterForKey("WinoMailSingleInstance");
|
||||
_forceAlternateModeOnLaunch = args.Kind == ExtendedActivationKind.Launch && IsCtrlKeyDown();
|
||||
|
||||
AppInstance keyInstance = AppInstance.FindOrRegisterForKey(SingleInstanceKey);
|
||||
|
||||
if (keyInstance.IsCurrent)
|
||||
{
|
||||
EnsureAlternateModeOverrideSignalHandle();
|
||||
keyInstance.Activated += OnActivated;
|
||||
}
|
||||
else
|
||||
{
|
||||
isRedirect = true;
|
||||
|
||||
if (_forceAlternateModeOnLaunch)
|
||||
{
|
||||
SignalForceAlternateMode();
|
||||
}
|
||||
|
||||
RedirectActivationTo(args, keyInstance);
|
||||
}
|
||||
|
||||
@@ -66,8 +82,83 @@ public class Program
|
||||
[DllImport("user32.dll")]
|
||||
static extern bool SetForegroundWindow(IntPtr hWnd);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern short GetAsyncKeyState(int vKey);
|
||||
|
||||
private static IntPtr redirectEventHandle = IntPtr.Zero;
|
||||
|
||||
public static bool TryConsumeCurrentProcessAlternateModeOverride()
|
||||
{
|
||||
if (!_forceAlternateModeOnLaunch)
|
||||
return false;
|
||||
|
||||
_forceAlternateModeOnLaunch = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool TryConsumeRedirectedAlternateModeOverride()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_forceAlternateModeSignalHandle != null)
|
||||
{
|
||||
return _forceAlternateModeSignalHandle.WaitOne(0);
|
||||
}
|
||||
|
||||
if (!EventWaitHandle.TryOpenExisting(ForceAlternateModeSignalEventName, out EventWaitHandle? signal))
|
||||
return false;
|
||||
|
||||
using (signal)
|
||||
{
|
||||
return signal.WaitOne(0);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsCtrlKeyDown() => (GetAsyncKeyState(VkControl) & 0x8000) != 0;
|
||||
|
||||
private static void EnsureAlternateModeOverrideSignalHandle()
|
||||
{
|
||||
if (_forceAlternateModeSignalHandle != null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
_forceAlternateModeSignalHandle = new EventWaitHandle(false, EventResetMode.AutoReset, ForceAlternateModeSignalEventName);
|
||||
}
|
||||
catch
|
||||
{
|
||||
_forceAlternateModeSignalHandle = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SignalForceAlternateMode()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (EventWaitHandle.TryOpenExisting(ForceAlternateModeSignalEventName, out EventWaitHandle? signal))
|
||||
{
|
||||
using (signal)
|
||||
{
|
||||
signal.Set();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
using EventWaitHandle fallbackSignal = new(false, EventResetMode.AutoReset, ForceAlternateModeSignalEventName);
|
||||
fallbackSignal.Set();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore signaling failures and continue with normal activation redirection.
|
||||
}
|
||||
}
|
||||
|
||||
// Do the redirection on another thread, and use a non-blocking
|
||||
// wait method to wait for the redirection to complete.
|
||||
public static void RedirectActivationTo(AppActivationArguments args,
|
||||
|
||||
@@ -21,7 +21,6 @@ namespace Wino.Mail.WinUI.Services;
|
||||
public class NotificationBuilder : INotificationBuilder
|
||||
{
|
||||
private const string MailApplicationId = "App";
|
||||
private const string CalendarApplicationId = "CalendarApp";
|
||||
|
||||
private readonly IAccountService _accountService;
|
||||
private readonly IFolderService _folderService;
|
||||
@@ -326,8 +325,8 @@ public class NotificationBuilder : INotificationBuilder
|
||||
|
||||
private static string GetAppUserModelId(ToastTargetApp targetApp)
|
||||
{
|
||||
var appId = targetApp == ToastTargetApp.Mail ? MailApplicationId : CalendarApplicationId;
|
||||
return $"{Package.Current.Id.FamilyName}!{appId}";
|
||||
_ = targetApp;
|
||||
return $"{Package.Current.Id.FamilyName}!{MailApplicationId}";
|
||||
}
|
||||
|
||||
private enum ToastTargetApp
|
||||
|
||||
Reference in New Issue
Block a user