add Issue Template & add SettingsUI proj

This commit is contained in:
DismissedLight
2022-05-01 19:23:40 +08:00
parent 0b6bdb741c
commit c2e0e63ed8
45 changed files with 2409 additions and 61 deletions

6
.gitignore vendored
View File

@@ -4,5 +4,9 @@
.vs/ .vs/
src/SettingsUI/bin
src/SettingsUI/obj
src/Snap.Hutao/Snap.Hutao/bin/ src/Snap.Hutao/Snap.Hutao/bin/
src/Snap.Hutao/Snap.Hutao/obj/ src/Snap.Hutao/Snap.Hutao/obj/
src/Snap.Hutao/Snap.Hutao/Snap.Hutao_TemporaryKey.pfx

View File

@@ -0,0 +1,79 @@
// 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.ComponentModel;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Automation;
using Microsoft.UI.Xaml.Controls;
namespace SettingsUI.Controls;
public class CheckBoxWithDescriptionControl : CheckBox
{
private CheckBoxWithDescriptionControl _checkBoxSubTextControl;
public CheckBoxWithDescriptionControl()
{
_checkBoxSubTextControl = (CheckBoxWithDescriptionControl) this;
this.Loaded += CheckBoxSubTextControl_Loaded;
}
protected override void OnApplyTemplate()
{
Update();
base.OnApplyTemplate();
}
private void Update()
{
if (!string.IsNullOrEmpty(Header))
{
AutomationProperties.SetName(this, Header);
}
}
private void CheckBoxSubTextControl_Loaded(object sender, RoutedEventArgs e)
{
StackPanel panel = new StackPanel() { Orientation = Orientation.Vertical };
// Add text box only if the description is not empty. Required for additional plugin options.
if (!string.IsNullOrWhiteSpace(Description))
{
panel.Children.Add(new TextBlock() { Margin = new Thickness(0, 10, 0, 0), Text = Header });
panel.Children.Add(new IsEnabledTextBlock() { Style = (Style) Application.Current.Resources["SecondaryIsEnabledTextBlockStyle"], Text = Description });
}
else
{
panel.Children.Add(new TextBlock() { Margin = new Thickness(0, 0, 0, 0), Text = Header });
}
_checkBoxSubTextControl.Content = panel;
}
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
"Header",
typeof(string),
typeof(CheckBoxWithDescriptionControl),
new PropertyMetadata(default(string)));
public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(
"Description",
typeof(object),
typeof(CheckBoxWithDescriptionControl),
new PropertyMetadata(default(string)));
[Localizable(true)]
public string Header
{
get => (string) GetValue(HeaderProperty);
set => SetValue(HeaderProperty, value);
}
[Localizable(true)]
public string Description
{
get => (string) GetValue(DescriptionProperty);
set => SetValue(DescriptionProperty, value);
}
}

View File

@@ -0,0 +1,50 @@
// 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.ComponentModel;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
namespace SettingsUI.Controls;
[TemplateVisualState(Name = "Normal", GroupName = "CommonStates")]
[TemplateVisualState(Name = "Disabled", GroupName = "CommonStates")]
public class IsEnabledTextBlock : Control
{
public IsEnabledTextBlock()
{
this.DefaultStyleKey = typeof(IsEnabledTextBlock);
}
protected override void OnApplyTemplate()
{
IsEnabledChanged -= IsEnabledTextBlock_IsEnabledChanged;
SetEnabledState();
IsEnabledChanged += IsEnabledTextBlock_IsEnabledChanged;
base.OnApplyTemplate();
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text",
typeof(string),
typeof(IsEnabledTextBlock),
null);
[Localizable(true)]
public string Text
{
get => (string) GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
private void IsEnabledTextBlock_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
SetEnabledState();
}
private void SetEnabledState()
{
VisualStateManager.GoToState(this, IsEnabled ? "Normal" : "Disabled", true);
}
}

View File

@@ -0,0 +1,38 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SettingsUI.Controls">
<Style TargetType="local:IsEnabledTextBlock">
<Setter Property="Foreground" Value="{ThemeResource DefaultTextForegroundThemeBrush}" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:IsEnabledTextBlock">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Target="Label.Foreground" Value="{ThemeResource TextFillColorDisabledBrush}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<TextBlock x:Name="Label"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
FontFamily="{TemplateBinding FontFamily}"
Foreground="{TemplateBinding Foreground}"
TextWrapping="WrapWholeWords"
Text="{TemplateBinding Text}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="local:IsEnabledTextBlock" x:Key="SecondaryIsEnabledTextBlockStyle">
<Setter Property="Foreground" Value="{ThemeResource TextFillColorSecondaryBrush}" />
<Setter Property="FontSize" Value="{StaticResource SecondaryTextFontSize}"/>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,156 @@
// 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.ComponentModel;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Automation;
using Microsoft.UI.Xaml.Controls;
namespace SettingsUI.Controls;
[TemplateVisualState(Name = "Normal", GroupName = "CommonStates")]
[TemplateVisualState(Name = "Disabled", GroupName = "CommonStates")]
[TemplatePart(Name = PartIconPresenter, Type = typeof(ContentPresenter))]
[TemplatePart(Name = PartDescriptionPresenter, Type = typeof(ContentPresenter))]
public class Setting : ContentControl
{
private const string PartIconPresenter = "IconPresenter";
private const string PartDescriptionPresenter = "DescriptionPresenter";
private ContentPresenter _iconPresenter;
private ContentPresenter _descriptionPresenter;
private Setting _setting;
public Setting()
{
this.DefaultStyleKey = typeof(Setting);
}
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
"Header",
typeof(string),
typeof(Setting),
new PropertyMetadata(default(string), OnHeaderChanged));
public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(
"Description",
typeof(object),
typeof(Setting),
new PropertyMetadata(null, OnDescriptionChanged));
public static readonly DependencyProperty IconProperty = DependencyProperty.Register(
"Icon",
typeof(object),
typeof(Setting),
new PropertyMetadata(default(string), OnIconChanged));
public static readonly DependencyProperty ActionContentProperty = DependencyProperty.Register(
"ActionContent",
typeof(object),
typeof(Setting),
null);
[Localizable(true)]
public string Header
{
get => (string) GetValue(HeaderProperty);
set => SetValue(HeaderProperty, value);
}
[Localizable(true)]
public object Description
{
get => (object) GetValue(DescriptionProperty);
set => SetValue(DescriptionProperty, value);
}
public object Icon
{
get => (object) GetValue(IconProperty);
set => SetValue(IconProperty, value);
}
public object ActionContent
{
get => (object) GetValue(ActionContentProperty);
set => SetValue(ActionContentProperty, value);
}
protected override void OnApplyTemplate()
{
IsEnabledChanged -= Setting_IsEnabledChanged;
_setting = (Setting) this;
_iconPresenter = (ContentPresenter) _setting.GetTemplateChild(PartIconPresenter);
_descriptionPresenter = (ContentPresenter) _setting.GetTemplateChild(PartDescriptionPresenter);
Update();
SetEnabledState();
IsEnabledChanged += Setting_IsEnabledChanged;
base.OnApplyTemplate();
}
private static void OnHeaderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((Setting) d).Update();
}
private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((Setting) d).Update();
}
private static void OnDescriptionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((Setting) d).Update();
}
private void Setting_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
SetEnabledState();
}
private void SetEnabledState()
{
VisualStateManager.GoToState(this, IsEnabled ? "Normal" : "Disabled", true);
}
private void Update()
{
if (_setting == null)
{
return;
}
if (_setting.ActionContent != null)
{
if (_setting.ActionContent.GetType() != typeof(Button))
{
// We do not want to override the default AutomationProperties.Name of a button. Its Content property already describes what it does.
if (!string.IsNullOrEmpty(_setting.Header))
{
AutomationProperties.SetName((UIElement) _setting.ActionContent, _setting.Header);
}
}
}
if (_setting._iconPresenter != null)
{
if (_setting.Icon == null)
{
_setting._iconPresenter.Visibility = Visibility.Collapsed;
}
else
{
_setting._iconPresenter.Visibility = Visibility.Visible;
}
}
if (_setting.Description == null)
{
_setting._descriptionPresenter.Visibility = Visibility.Collapsed;
}
else
{
_setting._descriptionPresenter.Visibility = Visibility.Visible;
}
}
}

View File

