添加代理支持 (#462)

* 添加代理支持

* 简化Expander
This commit is contained in:
Poker 2024-05-13 20:38:19 +08:00 committed by GitHub
parent b6d69dbb94
commit 44f7ea848b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
36 changed files with 457 additions and 148 deletions

View File

@ -96,8 +96,13 @@ public sealed partial class AdvancedItemsView : ItemsView
return false;
};
_ = RegisterPropertyChangedCallback(ScrollViewProperty, ScrollViewOnPropertyChanged);
_ = RegisterPropertyChangedCallback(ItemsSourceProperty, ItemsSourceOnPropertyChanged);
_scrollViewOnPropertyChangedToken = RegisterPropertyChangedCallback(ScrollViewProperty, ScrollViewOnPropertyChanged);
var itemsSourceOnPropertyChangedToken = RegisterPropertyChangedCallback(ItemsSourceProperty, ItemsSourceOnPropertyChanged);
Unloaded += (_, _) =>
{
UnregisterPropertyChangedCallback(ScrollViewProperty, _scrollViewOnPropertyChangedToken);
UnregisterPropertyChangedCallback(ItemsSourceProperty, itemsSourceOnPropertyChangedToken);
};
}
#region PropertyChanged
@ -250,14 +255,18 @@ public sealed partial class AdvancedItemsView : ItemsView
#region EventHandlers
private readonly long _scrollViewOnPropertyChangedToken;
/// <summary>
/// 本方法之后会触发<see cref="AdvancedItemsViewOnSizeChanged"/>
/// </summary>
private void ScrollViewOnPropertyChanged(DependencyObject sender, DependencyProperty dp)
{
UnregisterPropertyChangedCallback(ScrollViewProperty, _scrollViewOnPropertyChangedToken);
ScrollView.ViewChanged += ScrollView_ViewChanged;
ScrollView.PointerWheelChanged += ScrollView_PointerWheelChanged;
_itemsRepeater = ScrollView.Content.To<ItemsRepeater>();
ScrollView.Content = new Grid { Children = { _itemsRepeater } };
_itemsRepeater.SizeChanged += AdvancedItemsViewOnSizeChanged;
}

View File

@ -131,23 +131,7 @@ public partial class MakoClient
return RunWithLoggerAsync(task, T.CreateDefault);
}
internal void LogException(Exception e)
{
Logger.LogError("MakoClient Exception", e);
var now = DateTime.Now;
if (now < CoolDown)
return;
CoolDown = now.AddSeconds(5);
HttpClient.DefaultProxy = GetCurrentSystemProxy();
var oldCollection = ServiceCollection;
var old = MakoServices;
ServiceCollection = [];
MakoServices = BuildServiceProvider(ServiceCollection);
Dispose(oldCollection);
old.Dispose();
}
private DateTime CoolDown { get; set; } = DateTime.Now.AddSeconds(5);
internal void LogException(Exception e) => Logger.LogError("MakoClient Exception", e);
static MakoClient()
{
@ -155,8 +139,33 @@ public partial class MakoClient
var method = type?.GetMethod("ConstructSystemProxy");
var @delegate = method?.CreateDelegate<Func<IWebProxy>>();
GetCurrentSystemProxy = @delegate ?? ThrowUtils.Throw<MissingMethodException, Func<IWebProxy>>("Unable to find proxy functions");
_getCurrentSystemProxy = @delegate ?? ThrowUtils.Throw<MissingMethodException, Func<IWebProxy>>("Unable to find proxy functions");
HttpClient.DefaultProxy = _getCurrentSystemProxy();
}
private static Func<IWebProxy> GetCurrentSystemProxy { get; }
private static readonly Func<IWebProxy> _getCurrentSystemProxy;
public IWebProxy? CurrentSystemProxy
{
get
{
switch (Configuration.Proxy)
{
case null:
return null;
case "":
{
var now = DateTime.Now;
if (now < CoolDown)
return HttpClient.DefaultProxy;
CoolDown = now.AddSeconds(2);
return HttpClient.DefaultProxy = _getCurrentSystemProxy();
}
default:
return new WebProxy(Configuration.Proxy);
}
}
}
private static DateTime CoolDown { get; set; } = DateTime.Now.AddSeconds(2);
}

View File

@ -45,9 +45,9 @@ public partial class MakoClient
/// <summary>
/// The IoC container
/// </summary>
internal ServiceCollection ServiceCollection { get; private set; } = [];
internal ServiceCollection ServiceCollection { get; } = [];
internal ServiceProvider MakoServices { get; private set; }
internal ServiceProvider MakoServices { get; }
public bool IsCancelled { get; set; }
}

View File

@ -27,8 +27,8 @@ public abstract class MakoClientSupportedHttpMessageHandler(MakoClient makoClien
{
public MakoClient MakoClient { get; set; } = makoClient;
public static HttpMessageInvoker GetHttpMessageInvoker(bool domainFronting)
public HttpMessageInvoker GetHttpMessageInvoker(bool domainFronting)
{
return domainFronting ? MakoHttpOptions.CreateHttpMessageInvoker() : MakoHttpOptions.CreateDirectHttpMessageInvoker();
return domainFronting ? MakoHttpOptions.CreateHttpMessageInvoker() : MakoHttpOptions.CreateDirectHttpMessageInvoker(MakoClient);
}
}

View File

@ -91,14 +91,19 @@ public static partial class MakoHttpOptions
});
}
public static HttpMessageInvoker CreateDirectHttpMessageInvoker()
public static HttpMessageInvoker CreateDirectHttpMessageInvoker(MakoClient makoClient)
{
return new HttpMessageInvoker(new SocketsHttpHandler());
var useProxy = makoClient.CurrentSystemProxy is not null;
return new HttpMessageInvoker(new SocketsHttpHandler
{
UseProxy = useProxy,
Proxy = makoClient.CurrentSystemProxy
});
}
public static async Task<IPAddress[]> GetAddressesAsync(string host, CancellationToken token)
{
if (!NameResolvers.TryGetValue(host, out var ips))
if (!NameResolvers.TryGetValue(host, out var ips))
ips = await Dns.GetHostAddressesAsync(host, token);
return ips;
}

