mirror of
https://github.com/Pixeval/Pixeval.git
synced 2025-01-09 04:09:57 +08:00
Use better binding for SettingsPage.xaml
This commit is contained in:
parent
459c8596a4
commit
2e9d94eee7
@ -1,6 +1,9 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.ApplicationModel.Core;
|
||||
using Mako;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Pixeval.Events;
|
||||
using Pixeval.Util;
|
||||
@ -43,32 +46,23 @@ namespace Pixeval
|
||||
args.Handled = true;
|
||||
UncaughtExceptionHandler(args.Exception);
|
||||
};
|
||||
|
||||
TaskScheduler.UnobservedTaskException += (_, args) =>
|
||||
{
|
||||
UncaughtExceptionHandler(args.Exception);
|
||||
args.SetObserved();
|
||||
};
|
||||
AppDomain.CurrentDomain.UnhandledException += async (_, args) =>
|
||||
{
|
||||
if (args.ExceptionObject is Exception e)
|
||||
{
|
||||
UncaughtExceptionHandler(e);
|
||||
}
|
||||
|
||||
if (args.IsTerminating)
|
||||
{
|
||||
await ExitWithPushedNotification();
|
||||
}
|
||||
UncaughtExceptionHandler(args.Exception);
|
||||
};
|
||||
|
||||
static void UncaughtExceptionHandler(Exception e)
|
||||
AppDomain.CurrentDomain.UnhandledException += (sender, args) =>
|
||||
{
|
||||
Window.DispatcherQueue.TryEnqueue(async () =>
|
||||
{
|
||||
await MessageDialogBuilder
|
||||
.CreateAcknowledgement(Window, MiscResources.ExceptionEncountered, e.ToString()).ShowAsync();
|
||||
await ExitWithPushedNotification();
|
||||
});
|
||||
Debugger.Break();
|
||||
};
|
||||
|
||||
static async void UncaughtExceptionHandler(Exception e)
|
||||
{
|
||||
await MessageDialogBuilder
|
||||
.CreateAcknowledgement(Window, MiscResources.ExceptionEncountered, e.ToString()).ShowAsync();
|
||||
await ExitWithPushedNotification();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,7 +180,7 @@ namespace Pixeval
|
||||
ConfigurationContainer.Values[nameof(AppSetting.ExcludeTags)] = appSetting.ExcludeTags.ToJson();
|
||||
ConfigurationContainer.Values[nameof(AppSetting.DisableDomainFronting)] = appSetting.DisableDomainFronting;
|
||||
ConfigurationContainer.Values[nameof(AppSetting.DefaultSortOption)] = appSetting.DefaultSortOption.CastOrThrow<int>();
|
||||
ConfigurationContainer.Values[nameof(AppSetting.SearchTagMatchOption)] = appSetting.SearchTagMatchOption.CastOrThrow<int>();
|
||||
ConfigurationContainer.Values[nameof(AppSetting.TagMatchOption)] = appSetting.TagMatchOption.CastOrThrow<int>();
|
||||
ConfigurationContainer.Values[nameof(AppSetting.PageLimitForKeywordSearch)] = appSetting.PageLimitForKeywordSearch;
|
||||
ConfigurationContainer.Values[nameof(AppSetting.SearchStartingFromPageNumber)] = appSetting.SearchStartingFromPageNumber;
|
||||
ConfigurationContainer.Values[nameof(AppSetting.PageLimitForSpotlight)] = appSetting.PageLimitForSpotlight;
|
||||
@ -223,7 +223,7 @@ namespace Pixeval
|
||||
(ConfigurationContainer.Values[nameof(AppSetting.ExcludeTags)].CastOrThrow<string>().FromJson<string[]>() ?? Array.Empty<string>()).ToObservableCollection(),
|
||||
ConfigurationContainer.Values[nameof(AppSetting.DisableDomainFronting)].CastOrThrow<bool>(),
|
||||
ConfigurationContainer.Values[nameof(AppSetting.DefaultSortOption)].CastOrThrow<IllustrationSortOption>(),
|
||||
ConfigurationContainer.Values[nameof(AppSetting.SearchTagMatchOption)].CastOrThrow<SearchTagMatchOption>(),
|
||||
ConfigurationContainer.Values[nameof(AppSetting.TagMatchOption)].CastOrThrow<SearchTagMatchOption>(),
|
||||
ConfigurationContainer.Values[nameof(AppSetting.PageLimitForKeywordSearch)].CastOrThrow<int>(),
|
||||
ConfigurationContainer.Values[nameof(AppSetting.SearchStartingFromPageNumber)].CastOrThrow<int>(),
|
||||
ConfigurationContainer.Values[nameof(AppSetting.PageLimitForSpotlight)].CastOrThrow<int>(),
|
||||
|
@ -37,7 +37,7 @@ namespace Pixeval
|
||||
/// <summary>
|
||||
/// The tag match option for keyword search
|
||||
/// </summary>
|
||||
public SearchTagMatchOption SearchTagMatchOption { get; set; }
|
||||
public SearchTagMatchOption TagMatchOption { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the maximum page count that are allowed to be retrieved during
|
||||
@ -82,7 +82,7 @@ namespace Pixeval
|
||||
ExcludeTags = excludeTags;
|
||||
DisableDomainFronting = disableDomainFronting;
|
||||
DefaultSortOption = defaultSortOption;
|
||||
SearchTagMatchOption = searchTagMatchOption;
|
||||
TagMatchOption = searchTagMatchOption;
|
||||
PageLimitForKeywordSearch = pageLimitForKeywordSearch;
|
||||
SearchStartingFromPageNumber = searchStartingFromPageNumber;
|
||||
PageLimitForSpotlight = pageLimitForSpotlight;
|
||||
|
@ -1,7 +1,16 @@
|
||||
namespace Pixeval
|
||||
using Pixeval.Util;
|
||||
|
||||
namespace Pixeval
|
||||
{
|
||||
public enum ApplicationTheme
|
||||
{
|
||||
Dark, Light, SystemDefault
|
||||
[LocalizedResource(typeof(MiscResources), nameof(MiscResources.ApplicationThemeDark))]
|
||||
Dark,
|
||||
|
||||
[LocalizedResource(typeof(MiscResources), nameof(MiscResources.ApplicationThemeLight))]
|
||||
Light,
|
||||
|
||||
[LocalizedResource(typeof(MiscResources), nameof(MiscResources.ApplicationThemeSystemDefault))]
|
||||
SystemDefault
|
||||
}
|
||||
}
|
@ -117,12 +117,39 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="ApplicationThemeDark" xml:space="preserve">
|
||||
<value>暗色</value>
|
||||
</data>
|
||||
<data name="ApplicationThemeLight" xml:space="preserve">
|
||||
<value>亮色</value>
|
||||
</data>
|
||||
<data name="ApplicationThemeSystemDefault" xml:space="preserve">
|
||||
<value>跟随系统主题</value>
|
||||
</data>
|
||||
<data name="CannotFindLoginProxyServerExecutable" xml:space="preserve">
|
||||
<value>找不到用于登录的可执行文件,请重新打开应用或者联系开发者</value>
|
||||
</data>
|
||||
<data name="ExceptionEncountered" xml:space="preserve">
|
||||
<value>应用程序遇到了异常,即将关闭</value>
|
||||
</data>
|
||||
<data name="IllustrationSortOptionPopularityDescending" xml:space="preserve">
|
||||
<value>收藏数降序</value>
|
||||
</data>
|
||||
<data name="IllustrationSortOptionPublishDateAscending" xml:space="preserve">
|
||||
<value>发布日期升序</value>
|
||||
</data>
|
||||
<data name="IllustrationSortOptionPublishDateDescending" xml:space="preserve">
|
||||
<value>发布日期降序</value>
|
||||
</data>
|
||||
<data name="SearchTagMatchOptionExactMatchForTags" xml:space="preserve">
|
||||
<value>与关键字完全一致</value>
|
||||
</data>
|
||||
<data name="SearchTagMatchOptionPartialMatchForTags" xml:space="preserve">
|
||||
<value>与关键字部分一致</value>
|
||||
</data>
|
||||
<data name="SearchTagMatchOptionTitleAndCaption" xml:space="preserve">
|
||||
<value>匹配标题与说明文</value>
|
||||
</data>
|
||||
<data name="SortOptionComboBox.PlaceholderText" xml:space="preserve">
|
||||
<value>排序选项</value>
|
||||
</data>
|
||||
|
@ -123,18 +123,9 @@
|
||||
<data name="AboutSNIBypassHyperlinkButton.Content" xml:space="preserve">
|
||||
<value>了解更多关于域前置直连的信息</value>
|
||||
</data>
|
||||
<data name="ApplicationThemeDarkRadioButton.Content" xml:space="preserve">
|
||||
<value>暗色</value>
|
||||
</data>
|
||||
<data name="ApplicationThemeLightRadioButton.Content" xml:space="preserve">
|
||||
<value>亮色</value>
|
||||
</data>
|
||||
<data name="ApplicationThemeOpenSystemThemeSettingHyperlinkButton.Content" xml:space="preserve">
|
||||
<value>打开Windows系统主题设置</value>
|
||||
</data>
|
||||
<data name="ApplicationThemeSystemDefaultRadioButton.Content" xml:space="preserve">
|
||||
<value>跟随系统主题</value>
|
||||
</data>
|
||||
<data name="ApplicationThemeTextBlock.Text" xml:space="preserve">
|
||||
<value>应用程序主题(重启应用后生效)</value>
|
||||
</data>
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using System;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using Pixeval.Pages;
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:util="using:Pixeval.Util"
|
||||
xmlns:viewModel="using:Pixeval.ViewModel"
|
||||
d:DataContext="{d:DesignInstance viewModel:LoginPageViewModel}"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
||||
@ -19,7 +20,7 @@
|
||||
<TextBlock Margin="0,15,0,0"
|
||||
HorizontalAlignment="Center"
|
||||
FontSize="10"
|
||||
Text="{x:Bind viewModel:LoginPageViewModel.GetLoginPhaseString(_viewModel.LoginPhase), Mode=OneWay}" />
|
||||
Text="{x:Bind util:AttributeHelper.GetLocalizedResources(_viewModel.LoginPhase), Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
@ -3,12 +3,13 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:CommunityToolkit.WinUI.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mako="using:Mako.Global.Enum"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:numberFormatting="using:Windows.Globalization.NumberFormatting"
|
||||
xmlns:pixeval="using:Pixeval"
|
||||
xmlns:system="using:System"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI.UI"
|
||||
xmlns:util="using:Pixeval.Util"
|
||||
xmlns:viewModel="using:Pixeval.ViewModel"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
||||
mc:Ignorable="d">
|
||||
<!-- ReSharper disable UnusedMember.Local -->
|
||||
@ -87,19 +88,16 @@
|
||||
<TextBlock x:Uid="/SettingsPage/ApplicationThemeTextBlock"
|
||||
Style="{StaticResource SectionHeaderTextBlockStyle}" />
|
||||
<RadioButtons x:Name="ApplicationThemeRadioButtons"
|
||||
ItemsSource="{x:Bind viewModel:SettingsPageViewModel.AvailableApplicationThemes}"
|
||||
MaxColumns="1"
|
||||
SelectedItem="{x:Bind GetApplicationThemeRadioButtonsSelectedItem()}">
|
||||
<RadioButtons.Items>
|
||||
<RadioButton x:Uid="/SettingsPage/ApplicationThemeSystemDefaultRadioButton"
|
||||
Checked="ApplicationThemeSystemDefaultRadioButton_OnChecked"
|
||||
Tag="{x:Bind pixeval:ApplicationTheme.SystemDefault}" />
|
||||
<RadioButton x:Uid="/SettingsPage/ApplicationThemeLightRadioButton"
|
||||
Checked="ApplicationThemeLightRadioButton_OnChecked"
|
||||
Tag="{x:Bind pixeval:ApplicationTheme.Light}" />
|
||||
<RadioButton x:Uid="/SettingsPage/ApplicationThemeDarkRadioButton"
|
||||
Checked="ApplicationThemeDarkRadioButton_OnChecked"
|
||||
Tag="{x:Bind pixeval:ApplicationTheme.Dark}" />
|
||||
</RadioButtons.Items>
|
||||
SelectedItem="{x:Bind _viewModel.Theme}">
|
||||
<RadioButtons.ItemTemplate>
|
||||
<DataTemplate x:DataType="pixeval:ApplicationTheme">
|
||||
<RadioButton Checked="ApplicationThemeRadioButton_OnChecked"
|
||||
Content="{x:Bind util:AttributeHelper.GetLocalizedResources((pixeval:ApplicationTheme))}"
|
||||
DataContext="{x:Bind}" />
|
||||
</DataTemplate>
|
||||
</RadioButtons.ItemTemplate>
|
||||
</RadioButtons>
|
||||
<HyperlinkButton x:Uid="/SettingsPage/ApplicationThemeOpenSystemThemeSettingHyperlinkButton"
|
||||
Click="ApplicationThemeOpenSystemThemeSettingHyperlinkButton_OnClick"
|
||||
@ -141,16 +139,13 @@
|
||||
<ComboBox x:Name="DefaultSortOptionComboBox"
|
||||
x:Uid="/Misc/SortOptionComboBox"
|
||||
Margin="{StaticResource SettingsEntryPadding}"
|
||||
SelectedItem="{x:Bind GetDefaultSortOptionComboBoxSelectedItem()}"
|
||||
SelectionChanged="DefaultSortOptionComboBox_OnSelectionChanged">
|
||||
<ComboBox.Items>
|
||||
<ComboBoxItem x:Uid="/Misc/SortOptionComboBoxPublishDateDescendingComboBoxItem"
|
||||
Tag="{x:Bind mako:IllustrationSortOption.PublishDateDescending}" />
|
||||
<ComboBoxItem x:Uid="/Misc/SortOptionComboBoxPublishDateAscendingComboBoxItem"
|
||||
Tag="{x:Bind mako:IllustrationSortOption.PublishDateAscending}" />
|
||||
<ComboBoxItem x:Uid="/Misc/SortOptionComboBoxBookmarkDescendingComboBoxItem"
|
||||
Tag="{x:Bind mako:IllustrationSortOption.PopularityDescending}" />
|
||||
</ComboBox.Items>
|
||||
ItemsSource="{x:Bind viewModel:SettingsPageViewModel.AvailableIllustrationSortOptions}"
|
||||
SelectedItem="{x:Bind _viewModel.BoxSortOption(), BindBack=_viewModel.UnboxSortOption, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="viewModel:IllustrationSortOptionWrapper">
|
||||
<TextBlock Text="{x:Bind LocalizedString}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
<InfoBar x:Uid="/SettingsPage/DefaultSortOptionInfoBar"
|
||||
Style="{StaticResource SectionInfoBarStyle}" />
|
||||
@ -160,16 +155,13 @@
|
||||
<ComboBox x:Name="SearchKeywordMatchOptionComboBox"
|
||||
x:Uid="/SettingsPage/SearchKeywordMatchOptionComboBox"
|
||||
Margin="{StaticResource SettingsEntryPadding}"
|
||||
SelectedItem="{x:Bind GetSearchKeywordMatchOptionComboBoxSelectedItem()}"
|
||||
SelectionChanged="SearchKeywordMatchOptionComboBox_OnSelectionChanged">
|
||||
<ComboBox.Items>
|
||||
<ComboBoxItem x:Uid="/SettingsPage/SearchKeywordMatchOptionComboBoxPartialMatchComboBoxItem"
|
||||
Tag="{x:Bind mako:SearchTagMatchOption.PartialMatchForTags}" />
|
||||
<ComboBoxItem x:Uid="/SettingsPage/SearchKeywordMatchOptionComboBoxExactMatchComboBoxItem"
|
||||
Tag="{x:Bind mako:SearchTagMatchOption.ExactMatchForTags}" />
|
||||
<ComboBoxItem x:Uid="/SettingsPage/SearchKeywordMatchOptionComboBoxTitleAndCaptionMatchComboBoxItem"
|
||||
Tag="{x:Bind mako:SearchTagMatchOption.TitleAndCaption}" />
|
||||
</ComboBox.Items>
|
||||
ItemsSource="{x:Bind viewModel:SettingsPageViewModel.AvailableSearchTagMatchOption}"
|
||||
SelectedItem="{x:Bind _viewModel.BoxSearchTagMatchOption(), BindBack=_viewModel.UnboxSearchTagMatchOption, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="viewModel:SearchTagMatchOptionWrapper">
|
||||
<TextBlock Text="{x:Bind LocalizedString}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
<InfoBar x:Uid="/SettingsPage/SearchKeywordMatchOptionInfoBar"
|
||||
Style="{StaticResource SectionInfoBarStyle}" />
|
||||
|
@ -5,7 +5,6 @@ using System;
|
||||
using System.Linq;
|
||||
using Windows.System;
|
||||
using CommunityToolkit.WinUI.UI.Controls;
|
||||
using Mako.Global.Enum;
|
||||
using Pixeval.Util;
|
||||
using Pixeval.ViewModel;
|
||||
|
||||
@ -76,23 +75,6 @@ namespace Pixeval.Pages
|
||||
await Launcher.LaunchUriAsync(new Uri("ms-settings:themes"));
|
||||
}
|
||||
|
||||
// The RadioButtons.SelectionChanged always returns null, so we have to handle them separately
|
||||
// See issue https://github.com/microsoft/microsoft-ui-xaml/issues/3268
|
||||
private void ApplicationThemeSystemDefaultRadioButton_OnChecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_viewModel.Theme = ApplicationTheme.SystemDefault;
|
||||
}
|
||||
|
||||
private void ApplicationThemeLightRadioButton_OnChecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_viewModel.Theme = ApplicationTheme.Light;
|
||||
}
|
||||
|
||||
private void ApplicationThemeDarkRadioButton_OnChecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_viewModel.Theme = ApplicationTheme.Dark;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Sensitive Tags
|
||||
@ -163,33 +145,15 @@ namespace Pixeval.Pages
|
||||
await Launcher.LaunchUriAsync(new Uri("mailto:decem0730@hotmail.com"));
|
||||
}
|
||||
|
||||
private void DefaultSortOptionComboBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
// We cannot use RadioButtons.SelectionChanged since it always returns null
|
||||
// see https://github.com/microsoft/microsoft-ui-xaml/issues/3268
|
||||
private void ApplicationThemeRadioButton_OnChecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_viewModel.DefaultSortOption = (IllustrationSortOption) ((ComboBoxItem) DefaultSortOptionComboBox.SelectedItem).Tag;
|
||||
}
|
||||
|
||||
private void SearchKeywordMatchOptionComboBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
_viewModel.SearchTagMatchOption = (SearchTagMatchOption) ((ComboBoxItem) SearchKeywordMatchOptionComboBox.SelectedItem).Tag;
|
||||
_viewModel.Theme = sender.GetDataContext<ApplicationTheme>();
|
||||
}
|
||||
|
||||
#region Helper Functions
|
||||
|
||||
private object GetApplicationThemeRadioButtonsSelectedItem()
|
||||
{
|
||||
return ApplicationThemeRadioButtons.Items.Cast<RadioButton>().First(i => i.Tag.Equals(_viewModel.Theme));
|
||||
}
|
||||
|
||||
private object GetDefaultSortOptionComboBoxSelectedItem()
|
||||
{
|
||||
return DefaultSortOptionComboBox.Items.Cast<ComboBoxItem>().First(i => i.Tag.Equals(_viewModel.DefaultSortOption));
|
||||
}
|
||||
|
||||
private object GetSearchKeywordMatchOptionComboBoxSelectedItem()
|
||||
{
|
||||
return SearchKeywordMatchOptionComboBox.Items.Cast<ComboBoxItem>().First(i => i.Tag.Equals(_viewModel.SearchTagMatchOption));
|
||||
}
|
||||
|
||||
// TODO: use attached property
|
||||
private static void NumberBoxCoerceValueInAndShowTeachingTip(object sender, TeachingTip teachingTip, double startInclusive, double endInclusive)
|
||||
{
|
||||
|
142
src/Pixeval/Pixeval - Backup.csproj
Normal file
142
src/Pixeval/Pixeval - Backup.csproj
Normal file
@ -0,0 +1,142 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net5.0-windows10.0.19041</TargetFramework>
|
||||
<TargetPlatformMinVersion>10.0.18362.0</TargetPlatformMinVersion>
|
||||
<RootNamespace>Pixeval</RootNamespace>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<Platforms>x86;x64;arm64</Platforms>
|
||||
<RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
|
||||
<UseWinUI>true</UseWinUI>
|
||||
<Nullable>enable</Nullable>
|
||||
<DefaultLanguage>zh-CN</DefaultLanguage>
|
||||
<EnableNETAnalyzers>false</EnableNETAnalyzers>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<DefineConstants></DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Content Remove="Assets\Images\logo-no-caption.png" />
|
||||
<Content Remove="Assets\Strings\zh-CN\BookmarksPage.resw" />
|
||||
<Content Remove="Assets\Strings\zh-CN\IllustrationGridCommandBar.resw" />
|
||||
<Content Remove="Assets\Strings\zh-CN\RecommendsPage.resw" />
|
||||
<Content Remove="Assets\Strings\zh-CN\SettingsPage.resw" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Assets\Certs\pixeval_server_cert.pfx" />
|
||||
<None Remove="Assets\Strings\zh-CN\BookmarksPage.resw" />
|
||||
<None Remove="Pages\BookMarksPage.xaml" />
|
||||
<None Remove="Pages\DownloadListPage.xaml" />
|
||||
<None Remove="Pages\IllustrationGridPage.xaml" />
|
||||
<None Remove="Pages\IllustrationViewerPage.xaml" />
|
||||
<None Remove="Pages\RecommendsPage.xaml" />
|
||||
<None Remove="Pages\SettingsPage.xaml" />
|
||||
<None Remove="UserControls\IllustrationGridCommandBar.xaml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Animations" Version="7.0.3" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls" Version="7.0.3" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Media" Version="7.0.3" />
|
||||
<PackageReference Include="Mako" Version="1.0.11" />
|
||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.1.3" />
|
||||
<PackageReference Include="Microsoft.ProjectReunion" Version="0.8.1" />
|
||||
<PackageReference Include="Microsoft.ProjectReunion.Foundation" Version="0.8.1" />
|
||||
<PackageReference Include="Microsoft.ProjectReunion.WinUI" Version="0.8.1" />
|
||||
<PackageReference Include="Microsoft.Toolkit.Mvvm" Version="7.0.2" />
|
||||
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.0.2" />
|
||||
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.4" />
|
||||
<PackageReference Include="PInvoke.User32" Version="0.7.104" />
|
||||
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" />
|
||||
<PackageReference Include="System.Linq.Async" Version="5.0.0" />
|
||||
<Manifest Include="$(ApplicationManifest)" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- region Exposes PRI resources to the source generator -->
|
||||
|
||||
<Target Name="InjectAdditionalFiles" BeforeTargets="GenerateMSBuildEditorConfigFileShouldRun">
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="@(PRIResource)" SourceItemGroup="PRIResource" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
<CompilerVisibleItemMetadata Include="AdditionalFiles" MetadataName="SourceItemGroup" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- endregion Exposes PRI resources to the source generator -->
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Pixeval.SourceGen\Pixeval.SourceGen.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="Pages\SettingsPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="Pages\DownloadListPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="Pages\IllustrationViewerPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="UserControls\IllustrationGridCommandBar.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="Pages\RecommendsPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="UserControls\IllustrationGrid.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="Pages\MessageDialogContent.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="Pages\MainPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="Pages\LoginPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Assets\Binary\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PRIResource Include="Assets\Strings\zh-CN\BookmarksPage.resw" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="Pages\BookMarksPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -12,6 +12,9 @@
|
||||
<DefaultLanguage>zh-CN</DefaultLanguage>
|
||||
<EnableNETAnalyzers>false</EnableNETAnalyzers>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<DefineConstants>TRACE;DEBUG</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Content Remove="Assets\Images\logo-no-caption.png" />
|
||||
<Content Remove="Assets\Strings\zh-CN\BookmarksPage.resw" />
|
||||
@ -35,7 +38,7 @@
|
||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Animations" Version="7.0.3" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls" Version="7.0.3" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Media" Version="7.0.3" />
|
||||
<PackageReference Include="Mako" Version="1.0.10" />
|
||||
<PackageReference Include="Mako" Version="1.0.11" />
|
||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.1.3" />
|
||||
<PackageReference Include="Microsoft.ProjectReunion" Version="0.8.1" />
|
||||
<PackageReference Include="Microsoft.ProjectReunion.Foundation" Version="0.8.1" />
|
||||
|
49
src/Pixeval/Util/Attributes.cs
Normal file
49
src/Pixeval/Util/Attributes.cs
Normal file
@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Pixeval.Util
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public class Metadata : Attribute
|
||||
{
|
||||
public Metadata(string key)
|
||||
{
|
||||
Key = key;
|
||||
}
|
||||
|
||||
public string Key { get; }
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public class LocalizedResource : Attribute
|
||||
{
|
||||
public Type ResourceLoader { get; set; }
|
||||
|
||||
public string Key { get; set; }
|
||||
|
||||
public LocalizedResource(Type resourceLoader, string key)
|
||||
{
|
||||
ResourceLoader = resourceLoader;
|
||||
Key = key;
|
||||
}
|
||||
}
|
||||
|
||||
public static class AttributeHelper
|
||||
{
|
||||
public static TAttribute? GetCustomAttribute<TAttribute>(this Enum e) where TAttribute : Attribute
|
||||
{
|
||||
return e.GetType().GetField(e.ToString())?.GetCustomAttribute(typeof(TAttribute), false) as TAttribute;
|
||||
}
|
||||
|
||||
public static string? GetMetadataOnEnumMember(this Enum e)
|
||||
{
|
||||
return e.GetCustomAttribute<Metadata>()?.Key;
|
||||
}
|
||||
|
||||
public static string? GetLocalizedResources(this Enum e)
|
||||
{
|
||||
var attribute = e.GetCustomAttribute<LocalizedResource>();
|
||||
return attribute?.ResourceLoader?.GetField(attribute?.Key ?? string.Empty)?.GetValue(null) as string;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Pixeval.Util
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public class Metadata : Attribute
|
||||
{
|
||||
public Metadata(string key)
|
||||
{
|
||||
Key = key;
|
||||
}
|
||||
|
||||
public string Key { get; }
|
||||
}
|
||||
|
||||
public static class MetadataHelper
|
||||
{
|
||||
public static string? GetMetadataOnEnumMember(this Enum e)
|
||||
{
|
||||
return (e.GetType().GetField(e.ToString())?.GetCustomAttribute(typeof(Metadata), false) as Metadata)?.Key;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
@ -58,5 +59,10 @@ namespace Pixeval.Util
|
||||
var (startInclusive, endInclusive) = range;
|
||||
return Math.Max(startInclusive, Math.Min(i, endInclusive));
|
||||
}
|
||||
|
||||
public static IEnumerable<TEnum> GetEnumValues<TEnum>(this Type type)
|
||||
{
|
||||
return type.GetEnumValues().Cast<TEnum>();
|
||||
}
|
||||
}
|
||||
}
|
@ -39,12 +39,12 @@ namespace Pixeval.Util
|
||||
}
|
||||
}
|
||||
|
||||
public static T? GetDataContext<T>(this FrameworkElement element) where T : class
|
||||
public static T GetDataContext<T>(this FrameworkElement element)
|
||||
{
|
||||
return element.DataContext as T;
|
||||
return (T) element.DataContext;
|
||||
}
|
||||
|
||||
public static T? GetDataContext<T>(this object element) where T : class
|
||||
public static T GetDataContext<T>(this object element)
|
||||
{
|
||||
return ((FrameworkElement) element).GetDataContext<T>(); // direct cast will throw exception if the type check failed, and that's exactly what we want
|
||||
}
|
||||
|
@ -54,25 +54,25 @@ namespace Pixeval.ViewModel
|
||||
|
||||
public enum LoginPhaseEnum
|
||||
{
|
||||
[Metadata(nameof(LoginPageResources.LoginPhaseCheckingRefreshAvailable))]
|
||||
[LocalizedResource(typeof(LoginPageResources), nameof(LoginPageResources.LoginPhaseCheckingRefreshAvailable))]
|
||||
CheckingRefreshAvailable,
|
||||
|
||||
[Metadata(nameof(LoginPageResources.LoginPhaseRefreshing))]
|
||||
[LocalizedResource(typeof(LoginPageResources), nameof(LoginPageResources.LoginPhaseRefreshing))]
|
||||
Refreshing,
|
||||
|
||||
[Metadata(nameof(LoginPageResources.LoginPhaseNegotiatingPort))]
|
||||
[LocalizedResource(typeof(LoginPageResources), nameof(LoginPageResources.LoginPhaseNegotiatingPort))]
|
||||
NegotiatingPort,
|
||||
|
||||
[Metadata(nameof(LoginPageResources.LoginPhaseExecutingLoginProxy))]
|
||||
[LocalizedResource(typeof(LoginPageResources), nameof(LoginPageResources.LoginPhaseExecutingLoginProxy))]
|
||||
ExecutingLoginProxy,
|
||||
|
||||
[Metadata(nameof(LoginPageResources.LoginPhaseCheckingCertificateInstallation))]
|
||||
[LocalizedResource(typeof(LoginPageResources), nameof(LoginPageResources.LoginPhaseCheckingCertificateInstallation))]
|
||||
CheckingCertificateInstallation,
|
||||
|
||||
[Metadata(nameof(LoginPageResources.LoginPhaseInstallingCertificate))]
|
||||
[LocalizedResource(typeof(LoginPageResources), nameof(LoginPageResources.LoginPhaseInstallingCertificate))]
|
||||
InstallingCertificate,
|
||||
|
||||
[Metadata(nameof(LoginPageResources.LoginPhaseCheckingWebView2Installation))]
|
||||
[LocalizedResource(typeof(LoginPageResources), nameof(LoginPageResources.LoginPhaseCheckingWebView2Installation))]
|
||||
CheckingWebView2Installation
|
||||
}
|
||||
|
||||
@ -94,11 +94,6 @@ namespace Pixeval.ViewModel
|
||||
LoginPhase = newPhase;
|
||||
}
|
||||
|
||||
public static string GetLoginPhaseString(LoginPhaseEnum loginPhase)
|
||||
{
|
||||
return (string) typeof(LoginPageResources).GetField(loginPhase.GetMetadataOnEnumMember()!)?.GetValue(null)!;
|
||||
}
|
||||
|
||||
public bool CheckWebView2Installation()
|
||||
{
|
||||
AdvancePhase(LoginPhaseEnum.CheckingWebView2Installation);
|
||||
|
@ -1,12 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using Mako.Global.Enum;
|
||||
using Microsoft.Toolkit.Mvvm.ComponentModel;
|
||||
using Pixeval.Util;
|
||||
|
||||
namespace Pixeval.ViewModel
|
||||
{
|
||||
public record IllustrationSortOptionWrapper
|
||||
{
|
||||
public IllustrationSortOption Option { get; }
|
||||
|
||||
public string LocalizedString { get; }
|
||||
|
||||
public IllustrationSortOptionWrapper(IllustrationSortOption option, string localizedString)
|
||||
{
|
||||
Option = option;
|
||||
LocalizedString = localizedString;
|
||||
}
|
||||
}
|
||||
|
||||
public record SearchTagMatchOptionWrapper
|
||||
{
|
||||
public SearchTagMatchOption Option { get; }
|
||||
|
||||
public string LocalizedString { get; }
|
||||
|
||||
public SearchTagMatchOptionWrapper(SearchTagMatchOption option, string localizedString)
|
||||
{
|
||||
Option = option;
|
||||
LocalizedString = localizedString;
|
||||
}
|
||||
}
|
||||
|
||||
public class SettingsPageViewModel : ObservableObject
|
||||
{
|
||||
private readonly AppSetting _appSetting;
|
||||
@ -16,6 +43,49 @@ namespace Pixeval.ViewModel
|
||||
_appSetting = appSetting;
|
||||
}
|
||||
|
||||
public static readonly IEnumerable<ApplicationTheme> AvailableApplicationThemes = typeof(ApplicationTheme).GetEnumValues<ApplicationTheme>();
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IllustrationSortOption"/> is welded into Mako, we cannot add <see cref="LocalizedResource"/> on its fields
|
||||
/// so an alternative way is chosen
|
||||
/// </summary>
|
||||
public static readonly IEnumerable<IllustrationSortOptionWrapper> AvailableIllustrationSortOptions = new IllustrationSortOptionWrapper[]
|
||||
{
|
||||
new(IllustrationSortOption.PublishDateDescending, MiscResources.IllustrationSortOptionPublishDateDescending),
|
||||
new(IllustrationSortOption.PublishDateAscending, MiscResources.IllustrationSortOptionPublishDateAscending),
|
||||
new(IllustrationSortOption.PopularityDescending, MiscResources.IllustrationSortOptionPopularityDescending)
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The same reason as <see cref="AvailableIllustrationSortOptions"/>
|
||||
/// </summary>
|
||||
public static readonly IEnumerable<SearchTagMatchOptionWrapper> AvailableSearchTagMatchOption = new SearchTagMatchOptionWrapper[]
|
||||
{
|
||||
new(SearchTagMatchOption.PartialMatchForTags, MiscResources.SearchTagMatchOptionPartialMatchForTags),
|
||||
new(SearchTagMatchOption.ExactMatchForTags, MiscResources.SearchTagMatchOptionExactMatchForTags),
|
||||
new(SearchTagMatchOption.TitleAndCaption, MiscResources.SearchTagMatchOptionTitleAndCaption)
|
||||
};
|
||||
|
||||
public IllustrationSortOptionWrapper BoxSortOption()
|
||||
{
|
||||
return AvailableIllustrationSortOptions.First(s => s.Option == DefaultSortOption);
|
||||
}
|
||||
|
||||
public void UnboxSortOption(object wrapper)
|
||||
{
|
||||
DefaultSortOption = ((IllustrationSortOptionWrapper) wrapper).Option;
|
||||
}
|
||||
|
||||
public SearchTagMatchOptionWrapper BoxSearchTagMatchOption()
|
||||
{
|
||||
return AvailableSearchTagMatchOption.First(s => s.Option == TagMatchOption);
|
||||
}
|
||||
|
||||
public void UnboxSearchTagMatchOption(object wrapper)
|
||||
{
|
||||
TagMatchOption = ((SearchTagMatchOptionWrapper) wrapper).Option;
|
||||
}
|
||||
|
||||
public ApplicationTheme Theme
|
||||
{
|
||||
get => _appSetting.Theme;
|
||||
@ -44,10 +114,10 @@ namespace Pixeval.ViewModel
|
||||
set => SetProperty(_appSetting.DefaultSortOption, value, _appSetting, (setting, value) => setting.DefaultSortOption = value);
|
||||
}
|
||||
|
||||
public SearchTagMatchOption SearchTagMatchOption
|
||||
public SearchTagMatchOption TagMatchOption
|
||||
{
|
||||
get => _appSetting.SearchTagMatchOption;
|
||||
set => SetProperty(_appSetting.SearchTagMatchOption, value, _appSetting, (setting, value) => setting.SearchTagMatchOption = value);
|
||||
get => _appSetting.TagMatchOption;
|
||||
set => SetProperty(_appSetting.TagMatchOption, value, _appSetting, (setting, value) => setting.TagMatchOption = value);
|
||||
}
|
||||
|
||||
public int PageLimitForKeywordSearch
|
||||
|
Loading…
Reference in New Issue
Block a user