@@ -0,0 +1,107 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:SettingsUI.Controls">
<Style TargetType="controls:Setting">
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}"/>
<Setter Property="Background" Value="{ThemeResource CardBackgroundBrush}" />
<Setter Property="BorderThickness" Value="{ThemeResource CardBorderThickness}" />
<Setter Property="BorderBrush" Value="{ThemeResource CardStrokeColorDefaultBrush}" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Padding" Value="16" />
<Setter Property="Margin" Value="0,0,0,0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:Setting">
<Grid x:Name="RootGrid"
CornerRadius="{TemplateBinding CornerRadius}"
Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Padding="{TemplateBinding Padding}"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
MinHeight="48">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Target="HeaderPresenter.Foreground" Value="{ThemeResource TextFillColorDisabledBrush}" />
<Setter Target="DescriptionPresenter.Foreground" Value="{ThemeResource TextFillColorDisabledBrush}" />
<Setter Target="IconPresenter.Foreground" Value="{ThemeResource TextFillColorDisabledBrush}" />
<Setter Target="ContentPresenter.Foreground" Value="{ThemeResource TextFillColorDisabledBrush}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<!-- Icon -->
<ColumnDefinition Width="*"/>
<!-- Header and subtitle -->
<ColumnDefinition Width="Auto"/>
<!-- Action control -->
</Grid.ColumnDefinitions>
<ContentPresenter x:Name="IconPresenter"
Content="{TemplateBinding Icon}"
HorizontalAlignment="Center"
FontSize="20"
IsTextScaleFactorEnabled="False"
Margin="2,0,18,0"
MaxWidth="20"
AutomationProperties.AccessibilityView="Raw"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
Foreground="{ThemeResource CardPrimaryForegroundBrush}"
VerticalAlignment="Center"/>
<StackPanel
VerticalAlignment="Center"
Grid.Column="1"
HorizontalAlignment="Stretch"
Margin="0,0,16,0">
<TextBlock
x:Name="HeaderPresenter"
Text="{TemplateBinding Header}"
VerticalAlignment="Center"
Foreground="{ThemeResource CardPrimaryForegroundBrush}" />
<ContentPresenter
x:Name="DescriptionPresenter"
Content="{TemplateBinding Description}"
FontSize="{StaticResource SecondaryTextFontSize}"
TextWrapping="WrapWholeWords"
Foreground="{ThemeResource TextFillColorSecondaryBrush}">
<ContentPresenter.Resources>
<Style TargetType="TextBlock" BasedOn="{StaticResource CaptionTextBlockStyle}">
<Style.Setters>
<Setter Property="TextWrapping" Value="WrapWholeWords"/>
</Style.Setters>
</Style>
<Style TargetType="HyperlinkButton" BasedOn="{StaticResource TextButtonStyle}">
<Style.Setters>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Padding" Value="0,0,0,0"/>
</Style.Setters>
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</StackPanel>
<ContentPresenter
x:Name="ContentPresenter"
Content="{TemplateBinding ActionContent}"
Grid.Column="2"
VerticalAlignment="Center"
HorizontalAlignment="Right" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,37 @@
// 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.UI.Xaml;
using Microsoft.UI.Xaml.Automation;
using Microsoft.UI.Xaml.Controls;
namespace SettingsUI.Controls;
public partial class SettingExpander : Expander
{
public SettingExpander()
{
DefaultStyleKey = typeof(Expander);
this.Style = (Style) Application.Current.Resources["SettingExpanderStyle"];
this.RegisterPropertyChangedCallback(Expander.HeaderProperty, OnHeaderChanged);
}
private static void OnHeaderChanged(DependencyObject d, DependencyProperty dp)
{
SettingExpander self = (SettingExpander) d;
if (self.Header != null)
{
if (self.Header.GetType() == typeof(Setting))
{
Setting selfSetting = (Setting) self.Header;
selfSetting.Style = (Style) Application.Current.Resources["ExpanderHeaderSettingStyle"];
if (!string.IsNullOrEmpty(selfSetting.Header))
{
AutomationProperties.SetName(self, selfSetting.Header);
}
}
}
}
}

View File

@@ -0,0 +1,101 @@
// 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.ComponentModel;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Automation.Peers;
using Microsoft.UI.Xaml.Controls;
namespace SettingsUI.Controls;
/// <summary>
/// Represents a control that can contain multiple settings (or other) controls
/// </summary>
[TemplateVisualState(Name = "Normal", GroupName = "CommonStates")]
[TemplateVisualState(Name = "Disabled", GroupName = "CommonStates")]
[TemplatePart(Name = PartDescriptionPresenter, Type = typeof(ContentPresenter))]
public partial class SettingsGroup : ItemsControl
{
private const string PartDescriptionPresenter = "DescriptionPresenter";
private ContentPresenter _descriptionPresenter;
private SettingsGroup _settingsGroup;
public SettingsGroup()
{
DefaultStyleKey = typeof(SettingsGroup);
}
[Localizable(true)]
public string Header
{
get => (string) GetValue(HeaderProperty);
set => SetValue(HeaderProperty, value);
}
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
"Header",
typeof(string),
typeof(SettingsGroup),
new PropertyMetadata(default(string)));
[Localizable(true)]
public object Description
{
get => (object) GetValue(DescriptionProperty);
set => SetValue(DescriptionProperty, value);
}
public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(
"Description",
typeof(object),
typeof(SettingsGroup),
new PropertyMetadata(null, OnDescriptionChanged));
protected override void OnApplyTemplate()
{
IsEnabledChanged -= SettingsGroup_IsEnabledChanged;
_settingsGroup = (SettingsGroup) this;
_descriptionPresenter = (ContentPresenter) _settingsGroup.GetTemplateChild(PartDescriptionPresenter);
SetEnabledState();
IsEnabledChanged += SettingsGroup_IsEnabledChanged;
base.OnApplyTemplate();
}
private static void OnDescriptionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((SettingsGroup) d).Update();
}
private void SettingsGroup_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
SetEnabledState();
}
private void SetEnabledState()
{
VisualStateManager.GoToState(this, IsEnabled ? "Normal" : "Disabled", true);
}
private void Update()
{
if (_settingsGroup == null)
{
return;
}
if (_settingsGroup.Description == null)
{
_settingsGroup._descriptionPresenter.Visibility = Visibility.Collapsed;
}
else
{
_settingsGroup._descriptionPresenter.Visibility = Visibility.Visible;
}
}
protected override AutomationPeer OnCreateAutomationPeer()
{
return new SettingsGroupAutomationPeer(this);
}
}

View File

@@ -0,0 +1,71 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:SettingsUI.Controls">
<Style TargetType="controls:SettingsGroup">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"
Spacing="2"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="IsTabStop" Value="False" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:SettingsGroup">
<Grid HorizontalAlignment="Stretch">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Target="HeaderPresenter.Foreground" Value="{ThemeResource TextFillColorDisabledBrush}" />
<Setter Target="DescriptionPresenter.Foreground" Value="{ThemeResource TextFillColorDisabledBrush}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock x:Name="HeaderPresenter"
Text="{TemplateBinding Header}"
Grid.Row="0"
Style="{ThemeResource BodyStrongTextBlockStyle}"
Margin="1,32,0,0"
AutomationProperties.HeadingLevel="Level2"/>
<ContentPresenter
x:Name="DescriptionPresenter"
Content="{TemplateBinding Description}"
TextWrapping="WrapWholeWords"
Margin="1,4,0,0"
Grid.Row="1"
Foreground="{ThemeResource TextFillColorSecondaryBrush}">
<ContentPresenter.Resources>
<Style TargetType="TextBlock" BasedOn="{StaticResource CaptionTextBlockStyle}">
<Style.Setters>
<Setter Property="TextWrapping" Value="WrapWholeWords"/>
</Style.Setters>
</Style>
<Style TargetType="HyperlinkButton" BasedOn="{StaticResource TextButtonStyle}">
<Style.Setters>
<Setter Property="Padding" Value="0,0,0,0"/>
</Style.Setters>
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
<ItemsPresenter Grid.Row="2" Margin="0,8,0,0"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,21 @@
// 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.UI.Xaml.Automation.Peers;
namespace SettingsUI.Controls;
public class SettingsGroupAutomationPeer : FrameworkElementAutomationPeer
{
public SettingsGroupAutomationPeer(SettingsGroup owner)
: base(owner)
{
}
protected override string GetNameCore()
{
var selectedSettingsGroup = (SettingsGroup) Owner;
return selectedSettingsGroup.Header;
}
}

View File