View File

@ -30,10 +30,11 @@ namespace Pixeval.CoreApi.Preference;
public record MakoClientConfiguration(
int ConnectionTimeout,
bool DomainFronting,
string? Proxy,
string? MirrorHost,
CultureInfo CultureInfo)
{
public MakoClientConfiguration() : this(5000, false, "", CultureInfo.CurrentCulture) { }
public MakoClientConfiguration() : this(5000, false, "", "", CultureInfo.CurrentCulture) { }
[JsonIgnore] public CultureInfo CultureInfo { get; set; } = CultureInfo;
@ -55,6 +56,9 @@ public record MakoClientConfiguration(
[JsonPropertyName("domainFronting")]
public bool DomainFronting { get; set; } = DomainFronting;
[JsonPropertyName("proxy")]
public string? Proxy { get; set; } = Proxy;
/// <summary>
/// Mirror server's host of image downloading
/// </summary>

View File

@ -52,6 +52,11 @@ public static class Objects
return (value - min) / (max - min);
}
public static TReturn Using<T, TReturn>(this T disposable, Func<T, TReturn> action) where T : IDisposable
{
return action(disposable);
}
/// <summary>
/// 当<paramref name="str"/>为<see langword="const"/>时使用<see cref="GeneratedRegexAttribute"/>代替
/// </summary>

View File

@ -59,7 +59,7 @@ public partial record AppSettings : IWindowSettings
[SettingsEntry(IconGlyph.ColorE790, nameof(BackdropEntryHeader), null)]
public BackdropType Backdrop { get; set; } = MicaController.IsSupported() ? BackdropType.MicaAlt : DesktopAcrylicController.IsSupported() ? BackdropType.Acrylic : BackdropType.None;
[SettingsEntry(IconGlyph.NetworkE968, nameof(EnableDomainFrontingEntryHeader), nameof(EnableDomainFrontingEntryDescription))]
[SettingsEntry(IconGlyph.NetworkTowerEC05, nameof(EnableDomainFrontingEntryHeader), nameof(EnableDomainFrontingEntryDescription))]
public bool EnableDomainFronting { get; set; } = true;
[SettingsEntry(IconGlyph.FileExplorerEC50, nameof(UseFileCacheEntryHeader), nameof(UseFileCacheEntryDescription))]
@ -129,7 +129,7 @@ public partial record AppSettings : IWindowSettings
public bool UsePreciseRangeForSearch { get; set; }
[SettingsEntry(IconGlyph.SearchAndAppsE773, nameof(ReverseSearchApiKeyEntryHeader), nameof(ReverseSearchApiKeyEntryDescriptionHyperlinkButtonContent))]
public string? ReverseSearchApiKey { get; set; }
public string ReverseSearchApiKey { get; set; } = "";
[SettingsEntry(IconGlyph.FilterE71C, nameof(ReverseSearchResultSimilarityThresholdEntryHeader), nameof(ReverseSearchResultSimilarityThresholdEntryDescription))]
public int ReverseSearchResultSimilarityThreshold { get; set; } = 80;
@ -152,12 +152,17 @@ public partial record AppSettings : IWindowSettings
[SettingsEntry(IconGlyph.Blocked2ECE4, nameof(BlockedTagsEntryHeader), nameof(BlockedTagsEntryDescription))]
public HashSet<string> BlockedTags { get; set; } = [];
[SettingsEntry(IconGlyph.NetworkE968, nameof(ProxyTypeEntryHeader), nameof(ProxyTypeEntryDescription))]
public ProxyType ProxyType { get; set; }
public string Proxy { get; set; } = "";
/// <summary>
/// The mirror host for image server, Pixeval will do a simple substitution that
/// changes the host of the original url(i.pximg.net) to this one.
/// </summary>
[SettingsEntry(IconGlyph.HardDriveEDA2, nameof(ImageMirrorServerEntryHeader), nameof(ImageMirrorServerEntryDescription))]
public string? MirrorHost { get; set; } = null;
public string MirrorHost { get; set; } = "";
[SettingsEntry(IconGlyph.HistoryE81C, nameof(MaximumBrowseHistoryRecordsEntryHeader), nameof(MaximumBrowseHistoryRecordsEntryDescription))]
public int MaximumBrowseHistoryRecords { get; set; } = 100;
@ -286,7 +291,7 @@ public partial record AppSettings : IWindowSettings
var language = ApplicationLanguages.PrimaryLanguageOverride;
if (string.IsNullOrEmpty(language))
language = CultureInfo.CurrentUICulture.Name;
return new MakoClientConfiguration(5000, EnableDomainFronting, MirrorHost, CultureInfo.GetCultureInfo(language));
return new MakoClientConfiguration(5000, EnableDomainFronting, Proxy, MirrorHost, CultureInfo.GetCultureInfo(language));
}
private static string GetSpecialFolder()

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<ClassDiagram MajorVersion="1" MinorVersion="1">
<Class Name="Pixeval.Settings.ObservableSettingsEntryBase&lt;TSettings&gt;" Collapsed="true">
<Position X="16" Y="4" Width="3" />
<Position X="20.75" Y="4" Width="3" />
<TypeIdentifier>
<HashCode>AAAAAAAAQAAAAAAAMAAAAAAAgAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Settings\ObservableSettingsEntryBase.cs</FileName>
@ -9,7 +9,7 @@
<Lollipop Position="0.2" />
</Class>
<Class Name="Pixeval.Settings.SettingsEntryBase&lt;TSettings&gt;" Collapsed="true">
<Position X="20" Y="2.75" Width="2.25" />
<Position X="24.75" Y="2.75" Width="2.25" />
<TypeIdentifier>
<HashCode>BAAAAAAAAAIgAAAAAAgAAAAAAAAAgAAAgAAYAAAQAAA=</HashCode>
<FileName>Settings\SettingsEntryBase.cs</FileName>
@ -17,112 +17,140 @@
<Lollipop Position="0.2" />
</Class>
<Class Name="Pixeval.Settings.ClickableSettingsEntryBase&lt;TSettings&gt;" Collapsed="true">
<Position X="34" Y="4" Width="2.75" />
<Position X="38.25" Y="4" Width="2.75" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAgCAAAAAAEAAAAAA=</HashCode>
<FileName>Settings\ClickableSettingsEntryBase.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Pixeval.Settings.MultiValuesSettingsEntryBase&lt;TSettings&gt;" Collapsed="true">
<Position X="37.5" Y="4" Width="3" />
<Position X="41.75" Y="4" Width="3" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAACAAAAAAAAAAAAAAgAAAAAAAAAAAAAA=</HashCode>
<FileName>Settings\MultiValuesSettingsEntryBase.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Pixeval.Settings.SingleValueSettingsEntryBase&lt;TSettings&gt;" Collapsed="true">
<Position X="7" Y="5.5" Width="3" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Settings\SingleValueSettingsEntryBase.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Pixeval.Settings.Models.BoolAppSettingsEntry" Collapsed="true">
<Position X="1.5" Y="8.25" Width="3" />
<Position X="12.25" Y="8.25" Width="3" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAgAAAAAAEAAAAAAAAAAAAAAAAA=</HashCode>
<HashCode>AAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Settings\Models\BoolAppSettingsEntry.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Pixeval.Settings.Models.IntAppSettingsEntry" Collapsed="true">
<Position X="5.25" Y="8.25" Width="2.75" />
<Position X="17.75" Y="8.25" Width="2.75" />
<TypeIdentifier>
<HashCode>AAAAAAAAABAABAAAUAgAAAAAAEAACAAAAAAAAAAAAAA=</HashCode>
<HashCode>AAAAAAAAABAABAAAUAgAAAAAAAAACAAAAAAAAAAAAAA=</HashCode>
<FileName>Settings\Models\IntAppSettingsEntry.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Pixeval.Settings.Models.StringAppSettingsEntry" Collapsed="true">
<Position X="8.75" Y="8.25" Width="3" />
<Position X="22.5" Y="8.25" Width="3" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAABAAAAAgAAAAAAEAAAAAAAAAAAAAAAAA=</HashCode>
<HashCode>AAAAAAAAAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Settings\Models\StringAppSettingsEntry.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Pixeval.Settings.Models.DateRangeWithSwitchAppSettingsEntry" Collapsed="true">
<Position X="16.25" Y="5.5" Width="3" />
<Position X="10.75" Y="9.75" Width="3" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAgAAAAAAAAAgAAAAAAAAAAAAAA=</HashCode>
<HashCode>AAAAAAAAAAAAAAAAAAgAAAAAAAAAgIAAAAAAAAAAABA=</HashCode>
<FileName>Settings\Models\DateRangeWithSwitchAppSettingsEntry.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Pixeval.Settings.Models.DownloadMacroAppSettingsEntry" Collapsed="true">
<Position X="20" Y="5.5" Width="2.75" />
<Position X="21.25" Y="9.75" Width="2.75" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAgAAAAAAAACgAABAAgAAAAAAAA=</HashCode>
<HashCode>AAAAAAAAAAAAAAAAAAgAAAAAAAACAAAAAAgAAAAAAAA=</HashCode>
<FileName>Settings\Models\DownloadMacroAppSettingsEntry.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Pixeval.Settings.Models.FontAppSettingsEntry" Collapsed="true">
<Position X="12.5" Y="8.25" Width="3" />
<Position X="24.75" Y="9.75" Width="2" />
<TypeIdentifier>
<HashCode>AAEAAAAAAAAAAAAAAAgAAAAAAEAAAAAAAAAAAAAAAAA=</HashCode>
<HashCode>AAEAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Settings\Models\FontAppSettingsEntry.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Pixeval.Settings.Models.IpWithSwitchAppSettingsEntry" Collapsed="true">
<Position X="23.5" Y="5.5" Width="2.75" />
<Position X="14.5" Y="9.75" Width="2.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAIAQGAIAAkAAAAAAEAAgAAAACAAAAAAAAA=</HashCode>
<HashCode>AAAAAAAAAAIAQGAIAAkAAAAAAAAAgAAAACAAAAAAAAA=</HashCode>
<FileName>Settings\Models\IpWithSwitchAppSettingsEntry.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Pixeval.Settings.Models.LanguageAppSettingsEntry" Collapsed="true">
<Position X="27" Y="5.5" Width="2.75" />
<Position X="31.25" Y="5.5" Width="2.75" />
<TypeIdentifier>
<HashCode>AAAAAAAgAAAAAAAAAAgAAAAAAAAAgAAQAAAAAAAAAAA=</HashCode>
<FileName>Settings\Models\LanguageAppSettingsEntry.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Pixeval.Settings.Models.TokenizingAppSettingsEntry" Collapsed="true">
<Position X="30.5" Y="5.5" Width="2.75" />
<Position X="34.75" Y="5.5" Width="2.75" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAIAAAAAAAgAAAAAAAAAgAAAAQAAAAAAAAA=</HashCode>
<FileName>Settings\Models\TokenizingAppSettingsEntry.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Pixeval.Settings.Models.ClickableAppSettingsEntry" Collapsed="true">
<Position X="34" Y="5.5" Width="2.75" />
<Position X="38.25" Y="5.5" Width="2.75" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Settings\Models\ClickableAppSettingsEntry.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Pixeval.Settings.Models.MultiValuesAppSettingsEntry" Collapsed="true">
<Position X="37.75" Y="5.5" Width="2.75" />
<Position X="41.75" Y="5.5" Width="2.75" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Settings\Models\MultiValuesAppSettingsEntry.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Pixeval.Settings.SingleValueSettingsEntry&lt;TSettings, TValue&gt;" Collapsed="true">
<Position X="7" Y="7" Width="3" />
<Position X="17.25" Y="7" Width="3" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAACAAAEAAAAAAAAAAAAgAAAAAAgAAAAQAA=</HashCode>
<HashCode>AAAAAAAAAAACAAAEAAAAAAAAAEAAgAAAAAAgAAAAQAA=</HashCode>
<FileName>Settings\SingleValueSettingsEntry.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Pixeval.Settings.Models.ColorAppSettingsEntry" Collapsed="true">
<Position X="27.5" Y="8.25" Width="3" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Settings\Models\ColorAppSettingsEntry.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Pixeval.Settings.Models.EnumAppSettingsEntry&lt;TEnum&gt;" Collapsed="true">
<Position X="7" Y="9.75" Width="2.75" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Settings\Models\EnumAppSettingsEntry.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Pixeval.Settings.Models.EnumAppSettingsEntry" Collapsed="true">
<Position X="7" Y="8.25" Width="3" />
<TypeIdentifier>
<HashCode>AAAABAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Settings\Models\EnumAppSettingsEntry.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Pixeval.Settings.Models.ProxyAppSettingsEntry" Collapsed="true">
<Position X="7.25" Y="11.25" Width="2.5" />
<TypeIdentifier>
<HashCode>ABAAAAAACAAAAAAAAAgAAAAAAAAAgAAAAAAAEAAAAAA=</HashCode>
<FileName>Settings\Models\ProxyAppSettingsEntry.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Pixeval.Settings.SingleValueSettingsEntryBase&lt;TSettings&gt;" Collapsed="true">
<Position X="17.25" Y="5.5" Width="3" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Settings\SingleValueSettingsEntryBase.cs</FileName>
</TypeIdentifier>
</Class>
<Interface Name="Pixeval.Settings.ISettingsEntry" Collapsed="true">
<Position X="41.5" Y="2.75" Width="1.5" />
<Position X="45.75" Y="2.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAIAAAAAAAgAAAAAAAAAgAAAAAAAAAAAAAA=</HashCode>
<FileName>Settings\ISettingsEntry.cs</FileName>

