mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 03:37:59 +01:00
Continuing part deux
This commit is contained in:
@@ -356,6 +356,29 @@
|
||||
<Project Path="src/modules/CropAndLock/CropAndLock/CropAndLock.vcxproj" Id="f5e1146e-b7b3-4e11-85fd-270a500bd78c" />
|
||||
<Project Path="src/modules/CropAndLock/CropAndLockModuleInterface/CropAndLockModuleInterface.vcxproj" Id="3157fa75-86cf-4ee2-8f62-c43f776493c6" />
|
||||
</Folder>
|
||||
<Folder Name="/modules/Deux/" />
|
||||
<Folder Name="/modules/Deux/SDK/">
|
||||
<Project Path="src/modules/Deux/SDK/Microsoft.CommandPalette.Extensions.Toolkit/Microsoft.CommandPalette.Extensions.Toolkit.csproj">
|
||||
<Platform Solution="*|ARM64" Project="ARM64" />
|
||||
<Platform Solution="*|x64" Project="x64" />
|
||||
</Project>
|
||||
<Project Path="src/modules/Deux/SDK/Microsoft.CommandPalette.Extensions/Microsoft.CommandPalette.Extensions.vcxproj" Id="7997dad4-31d6-496b-95db-6c028d699370" />
|
||||
</Folder>
|
||||
<Folder Name="/modules/Deux/UI/">
|
||||
<Project Path="src/modules/Deux/UI/Microsoft.CommandPalette.UI.Models/Microsoft.CommandPalette.UI.Models.csproj">
|
||||
<Platform Solution="*|ARM64" Project="ARM64" />
|
||||
<Platform Solution="*|x64" Project="x64" />
|
||||
</Project>
|
||||
<Project Path="src/modules/Deux/UI/Microsoft.CommandPalette.UI.ViewModels/Microsoft.CommandPalette.UI.ViewModels.csproj">
|
||||
<Platform Solution="*|ARM64" Project="ARM64" />
|
||||
<Platform Solution="*|x64" Project="x64" />
|
||||
</Project>
|
||||
<Project Path="src/modules/Deux/UI/Microsoft.CommandPalette.UI/Microsoft.CommandPalette.UI.csproj">
|
||||
<Platform Solution="*|ARM64" Project="ARM64" />
|
||||
<Platform Solution="*|x64" Project="x64" />
|
||||
<Deploy />
|
||||
</Project>
|
||||
</Folder>
|
||||
<Folder Name="/modules/EnvironmentVariables/">
|
||||
<Project Path="src/modules/EnvironmentVariables/EnvironmentVariables/EnvironmentVariables.csproj">
|
||||
<Platform Solution="*|ARM64" Project="ARM64" />
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.CommandPalette.UI.Models.Messages;
|
||||
|
||||
public record DismissMessage()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.CommandPalette.UI.Models.Messages;
|
||||
|
||||
public record GoBackMessage(bool WithAnimation = true, bool FocusSearch = true)
|
||||
{
|
||||
// TODO! sticking these properties here feels like leaking the UI into the models
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.CommandPalette.UI.Models.Messages;
|
||||
|
||||
// TODO! sticking these properties here feels like leaking the UI into the models
|
||||
public record GoHomeMessage(bool WithAnimation = true, bool FocusSearch = true)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.CommandPalette.UI.Models.Messages;
|
||||
|
||||
/// <summary>
|
||||
/// Message to request hiding the window.
|
||||
/// </summary>
|
||||
public partial record HideWindowMessage()
|
||||
{
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.CmdPal.UI.Models.Messages;
|
||||
namespace Microsoft.CommandPalette.UI.Models.Messages;
|
||||
|
||||
public record HotkeySummonMessage(string CommandId, IntPtr Hwnd)
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.CmdPal.UI.Models.Messages;
|
||||
namespace Microsoft.CommandPalette.UI.Models.Messages;
|
||||
|
||||
public record OpenSettingsMessage()
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.CmdPal.UI.Models.Messages;
|
||||
namespace Microsoft.CommandPalette.UI.Models.Messages;
|
||||
|
||||
/// <summary>
|
||||
/// Message which closes the application. Used by <see cref="QuitCommand"/> via <see cref="BuiltInsCommandProvider"/>.
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.CommandPalette.UI.Models.Messages;
|
||||
|
||||
public record ReloadCommandsMessage()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.CommandPalette.UI.Models.Messages;
|
||||
|
||||
public record ShowWindowMessage(IntPtr Hwnd)
|
||||
{
|
||||
}
|
||||
@@ -25,6 +25,11 @@
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" />
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -39,6 +44,7 @@
|
||||
<ProjectReference Include="..\..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
<ProjectReference Include="..\..\SDK\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Events\" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CommandPalette.UI.ViewModels.Helpers;
|
||||
using Microsoft.UI;
|
||||
using Windows.System;
|
||||
using Windows.UI;
|
||||
using DispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue;
|
||||
|
||||
namespace Microsoft.CommandPalette.UI.ViewModels;
|
||||
|
||||
public sealed partial class DevRibbonViewModel : ObservableObject
|
||||
{
|
||||
private const int MaxLogEntries = 2;
|
||||
private const string Release = "Release";
|
||||
private const string Debug = "Debug";
|
||||
|
||||
private static readonly Color ReleaseAotColor = ColorHelper.FromArgb(255, 124, 58, 237);
|
||||
private static readonly Color ReleaseColor = ColorHelper.FromArgb(255, 51, 65, 85);
|
||||
private static readonly Color DebugAotColor = ColorHelper.FromArgb(255, 99, 102, 241);
|
||||
private static readonly Color DebugColor = ColorHelper.FromArgb(255, 107, 114, 128);
|
||||
|
||||
private readonly DispatcherQueue _dispatcherQueue;
|
||||
|
||||
public DevRibbonViewModel()
|
||||
{
|
||||
_dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||
Trace.Listeners.Add(new DevRibbonTraceListener(this));
|
||||
|
||||
var configLabel = BuildConfiguration == Release ? "RLS" : "DBG"; /* #no-spell-check-line */
|
||||
var aotLabel = BuildInfo.IsNativeAot ? "⚡AOT" : "NO AOT";
|
||||
Tag = $"{configLabel} | {aotLabel}";
|
||||
|
||||
TagColor = (BuildConfiguration, BuildInfo.IsNativeAot) switch
|
||||
{
|
||||
(Release, true) => ReleaseAotColor,
|
||||
(Release, false) => ReleaseColor,
|
||||
(Debug, true) => DebugAotColor,
|
||||
(Debug, false) => DebugColor,
|
||||
_ => Colors.Fuchsia,
|
||||
};
|
||||
}
|
||||
|
||||
public string BuildConfiguration => BuildInfo.Configuration;
|
||||
|
||||
public bool IsAotReleaseConfiguration => BuildConfiguration == Release && BuildInfo.IsNativeAot;
|
||||
|
||||
public bool IsAot => BuildInfo.IsNativeAot;
|
||||
|
||||
public bool IsPublishTrimmed => BuildInfo.PublishTrimmed;
|
||||
|
||||
public ObservableCollection<LogEntryViewModel> LatestLogs { get; } = [];
|
||||
|
||||
[ObservableProperty]
|
||||
public partial int WarningCount { get; private set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial int ErrorCount { get; private set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string Tag { get; private set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Color TagColor { get; private set; }
|
||||
|
||||
[RelayCommand]
|
||||
private async Task OpenLogFileAsync()
|
||||
{
|
||||
var logPath = Logger.CurrentLogFile;
|
||||
if (File.Exists(logPath))
|
||||
{
|
||||
await Launcher.LaunchUriAsync(new Uri(logPath));
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task OpenLogFolderAsync()
|
||||
{
|
||||
var logFolderPath = Logger.CurrentVersionLogDirectoryPath;
|
||||
if (Directory.Exists(logFolderPath))
|
||||
{
|
||||
await Launcher.LaunchFolderPathAsync(logFolderPath);
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void ResetErrorCounters()
|
||||
{
|
||||
WarningCount = 0;
|
||||
ErrorCount = 0;
|
||||
LatestLogs.Clear();
|
||||
}
|
||||
|
||||
private sealed partial class DevRibbonTraceListener(DevRibbonViewModel viewModel) : TraceListener
|
||||
{
|
||||
private const string TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff";
|
||||
|
||||
[GeneratedRegex(@"^\[(?<timestamp>.*?)\] \[(?<severity>.*?)\] (?<message>.*)")]
|
||||
private static partial Regex LogRegex();
|
||||
|
||||
private readonly Lock _lock = new();
|
||||
private LogEntryViewModel? _latestLogEntry;
|
||||
|
||||
public override void Write(string? message)
|
||||
{
|
||||
// Not required for this scenario.
|
||||
}
|
||||
|
||||
public override void WriteLine(string? message)
|
||||
{
|
||||
if (message is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
var match = LogRegex().Match(message);
|
||||
if (match.Success)
|
||||
{
|
||||
var severity = match.Groups["severity"].Value;
|
||||
var isWarning = severity.Equals("Warning", StringComparison.OrdinalIgnoreCase);
|
||||
var isError = severity.Equals("Error", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (isWarning || isError)
|
||||
{
|
||||
var timestampStr = match.Groups["timestamp"].Value;
|
||||
var timestamp = DateTimeOffset.TryParseExact(
|
||||
timestampStr,
|
||||
TimestampFormat,
|
||||
CultureInfo.InvariantCulture,
|
||||
DateTimeStyles.AssumeLocal,
|
||||
out var parsed)
|
||||
? parsed
|
||||
: DateTimeOffset.Now;
|
||||
|
||||
var logEntry = new LogEntryViewModel(
|
||||
timestamp,
|
||||
severity,
|
||||
match.Groups["message"].Value,
|
||||
string.Empty);
|
||||
|
||||
_latestLogEntry = logEntry;
|
||||
|
||||
viewModel._dispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
if (isWarning)
|
||||
{
|
||||
viewModel.WarningCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
viewModel.ErrorCount++;
|
||||
}
|
||||
|
||||
viewModel.LatestLogs.Insert(0, logEntry);
|
||||
|
||||
while (viewModel.LatestLogs.Count > MaxLogEntries)
|
||||
{
|
||||
viewModel.LatestLogs.RemoveAt(viewModel.LatestLogs.Count - 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
_latestLogEntry = null;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (IndentLevel > 0 && _latestLogEntry is { } latest)
|
||||
{
|
||||
viewModel._dispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
latest.AppendDetails(message);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Microsoft.CommandPalette.UI.ViewModels.Helpers;
|
||||
|
||||
public static class BuildInfo
|
||||
{
|
||||
#if DEBUG
|
||||
public const string Configuration = "Debug";
|
||||
#else
|
||||
public const string Configuration = "Release";
|
||||
#endif
|
||||
|
||||
// Runtime AOT detection
|
||||
public static bool IsNativeAot => !RuntimeFeature.IsDynamicCodeSupported;
|
||||
|
||||
// From assembly metadata (build-time values)
|
||||
public static bool PublishTrimmed => GetBoolMetadata("PublishTrimmed", false);
|
||||
|
||||
// From assembly metadata (build-time values)
|
||||
public static bool PublishAot => GetBoolMetadata("PublishAot", false);
|
||||
|
||||
public static bool IsCiBuild => GetBoolMetadata("CIBuild", false);
|
||||
|
||||
private static string? GetMetadata(string key) =>
|
||||
Assembly.GetExecutingAssembly()
|
||||
.GetCustomAttributes<AssemblyMetadataAttribute>()
|
||||
.FirstOrDefault(a => a.Key == key)?.Value;
|
||||
|
||||
private static bool GetBoolMetadata(string key, bool defaultValue) =>
|
||||
bool.TryParse(GetMetadata(key), out var result) ? result : defaultValue;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Globalization;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace Microsoft.CommandPalette.UI.ViewModels;
|
||||
|
||||
public sealed partial class LogEntryViewModel : ObservableObject
|
||||
{
|
||||
private const int HeaderMaxLength = 80;
|
||||
private const string WarningGlyph = "\uE7BA";
|
||||
private const string ErrorGlyph = "\uEA39";
|
||||
private const string TimestampFormat = "HH:mm:ss";
|
||||
|
||||
private DateTimeOffset Timestamp { get; }
|
||||
|
||||
private string Severity { get; }
|
||||
|
||||
private string Message { get; }
|
||||
|
||||
private string FormattedTimestamp { get; }
|
||||
|
||||
public string SeverityGlyph { get; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string Header { get; private set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string Description { get; private set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string Details { get; private set; }
|
||||
|
||||
public LogEntryViewModel(DateTimeOffset timestamp, string severity, string message, string details)
|
||||
{
|
||||
Timestamp = timestamp;
|
||||
Severity = severity;
|
||||
Message = message;
|
||||
Details = details;
|
||||
|
||||
SeverityGlyph = severity.ToUpperInvariant() switch
|
||||
{
|
||||
"WARNING" => WarningGlyph,
|
||||
"ERROR" => ErrorGlyph,
|
||||
_ => string.Empty,
|
||||
};
|
||||
|
||||
FormattedTimestamp = timestamp.ToString(TimestampFormat, CultureInfo.CurrentCulture);
|
||||
Description = $"{FormattedTimestamp} • {Message}";
|
||||
Header = Message;
|
||||
}
|
||||
|
||||
public void AppendDetails(string? message)
|
||||
{
|
||||
if (string.IsNullOrEmpty(message))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Details += Environment.NewLine + message;
|
||||
|
||||
// Make header the second line of details (because that's actually the message itself):
|
||||
var detailsLines = Details.Split([Environment.NewLine], StringSplitOptions.None);
|
||||
if (detailsLines.Length < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Header = detailsLines[1].Trim();
|
||||
if (Header.Length > HeaderMaxLength)
|
||||
{
|
||||
Header = Header[..(HeaderMaxLength - 1)] + "…";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="Microsoft.CommandPalette.UI.Controls.DevRibbon"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:converters="using:CommunityToolkit.WinUI.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:viewModels="using:Microsoft.CommandPalette.UI.ViewModels"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<DataTemplate x:Key="LogEntryTemplate" x:DataType="viewModels:LogEntryViewModel">
|
||||
<controls:SettingsExpander Description="{x:Bind Description}" Header="{x:Bind Header}">
|
||||
<controls:SettingsExpander.HeaderIcon>
|
||||
<FontIcon Glyph="{x:Bind SeverityGlyph}" />
|
||||
</controls:SettingsExpander.HeaderIcon>
|
||||
<controls:SettingsExpander.Items>
|
||||
<controls:SettingsCard HorizontalContentAlignment="Stretch" ContentAlignment="Vertical">
|
||||
<ScrollViewer
|
||||
MaxWidth="1160"
|
||||
HorizontalScrollMode="Auto"
|
||||
VerticalScrollMode="Auto">
|
||||
<TextBlock
|
||||
FontFamily="Consolas"
|
||||
FontSize="11"
|
||||
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"
|
||||
IsTextSelectionEnabled="True"
|
||||
Text="{x:Bind Details}"
|
||||
TextWrapping="NoWrap" />
|
||||
</ScrollViewer>
|
||||
</controls:SettingsCard>
|
||||
</controls:SettingsExpander.Items>
|
||||
</controls:SettingsExpander>
|
||||
</DataTemplate>
|
||||
|
||||
<converters:BoolToVisibilityConverter
|
||||
x:Key="InvertedBoolToVisibilityConverter"
|
||||
FalseValue="Visible"
|
||||
TrueValue="Collapsed" />
|
||||
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<Border
|
||||
x:Name="RootBorder"
|
||||
Height="26"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
Background="{ThemeResource SettingsCardBackground}"
|
||||
BorderBrush="{ThemeResource SurfaceStrokeColorFlyoutBrush}"
|
||||
BorderThickness="1,0,1,1"
|
||||
CornerRadius="0,0,8,8"
|
||||
Opacity="0.3">
|
||||
<Button
|
||||
Padding="0"
|
||||
CornerRadius="0,0,8,8"
|
||||
FontSize="11"
|
||||
PointerEntered="DevRibbonButton_PointerEntered"
|
||||
PointerExited="DevRibbonButton_PointerExited">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<StackPanel
|
||||
Padding="8,4"
|
||||
VerticalAlignment="Center"
|
||||
Background="DarkOrange"
|
||||
Orientation="Horizontal"
|
||||
Visibility="{x:Bind VisibleIfGreaterThanZero(ViewModel.WarningCount), Mode=OneWay}">
|
||||
<FontIcon
|
||||
Margin="0,0,8,0"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
FontSize="12"
|
||||
Glyph="" />
|
||||
<TextBlock VerticalAlignment="Center">
|
||||
<Run Text="{x:Bind ViewModel.WarningCount, Mode=OneWay}" />
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Padding="8,4"
|
||||
VerticalAlignment="Center"
|
||||
Background="Maroon"
|
||||
Orientation="Horizontal"
|
||||
Visibility="{x:Bind VisibleIfGreaterThanZero(ViewModel.ErrorCount), Mode=OneWay}">
|
||||
<FontIcon
|
||||
Margin="0,0,8,0"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
FontSize="12"
|
||||
Glyph="" />
|
||||
<TextBlock VerticalAlignment="Center">
|
||||
<Run Text="{x:Bind ViewModel.ErrorCount, Mode=OneWay}" />
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<Border Padding="8,4">
|
||||
<Border.Background>
|
||||
<SolidColorBrush Color="{x:Bind ViewModel.TagColor}" />
|
||||
</Border.Background>
|
||||
<TextBlock Padding="4" VerticalAlignment="Center">
|
||||
<Run Text="{x:Bind ViewModel.Tag}" />
|
||||
</TextBlock>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
<Button.Flyout>
|
||||
<Flyout
|
||||
Placement="Bottom"
|
||||
ShouldConstrainToRootBounds="False"
|
||||
SystemBackdrop="{ThemeResource AcrylicBackgroundFillColorDefaultBackdrop}">
|
||||
<Flyout.FlyoutPresenterStyle>
|
||||
<Style BasedOn="{StaticResource DefaultFlyoutPresenterStyle}" TargetType="FlyoutPresenter">
|
||||
<Setter Property="MinWidth" Value="600" />
|
||||
<Setter Property="MaxWidth" Value="1200" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
</Style>
|
||||
</Flyout.FlyoutPresenterStyle>
|
||||
|
||||
<Grid x:Name="FlyoutContent">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Padding="16" Spacing="8">
|
||||
|
||||
<!-- Logs section -->
|
||||
<TextBlock
|
||||
Margin="1,0,0,6"
|
||||
Style="{ThemeResource SettingsSectionHeaderTextBlockStyle}"
|
||||
Text="Logs" />
|
||||
<ItemsControl ItemTemplate="{StaticResource LogEntryTemplate}" ItemsSource="{x:Bind ViewModel.LatestLogs, Mode=OneWay}" />
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<Button Command="{x:Bind ViewModel.OpenLogFileCommand}" Content="Open Log File" />
|
||||
<Button Command="{x:Bind ViewModel.OpenLogFolderCommand}" Content="Open Log Folder" />
|
||||
<Button Command="{x:Bind ViewModel.ResetErrorCountersCommand}" Content="Clear Counters" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Build info section -->
|
||||
<TextBlock Style="{ThemeResource SettingsSectionHeaderTextBlockStyle}" Text="Build Info" />
|
||||
<Border
|
||||
Padding="16"
|
||||
Background="{ThemeResource SettingsCardBackground}"
|
||||
BorderBrush="{ThemeResource SettingsCardBorderBrush}"
|
||||
BorderThickness="1">
|
||||
<Grid ColumnSpacing="8">
|
||||
<Grid.Resources>
|
||||
<Style
|
||||
x:Key="KeyTextBlockStyle"
|
||||
BasedOn="{StaticResource CaptionTextBlockStyle}"
|
||||
TargetType="TextBlock">
|
||||
<Setter Property="IsTextSelectionEnabled" Value="True" />
|
||||
<Setter Property="Foreground" Value="{ThemeResource TextFillColorSecondaryBrush}" />
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="ValueTextBlockStyle"
|
||||
BasedOn="{StaticResource CaptionTextBlockStyle}"
|
||||
TargetType="TextBlock">
|
||||
<Setter Property="IsTextSelectionEnabled" Value="True" />
|
||||
<Setter Property="TextAlignment" Value="Right" />
|
||||
</Style>
|
||||
</Grid.Resources>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Style="{StaticResource KeyTextBlockStyle}"
|
||||
Text="Configuration:" />
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Style="{StaticResource ValueTextBlockStyle}"
|
||||
Text="{x:Bind ViewModel.BuildConfiguration, Mode=OneWay}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Style="{StaticResource KeyTextBlockStyle}"
|
||||
Text="AOT:" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Style="{StaticResource ValueTextBlockStyle}"
|
||||
Text="{x:Bind ViewModel.IsAot, Mode=OneWay}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Style="{StaticResource KeyTextBlockStyle}"
|
||||
Text="Trimmed:" />
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Style="{StaticResource ValueTextBlockStyle}"
|
||||
Text="{x:Bind ViewModel.IsPublishTrimmed, Mode=OneWay}" />
|
||||
|
||||
</Grid>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Footer -->
|
||||
<Border
|
||||
Grid.Row="1"
|
||||
Padding="16"
|
||||
Background="{ThemeResource SettingsCardBackground}"
|
||||
BorderBrush="{ThemeResource SettingsCardBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="{ThemeResource ControlCornerRadius}"
|
||||
Visibility="{x:Bind ViewModel.IsAotReleaseConfiguration, Mode=OneWay, Converter={StaticResource InvertedBoolToVisibilityConverter}}">
|
||||
<TextBlock Text="Warning: Test in Release/AOT configuration to verify everything works." TextWrapping="Wrap" />
|
||||
</Border>
|
||||
|
||||
</Grid>
|
||||
</Flyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
</Border>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="PointerOver">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="RootBorder"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="1.0"
|
||||
Duration="0:0:0.1" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="SeverityStates">
|
||||
<VisualState x:Name="NoLog" />
|
||||
<VisualState x:Name="WarningLog">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SeverityIcon" Storyboard.TargetProperty="Glyph">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="ErrorLog">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SeverityIcon" Storyboard.TargetProperty="Glyph">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.CommandPalette.UI.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
|
||||
namespace Microsoft.CommandPalette.UI.Controls;
|
||||
|
||||
internal sealed partial class DevRibbon : UserControl
|
||||
{
|
||||
public DevRibbonViewModel ViewModel { get; }
|
||||
|
||||
public DevRibbon()
|
||||
{
|
||||
InitializeComponent();
|
||||
ViewModel = new DevRibbonViewModel();
|
||||
|
||||
if (FlyoutContent != null)
|
||||
{
|
||||
FlyoutContent.DataContext = ViewModel;
|
||||
}
|
||||
}
|
||||
|
||||
private void DevRibbonButton_PointerEntered(object sender, PointerRoutedEventArgs e)
|
||||
{
|
||||
VisualStateManager.GoToState(this, "PointerOver", true);
|
||||
}
|
||||
|
||||
private void DevRibbonButton_PointerExited(object sender, PointerRoutedEventArgs e)
|
||||
{
|
||||
VisualStateManager.GoToState(this, "Normal", true);
|
||||
}
|
||||
|
||||
private Visibility VisibleIfGreaterThanZero(int value)
|
||||
{
|
||||
return value > 0 ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using ManagedCommon;
|
||||
|
||||
using Windows.System;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
|
||||
namespace Microsoft.CommandPalette.UI.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// A class that listens for local keyboard events using a Windows hook.
|
||||
/// </summary>
|
||||
internal sealed partial class LocalKeyboardListener : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Event that is raised when a key is pressed down.
|
||||
/// </summary>
|
||||
public event EventHandler<LocalKeyboardListenerKeyPressedEventArgs>? KeyPressed;
|
||||
|
||||
private bool _disposed;
|
||||
private UnhookWindowsHookExSafeHandle? _handle;
|
||||
private HOOKPROC? _hookProc; // Keep reference to prevent GC collection
|
||||
|
||||
/// <summary>
|
||||
/// Registers a global keyboard hook to listen for key down events.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Throws if the hook could not be registered, which may happen if the system is unable to set the hook.
|
||||
/// </exception>
|
||||
public void RegisterKeyboardHook()
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
if (_handle is not null && !_handle.IsInvalid)
|
||||
{
|
||||
// Hook is already set
|
||||
return;
|
||||
}
|
||||
|
||||
_hookProc = KeyEventHook;
|
||||
if (!SetWindowKeyHook(_hookProc))
|
||||
{
|
||||
throw new InvalidOperationException("Failed to register keyboard hook.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to register a global keyboard hook to listen for key down events.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the keyboard hook was successfully registered; otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
public bool Start()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
RegisterKeyboardHook();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Failed to register hook", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void UnregisterKeyboardHook()
|
||||
{
|
||||
if (_handle is not null && !_handle.IsInvalid)
|
||||
{
|
||||
// The SafeHandle should automatically call UnhookWindowsHookEx when disposed
|
||||
_handle.Dispose();
|
||||
_handle = null;
|
||||
}
|
||||
|
||||
_hookProc = null;
|
||||
}
|
||||
|
||||
private bool SetWindowKeyHook(HOOKPROC hookProc)
|
||||
{
|
||||
if (_handle is not null && !_handle.IsInvalid)
|
||||
{
|
||||
// Hook is already set
|
||||
return false;
|
||||
}
|
||||
|
||||
_handle = PInvoke.SetWindowsHookEx(
|
||||
WINDOWS_HOOK_ID.WH_KEYBOARD,
|
||||
hookProc,
|
||||
PInvoke.GetModuleHandle(null),
|
||||
PInvoke.GetCurrentThreadId());
|
||||
|
||||
// Check if the hook was successfully set
|
||||
return _handle is not null && !_handle.IsInvalid;
|
||||
}
|
||||
|
||||
private static bool IsKeyDownHook(LPARAM lParam)
|
||||
{
|
||||
// The 30th bit tells what the previous key state is with 0 being the "UP" state
|
||||
// For more info see https://learn.microsoft.com/windows/win32/winmsg/keyboardproc#lparam-in
|
||||
return ((lParam.Value >> 30) & 1) == 0;
|
||||
}
|
||||
|
||||
private LRESULT KeyEventHook(int nCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (nCode >= 0 && IsKeyDownHook(lParam))
|
||||
{
|
||||
InvokeKeyDown((VirtualKey)wParam.Value);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Failed when invoking key down keyboard hook event", ex);
|
||||
}
|
||||
|
||||
// Call next hook in chain - pass null as first parameter for current hook
|
||||
return PInvoke.CallNextHookEx(null, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
private void InvokeKeyDown(VirtualKey virtualKey)
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
KeyPressed?.Invoke(this, new LocalKeyboardListenerKeyPressedEventArgs(virtualKey));
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
UnregisterKeyboardHook();
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Windows.System;
|
||||
|
||||
namespace Microsoft.CommandPalette.UI.Helpers;
|
||||
|
||||
public class LocalKeyboardListenerKeyPressedEventArgs(VirtualKey key) : EventArgs
|
||||
{
|
||||
public VirtualKey Key { get; } = key;
|
||||
}
|
||||
@@ -10,7 +10,9 @@
|
||||
Height="480"
|
||||
MinWidth="320"
|
||||
MinHeight="240"
|
||||
Activated="MainWindow_Activated"
|
||||
Closed="MainWindow_Closed"
|
||||
mc:Ignorable="d">
|
||||
<Frame x:Name="RootElement">
|
||||
</Frame>
|
||||
<Grid x:Name="RootElement">
|
||||
</Grid>
|
||||
</winuiex:WindowEx>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,7 @@
|
||||
x:Class="Microsoft.CommandPalette.UI.Pages.ShellPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:animations="using:CommunityToolkit.WinUI.Animations"
|
||||
xmlns:converters="using:CommunityToolkit.WinUI.Converters"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Microsoft.CommandPalette.UI.Pages"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
@@ -12,6 +13,14 @@
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
<ResourceDictionary>
|
||||
<converters:BoolToVisibilityConverter
|
||||
x:Key="BoolToInvertedVisibilityConverter"
|
||||
FalseValue="Visible"
|
||||
TrueValue="Collapsed" />
|
||||
</ResourceDictionary>
|
||||
</Page.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
@@ -26,178 +35,6 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Back button and search box -->
|
||||
<Grid
|
||||
x:Name="TopBarGrid"
|
||||
Padding="0,12,0,12"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
|
||||
BorderThickness="0,0,0,1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Back button -->
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Image
|
||||
Width="20"
|
||||
Margin="20,0,6,0"
|
||||
HorizontalAlignment="Center"
|
||||
ui:VisualExtensions.NormalizedCenterPoint="0.5,0.5"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Source="ms-appx:///Assets/icon.svg"
|
||||
Visibility="{x:Bind viewModel.IsNested, Mode=OneWay, Converter={StaticResource BoolToInvertedVisibilityConverter}}">
|
||||
<animations:Implicit.ShowAnimations>
|
||||
<animations:OpacityAnimation
|
||||
EasingMode="EaseIn"
|
||||
EasingType="Cubic"
|
||||
From="0"
|
||||
To="1.0"
|
||||
Duration="0:0:0.187" />
|
||||
<animations:ScaleAnimation
|
||||
EasingMode="EaseIn"
|
||||
EasingType="Cubic"
|
||||
From="0.5"
|
||||
To="1"
|
||||
Duration="0:0:0.187" />
|
||||
</animations:Implicit.ShowAnimations>
|
||||
<animations:Implicit.HideAnimations>
|
||||
<animations:OpacityAnimation
|
||||
EasingMode="EaseOut"
|
||||
EasingType="Cubic"
|
||||
From="1.0"
|
||||
To="0"
|
||||
Duration="0:0:0.187" />
|
||||
<animations:ScaleAnimation
|
||||
EasingMode="EaseOut"
|
||||
EasingType="Cubic"
|
||||
From="1"
|
||||
To="0.5"
|
||||
Duration="0:0:0.187" />
|
||||
</animations:Implicit.HideAnimations>
|
||||
</Image>
|
||||
<Button
|
||||
x:Name="BackButton"
|
||||
x:Uid="BackButton"
|
||||
Margin="4,0,4,0"
|
||||
Padding="4"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
ui:VisualExtensions.NormalizedCenterPoint="0.5,0.5"
|
||||
Content="{ui:FontIcon Glyph=,
|
||||
FontSize=14}"
|
||||
FontSize="16"
|
||||
Style="{StaticResource SubtleButtonStyle}"
|
||||
Visibility="{x:Bind viewModel.IsNested, Mode=OneWay}">
|
||||
<animations:Implicit.ShowAnimations>
|
||||
<animations:OpacityAnimation
|
||||
EasingMode="EaseIn"
|
||||
EasingType="Cubic"
|
||||
From="0"
|
||||
To="1.0"
|
||||
Duration="0:0:0.333" />
|
||||
<animations:ScaleAnimation
|
||||
From="0.5"
|
||||
To="1"
|
||||
Duration="0:0:0.333" />
|
||||
<animations:TranslationAnimation
|
||||
From="16,0,0"
|
||||
To="0,0,0"
|
||||
Duration="0:0:0.333" />
|
||||
</animations:Implicit.ShowAnimations>
|
||||
<animations:Implicit.HideAnimations>
|
||||
<animations:OpacityAnimation
|
||||
EasingMode="EaseOut"
|
||||
EasingType="Cubic"
|
||||
From="1.0"
|
||||
To="0"
|
||||
Duration="0:0:0.333" />
|
||||
<animations:ScaleAnimation
|
||||
EasingMode="EaseOut"
|
||||
EasingType="Cubic"
|
||||
From="1"
|
||||
To="0.5"
|
||||
Duration="0:0:0.333" />
|
||||
<animations:TranslationAnimation
|
||||
EasingMode="EaseOut"
|
||||
EasingType="Cubic"
|
||||
From="0,0,0"
|
||||
To="16,0,0"
|
||||
Duration="0:0:0.187" />
|
||||
</animations:Implicit.HideAnimations>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
<!-- Search box: wrapped in a grid to enable RepositionThemeTransitions -->
|
||||
<Grid Grid.Column="1" HorizontalAlignment="Stretch">
|
||||
|
||||
<Grid.Transitions>
|
||||
<TransitionCollection>
|
||||
<RepositionThemeTransition />
|
||||
</TransitionCollection>
|
||||
</Grid.Transitions>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid x:Name="ContentGrid" Grid.Row="1">
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="3*" />
|
||||
<ColumnDefinition x:Name="DetailsColumn" Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Frame
|
||||
Name="RootFrame"
|
||||
AutomationProperties.AutomationControlType="Pane"
|
||||
AutomationProperties.LandmarkType="Navigation"
|
||||
AutomationProperties.LiveSetting="Assertive"
|
||||
IsNavigationStackEnabled="True" />
|
||||
|
||||
<ScrollViewer
|
||||
x:Name="DetailsContent"
|
||||
Grid.Column="1"
|
||||
Margin="4"
|
||||
HorizontalAlignment="Stretch"
|
||||
ui:VisualExtensions.NormalizedCenterPoint="0.5,0.5"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="{StaticResource ControlCornerRadius}"
|
||||
Visibility="Collapsed">
|
||||
<animations:Implicit.ShowAnimations>
|
||||
<animations:OpacityAnimation
|
||||
From="0"
|
||||
To="1.0"
|
||||
Duration="0:0:0.187" />
|
||||
<animations:TranslationAnimation
|
||||
From="24,0,0"
|
||||
To="0,0,0"
|
||||
Duration="0:0:0.187" />
|
||||
</animations:Implicit.ShowAnimations>
|
||||
<animations:Implicit.HideAnimations>
|
||||
<animations:OpacityAnimation
|
||||
From="1.0"
|
||||
To="0"
|
||||
Duration="0:0:0.187" />
|
||||
<animations:TranslationAnimation
|
||||
From="0,0,0"
|
||||
To="24,0,0"
|
||||
Duration="0:0:0.187" />
|
||||
</animations:Implicit.HideAnimations>
|
||||
<Grid Margin="16">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
<!-- /DetailsContent -->
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
||||
Reference in New Issue
Block a user