Improve UAC dialog

This commit is contained in:
Jack251970 2025-05-22 20:26:41 +08:00
parent 10d379f350
commit 484f91c52d
4 changed files with 243 additions and 4 deletions

View file

@ -99,5 +99,6 @@
<system:String x:Key="flowlauncher_plugin_program_run_failed">Unable to run {0}</system:String>
<system:String x:Key="flowlauncher_plugin_program_user_account_control_title">User Account Control</system:String>
<system:String x:Key="flowlauncher_plugin_program_user_account_control_subtitle">Do you want to allow this app to make changes to your device?</system:String>
<system:String x:Key="flowlauncher_plugin_program_user_account_control_program_location">Program location: {0}</system:String>
</ResourceDictionary>

View file

@ -221,10 +221,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
if (elevated)
{
// Since we are already elevated, we need to create UAC dialog manually
if (Main.Context.API.ShowMsgBox(
Main.Context.API.GetTranslation("flowlauncher_plugin_program_user_account_control_subtitle"),
Main.Context.API.GetTranslation("flowlauncher_plugin_program_user_account_control_title"),
MessageBoxButton.YesNo) != MessageBoxResult.Yes)
if (UACDialog.Show(IcoPath, Name, FullPath) != MessageBoxResult.Yes)
{
return;
}

View file

@ -0,0 +1,154 @@
<Window
x:Class="Flow.Launcher.Plugin.Program.UACDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Name="MessageBoxWindow"
Width="420"
Height="Auto"
Background="{DynamicResource PopuBGColor}"
Foreground="{DynamicResource PopupTextColor}"
ResizeMode="NoResize"
SizeToContent="Height"
Topmost="True"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<WindowChrome.WindowChrome>
<WindowChrome CaptionHeight="32" ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}" />
</WindowChrome.WindowChrome>
<Window.InputBindings>
<KeyBinding Key="Escape" Command="Close" />
</Window.InputBindings>
<Window.CommandBindings>
<CommandBinding Command="Close" Executed="KeyEsc_OnPress" />
</Window.CommandBindings>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition MinHeight="68" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button
Grid.Column="1"
Click="Button_Cancel"
Style="{StaticResource TitleBarCloseButtonStyle}">
<Path
Width="46"
Height="32"
Data="M 18,11 27,20 M 18,20 27,11"
Stroke="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
StrokeThickness="1">
<Path.Style>
<Style TargetType="Path">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsActive, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" Value="False">
<Setter Property="Opacity" Value="0.5" />
</DataTrigger>
</Style.Triggers>
</Style>
</Path.Style>
</Path>
</Button>
</Grid>
</StackPanel>
</StackPanel>
<Grid Grid.Row="1" Margin="30 0 30 24">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Margin="0 0 0 12">
<TextBlock
Grid.Column="1"
MaxWidth="400"
Margin="0 0 26 0"
VerticalAlignment="Center"
FontFamily="Segoe UI"
FontSize="20"
FontWeight="SemiBold"
Text="{DynamicResource flowlauncher_plugin_program_user_account_control_title}"
TextAlignment="Left"
TextWrapping="Wrap" />
</Grid>
<TextBlock
Grid.Row="1"
MaxWidth="400"
Margin="0 0 26 0"
HorizontalAlignment="Stretch"
FontSize="14"
Text="{DynamicResource flowlauncher_plugin_program_user_account_control_subtitle}"
TextAlignment="Left"
TextWrapping="Wrap" />
</Grid>
<Grid Grid.Row="2" Margin="30 0 30 16">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image
Name="Img"
Grid.Column="0"
Width="18"
Height="18"
Margin="0 0 10 0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
RenderOptions.BitmapScalingMode="Fant"
Stretch="UniformToFill" />
<TextBlock
x:Name="AppName"
Grid.Column="1"
MaxWidth="400"
Margin="0 0 26 0"
HorizontalAlignment="Stretch"
FontSize="16"
TextAlignment="Left"
TextWrapping="Wrap" />
</Grid>
<Grid Grid.Row="3" Margin="30 0 30 24">
<TextBlock
x:Name="ProgramLocation"
Grid.Column="1"
MaxWidth="400"
Margin="0 0 26 0"
HorizontalAlignment="Stretch"
FontSize="14"
TextAlignment="Left"
TextWrapping="Wrap" />
</Grid>
<Border
Grid.Row="4"
Margin="0 0 0 0"
Background="{DynamicResource PopupButtonAreaBGColor}"
BorderBrush="{DynamicResource PopupButtonAreaBorderColor}"
BorderThickness="0 1 0 0">
<WrapPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Horizontal">
<Button
x:Name="btnYes"
MinWidth="120"
Margin="5 0 5 0"
Click="Button_Click"
Content="{DynamicResource commonYes}" />
<Button
x:Name="btnNo"
MinWidth="120"
Margin="5 0 5 0"
Click="Button_Click"
Content="{DynamicResource commonNo}" />
</WrapPanel>
</Border>
</Grid>
</Window>

View file

@ -0,0 +1,87 @@
using System;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace Flow.Launcher.Plugin.Program
{
public partial class UACDialog : Window
{
private static readonly string ClassName = nameof(UACDialog);
private static UACDialog msgBox;
private static MessageBoxResult _result = MessageBoxResult.None;
private UACDialog()
{
InitializeComponent();
}
public static MessageBoxResult Show(string iconPath, string appName, string fullPath)
{
if (!Application.Current.Dispatcher.CheckAccess())
{
return Application.Current.Dispatcher.Invoke(() => Show(iconPath, appName, fullPath));
}
try
{
msgBox = new UACDialog
{
Title = Main.Context.API.GetTranslation("flowlauncher_plugin_program_user_account_control_title")
};
// Set icon & app name & program location
_ = msgBox.SetImageAsync(iconPath);
msgBox.AppName.Text = appName;
msgBox.ProgramLocation.Text = string.Format(
Main.Context.API.GetTranslation("flowlauncher_plugin_program_user_account_control_program_location"),
fullPath);
// Focus No by default
msgBox.btnNo.Focus();
_result = MessageBoxResult.No;
msgBox.ShowDialog();
return _result;
}
catch (Exception e)
{
Main.Context.API.LogError(ClassName, $"An error occurred: {e.Message}");
msgBox = null;
return MessageBoxResult.None;
}
}
private async Task SetImageAsync(string imagePath)
{
var imageSource = await Main.Context.API.LoadImageAsync(imagePath);
Img.Source = imageSource;
}
private void KeyEsc_OnPress(object sender, ExecutedRoutedEventArgs e)
{
DialogResult = false;
Close();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (sender == btnYes)
_result = MessageBoxResult.Yes;
else if (sender == btnNo)
_result = MessageBoxResult.No;
else
_result = MessageBoxResult.None;
msgBox.Close();
msgBox = null;
}
private void Button_Cancel(object sender, RoutedEventArgs e)
{
_result = MessageBoxResult.Cancel;
msgBox.Close();
msgBox = null;
}
}
}