View File

@ -1,5 +1,7 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Pixeval.Settings.Models;
using WinUI3Utilities;
namespace Pixeval.Controls.Settings;
@ -11,6 +13,6 @@ public sealed partial class BoolSettingsCard
private void ToggleSwitch_OnToggled(object sender, RoutedEventArgs e)
{
Entry.ValueChanged?.Invoke(Entry.Value);
Entry.ValueChanged?.Invoke(sender.To<ToggleSwitch>().IsOn);
}
}

View File

@ -4,31 +4,29 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
xmlns:controls1="using:WinUI3Utilities.Controls"
xmlns:converters="using:CommunityToolkit.WinUI.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Pixeval.Settings"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Uid="/SettingsPage/UsePreciseRangeForSearchEntry"
HeaderIcon="{controls1:GlyphIcon Glyph=StopwatchE916}"
Description="{x:Bind Entry.DescriptionControl}"
Header="{x:Bind Entry.Header}"
Tag="{x:Bind Entry.Attribute}"
mc:Ignorable="d">
<controls:SettingsExpander.Resources>
<converters:BoolNegationConverter x:Key="BoolNegationConverter" />
</controls:SettingsExpander.Resources>
<ToggleSwitch IsOn="{x:Bind Entry.Settings.UsePreciseRangeForSearch, Mode=TwoWay}" Toggled="ToggleSwitch_OnToggled" />
<controls:SettingsExpander.HeaderIcon>
<controls1:GlyphIcon IconGlyph="{x:Bind Entry.HeaderIcon}" />
</controls:SettingsExpander.HeaderIcon>
<ToggleSwitch IsOn="{x:Bind Entry.Value, Mode=TwoWay}" Toggled="ToggleSwitch_OnToggled" />
<controls:SettingsExpander.Items>
<controls:SettingsCard
x:Name="SettingsCard"
x:Uid="/SettingsPage/SearchStartDateEntry"
HeaderIcon="{controls1:GlyphIcon Glyph=PageLeftE760}"
IsEnabled="{x:Bind Entry.Settings.UsePreciseRangeForSearch, Converter={StaticResource BoolNegationConverter}}">
<CalendarDatePicker x:Uid="/SettingsPage/SearchStartCalendarDatePicker" Date="{x:Bind Entry.Settings.SearchStartDate, Mode=TwoWay}" />
IsEnabled="{x:Bind Entry.Value, Mode=OneWay}">
<CalendarDatePicker x:Uid="/SettingsPage/SearchStartCalendarDatePicker" Date="{x:Bind Entry.SearchStartDate, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard
x:Name="SettingsCard2"
x:Uid="/SettingsPage/SearchEndDateEntry"
HeaderIcon="{controls1:GlyphIcon Glyph=PageRightE761}"
IsEnabled="{x:Bind Entry.Settings.UsePreciseRangeForSearch, Converter={StaticResource BoolNegationConverter}}">
<CalendarDatePicker x:Uid="/SettingsPage/SearchEndCalendarDatePicker" Date="{x:Bind Entry.Settings.SearchEndDate, Mode=TwoWay}" />
IsEnabled="{x:Bind Entry.Value, Mode=OneWay}">
<CalendarDatePicker x:Uid="/SettingsPage/SearchEndCalendarDatePicker" Date="{x:Bind Entry.SearchEndDate, Mode=TwoWay}" />
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>