@@ -0,0 +1,51 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0-windows10.0.17763.0</TargetFrameworks>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<RootNamespace>SettingsUI</RootNamespace>
<RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
<UseWinUI>true</UseWinUI>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.0.3" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22000.197" />
<PackageReference Include="nucs.JsonSettings" Version="2.0.0-alpha7" />
<PackageReference Include="nucs.JsonSettings.Autosave" Version="2.0.0-alpha7" />
</ItemGroup>
<ItemGroup>
<Page Update="Controls\IsEnabledTextBlock\IsEnabledTextBlock.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Update="Controls\SettingsGroup\SettingsGroup.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Update="Controls\Setting\Setting.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Update="Styles\Button.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Update="Styles\Common.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Update="Styles\TextBlock.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Update="Themes\Colors.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Update="Themes\Generic.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Update="Themes\SettingsExpanderStyles.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Update="Themes\SettingsUI.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,581 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:contract7NotPresent="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractNotPresent(Windows.Foundation.UniversalApiContract,7)"
xmlns:contract7Present="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,7)">
<Style x:Key="SettingButtonStyle" TargetType="Button" BasedOn="{StaticResource DefaultButtonStyle}" >
<Setter Property="BorderBrush" Value="{ThemeResource CardBorderBrush}" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
<Setter Property="Padding" Value="16,0,16,0" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
<Style x:Key="HyperlinkButtonStyle" TargetType="HyperlinkButton" >
</Style>
<Style x:Key="TextButtonStyle" TargetType="ButtonBase">
<Setter Property="Background" Value="{ThemeResource HyperlinkButtonBackground}" />
<Setter Property="Foreground" Value="{ThemeResource HyperlinkButtonForeground}" />
<Setter Property="MinWidth" Value="0" />
<Setter Property="MinHeight" Value="0" />
<Setter Property="Margin" Value="0" />
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ButtonBase">
<Grid Margin="{TemplateBinding Padding}" CornerRadius="4" Background="{TemplateBinding Background}">
<ContentPresenter x:Name="Text"
Content="{TemplateBinding Content}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
FontWeight="SemiBold"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource HyperlinkButtonForegroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource HyperlinkButtonBackgroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource HyperlinkButtonBorderBrushPointerOver}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource HyperlinkButtonForegroundPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource HyperlinkButtonBackgroundPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource HyperlinkButtonBorderBrushPressed}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource HyperlinkButtonForegroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource HyperlinkButtonBackgroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource HyperlinkButtonBorderBrushDisabled}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- This style overrides the default style so that all ToggleSwitches are right aligned, with the label on the left -->
<Style x:Key="ToggleSwitchSettingStyle" TargetType="ToggleSwitch">
<Setter Property="Foreground" Value="{ThemeResource ToggleSwitchContentForeground}" />
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Right" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="ManipulationMode" Value="System,TranslateX" />
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
<Setter Property="FocusVisualMargin" Value="-7,-3,-7,-3" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleSwitch">
<Grid
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
contract7Present:CornerRadius="{TemplateBinding CornerRadius}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="OuterBorder" Storyboard.TargetProperty="Stroke">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchStrokeOff}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="OuterBorder" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchFillOff}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOff" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchKnobFillOff}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOn" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchKnobFillOn}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobBounds" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchFillOn}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobBounds" Storyboard.TargetProperty="Stroke">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchStrokeOn}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SwitchAreaGrid" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchContainerBackground}" />
</ObjectAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOn" Storyboard.TargetProperty="Width" EnableDependentAnimation="True" >
<SplineDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" KeySpline="{StaticResource ControlFastOutSlowInKeySpline}" Value="12" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOn" Storyboard.TargetProperty="Height" EnableDependentAnimation="True">
<SplineDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" KeySpline="{StaticResource ControlFastOutSlowInKeySpline}" Value="12" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOff" Storyboard.TargetProperty="Width" EnableDependentAnimation="True">
<SplineDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" KeySpline="{StaticResource ControlFastOutSlowInKeySpline}" Value="12" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOff" Storyboard.TargetProperty="Height" EnableDependentAnimation="True">
<SplineDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" KeySpline="{StaticResource ControlFastOutSlowInKeySpline}" Value="12" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOver">
<Storyboard>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="OuterBorder" Storyboard.TargetProperty="(Shape.Stroke).(SolidColorBrush.Color)">
<LinearColorKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="{ThemeResource ToggleSwitchStrokeOffPointerOver}" />
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="OuterBorder" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)">
<LinearColorKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="{ThemeResource ToggleSwitchFillOffPointerOver}" />
</ColorAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOff" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchKnobFillOffPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOn" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchKnobFillOnPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobBounds" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchFillOnPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobBounds" Storyboard.TargetProperty="Stroke">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchStrokeOnPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="SwitchAreaGrid" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
<LinearColorKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="{ThemeResource ToggleSwitchContainerBackgroundPointerOver}" />
</ColorAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOn" Storyboard.TargetProperty="Width" EnableDependentAnimation="True" >
<SplineDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" KeySpline="{StaticResource ControlFastOutSlowInKeySpline}" Value="14" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOn" Storyboard.TargetProperty="Height" EnableDependentAnimation="True">
<SplineDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" KeySpline="{StaticResource ControlFastOutSlowInKeySpline}" Value="14" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOff" Storyboard.TargetProperty="Width" EnableDependentAnimation="True">
<SplineDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" KeySpline="{StaticResource ControlFastOutSlowInKeySpline}" Value="14" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOff" Storyboard.TargetProperty="Height" EnableDependentAnimation="True">
<SplineDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" KeySpline="{StaticResource ControlFastOutSlowInKeySpline}" Value="14" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Target="SwitchKnobOn.HorizontalAlignment" Value="Right" />
<Setter Target="SwitchKnobOn.Margin" Value="0,0,3,0" />
<Setter Target="SwitchKnobOff.HorizontalAlignment" Value="Left" />
<Setter Target="SwitchKnobOff.Margin" Value="3,0,0,0" />
</VisualState.Setters>
<Storyboard>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="OuterBorder" Storyboard.TargetProperty="(Shape.Stroke).(SolidColorBrush.Color)">
<LinearColorKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="{ThemeResource ToggleSwitchStrokeOffPressed}" />
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="OuterBorder" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)">
<LinearColorKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="{ThemeResource ToggleSwitchFillOffPressed}" />
</ColorAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobBounds" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchFillOnPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobBounds" Storyboard.TargetProperty="Stroke">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchStrokeOnPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOff" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchKnobFillOffPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOn" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchKnobFillOnPressed}" />
</ObjectAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="SwitchAreaGrid" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
<LinearColorKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="{ThemeResource ToggleSwitchContainerBackgroundPressed}" />
</ColorAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOn" Storyboard.TargetProperty="Width" EnableDependentAnimation="True" >
<SplineDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" KeySpline="{StaticResource ControlFastOutSlowInKeySpline}" Value="17" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOn" Storyboard.TargetProperty="Height" EnableDependentAnimation="True">
<SplineDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" KeySpline="{StaticResource ControlFastOutSlowInKeySpline}" Value="14" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOff" Storyboard.TargetProperty="Width" EnableDependentAnimation="True">
<SplineDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" KeySpline="{StaticResource ControlFastOutSlowInKeySpline}" Value="17" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOff" Storyboard.TargetProperty="Height" EnableDependentAnimation="True">
<SplineDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" KeySpline="{StaticResource ControlFastOutSlowInKeySpline}" Value="14" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HeaderContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchHeaderForegroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="OffContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchContentForegroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="OnContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchContentForegroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="OuterBorder" Storyboard.TargetProperty="(Shape.Stroke).(SolidColorBrush.Color)">
<LinearColorKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="{ThemeResource ToggleSwitchStrokeOffDisabled}" />
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="OuterBorder" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)">
<LinearColorKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="{ThemeResource ToggleSwitchFillOffDisabled}" />
</ColorAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobBounds" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchFillOnDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobBounds" Storyboard.TargetProperty="Stroke">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchStrokeOnDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOff" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchKnobFillOffDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOn" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleSwitchKnobFillOnDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="SwitchAreaGrid" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
<LinearColorKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="{ThemeResource ToggleSwitchContainerBackgroundDisabled}" />
</ColorAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOn" Storyboard.TargetProperty="Width" EnableDependentAnimation="True" >
<SplineDoubleKeyFrame KeyTime="{StaticResource ControlNormalAnimationDuration}" KeySpline="{StaticResource ControlFastOutSlowInKeySpline}" Value="12" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOn" Storyboard.TargetProperty="Height" EnableDependentAnimation="True">
<SplineDoubleKeyFrame KeyTime="{StaticResource ControlNormalAnimationDuration}" KeySpline="{StaticResource ControlFastOutSlowInKeySpline}" Value="12" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOff" Storyboard.TargetProperty="Width" EnableDependentAnimation="True">
<SplineDoubleKeyFrame KeyTime="{StaticResource ControlNormalAnimationDuration}" KeySpline="{StaticResource ControlFastOutSlowInKeySpline}" Value="12" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOff" Storyboard.TargetProperty="Height" EnableDependentAnimation="True">
<SplineDoubleKeyFrame KeyTime="{StaticResource ControlNormalAnimationDuration}" KeySpline="{StaticResource ControlFastOutSlowInKeySpline}" Value="12" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="ToggleStates">
<VisualStateGroup.Transitions>
<VisualTransition x:Name="DraggingToOnTransition"
From="Dragging"
To="On"
GeneratedDuration="0">
<Storyboard>
<RepositionThemeAnimation TargetName="SwitchKnob" FromHorizontalOffset="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.KnobCurrentToOnOffset}" />
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobBounds" Storyboard.TargetProperty="Opacity">
<LinearDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="1" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="OuterBorder" Storyboard.TargetProperty="Opacity">
<LinearDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOn" Storyboard.TargetProperty="Opacity">
<LinearDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="1" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOff" Storyboard.TargetProperty="Opacity">
<LinearDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition x:Name="OnToDraggingTransition"
From="On"
To="Dragging"
GeneratedDuration="0">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobBounds" Storyboard.TargetProperty="Opacity">
<LinearDoubleKeyFrame KeyTime="0" Value="1" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOn" Storyboard.TargetProperty="Opacity">
<LinearDoubleKeyFrame KeyTime="0" Value="1" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOff" Storyboard.TargetProperty="Opacity">
<LinearDoubleKeyFrame KeyTime="0" Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition x:Name="DraggingToOffTransition"
From="Dragging"
To="Off"
GeneratedDuration="0">
<Storyboard>
<RepositionThemeAnimation TargetName="SwitchKnob" FromHorizontalOffset="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.KnobCurrentToOffOffset}" />
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobBounds" Storyboard.TargetProperty="Opacity">
<LinearDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOn" Storyboard.TargetProperty="Opacity">
<LinearDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOff" Storyboard.TargetProperty="Opacity">
<LinearDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="1" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition x:Name="OnToOffTransition"
From="On"
To="Off"
GeneratedDuration="0">
<Storyboard>
<RepositionThemeAnimation TargetName="SwitchKnob" FromHorizontalOffset="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.KnobOnToOffOffset}" />
</Storyboard>
</VisualTransition>
<VisualTransition x:Name="OffToOnTransition"
From="Off"
To="On"
GeneratedDuration="0">
<Storyboard>
<RepositionThemeAnimation TargetName="SwitchKnob" FromHorizontalOffset="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.KnobOffToOnOffset}"/>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobBounds" Storyboard.TargetProperty="Opacity">
<LinearDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="1" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="OuterBorder" Storyboard.TargetProperty="Opacity">
<LinearDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOn" Storyboard.TargetProperty="Opacity">
<LinearDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="1" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOff" Storyboard.TargetProperty="Opacity">
<LinearDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Dragging" />
<VisualState x:Name="Off" />
<VisualState x:Name="On">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="KnobTranslateTransform"
Storyboard.TargetProperty="X"
To="20"
Duration="0" />
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobBounds" Storyboard.TargetProperty="Opacity">
<LinearDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="1" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="OuterBorder" Storyboard.TargetProperty="Opacity">
<LinearDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOn" Storyboard.TargetProperty="Opacity">
<LinearDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="1" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SwitchKnobOff" Storyboard.TargetProperty="Opacity">
<LinearDoubleKeyFrame KeyTime="{StaticResource ControlFasterAnimationDuration}" Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="ContentStates">
<VisualState x:Name="OffContent">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="OffContentPresenter"
Storyboard.TargetProperty="Opacity"
To="1"
Duration="0" />
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="IsHitTestVisible" Storyboard.TargetName="OffContentPresenter">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<x:Boolean>True</x:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="OnContent">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="OnContentPresenter"
Storyboard.TargetProperty="Opacity"
To="1"
Duration="0" />
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="IsHitTestVisible" Storyboard.TargetName="OnContentPresenter">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<x:Boolean>True</x:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ContentPresenter x:Name="HeaderContentPresenter"
x:DeferLoadStrategy="Lazy"
Grid.Row="0"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}"
Foreground="{ThemeResource ToggleSwitchHeaderForeground}"
IsHitTestVisible="False"
Margin="{ThemeResource ToggleSwitchTopHeaderMargin}"
TextWrapping="Wrap"
VerticalAlignment="Top"
Visibility="Collapsed"
AutomationProperties.AccessibilityView="Raw" />
<Grid
Grid.Row="1"
HorizontalAlignment="Right"
VerticalAlignment="Top">
<Grid.RowDefinitions>
<RowDefinition Height="{ThemeResource ToggleSwitchPreContentMargin}" />
<RowDefinition Height="Auto" />
<RowDefinition Height="{ThemeResource ToggleSwitchPostContentMargin}" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="12" MaxWidth="12" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid x:Name="SwitchAreaGrid"
Grid.RowSpan="3"
Grid.ColumnSpan="3"
Margin="0,5"
contract7Present:CornerRadius="{TemplateBinding CornerRadius}"
contract7NotPresent:CornerRadius="{StaticResource ControlCornerRadius}"
Control.IsTemplateFocusTarget="True"
Background="{ThemeResource ToggleSwitchContainerBackground}" />
<ContentPresenter x:Name="OffContentPresenter"
Grid.RowSpan="3"
Grid.Column="0"
Opacity="0"
Foreground="{TemplateBinding Foreground}"
IsHitTestVisible="False"
Content="{TemplateBinding OffContent}"
ContentTemplate="{TemplateBinding OffContentTemplate}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
AutomationProperties.AccessibilityView="Raw" />
<ContentPresenter x:Name="OnContentPresenter"
Grid.RowSpan="3"
Grid.Column="0"
Opacity="0"
Foreground="{TemplateBinding Foreground}"
IsHitTestVisible="False"
Content="{TemplateBinding OnContent}"
ContentTemplate="{TemplateBinding OnContentTemplate}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
AutomationProperties.AccessibilityView="Raw" />
<Rectangle x:Name="OuterBorder"
Grid.Row="1"
Grid.Column="2"
Height="20"
Width="40"
RadiusX="10"
RadiusY="10"
Fill="{ThemeResource ToggleSwitchFillOff}"
Stroke="{ThemeResource ToggleSwitchStrokeOff}"
StrokeThickness="{ThemeResource ToggleSwitchOuterBorderStrokeThickness}" />
<Rectangle x:Name="SwitchKnobBounds"
Grid.Row="1"
Height="20"
Width="40"
RadiusX="10"
RadiusY="10"
Grid.Column="2"
Fill="{ThemeResource ToggleSwitchFillOn}"
Stroke="{ThemeResource ToggleSwitchStrokeOn}"
StrokeThickness="{ThemeResource ToggleSwitchOnStrokeThickness}"
Opacity="0" />
<Grid x:Name="SwitchKnob"
Grid.Row="1"
Grid.Column="2"
HorizontalAlignment="Left"
Width="20"
Height="20">
<Border x:Name="SwitchKnobOn"
Background="{ThemeResource ToggleSwitchKnobFillOn}"
BorderBrush="{ThemeResource ToggleSwitchKnobStrokeOn}"
contract7Present:BackgroundSizing="OuterBorderEdge"
Width="12"
Height="12"
CornerRadius="7"
Grid.Column="2"
Opacity="0"
HorizontalAlignment="Center"
Margin="0,0,1,0"
RenderTransformOrigin="0.5, 0.5">
<Border.RenderTransform>
<CompositeTransform/>
</Border.RenderTransform>
</Border>
<Rectangle x:Name="SwitchKnobOff"
Fill="{ThemeResource ToggleSwitchKnobFillOff}"
Width="12"
Height="12"
RadiusX="7"
Grid.Column="2"
RadiusY="7"
HorizontalAlignment="Center"
Margin="-1,0,0,0"
RenderTransformOrigin="0.5, 0.5">
<Rectangle.RenderTransform>
<CompositeTransform/>
</Rectangle.RenderTransform>
</Rectangle>
<Grid.RenderTransform>
<TranslateTransform x:Name="KnobTranslateTransform" />
</Grid.RenderTransform>
</Grid>
<Thumb x:Name="SwitchThumb"
AutomationProperties.AccessibilityView="Raw"
Grid.RowSpan="3"
Grid.ColumnSpan="3">
<Thumb.Template>
<ControlTemplate TargetType="Thumb">
<Rectangle Fill="Transparent" />
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,15 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:controls="using:SettingsUI.Controls"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="ListViewItemSettingStyle" TargetType="ListViewItem">
<Setter Property="Margin" Value="0,0,0,2" />
<Setter Property="Padding" Value="0,0,0,0" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
<Style
TargetType="controls:CheckBoxWithDescriptionControl"
BasedOn="{StaticResource DefaultCheckBoxStyle}" />
</ResourceDictionary>