View File

@ -1,5 +1,7 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Pixeval.Settings.Models;
using WinUI3Utilities;
namespace Pixeval.Controls.Settings;
@ -11,6 +13,6 @@ public sealed partial class DateRangeWithSwitchSettingsExpander
private void ToggleSwitch_OnToggled(object sender, RoutedEventArgs e)
{
SettingsCard.IsEnabled = SettingsCard2.IsEnabled = !Entry.Settings.UsePreciseRangeForSearch;
Entry.ValueChanged?.Invoke(sender.To<ToggleSwitch>().IsOn);
}
}

View File

@ -11,9 +11,14 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:models="using:Pixeval.Settings.Models"
x:Uid="/SettingsPage/DownloadPathMacroEntry"
HeaderIcon="{controls1:GlyphIcon Glyph=RenameE8AC}"
Description="{x:Bind Entry.DescriptionControl}"
Header="{x:Bind Entry.Header}"
Loading="DownloadMacroSettingsExpander_OnLoading"
Tag="{x:Bind Entry.Attribute}"
mc:Ignorable="d">
<controls:SettingsExpander.HeaderIcon>
<controls1:GlyphIcon IconGlyph="{x:Bind Entry.HeaderIcon}" />
</controls:SettingsExpander.HeaderIcon>
<controls:SettingsExpander.Items>
<controls:SettingsCard ContentAlignment="Left">
<StackPanel Spacing="3">

View File

@ -46,32 +46,32 @@ public sealed partial class DownloadMacroSettingsExpander
void EntryOnPropertyChanged()
{
// The first time viewmodel get the value of DownloadPathMacro from AppSettings won't trigger the property changed event
_previousPath = Entry.DownloadPathMacro;
SetPathMacroRichEditBoxDocument(Entry.DownloadPathMacro);
_previousPath = Entry.Value;
SetPathMacroRichEditBoxDocument(Entry.Value);
}
}
private void DownloadPathMacroTextBox_OnGotFocus(object sender, RoutedEventArgs e)
{
DownloadMacroInvalidInfoBar.IsOpen = false;
_previousPath = Entry.DownloadPathMacro;
_previousPath = Entry.Value;
if (sender.To<RichEditBox>().Document.Selection is { Length: 0 } selection)
selection.CharacterFormat.ForegroundColor = Application.Current.GetResource<SolidColorBrush>("TextFillColorPrimaryBrush").Color;
}
private void DownloadPathMacroTextBox_OnLostFocus(object sender, RoutedEventArgs e)
{
if (Entry.DownloadPathMacro.IsNullOrBlank())
if (Entry.Value.IsNullOrBlank())
{
DownloadMacroInvalidInfoBar.Message = SettingsPageResources.DownloadMacroInvalidInfoBarInputCannotBeBlank;
DownloadMacroInvalidInfoBar.IsOpen = true;
Entry.DownloadPathMacro = _previousPath;
Entry.Value = _previousPath;
return;
}
try
{
_testParser.SetupParsingEnvironment(new Lexer(Entry.DownloadPathMacro));
_testParser.SetupParsingEnvironment(new Lexer(Entry.Value));
var result = _testParser.Parse();
if (result is not null)
{
@ -81,14 +81,14 @@ public sealed partial class DownloadMacroSettingsExpander
{
_ = ThrowUtils.MacroParse<MacroParseException>(MacroParserResources.UnknownMacroNameFormatted.Format(name));
}
SetPathMacroRichEditBoxDocument(Entry.DownloadPathMacro);
SetPathMacroRichEditBoxDocument(Entry.Value);
}
}
catch (Exception exception)
{
DownloadMacroInvalidInfoBar.Message = SettingsPageResources.DownloadMacroInvalidInfoBarMacroInvalidFormatted.Format(exception.Message);
DownloadMacroInvalidInfoBar.IsOpen = true;
Entry.DownloadPathMacro = _previousPath;
Entry.Value = _previousPath;
}
}
@ -198,7 +198,7 @@ public sealed partial class DownloadMacroSettingsExpander
sender.To<RichEditBox>().Document.GetText(TextGetOptions.None, out var text);
if (sender.To<RichEditBox>().Document.Selection is { Length: 0 } selection)
selection.CharacterFormat.ForegroundColor = Application.Current.GetResource<SolidColorBrush>("TextFillColorPrimaryBrush").Color;
Entry.DownloadPathMacro = text.ReplaceLineEndings("");
Entry.Value = text.ReplaceLineEndings("");
}
private void DownloadPathMacroTextBox_OnContextMenuOpening(object sender, ContextMenuEventArgs e)

View File

@ -9,9 +9,13 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Pixeval.Settings"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Uid="/SettingsPage/EnableDomainFrontingEntry"
HeaderIcon="{controls2:GlyphIcon Glyph=NetworkE968}"
Description="{x:Bind Entry.DescriptionControl}"
Header="{x:Bind Entry.Header}"
Tag="{x:Bind Entry.Attribute}"
mc:Ignorable="d">
<controls:SettingsExpander.HeaderIcon>
<controls2:GlyphIcon IconGlyph="{x:Bind Entry.HeaderIcon}" />
</controls:SettingsExpander.HeaderIcon>
<ToggleSwitch IsOn="{x:Bind Entry.Settings.EnableDomainFronting, Mode=TwoWay}" Toggled="ToggleSwitch_OnToggled" />
<controls:SettingsExpander.Items>
<controls:SettingsCard HorizontalContentAlignment="Stretch" ContentAlignment="Left">