View File

@@ -0,0 +1,22 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="OobeSubtitleStyle" TargetType="TextBlock">
<Setter Property="Margin" Value="0,16,0,0" />
<Setter Property="Foreground" Value="{ThemeResource DefaultTextForegroundThemeBrush}" />
<Setter Property="AutomationProperties.HeadingLevel" Value="Level3" />
<Setter Property="FontFamily" Value="XamlAutoFontFamily" />
<Setter Property="FontSize" Value="{StaticResource BodyTextBlockFontSize}" />
<Setter Property="FontWeight" Value="SemiBold" />
<Setter Property="TextTrimming" Value="CharacterEllipsis" />
<Setter Property="TextWrapping" Value="Wrap" />
<Setter Property="LineStackingStrategy" Value="MaxHeight" />
<Setter Property="TextLineBounds" Value="Full" />
</Style>
<x:Double x:Key="SecondaryTextFontSize">12</x:Double>
<Style x:Key="SecondaryTextStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="{StaticResource SecondaryTextFontSize}"/>
<Setter Property="Foreground" Value="{ThemeResource TextFillColorSecondaryBrush}"/>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,32 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Dark">
<StaticResource x:Key="CardBackgroundBrush" ResourceKey="CardBackgroundFillColorDefaultBrush" />
<StaticResource x:Key="CardBorderBrush" ResourceKey="CardStrokeColorDefaultBrush" />
<StaticResource x:Key="CardPrimaryForegroundBrush" ResourceKey="TextFillColorPrimaryBrush" />
<SolidColorBrush x:Key="InfoBarInformationalSeverityBackgroundBrush" Color="#FF34424d"/>
<Color x:Key="InfoBarInformationalSeverityIconBackground">#FF5fb2f2</Color>
<Thickness x:Key="CardBorderThickness">1</Thickness>
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<StaticResource x:Key="CardBackgroundBrush" ResourceKey="CardBackgroundFillColorDefaultBrush" />
<StaticResource x:Key="CardBorderBrush" ResourceKey="CardStrokeColorDefaultBrush" />
<StaticResource x:Key="CardPrimaryForegroundBrush" ResourceKey="TextFillColorPrimaryBrush" />
<SolidColorBrush x:Key="InfoBarInformationalSeverityBackgroundBrush" Color="#FFd3e7f7"/>
<Color x:Key="InfoBarInformationalSeverityIconBackground">#FF0063b1</Color>
<Thickness x:Key="CardBorderThickness">1</Thickness>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<StaticResource x:Key="CardBackgroundBrush" ResourceKey="SystemColorButtonFaceColorBrush" />
<StaticResource x:Key="CardBorderBrush" ResourceKey="SystemColorButtonTextColorBrush" />
<StaticResource x:Key="CardPrimaryForegroundBrush" ResourceKey="SystemColorButtonTextColorBrush" />
<SolidColorBrush x:Key="InfoBarInformationalSeverityBackgroundBrush" Color="#FF34424d"/>
<Color x:Key="InfoBarInformationalSeverityIconBackground">#FF5fb2f2</Color>
<Thickness x:Key="CardBorderThickness">2</Thickness>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>

View File

@@ -0,0 +1,9 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///SettingsUI/Controls/Setting/Setting.xaml" />
<ResourceDictionary Source="ms-appx:///SettingsUI/Controls/SettingsGroup/SettingsGroup.xaml" />
<ResourceDictionary Source="ms-appx:///SettingsUI/Controls/IsEnabledTextBlock/IsEnabledTextBlock.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

View File

@@ -0,0 +1,52 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:SettingsUI.Controls">
<!-- Thickness -->
<Thickness x:Key="ExpanderContentPadding">0</Thickness>
<Thickness x:Key="ExpanderSettingMargin">56, 8, 40, 8</Thickness>
<SolidColorBrush x:Key="ExpanderChevronPointerOverBackground">Transparent</SolidColorBrush>
<!-- Styles -->
<!-- Setting used in a Expander header -->
<Style x:Key="ExpanderHeaderSettingStyle"
TargetType="controls:Setting">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Padding" Value="0,14,0,14" />
<Setter Property="Margin" Value="0" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>
<Thickness x:Key="ExpanderChevronMargin">0,0,8,0</Thickness>
<!-- Setting used in a Expander header -->
<Style x:Key="ExpanderContentSettingStyle"
TargetType="controls:Setting">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0,1,0,0" />
<Setter Property="BorderBrush" Value="{ThemeResource CardBorderBrush}" />
<Setter Property="CornerRadius" Value="0" />
<Setter Property="Padding" Value="{StaticResource ExpanderSettingMargin}" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>
<!-- Setting expander style -->
<Style x:Key="SettingExpanderStyle"
TargetType="Expander">
<Setter Property="Background" Value="{ThemeResource CardBackgroundBrush}" />
<Setter Property="BorderThickness" Value="{ThemeResource CardBorderThickness}" />
<Setter Property="BorderBrush" Value="{ThemeResource CardBorderBrush}" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
<Style x:Key="ExpanderSeparatorStyle"
TargetType="Rectangle">
<Setter Property="Height" Value="1" />
<Setter Property="Stroke" Value="{ThemeResource CardBorderBrush}" />
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,14 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Styles/Common.xaml"/>
<ResourceDictionary Source="../Styles/TextBlock.xaml"/>
<ResourceDictionary Source="../Styles/Button.xaml"/>
<ResourceDictionary Source="../Themes/Colors.xaml"/>
<ResourceDictionary Source="../Themes/SettingsExpanderStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
<x:Double x:Key="SettingActionControlMinWidth">240</x:Double>
</ResourceDictionary>