View File

@ -1,5 +1,7 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Pixeval.Settings.Models;
using WinUI3Utilities;
namespace Pixeval.Controls.Settings;
@ -11,6 +13,6 @@ public sealed partial class IpWithSwitchSettingsExpander
private void ToggleSwitch_OnToggled(object sender, RoutedEventArgs e)
{
Entry.ValueChanged?.Invoke(Entry.Settings.EnableDomainFronting);
Entry.ValueChanged?.Invoke(sender.To<ToggleSwitch>().IsOn);
}
}

View File

@ -0,0 +1,31 @@
<controls:SettingsExpander
x:Class="Pixeval.Controls.Settings.ProxySettingsExpander"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
xmlns:controls1="using:WinUI3Utilities.Controls"
xmlns:controls2="using:Pixeval.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Pixeval.Controls.Settings"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Description="{x:Bind Entry.DescriptionControl}"
Header="{x:Bind Entry.Header}"
Tag="{x:Bind Entry.Attribute}"
mc:Ignorable="d">
<controls:SettingsExpander.HeaderIcon>
<controls1:GlyphIcon IconGlyph="{x:Bind Entry.HeaderIcon}" />
</controls:SettingsExpander.HeaderIcon>
<controls2:EnumComboBox
EnumSource="{x:Bind Entry.EnumValues}"
SelectedEnum="{x:Bind Entry.Value, Mode=TwoWay}"
SelectionChanged="EnumComboBox_OnSelectionChanged"
Style="{StaticResource SettingsEnumComboBoxStyle}" />
<controls:SettingsExpander.Items>
<controls:SettingsCard x:Uid="/SettingsPage/ProxyTextBoxEntry" HorizontalContentAlignment="Stretch">
<TextBox
MinWidth="200"
LostFocus="TextBox_OnLostFocus"
Text="{x:Bind Entry.Proxy, Mode=TwoWay}" />
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>

View File

@ -0,0 +1,47 @@
using System;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Pixeval.Controls.Windowing;
using Pixeval.Settings.Models;
using WinUI3Utilities;
namespace Pixeval.Controls.Settings;
public sealed partial class ProxySettingsExpander
{
public ProxyAppSettingsEntry Entry { get; set; } = null!;
public ProxySettingsExpander() => InitializeComponent();
private void TextBox_OnLostFocus(object sender, RoutedEventArgs e)
{
var text = sender.To<TextBox>().Text;
if (string.IsNullOrWhiteSpace(text))
{
Entry.Proxy = null;
return;
}
var proxy = text;
if (!text.Contains("://"))
proxy = "http://" + proxy;
if (!Uri.IsWellFormedUriString(proxy, UriKind.Absolute))
{
WindowFactory.GetWindowForElement(this).HWnd.ErrorGrowl(SettingsPageResources.ProxyTextBoxErrorUri, proxy);
Entry.Proxy = null;
return;
}
Entry.Proxy = proxy;
Entry.ProxyChanged?.Invoke(Entry.MakoProxy);
}
private void EnumComboBox_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
{
Entry.ValueChanged?.Invoke(Entry.Value);
}
}

View File

@ -16,7 +16,7 @@
</controls:SettingsCard.HeaderIcon>
<TextBox
Width="200"
LostFocus="TextBox_OnLostFocus"
PlaceholderText="{x:Bind Entry.Placeholder}"
Text="{x:Bind Entry.Value, Mode=TwoWay}"
TextChanged="TextBox_OnTextChanged" />
Text="{x:Bind Entry.Value, Mode=TwoWay}" />
</controls:SettingsCard>

View File

@ -1,4 +1,4 @@
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml;
using Pixeval.Settings.Models;
namespace Pixeval.Controls.Settings;
@ -9,7 +9,7 @@ public sealed partial class StringSettingsCard
public StringSettingsCard() => InitializeComponent();
private void TextBox_OnTextChanged(object sender, TextChangedEventArgs e)
private void TextBox_OnLostFocus(object sender, RoutedEventArgs e)
{
Entry.ValueChanged?.Invoke(Entry.Value);
}

View File

@ -0,0 +1,40 @@
#region Copyright
// GPL v3 License
//
// Pixeval/Pixeval
// Copyright (c) 2024 Pixeval/ProxyType.cs
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#endregion
using Pixeval.Attributes;
namespace Pixeval.Options;
public enum ProxyType
{
[LocalizedResource(typeof(MiscResources), nameof(MiscResources.ProxyOptionSystem))]
System,
[LocalizedResource(typeof(MiscResources), nameof(MiscResources.ProxyOptionNone))]
None,
Http,
Socks4,
Socks4A,
Socks5
}

View File

@ -91,6 +91,10 @@ public partial class SettingsPageViewModel : UiObservableObject, IDisposable
{
ValueChanged = t => App.AppViewModel.MakoClient.Configuration.DomainFronting = t
},
new ProxyAppSettingsEntry(AppSettings)
{
ProxyChanged = t => App.AppViewModel.MakoClient.Configuration.Proxy = t
},
new BoolAppSettingsEntry(AppSettings,
t => t.UseFileCache),
new EnumAppSettingsEntry<MainPageTabItem>(AppSettings,

View File

@ -1,5 +1,6 @@
using System;
using System.Linq.Expressions;
using Microsoft.UI.Xaml;
using Pixeval.AppManagement;
using Pixeval.Controls.Settings;
@ -10,9 +11,7 @@ public class BoolAppSettingsEntry(
Expression<Func<AppSettings, bool>> property)
: SingleValueSettingsEntry<AppSettings, bool>(appSettings, property)
{
public override BoolSettingsCard Element => new() { Entry = this };
public Action<bool>? ValueChanged { get; set; }
public override FrameworkElement Element => new BoolSettingsCard { Entry = this };
public BoolAppSettingsEntry(
AppSettings appSettings,

View File

@ -32,7 +32,5 @@ public class ColorAppSettingsEntry(
Expression<Func<AppSettings, uint>> property)
: SingleValueSettingsEntry<AppSettings, uint>(appSettings, property)
{
public Action<uint>? ValueChanged { get; set; }
public override ColorSettingsCard Element => new() { Entry = this };
}

View File

@ -1,3 +1,4 @@
using System;
using Pixeval.AppManagement;
using Pixeval.Controls.Settings;
@ -5,9 +6,38 @@ namespace Pixeval.Settings.Models;
public class DateRangeWithSwitchAppSettingsEntry(
AppSettings appSettings)
: ObservableSettingsEntryBase<AppSettings>(appSettings, "", "", default)
: BoolAppSettingsEntry(appSettings, t => t.UsePreciseRangeForSearch)
{
public override DateRangeWithSwitchSettingsExpander Element => new() { Entry = this };
public override void ValueReset() => OnPropertyChanged(nameof(Settings));
}
public DateTimeOffset SearchStartDate
{
get => Settings.SearchStartDate;
set
{
if (Settings.SearchStartDate != value)
return;
Settings.SearchStartDate = value;
OnPropertyChanged();
}
}
public DateTimeOffset SearchEndDate
{
get => Settings.SearchEndDate;
set
{
if (Settings.SearchEndDate != value)
return;
Settings.SearchEndDate = value;
OnPropertyChanged();
}
}
public override void ValueReset()
{
base.ValueReset();
OnPropertyChanged(nameof(SearchStartDate));
OnPropertyChanged(nameof(SearchEndDate));
}
}

View File

@ -10,18 +10,10 @@ namespace Pixeval.Settings.Models;
public class DownloadMacroAppSettingsEntry(
AppSettings appSettings)
: ObservableSettingsEntryBase<AppSettings>(appSettings, "", "", default)
: StringAppSettingsEntry(appSettings, t => t.DownloadPathMacro)
{
public override DownloadMacroSettingsExpander Element => new() { Entry = this };
public string DownloadPathMacro
{
get => Settings.DownloadPathMacro;
set => Settings.DownloadPathMacro = value;
}
public override void ValueReset() => OnPropertyChanged(nameof(DownloadPathMacro));
private static readonly IDictionary<string, string> _macroTooltips = new Dictionary<string, string>
{
["ext"] = SettingsPageResources.ExtMacroTooltip,

View File

@ -1,5 +1,6 @@
using System;
using System.Linq.Expressions;
using Microsoft.UI.Xaml;
using Pixeval.AppManagement;
using Pixeval.Controls.Settings;
@ -11,9 +12,7 @@ public class EnumAppSettingsEntry(
Array array)
: SingleValueSettingsEntry<AppSettings, Enum>(appSettings, property)
{
public override EnumSettingsCard Element => new() { Entry = this };
public Action<Enum>? ValueChanged { get; set; }
public override FrameworkElement Element => new EnumSettingsCard { Entry = this };
public Array EnumValues { get; set; } = array;

View File

@ -1,27 +1,19 @@
using System;
using System.Collections.Generic;
using System.Drawing.Text;
using System.Linq;
using System.Linq.Expressions;
using Pixeval.AppManagement;
using Pixeval.Controls.Settings;
using Pixeval.Utilities;
namespace Pixeval.Settings.Models;
public class FontAppSettingsEntry(
AppSettings appSettings,
Expression<Func<AppSettings, string>> property)
: SingleValueSettingsEntry<AppSettings, string>(appSettings, property)
: StringAppSettingsEntry(appSettings, property)
{
public static IEnumerable<string> AvailableFonts { get; }
public Action<string>? ValueChanged { get; set; }
static FontAppSettingsEntry()
{
using var collection = new InstalledFontCollection();
AvailableFonts = collection.Families.Select(t => t.Name);
}
public override FontSettingsCard Element => new() { Entry = this };
public static string[] AvailableFonts { get; } = new InstalledFontCollection().Using(t => t.Families.Select(t => t.Name).ToArray());
}

View File

@ -12,8 +12,6 @@ public class IntAppSettingsEntry(
{
public override IntSettingsCard Element => new() { Entry = this };
public Action<int>? ValueChanged { get; set; }
public string? Placeholder { get; set; }
public double Max { get; set; } = double.MaxValue;

View File

@ -1,4 +1,3 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using Pixeval.AppManagement;
@ -9,14 +8,13 @@ namespace Pixeval.Settings.Models;
public class IpWithSwitchAppSettingsEntry(
AppSettings appSettings)
: ObservableSettingsEntryBase<AppSettings>(appSettings, "", "", default)
: BoolAppSettingsEntry(appSettings, t => t.EnableDomainFronting)
{
public override IpWithSwitchSettingsExpander Element => new() { Entry = this };
public Action<bool>? ValueChanged { get; set; }
public override void ValueReset()
{
base.ValueReset();
PixivAppApiNameResolver = [.. Settings.PixivAppApiNameResolver];
PixivImageNameResolver = [.. Settings.PixivImageNameResolver];
PixivImageNameResolver2 = [.. Settings.PixivImageNameResolver2];
@ -63,4 +61,4 @@ public class IpWithSwitchAppSettingsEntry(
public ObservableCollection<string> PixivAccountNameResolver { get; set; } = [.. appSettings.PixivAccountNameResolver];
public ObservableCollection<string> PixivWebApiNameResolver { get; set; } = [.. appSettings.PixivWebApiNameResolver];
}
}

View File

@ -0,0 +1,85 @@
#region Copyright
// GPL v3 License
//
// Pixeval/Pixeval
// Copyright (c) 2024 Pixeval/ProxyAppSettingsEntry.cs
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#endregion
using System;
using Pixeval.AppManagement;
using Pixeval.Controls.Settings;
using Pixeval.Options;
namespace Pixeval.Settings.Models;
public class ProxyAppSettingsEntry(AppSettings appSettings)
: EnumAppSettingsEntry<ProxyType>(appSettings, t => t.ProxyType)
{
public override ProxySettingsExpander Element => new() { Entry = this };
public Action<string?>? ProxyChanged { get; set; }
public string? Proxy
{
get => Settings.Proxy;
set
{
if (Settings.Proxy != value)
return;
Settings.Proxy = value;
OnPropertyChanged();
}
}
public string? MakoProxy
{
get
{
string scheme;
switch (Value)
{
case ProxyType.System:
return "";
case ProxyType.Http:
scheme = "http";
break;
case ProxyType.Socks4:
scheme = "socks4";
break;
case ProxyType.Socks4A:
scheme = "socks4a";
break;
case ProxyType.Socks5:
scheme = "socks5";
break;
default:
return null;
}
if (!Uri.TryCreate(Proxy, UriKind.Absolute, out var uri))
return null;
var builder = new UriBuilder(uri) { Scheme = scheme };
return builder.ToString();
}
}
public override void ValueReset()
{
base.ValueReset();
OnPropertyChanged(nameof(Proxy));
ProxyChanged?.Invoke(MakoProxy);
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Linq.Expressions;
using Microsoft.UI.Xaml;
using Pixeval.AppManagement;
using Pixeval.Controls.Settings;
@ -7,19 +8,17 @@ namespace Pixeval.Settings.Models;
public class StringAppSettingsEntry(
AppSettings appSettings,
Expression<Func<AppSettings, string?>> property)
: SingleValueSettingsEntry<AppSettings, string?>(appSettings, property)
Expression<Func<AppSettings, string>> property)
: SingleValueSettingsEntry<AppSettings, string>(appSettings, property)
{
public override StringSettingsCard Element => new() { Entry = this };
public Action<string?>? ValueChanged { get; set; }
public override FrameworkElement Element => new StringSettingsCard { Entry = this };
public string? Placeholder { get; set; }
public StringAppSettingsEntry(
AppSettings appSettings,
WorkTypeEnum workType,
Expression<Func<AppSettings, string?>> property)
Expression<Func<AppSettings, string>> property)
: this(appSettings, property)
{
Header = SubHeader(workType);

View File

@ -81,9 +81,7 @@ public abstract class SingleValueSettingsEntry<TSettings, TValue> : SingleValueS
public SettingsEntryAttribute? Attribute { get; }
private readonly Func<TSettings, TValue> _getter;
private readonly Action<TSettings, TValue> _setter;
public Action<TValue>? ValueChanged { get; set; }
public TValue Value
{
@ -97,5 +95,13 @@ public abstract class SingleValueSettingsEntry<TSettings, TValue> : SingleValueS
}
}
public override void ValueReset() => OnPropertyChanged(nameof(Value));
public override void ValueReset()
{
OnPropertyChanged(nameof(Value));
ValueChanged?.Invoke(Value);
}
private readonly Func<TSettings, TValue> _getter;
private readonly Action<TSettings, TValue> _setter;
}

View File

@ -71,6 +71,8 @@
"Black": "黑",
"ExtraBlack": "特黑",
"AllCountedTagName": "所有标签",
"ProxyOptionSystem": "系统代理",
"ProxyOptionNone": "无代理",
"DownloadListEntryOpenFailed": "打开文件(夹)失败",
"DownloadListEntryMaybeDeleted": "可能你已经删除了该作品",

View File

@ -150,6 +150,11 @@
"SpotlightSearchPageLimitNumberBox/PlaceholderText": "特辑搜索页数限制[1, 100]",
"TargetAPIPlatformEntry/Description": "指定发送请求时使用哪个平台对应的 API如果不知道这是什么意思请保持默认",
"TargetAPIPlatformEntry/Header": "使用的 API 平台",
"ProxyTypeEntry/Description": "当不使用域前置时Pixeval 会使用此处指定的代理",
"ProxyTypeEntry/Header": "代理类型",
"ProxyTextBoxEntry/Description": "协议前缀将被忽略",
"ProxyTextBoxEntry/Header": "代理服务器",
"ProxyTextBoxErrorUri": "代理服务器地址输入有误,请重新输入",
"ThemeEntry/Header": "应用程序主题",
"ThemeEntryDescriptionHyperlinkButton/Content": "打开 Windows 系统主题设置",
"ThumbnailDirectionEntry/Description": "浏览图片时使用的页面方向",

View File

@ -25,6 +25,7 @@ using Microsoft.UI.Xaml;
using Pixeval.Attributes;
using Pixeval.Controls;
using Pixeval.CoreApi.Global.Enum;
using Pixeval.Options;
using WinUI3Utilities;
namespace Pixeval.Util;
@ -80,14 +81,19 @@ public static class LocalizedResourceAttributeHelper
{
return resourceLoader.GetMember(key, BindingFlags.Static | BindingFlags.Public) switch
{
[FieldInfo fi] => fi?.GetValue(null),
[PropertyInfo pi] => pi?.GetValue(null),
[FieldInfo fi] => fi?.GetValue(null),
[PropertyInfo pi] => pi?.GetValue(null),
_ => null
} as string;
}
private static readonly Dictionary<Enum, string> _predefinedResources = new()
{
[ProxyType.Http] = "http/https",
[ProxyType.Socks4] = "socks4",
[ProxyType.Socks4A] = "socks4a",
[ProxyType.Socks5] = "socks5",
[TargetFilter.ForAndroid] = MiscResources.TargetFilterForAndroid,
[TargetFilter.ForIos] = MiscResources.TargetFilterForIOS,