View File

@@ -79,6 +79,18 @@ dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_diagnostic.SA1629.severity = silent dotnet_diagnostic.SA1629.severity = silent
dotnet_diagnostic.SA1642.severity = silent dotnet_diagnostic.SA1642.severity = silent
# SA1208: System using directives should be placed before other using directives
dotnet_diagnostic.SA1208.severity = none
# SA1404: Code analysis suppression should have justification
dotnet_diagnostic.SA1404.severity = none
# SA1623: Property summary documentation should match accessors
dotnet_diagnostic.SA1623.severity = none
# SA1636: File header copyright text should match
dotnet_diagnostic.SA1636.severity = none
[*.vb] [*.vb]
#### 命名样式 #### #### 命名样式 ####

View File

@@ -0,0 +1,62 @@
name: 问题反馈
description: 告诉我们你的问题
title: "[Bug]: 取一个合适的标题"
labels: ["BUG"]
assignees:
- Lightczx
body:
- type: markdown
attributes:
value: |
请按下方的要求填写完整的问题表单,以便我们更快的定位问题。
- type: input
id: winver
attributes:
label: Windows 版本
description: |
`Win+R` 输入 `winver` 回车后在打开的窗口第二行可以找到
placeholder: 22000.556
validations:
required: true
- type: input
id: shver
attributes:
label: Snap Hutao 版本
description: 在应用程序的设置界面中靠下的位置可以找到
placeholder: 2022.3.23.1
validations:
required: true
- type: input
id: shuuid
attributes:
label: Snap Hutao 用户设备ID
description: 在应用程序的设置界面中靠下的位置可以找到,并可以通过右侧按钮复制
placeholder: 此ID不包含敏感信息可以放心填写
validations:
required: true
- type: textarea
id: what-happened
attributes:
label: 发生了什么?
description: 详细的描述问题发生前后的行为,以便我们解决问题
validations:
required: true
- type: textarea
id: what-expected
attributes:
label: 你期望发生的行为?
description: 详细的描述你期望发生的行为,突出与目前(可能不正确的)行为的不同
validations:
required: false
- type: textarea
id: logs
attributes:
label: 相关的崩溃日志
description: 如果应用程序崩溃了,可以将崩溃日志复制后粘贴在此处
render: shell

View File

@@ -0,0 +1,9 @@
blank_issues_enabled: false
contact_links:
- name: 问题与操作指南文档
url: https://www.snapgenshin.com/documents/
about: 在发起 Issue 前 请查阅此文档确认文档中尚未包含你的问题的解决方案
- name: 功能建议
url: https://github.com/DGP-Studio/Snap.Genshin/discussions
about: Issues 仅用于反馈与追踪 Bug

View File

@@ -0,0 +1,19 @@
name: 功能请求
description: 告诉我们你的想法
title: "[Feat]: 取一个合适的标题"
labels: ["功能"]
assignees:
- Lightczx
body:
- type: markdown
attributes:
value: |
请按下方的要求填写完整的问题表单,以便我们更快的定位问题。
- type: textarea
id: req
attributes:
label: 你想要实现或优化的功能?
description: 详细的描述一下你想要的功能
validations:
required: true

View File

@@ -10,9 +10,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.editorconfig = .editorconfig .editorconfig = .editorconfig
EndProjectSection EndProjectSection
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{F5886EF9-4D7D-46AF-B2E0-5D1825B6ECCF}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SettingsUI", "..\SettingsUI\SettingsUI.csproj", "{FC2E96B6-775E-465C-82FB-9931826C8049}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Snap.Core.Mvvm", "Common\Snap.Core.Mvvm\Snap.Core.Mvvm.csproj", "{62CEF8A4-4F38-4EC5-9FFD-B9C767AFAB8C}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -50,29 +48,26 @@ Global
{AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Release|x86.ActiveCfg = Release|x86 {AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Release|x86.ActiveCfg = Release|x86
{AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Release|x86.Build.0 = Release|x86 {AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Release|x86.Build.0 = Release|x86
{AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Release|x86.Deploy.0 = Release|x86 {AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Release|x86.Deploy.0 = Release|x86
{62CEF8A4-4F38-4EC5-9FFD-B9C767AFAB8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FC2E96B6-775E-465C-82FB-9931826C8049}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{62CEF8A4-4F38-4EC5-9FFD-B9C767AFAB8C}.Debug|Any CPU.Build.0 = Debug|Any CPU {FC2E96B6-775E-465C-82FB-9931826C8049}.Debug|Any CPU.Build.0 = Debug|Any CPU
{62CEF8A4-4F38-4EC5-9FFD-B9C767AFAB8C}.Debug|arm64.ActiveCfg = Debug|Any CPU {FC2E96B6-775E-465C-82FB-9931826C8049}.Debug|arm64.ActiveCfg = Debug|Any CPU
{62CEF8A4-4F38-4EC5-9FFD-B9C767AFAB8C}.Debug|arm64.Build.0 = Debug|Any CPU {FC2E96B6-775E-465C-82FB-9931826C8049}.Debug|arm64.Build.0 = Debug|Any CPU
{62CEF8A4-4F38-4EC5-9FFD-B9C767AFAB8C}.Debug|x64.ActiveCfg = Debug|Any CPU {FC2E96B6-775E-465C-82FB-9931826C8049}.Debug|x64.ActiveCfg = Debug|Any CPU
{62CEF8A4-4F38-4EC5-9FFD-B9C767AFAB8C}.Debug|x64.Build.0 = Debug|Any CPU {FC2E96B6-775E-465C-82FB-9931826C8049}.Debug|x64.Build.0 = Debug|Any CPU
{62CEF8A4-4F38-4EC5-9FFD-B9C767AFAB8C}.Debug|x86.ActiveCfg = Debug|Any CPU {FC2E96B6-775E-465C-82FB-9931826C8049}.Debug|x86.ActiveCfg = Debug|Any CPU
{62CEF8A4-4F38-4EC5-9FFD-B9C767AFAB8C}.Debug|x86.Build.0 = Debug|Any CPU {FC2E96B6-775E-465C-82FB-9931826C8049}.Debug|x86.Build.0 = Debug|Any CPU
{62CEF8A4-4F38-4EC5-9FFD-B9C767AFAB8C}.Release|Any CPU.ActiveCfg = Release|Any CPU {FC2E96B6-775E-465C-82FB-9931826C8049}.Release|Any CPU.ActiveCfg = Release|Any CPU
{62CEF8A4-4F38-4EC5-9FFD-B9C767AFAB8C}.Release|Any CPU.Build.0 = Release|Any CPU {FC2E96B6-775E-465C-82FB-9931826C8049}.Release|Any CPU.Build.0 = Release|Any CPU
{62CEF8A4-4F38-4EC5-9FFD-B9C767AFAB8C}.Release|arm64.ActiveCfg = Release|Any CPU {FC2E96B6-775E-465C-82FB-9931826C8049}.Release|arm64.ActiveCfg = Release|Any CPU
{62CEF8A4-4F38-4EC5-9FFD-B9C767AFAB8C}.Release|arm64.Build.0 = Release|Any CPU {FC2E96B6-775E-465C-82FB-9931826C8049}.Release|arm64.Build.0 = Release|Any CPU
{62CEF8A4-4F38-4EC5-9FFD-B9C767AFAB8C}.Release|x64.ActiveCfg = Release|Any CPU {FC2E96B6-775E-465C-82FB-9931826C8049}.Release|x64.ActiveCfg = Release|Any CPU
{62CEF8A4-4F38-4EC5-9FFD-B9C767AFAB8C}.Release|x64.Build.0 = Release|Any CPU {FC2E96B6-775E-465C-82FB-9931826C8049}.Release|x64.Build.0 = Release|Any CPU
{62CEF8A4-4F38-4EC5-9FFD-B9C767AFAB8C}.Release|x86.ActiveCfg = Release|Any CPU {FC2E96B6-775E-465C-82FB-9931826C8049}.Release|x86.ActiveCfg = Release|Any CPU
{62CEF8A4-4F38-4EC5-9FFD-B9C767AFAB8C}.Release|x86.Build.0 = Release|Any CPU {FC2E96B6-775E-465C-82FB-9931826C8049}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{62CEF8A4-4F38-4EC5-9FFD-B9C767AFAB8C} = {F5886EF9-4D7D-46AF-B2E0-5D1825B6ECCF}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E4449B1C-0E6A-4D19-955E-1CA491656ABA} SolutionGuid = {E4449B1C-0E6A-4D19-955E-1CA491656ABA}
EndGlobalSection EndGlobalSection

View File

@@ -1,15 +1,19 @@
<Application <Application
x:Class="Snap.Hutao.App" x:Class="Snap.Hutao.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:local="using:Snap.Hutao">
<Application.Resources> <Application.Resources>
<ResourceDictionary> <ResourceDictionary>
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" /> <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<!-- Other merged dictionaries here --> <ResourceDictionary Source="ms-appx:///SettingsUI/Themes/SettingsUI.xaml"/>
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
<!-- Other app resources here --> <!-- Other app resources here -->
<StaticResource x:Key="WindowCaptionBackground" ResourceKey="ControlFillColorTransparentBrush" />
<StaticResource x:Key="WindowCaptionBackgroundDisabled" ResourceKey="ControlFillColorTransparentBrush" />
<StaticResource x:Key="WindowCaptionForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="WindowCaptionForegroundDisabled" ResourceKey="SystemControlForegroundBaseHighBrush" />
</ResourceDictionary> </ResourceDictionary>
</Application.Resources> </Application.Resources>
</Application> </Application>

View File

@@ -1,6 +1,8 @@
// Copyright (c) DGP Studio. All rights reserved. // Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license. // Licensed under the MIT license.
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
namespace Snap.Hutao; namespace Snap.Hutao;
@@ -10,25 +12,33 @@ namespace Snap.Hutao;
/// </summary> /// </summary>
public partial class App : Application public partial class App : Application
{ {
private Window mainWindow; private Window? mainWindow;
/// <summary> /// <summary>
/// Initializes the singleton application object. This is the first line of authored code /// Initializes the singleton application object.
/// executed, and as such is the logical equivalent of main() or WinMain(). /// This is the first line of authored code executed, and as such is the logical equivalent of main() or WinMain().
/// </summary> /// </summary>
public App() public App()
{ {
// load app resource
InitializeComponent(); InitializeComponent();
// prepare DI
Ioc.Default.ConfigureServices(new ServiceCollection()
.AddLogging(builder => builder.AddDebug())
.AddHttpClient()
.AddInjections(typeof(App))
.BuildServiceProvider());
} }
/// <summary> /// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points /// Invoked when the application is launched normally by the end user.
/// will be used such as when the application is launched to open a specific file. /// Other entry points will be used such as when the application is launched to open a specific file.
/// </summary> /// </summary>
/// <param name="args">Details about the launch request and process.</param> /// <param name="args">Details about the launch request and process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs args) protected override void OnLaunched(LaunchActivatedEventArgs args)
{ {
mainWindow = new MainWindow(); mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
mainWindow.Activate(); mainWindow.Activate();
} }
} }

View File

@@ -0,0 +1,41 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.DependencyInjection.Annotation;
/// <summary>
/// 指示被标注的类型可注入
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class InjectionAttribute : Attribute
{
/// <summary>
/// 指示该类将注入为不带有接口实现的类
/// </summary>
/// <param name="injectAs">指示注入方法</param>
public InjectionAttribute(InjectAs injectAs)
{
InjectAs = injectAs;
}
/// <summary>
/// 指示该类将注入为带有接口实现的类
/// </summary>
/// <param name="injectAs">指示注入方法</param>
/// <param name="impl">实现的接口类型</param>
public InjectionAttribute(InjectAs injectAs, Type impl)
{
InterfaceType = impl;
InjectAs = injectAs;
}
/// <summary>
/// 注入类型
/// </summary>
public InjectAs InjectAs { get; set; }
/// <summary>
/// 该类实现的接口类型
/// </summary>
public Type? InterfaceType { get; set; }
}

View File

@@ -0,0 +1,17 @@
namespace Snap.Hutao.Core.DependencyInjection;
/// <summary>
/// 注入方法
/// </summary>
public enum InjectAs
{
/// <summary>
/// 指示应注册为单例对象
/// </summary>
Singleton,
/// <summary>
/// 指示应注册为短期对象
/// </summary>
Transient,
}

View File

@@ -0,0 +1,61 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Extensions.DependencyInjection;
using Snap.Hutao.Core.DependencyInjection.Annotation;
using Snap.Hutao.Core.Validation;
using Snap.Hutao.Extension;
namespace Snap.Hutao.Core.DependencyInjection;
/// <summary>
/// 服务管理器
/// 依赖注入的核心管理类
/// </summary>
internal static class ServiceCollectionExtensions
{
/// <summary>
/// 向容器注册服务, 调用 <see cref="Register(IServiceCollection, Type)"/>
/// </summary>
/// <param name="services">容器</param>
/// <param name="entryType">入口类型,该类型所在的程序集均会被扫描</param>
/// <returns>可继续操作的服务集合</returns>
public static IServiceCollection AddInjections(this IServiceCollection services, Type entryType)
{
entryType.Assembly.ForEachType(type => Register(services, type));
return services;
}
/// <summary>
/// 向容器注册类型
/// </summary>
/// <param name="services">容器</param>
/// <param name="type">待检测的类型</param>
/// <returns>可继续操作的服务集合</returns>
public static IServiceCollection Register(this IServiceCollection services, Type type)
{
if (type.TryGetAttribute(out InjectionAttribute? attr))
{
if (attr.InterfaceType is not null)
{
return attr.InjectAs switch
{
InjectAs.Singleton => services.AddSingleton(attr.InterfaceType, type),
InjectAs.Transient => services.AddTransient(attr.InterfaceType, type),
_ => Must.NeverHappen<IServiceCollection>(),
};
}
else
{
return attr.InjectAs switch
{
InjectAs.Singleton => services.AddSingleton(type),
InjectAs.Transient => services.AddTransient(type),
_ => throw Must.NeverHappen(),
};
}
}
return services;
}
}

View File

@@ -0,0 +1,17 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Extensions.Logging;
namespace Snap.Hutao.Core.Logging;
/// <summary>
/// 事件Id定义
/// </summary>
internal static class EventIds
{
/// <summary>
/// 导航失败
/// </summary>
public static readonly EventId NavigationFailed = new(100000, "NavigationFailed");
}

View File

@@ -0,0 +1,84 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
namespace Snap.Hutao.Core;
/// <summary>
/// 快速创建 <see cref="TOwner"/> 的 <see cref="DependencyProperty"/>
/// </summary>
/// <typeparam name="TOwner">所有者的类型</typeparam>
internal static class Property<TOwner>
{
/// <summary>
/// 注册依赖属性
/// </summary>
/// <typeparam name="TProperty">属性的类型</typeparam>
/// <param name="name">属性名称</param>
/// <returns>注册的依赖属性</returns>
public static DependencyProperty Depend<TProperty>(string name)
{
return DependencyProperty.Register(name, typeof(TProperty), typeof(TOwner), new PropertyMetadata(default(TProperty)));
}
/// <summary>
/// 注册依赖属性
/// </summary>
/// <typeparam name="TProperty">属性的类型</typeparam>
/// <param name="name">属性名称</param>
/// <param name="defaultValue">默认值</param>
/// <returns>注册的依赖属性</returns>
public static DependencyProperty Depend<TProperty>(string name, TProperty defaultValue)
{
return DependencyProperty.Register(name, typeof(TProperty), typeof(TOwner), new PropertyMetadata(defaultValue));
}
/// <summary>
/// 注册依赖属性
/// </summary>
/// <typeparam name="TProperty">属性的类型</typeparam>
/// <param name="name">属性名称</param>
/// <param name="defaultValue">默认值</param>
/// <param name="callback">属性更改回调</param>
/// <returns>注册的依赖属性</returns>
public static DependencyProperty Depend<TProperty>(string name, TProperty defaultValue, PropertyChangedCallback callback)
{
return DependencyProperty.Register(name, typeof(TProperty), typeof(TOwner), new PropertyMetadata(defaultValue, callback));
}
/// <summary>
/// 注册附加属性
/// </summary>
/// <typeparam name="TProperty">属性的类型</typeparam>
/// <param name="name">属性名称</param>
/// <returns>注册的附加属性</returns>
public static DependencyProperty Attach<TProperty>(string name)
{
return DependencyProperty.RegisterAttached(name, typeof(TProperty), typeof(TOwner), new PropertyMetadata(default(TProperty)));
}
/// <summary>
/// 注册附加属性
/// </summary>
/// <typeparam name="TProperty">属性的类型</typeparam>
/// <param name="name">属性名称</param>
/// <param name="defaultValue">默认值</param>
/// <returns>注册的附加属性</returns>
public static DependencyProperty Attach<TProperty>(string name, TProperty defaultValue)
{
return DependencyProperty.RegisterAttached(name, typeof(TProperty), typeof(TOwner), new PropertyMetadata(defaultValue));
}
/// <summary>
/// 注册附加属性
/// </summary>
/// <typeparam name="TProperty">属性的类型</typeparam>
/// <param name="name">属性名称</param>
/// <param name="callback">属性更改回调</param>
/// <returns>注册的附加属性</returns>
public static DependencyProperty Attach<TProperty>(string name, PropertyChangedCallback callback)
{
return DependencyProperty.RegisterAttached(name, typeof(TProperty), typeof(TOwner), new PropertyMetadata(callback));
}
}

View File

@@ -0,0 +1,87 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Diagnostics;
using System.Runtime;
using System.Runtime.CompilerServices;
namespace Snap.Hutao.Core.Validation;
/// <summary>
/// 封装验证方法,简化微软验证
/// </summary>
public static class Must
{
/// <summary>
/// Throws an exception if the specified parameter's value is null.
/// </summary>
/// <typeparam name="T">The type of the parameter.</typeparam>
/// <param name="value">The value of the argument.</param>
/// <param name="parameterName">The name of the parameter to include in any thrown exception.</param>
/// <returns>The value of the parameter.</returns>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="value"/> is <c>null</c>.</exception>
[DebuggerStepThrough]
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public static T NotNull<T>([NotNull] T value, [CallerArgumentExpression("value")] string? parameterName = null)
where T : class // ensures value-types aren't passed to a null checking method
{
if (value is null)
{
throw new ArgumentNullException(parameterName);
}
return value;
}
/// <summary>
/// Unconditionally throws an <see cref="NotSupportedException"/>.
/// </summary>
/// <returns>Nothing. This method always throws.</returns>
[DebuggerStepThrough]
[DoesNotReturn]
public static Exception NeverHappen()
{
// Keep these two as separate lines of code, so the debugger can come in during the assert dialog
// that the exception's constructor displays, and the debugger can then be made to skip the throw
// in order to continue the investigation.
NotSupportedException exception = new("该行为不应发生,请联系开发者进一步确认");
bool proceed = true; // allows debuggers to skip the throw statement
if (proceed)
{
throw exception;
}
else
{
#pragma warning disable CS8763
return new Exception();
#pragma warning restore CS8763
}
}
/// <summary>
/// Unconditionally throws an <see cref="NotSupportedException"/>.
/// </summary>
/// <typeparam name="T">The type that the method should be typed to return (although it never returns anything).</typeparam>
/// <returns>Nothing. This method always throws.</returns>
[DebuggerStepThrough]
[DoesNotReturn]
[return: MaybeNull]
public static T NeverHappen<T>()
{
// Keep these two as separate lines of code, so the debugger can come in during the assert dialog
// that the exception's constructor displays, and the debugger can then be made to skip the throw
// in order to continue the investigation.
NotSupportedException exception = new("该行为不应发生,请联系开发者进一步确认");
bool proceed = true; // allows debuggers to skip the throw statement
if (proceed)
{
throw exception;
}
else
{
#pragma warning disable CS8763 // 不应返回标记为 [DoesNotReturn] 的方法。
return default;
#pragma warning restore CS8763 // 不应返回标记为 [DoesNotReturn] 的方法。
}
}
}

View File

@@ -0,0 +1,60 @@
using System.Reflection;
namespace Snap.Hutao.Extension;
/// <summary>
/// 反射扩展
/// </summary>
internal static class ReflectionExtension
{
/// <summary>
/// 在指定的成员中尝试获取标记的特性
/// </summary>
/// <typeparam name="TAttribute">特性的类型</typeparam>
/// <param name="type">类型</param>
/// <param name="attribute">获取的特性</param>
/// <returns>是否获取成功</returns>
public static bool TryGetAttribute<TAttribute>(this Type type, [NotNullWhen(true)] out TAttribute? attribute)
where TAttribute : Attribute
{
attribute = type.GetCustomAttribute<TAttribute>();
return attribute != null;
}
/// <summary>
/// 检测类型是否实现接口
/// </summary>
/// <typeparam name="TInterface">被实现的类型</typeparam>
/// <param name="type">被检测的类型/param>
/// <returns>是否实现接口</returns>
[SuppressMessage("", "SA1615")]
public static bool Implement<TInterface>(this Type type)
{
return type.IsAssignableTo(typeof(TInterface));
}
/// <summary>
/// 检查程序集是否标记了指定的特性
/// </summary>
/// <typeparam name="TAttribute">特性类型</typeparam>
/// <param name="assembly">指定的程序集</param>
/// <returns>是否标记了指定的特性</returns>
public static bool HasAttribute<TAttribute>(this Assembly assembly)
where TAttribute : Attribute
{
return assembly.GetCustomAttribute<TAttribute>() is not null;
}
/// <summary>
/// 对程序集中的所有类型进行指定的操作
/// </summary>
/// <param name="assembly">指定的程序集</param>
/// <param name="action">进行的操作</param>
public static void ForEachType(this Assembly assembly, Action<Type> action)
{
foreach (Type type in assembly.GetTypes())
{
action.Invoke(type);
}
}
}

View File

@@ -0,0 +1,25 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Collections.Generic;
namespace Snap.Hutao.Extension;
/// <summary>
/// 元组扩展
/// </summary>
public static class TupleExtensions
{
/// <summary>
/// 将二项元组转化为一个单项的字典
/// </summary>
/// <typeparam name="TKey">键类型</typeparam>
/// <typeparam name="TValue">值类型</typeparam>
/// <param name="tuple">元组</param>
/// <returns>仅包含一个项的字典</returns>
public static IDictionary<TKey, TValue> AsDictionary<TKey, TValue>(this (TKey Key, TValue Value) tuple)
where TKey : notnull
{
return new Dictionary<TKey, TValue>(1) { { tuple.Key, tuple.Value } };
}
}

View File

@@ -0,0 +1,12 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
global using CommunityToolkit.Mvvm.DependencyInjection;
global using Microsoft;
global using Snap.Hutao.Core.DependencyInjection;
global using Snap.Hutao.Core.DependencyInjection.Annotation;
global using Snap.Hutao.Core.Validation;
global using System;
global using System.Diagnostics.CodeAnalysis;
global using System.Windows;
global using System.Windows.Input;

View File

@@ -7,5 +7,18 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:view="using:Snap.Hutao.View" xmlns:view="using:Snap.Hutao.View"
mc:Ignorable="d"> mc:Ignorable="d">
<view:MainView/>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="28"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid
x:Name="TitleBarGrid"
Background="Transparent"/>
<view:MainView
Grid.Row="1"/>
</Grid>
</Window> </Window>

View File

@@ -8,6 +8,7 @@ namespace Snap.Hutao;
/// <summary> /// <summary>
/// 主窗体 /// 主窗体
/// </summary> /// </summary>
[Injection(InjectAs.Transient)]
public sealed partial class MainWindow : Window public sealed partial class MainWindow : Window
{ {
/// <summary> /// <summary>
@@ -17,5 +18,6 @@ public sealed partial class MainWindow : Window
{ {
InitializeComponent(); InitializeComponent();
ExtendsContentIntoTitleBar = true; ExtendsContentIntoTitleBar = true;
SetTitleBar(TitleBarGrid);
} }
} }

View File

@@ -8,7 +8,7 @@
<Identity <Identity
Name="7f0db578-026f-4e0b-a75b-d5d06bb0a74d" Name="7f0db578-026f-4e0b-a75b-d5d06bb0a74d"
Publisher="CN=16861" Publisher="CN=DGP Studio"
Version="1.0.0.0" /> Version="1.0.0.0" />
<Properties> <Properties>
@@ -25,7 +25,7 @@
<Resources> <Resources>
<Resource Language="x-generate"/> <Resource Language="x-generate"/>
</Resources> </Resources>
<Applications> <Applications>
<Application Id="App" <Application Id="App"
Executable="$targetnametoken$.exe" Executable="$targetnametoken$.exe"

View File

@@ -0,0 +1,65 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml.Controls;
namespace Snap.Hutao.Service.Abstraction;
/// <summary>
/// 导航服务
/// </summary>
public interface INavigationService
{
/// <summary>
/// 管理的 <see cref="Frame"/>
/// </summary>
Frame? Frame { get; set; }
/// <summary>
/// 指示是否曾导航过,用于启动时导航判断
/// </summary>
bool HasEverNavigated { get; set; }
/// <summary>
/// 管理的 <see cref="NavigationView"/>
/// </summary>
NavigationView? NavigationView { get; set; }
/// <summary>
/// 选中的 <see cref="NavigationViewItem"/>
/// </summary>
NavigationViewItem? Selected { get; set; }
/// <summary>
/// 使用指定的对象进行初始化
/// </summary>
/// <param name="navigationView">管理的 <see cref="NavigationView"/></param>
/// <param name="frame">管理的 <see cref="Frame"/></param>
void Initialize(NavigationView navigationView, Frame frame);
/// <summary>
/// 导航到指定类型的页面
/// </summary>
/// <param name="pageType">指定的页面类型</param>
/// <param name="isSyncTabRequested">是否同步标签,当在代码中调用时应设为 true</param>
/// <param name="data">要传递的数据</param>
/// <returns>是否导航成功</returns>
bool Navigate(Type? pageType, bool isSyncTabRequested = false, object? data = null);
/// <summary>
/// 导航到指定类型的页面
/// </summary>
/// <typeparam name="T">指定的页面类型</typeparam>
/// <param name="isSyncTabRequested">是否同步标签,当在代码中调用时应设为 true</param>
/// <param name="data">要传递的数据</param>
/// <returns>是否导航成功</returns>
bool Navigate<T>(bool isSyncTabRequested = false, object? data = null)
where T : Page;
/// <summary>
/// 同步导航标签
/// </summary>
/// <param name="pageType">同步的页面类型</param>
/// <returns>是否同步成功</returns>
bool SyncTabWith(Type pageType);
}

View File

@@ -0,0 +1,157 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.AppCenter.Analytics;
using Microsoft.Extensions.Logging;
using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Core.Logging;
using Snap.Hutao.Extension;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.View.Helper;
using Snap.Hutao.View.Page;
using System.Linq;
namespace Snap.Hutao.Service;
/// <summary>
/// 导航服务
/// </summary>
[Injection(InjectAs.Transient, typeof(INavigationService))]
internal class NavigationService : INavigationService
{
private readonly ILogger<INavigationService> logger;
private NavigationView? navigationView;
/// <summary>
/// 构造一个新的导航服务
/// </summary>
/// <param name="logger">日志器</param>
public NavigationService(ILogger<INavigationService> logger)
{
this.logger = logger;
}
/// <inheritdoc/>
public Frame? Frame { get; set; }
/// <inheritdoc/>
public NavigationView? NavigationView
{
get => navigationView;
set
{
// remove old listener
if (navigationView != null)
{
navigationView.ItemInvoked -= OnItemInvoked;
navigationView.BackRequested -= OnBackRequested;
}
navigationView = Must.NotNull(value!, "NavigationView");
// add new listener
if (navigationView != null)
{
navigationView.ItemInvoked += OnItemInvoked;
navigationView.BackRequested += OnBackRequested;
}
}
}
/// <inheritdoc/>
public NavigationViewItem? Selected { get; set; }
/// <inheritdoc/>
public bool HasEverNavigated { get; set; }
/// <inheritdoc/>
public bool SyncTabWith(Type pageType)
{
if (NavigationView is null)
{
return false;
}
if (pageType == typeof(SettingPage))
{
NavigationView.SelectedItem = NavigationView.SettingsItem;
}
else
{
NavigationViewItem? target = NavigationView.MenuItems
.OfType<NavigationViewItem>()
.SingleOrDefault(menuItem => NavHelper.GetNavigateTo(menuItem) == pageType);
NavigationView.SelectedItem = target;
}
Selected = NavigationView.SelectedItem as NavigationViewItem;
return true;
}
/// <inheritdoc/>
public bool Navigate(Type? pageType, bool isSyncTabRequested = false, object? data = null)
{
Type? currentType = Frame?.Content?.GetType();
if (pageType is null || (currentType == pageType))
{
return false;
}
_ = isSyncTabRequested && SyncTabWith(pageType);
bool result = false;
try
{
result = Frame?.Navigate(pageType, data) ?? false;
}
catch (Exception ex)
{
logger.LogError(EventIds.NavigationFailed, ex, "导航到指定页面时发生了错误");
}
logger.LogInformation("Navigate to {pageType}:{result}", pageType, result ? "succeed" : "failed");
// 分析页面统计数据时不应加入启动时导航的首个页面
if (HasEverNavigated)
{
Analytics.TrackEvent("General", ("OpenUI", pageType.ToString()).AsDictionary());
}
// 首次导航失败时使属性持续保存为false
HasEverNavigated |= result;
return result;
}
/// <inheritdoc/>
public bool Navigate<T>(bool isSyncTabRequested = false, object? data = null)
where T : Page
{
return Navigate(typeof(T), isSyncTabRequested, data);
}
/// <inheritdoc/>
public void Initialize(NavigationView navigationView, Frame frame)
{
NavigationView = navigationView;
Frame = frame;
}
private void OnItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
{
Selected = NavigationView?.SelectedItem as NavigationViewItem;
Type? targetType = args.IsSettingsInvoked
? typeof(SettingPage)
: NavHelper.GetNavigateTo(Selected);
Navigate(targetType, false, NavHelper.GetExtraData(Selected));
}
private void OnBackRequested(NavigationView sender, NavigationViewBackRequestedEventArgs args)
{
if (Frame != null && Frame.CanGoBack)
{
Frame.GoBack();
}
}
}

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows10.0.19041.0</TargetFramework> <TargetFramework>net6.0-windows10.0.18362.0</TargetFramework>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion> <TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<RootNamespace>Snap.Hutao</RootNamespace> <RootNamespace>Snap.Hutao</RootNamespace>
<ApplicationManifest>app.manifest</ApplicationManifest> <ApplicationManifest>app.manifest</ApplicationManifest>
@@ -10,12 +10,24 @@
<PublishProfile>win10-$(Platform).pubxml</PublishProfile> <PublishProfile>win10-$(Platform).pubxml</PublishProfile>
<UseWinUI>true</UseWinUI> <UseWinUI>true</UseWinUI>
<ImplicitUsings>false</ImplicitUsings> <ImplicitUsings>false</ImplicitUsings>
<Nullable>enable</Nullable>
<EnablePreviewMsixTooling>true</EnablePreviewMsixTooling> <EnablePreviewMsixTooling>true</EnablePreviewMsixTooling>
<NeutralLanguage>zh-CN</NeutralLanguage>
<DefaultLanguage>zh-CN</DefaultLanguage> <DefaultLanguage>zh-CN</DefaultLanguage>
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
<AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
<PackageCertificateThumbprint>F8C2255969BEA4A681CED102771BF807856AEC02</PackageCertificateThumbprint>
<AppxPackageSigningTimestampDigestAlgorithm>SHA256</AppxPackageSigningTimestampDigestAlgorithm>
<AppxAutoIncrementPackageRevision>True</AppxAutoIncrementPackageRevision>
<AppxSymbolPackageEnabled>False</AppxSymbolPackageEnabled>
<GenerateTestArtifacts>True</GenerateTestArtifacts>
<AppxBundle>Never</AppxBundle>
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<None Remove="stylecop.json" /> <None Remove="stylecop.json" />
<None Remove="View\MainView.xaml" /> <None Remove="View\MainView.xaml" />
<None Remove="View\Page\SettingPage.xaml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<AdditionalFiles Include="stylecop.json" /> <AdditionalFiles Include="stylecop.json" />
@@ -32,8 +44,18 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.0.2" /> <PackageReference Include="CommunityToolkit.Mvvm" Version="7.1.2" />
<PackageReference Include="CommunityToolkit.WinUI" Version="7.1.2" />
<PackageReference Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" />
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls" Version="7.1.2" />
<PackageReference Include="Microsoft.AppCenter.Analytics" Version="4.5.1" />
<PackageReference Include="Microsoft.AppCenter.Crashes" Version="4.5.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="6.0.0" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.0.3" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22000.197" /> <PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22000.197" />
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.8" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.406"> <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.406">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
@@ -51,12 +73,17 @@
<None Include="..\.editorconfig" Link=".editorconfig" /> <None Include="..\.editorconfig" Link=".editorconfig" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Common\Snap.Core.Mvvm\Snap.Core.Mvvm.csproj" /> <Folder Include="Control\" />
<Folder Include="ViewModel\" />
<Folder Include="Model\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Service\Abstraction\" /> <ProjectReference Include="..\..\SettingsUI\SettingsUI.csproj" />
<Folder Include="ViewModel\" /> </ItemGroup>
<Folder Include="DataModel\" /> <ItemGroup>
<Page Update="View\Page\SettingPage.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Page Update="View\MainView.xaml"> <Page Update="View\MainView.xaml">

View File

@@ -0,0 +1,57 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Core;
namespace Snap.Hutao.View.Helper;
/// <summary>
/// 导航项帮助类
/// </summary>
public sealed class NavHelper
{
private static readonly DependencyProperty NavigateToProperty = Property<NavHelper>.Attach<Type>("NavigateTo");
private static readonly DependencyProperty ExtraDataProperty = Property<NavHelper>.Attach<object>("ExtraData");
/// <summary>
/// 获取导航项的目标页面类型
/// </summary>
/// <param name="item">待获取的导航项</param>
/// <returns>目标页面类型</returns>
public static Type? GetNavigateTo(NavigationViewItem? item)
{
return item?.GetValue(NavigateToProperty) as Type;
}
/// <summary>
/// 设置导航项的目标页面类型
/// </summary>
/// <param name="item">待设置的导航项</param>
/// <param name="value">新的目标页面类型</param>
public static void SetNavigateTo(NavigationViewItem item, Type value)
{
item.SetValue(NavigateToProperty, value);
}
/// <summary>
/// 获取导航项的目标页面的额外数据
/// </summary>
/// <param name="item">待获取的导航项</param>
/// <returns>目标页面类型的额外数据</returns>
public static object? GetExtraData(NavigationViewItem? item)
{
return item?.GetValue(ExtraDataProperty);
}
/// <summary>
/// 设置导航项的目标页面类型
/// </summary>
/// <param name="item">待设置的导航项</param>
/// <param name="value">新的目标页面类型</param>
public static void SetExtraData(NavigationViewItem item, object value)
{
item.SetValue(ExtraDataProperty, value);
}
}

View File

@@ -6,10 +6,21 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"> mc:Ignorable="d">
<Grid> <Grid>
<NavigationView OpenPaneLength="240" IsTitleBarAutoPaddingEnabled="False" Margin="0,32,0,0"> <NavigationView
x:Name="NavView"
OpenPaneLength="172"
Margin="0,0,0,0"
CompactModeThresholdWidth="360"
ExpandedModeThresholdWidth="720">
<Frame
x:Name="ContentFrame">
<Frame.ContentTransitions>
<NavigationThemeTransition>
<DrillInNavigationTransitionInfo/>
</NavigationThemeTransition>
</Frame.ContentTransitions>
</Frame>
</NavigationView> </NavigationView>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@@ -1,26 +1,26 @@
using Microsoft.UI.Xaml; // Copyright (c) DGP Studio. All rights reserved.
using Microsoft.UI.Xaml.Controls; // Licensed under the MIT license.
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
// To learn more about WinUI, the WinUI project structure, using Microsoft.UI.Xaml.Controls;
// and more about our project templates, see: http://aka.ms/winui-project-info. using Snap.Hutao.Service.Abstraction;
namespace Snap.Hutao.View; namespace Snap.Hutao.View;
/// <summary>
/// 主视图
/// </summary>
public sealed partial class MainView : UserControl public sealed partial class MainView : UserControl
{ {
private readonly INavigationService navigationService;
/// <summary>
/// 构造一个新的主视图
/// </summary>
public MainView() public MainView()
{ {
this.InitializeComponent(); this.InitializeComponent();
navigationService = Ioc.Default.GetRequiredService<INavigationService>();
navigationService.Initialize(NavView, ContentFrame);
} }
} }

View File

@@ -0,0 +1,43 @@
<Page
x:Class="Snap.Hutao.View.Page.SettingPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Snap.Hutao.View.Page"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:SettingsUI.Controls"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.Resources>
<Style TargetType="Expander">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</Page.Resources>
<ScrollViewer>
<StackPanel
Margin="32,0,24,0">
<controls:SettingsGroup
Header="关于 胡桃">
<controls:SettingExpander>
<controls:SettingExpander.Header>
<controls:Setting
Icon="&#xE117;"
Header="检查更新"
Description="根本没有检查更新选项">
</controls:Setting>
</controls:SettingExpander.Header>
<InfoBar
IsClosable="False"
Severity="Informational"
Message="都说了没有了"
IsOpen="True"
CornerRadius="0,0,4,4"/>
</controls:SettingExpander>
</controls:SettingsGroup>
</StackPanel>
</ScrollViewer>
</Page>

View File

@@ -0,0 +1,18 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.View.Page;
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class SettingPage : Microsoft.UI.Xaml.Controls.Page
{
/// <summary>
/// 构造新的设置页面
/// </summary>
public SettingPage()
{
this.InitializeComponent();
}
}