Compare commits

...
Author SHA1 Message Date
Aigio 7c16daafba 🐛 RequestCacheRepository 2023-08-31 03:48:21 +08:00
Aigio 2acc0a95e0 Merge branch 'develop' of https://github.com/BeyondDimension/SteamTools into develop 2023-08-31 03:26:30 +08:00
Aigio 8072b16d42 🐛 RequestCache 2023-08-31 03:26:11 +08:00
ff m 9766e9e71b 🐛修复 Mac Debug 无法启动加速进程 修复 Mac 启动加速退出卡死
🎨 Misc PlatformSetTextAsync
2023-08-31 02:34:52 +08:00
Aigio d39f63db65 🐛 UniqueKeyForRequest 2023-08-31 02:22:41 +08:00
Aigio fd6235f110 Merge branch 'develop' of https://github.com/BeyondDimension/SteamTools into develop 2023-08-31 02:01:07 +08:00
Aigio 4a9a53dda8 🐛 HttpCache 2023-08-31 02:00:52 +08:00
RMBGAME 4668e26b65 🐛 Misc 2023-08-31 01:05:55 +08:00
RMBGAME c5f24ae32c ⬆️ Update BD.Common 2023-08-31 00:10:14 +08:00
ff m 1acf872e80 🐛 PlatformSetTextAsync 不能用 await 等待 Linux 上不知原因不执行后续 2023-08-30 23:26:24 +08:00
ff m 82ea1a62e9 🐛 LinuxDeviceInfoPlatformServiceImpl 2023-08-30 21:35:02 +08:00
Aigio Liu 04b0c0e433 🐛 LinuxDeviceInfoPlatformServiceImpl 2023-08-30 21:29:52 +08:00
Aigio Liu 8dfb37bf8b ✨ LinuxDeviceInfoPlatformServiceImpl 2023-08-30 21:08:36 +08:00
ff m a19b3128db 🐛 127.* 与 localhost 不能添加不然会导致 不走代理 2023-08-30 21:03:23 +08:00
Aigio Liu f70b349229 🚧 3.0.0-preview.5 2023-08-30 20:58:25 +08:00
ff m ed104071c2 🐛 取消平台限制 打开换成文件夹 2023-08-30 20:44:31 +08:00
Aigio Liu 21ae674895 ⬆️ Update Common 2023-08-30 19:47:52 +08:00
Aigio Liu 500a87d62f ✨ AvaloniaFilePickerFileTypeFilter 2023-08-30 15:35:53 +08:00
john.jiang d1ae1787b7 🎨 fixs 2023-08-30 13:43:42 +08:00
RMBGAME 5742158c83 🚧 Misc 2023-08-30 09:31:13 +08:00
RMBGAME 235525a9f3 🐛 库存游戏加载图片逻辑优化 2023-08-30 05:52:05 +08:00
RMBGAME 329340ae2d 🐛 Fixed Bugs 2023-08-30 04:29:52 +08:00
RMBGAME e8e6808930 💄 文本过长宽度过小 显示优化 2023-08-30 02:54:56 +08:00
RMBGAME a77fb08a04 🐛 Fixed Bugs 2023-08-30 02:27:05 +08:00
RMBGAME c05fe78d2d 🐛 修复交易确认首次登录失败 2023-08-30 02:27:04 +08:00
ff m 7b6b8a9b2d 🐛脚本匹配域名等优先读取本地文件的内容 2023-08-30 02:11:06 +08:00
Aigio Liu 3886a96f61 🚧 3.0.0-preview.4 2023-08-29 18:13:38 +08:00
53 changed files with 812 additions and 538 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ public static partial class AssemblyInfo
/// <summary>
/// 预览版本号,范围 1~9
/// </summary>
const string ver_for_preview = "3";
const string ver_for_preview = "5";
/// <summary>
/// RC 版本号,范围 0~9
@@ -58,6 +58,7 @@ sealed partial class Program : Startup
// Essentials
#if LINUX
services.TryAddSingleton<IApplicationVersionService, Essentials_AppVerS>();
services.AddSingleton<IDeviceInfoPlatformService, LinuxDeviceInfoPlatformServiceImpl>();
#else
#if WINDOWS
#if AVALONIA
@@ -252,6 +253,30 @@ sealed partial class Program : Startup
string IApplicationVersionService.AssemblyTrademark => AssemblyInfo.Trademark;
}
#if LINUX
sealed class LinuxDeviceInfoPlatformServiceImpl : IDeviceInfoPlatformService
{
public string Model => "";
public string Manufacturer => "";
public string Name => "";
public string VersionString => Environment.OSVersion.VersionString;
public DeviceType DeviceType => DeviceType.Physical;
public bool IsChromeOS => false;
public bool IsWinUI => false;
public bool IsUWP => false;
public DeviceIdiom Idiom => DeviceIdiom.Desktop;
}
#endif
#if AVALONIA && WINDOWS
sealed class AvaWinDeviceInfoPlatformServiceImpl :
Common.Services.Implementation.Essentials.DeviceInfoPlatformServiceImpl
@@ -1,4 +1,6 @@
#if LINUX
using static System.Net.Mime.MediaTypeNames;
namespace BD.WTTS.Services.Implementation;
public sealed class AvaloniaClipboardPlatformService : IClipboardPlatformService
@@ -28,7 +30,9 @@ public sealed class AvaloniaClipboardPlatformService : IClipboardPlatformService
var clipboard = topLevel.Clipboard;
if (clipboard != null)
{
await clipboard.SetTextAsync(text);
//不能用 await 等待 Linux 上不知啥原因导致卡死
clipboard.SetTextAsync(text).GetAwaiter();
await Task.CompletedTask;
}
}
}
@@ -197,11 +197,27 @@ sealed class AvaloniaFilePickerPlatformService : BaseService, IServiceBase, IOpe
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static IReadOnlyList<APS_FilePickerFileType>? Convert(IFilePickerFileType? fileTypes)
{
if (fileTypes is FilePickerFileTypeWrapper impl)
if (fileTypes is AvaloniaFilePickerFileTypeFilter ava)
{
var items = ava.Values;
if (items != null)
{
var query = from m in items
select new APS_FilePickerFileType(m.Name)
{
Patterns = m.Patterns,
AppleUniformTypeIdentifiers = m.AppleUniformTypeIdentifiers,
MimeTypes = m.MimeTypes,
};
return query.ToArray();
}
return null;
}
else if (fileTypes is FilePickerFileTypeWrapper impl)
{
return impl.Values;
}
if (fileTypes is FilePickerFileType.IFilePickerFileTypeWithName @interface)
else if (fileTypes is FilePickerFileType.IFilePickerFileTypeWithName @interface)
{
var values = @interface.GetFileTypes();
if (values.Any())
@@ -1,6 +1,8 @@
using Avalonia.Controls;
using FluentAvalonia.UI.Controls;
using FluentAvalonia.UI.Media.Animation;
using FluentAvalonia.UI.Navigation;
using System.Xml.Linq;
namespace BD.WTTS.Services.Implementation;
@@ -50,11 +52,20 @@ public sealed class NavigationService : INavigationService
_overlayHost = p;
}
public void Navigate(Type? t, NavigationTransitionEffect effect = NavigationTransitionEffect.None)
public void Navigate(Type? t, NavigationTransitionEffect effect = NavigationTransitionEffect.None, bool useCache = true)
{
_frame.ThrowIsNull();
var navOptions = new FrameNavigationOptions
{
IsNavigationStackEnabled = useCache,
TransitionInfoOverride = GetNavigationTransitionInfo(effect)
};
if (t == null)
{
_frame?.Navigate(typeof(ErrorPage), null, GetNavigationTransitionInfo(effect));
navOptions.IsNavigationStackEnabled = false;
_frame.NavigateToType(typeof(ErrorPage), null, navOptions);
return;
}
@@ -66,19 +77,45 @@ public sealed class NavigationService : INavigationService
if (t == null)
{
_frame?.Navigate(typeof(ErrorPage), null, GetNavigationTransitionInfo(effect));
navOptions.IsNavigationStackEnabled = false;
_frame.NavigateToType(typeof(ErrorPage), null, navOptions);
return;
}
if (_frame?.Content?.GetType() != t)
if (_frame.Content?.GetType() != t)
{
_frame?.Navigate(t, null, GetNavigationTransitionInfo(effect));
_frame.NavigateToType(t, null, navOptions);
//if (!useCache && navOptions.IsNavigationStackEnabled)
//{
// _frame.BackStack.Remove(_frame.BackStack.Last());
//}
}
}
public void GoBack()
public void GoBack(Type? t = null)
{
_frame?.GoBack();
if (t == null)
{
_frame?.GoBack();
return;
}
if (t.IsSubclassOf(typeof(ViewModelBase)))
{
var pageType = GetViewModelToPageContent(t, false);
t = pageType as Type;
}
if (t == null)
{
_frame?.GoBack();
return;
}
if (_frame?.CurrentSourcePageType == t)
{
_frame?.GoBack();
}
}
public void NavigateFromContext(object dataContext, NavigationTransitionEffect effect = NavigationTransitionEffect.None)
@@ -105,7 +142,6 @@ public sealed class NavigationService : INavigationService
public void ClearOverlay()
{
_overlayHost?.Children.Clear();
}
private static NavigationTransitionInfo GetNavigationTransitionInfo(NavigationTransitionEffect effect)
@@ -20,8 +20,8 @@
IsVisible="{TemplateBinding IsLoading}"
Spacing="8">
<spp:Image2
Width="150"
Height="150"
Width="100"
Height="100"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
RenderOptions.BitmapInterpolationMode="HighQuality"
@@ -31,6 +31,14 @@
HorizontalAlignment="Center"
Text="{Binding Path=Res.GameList_IsLoading, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
Theme="{StaticResource SubtitleTextBlockStyle}" />
<TextBlock
HorizontalAlignment="Center"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
IsVisible="{TemplateBinding CustomLoadingText,
Converter={StaticResource IsNullConverter},
ConverterParameter=invert}"
Text="{TemplateBinding CustomLoadingText}"
Theme="{StaticResource BodyStrongTextBlockStyle}" />
<Border
Width="35"
Height="35"
@@ -157,6 +157,7 @@
<TextBlock
Name="ControlNameTextBlock"
FontSize="36"
MaxLines="2"
Text="{TemplateBinding Title}"
Theme="{StaticResource TitleTextBlockStyle}">
<TextBlock.Transitions>
@@ -174,6 +175,7 @@
<TextBlock
FontStyle="Italic"
Foreground="{DynamicResource AccentTextFillColorPrimaryBrush}"
MaxLines="2"
Text="{TemplateBinding Subtitle}"
Theme="{StaticResource CaptionTextBlockStyle}" />
</Button>
@@ -182,6 +184,7 @@
FontStyle="Italic"
Foreground="{DynamicResource TextFillColorTertiaryBrush}"
IsVisible="False"
MaxLines="4"
Text="{Binding Path=Description, RelativeSource={RelativeSource TemplatedParent}}"
Theme="{StaticResource CaptionTextBlockStyle}" />
</StackPanel>
@@ -270,6 +273,11 @@
</Setter>
</Style>
<Style Selector="spp|PageBase:namespace /template/ Panel#OptionsRegion Button">
<Setter Property="MaxWidth" Value="200" />
<Setter Property="TextBlock.TextWrapping" Value="Wrap" />
</Style>
<Style Selector="spp|PageBase:namespace /template/ Button#NamespaceText">
<Setter Property="IsVisible" Value="True" />
</Style>
@@ -163,9 +163,9 @@ public class PageBase : UserControl
{
var sz = e.NewSize.Width;
bool isSmallWidth2 = sz < 580;
bool isSmallWidth2 = sz < 640;
PseudoClasses.Set(":smallWidth", sz < 710);
PseudoClasses.Set(":smallWidth", sz < 800);
PseudoClasses.Set(":smallWidth2", isSmallWidth2);
if (isSmallWidth2 && !_isSmallWidth2)
@@ -48,6 +48,12 @@ public class ContentLoader : ContentControl
public static readonly StyledProperty<bool> IsShowNoResultTextProperty =
AvaloniaProperty.Register<ContentLoader, bool>(nameof(IsShowNoResultText), false);
/// <summary>
/// Defines the <see cref="CustomLoadingText"/> property
/// </summary>
public static readonly StyledProperty<string?> CustomLoadingTextProperty =
AvaloniaProperty.Register<ContentLoader, string?>(nameof(CustomLoadingText), null);
/// <summary>
/// 是否正在加载中
/// </summary>
@@ -69,6 +75,15 @@ public class ContentLoader : ContentControl
set => SetValue(IsShowNoResultTextProperty, value);
}
/// <summary>
/// 自定义加载提示
/// </summary>
public string? CustomLoadingText
{
get => GetValue(CustomLoadingTextProperty);
set => SetValue(CustomLoadingTextProperty, value);
}
/// <summary>
/// 无结果时提示
/// </summary>
@@ -76,26 +76,14 @@ public sealed class CustomFilePicker : ContentControl
private async void CustomFilePicker_Tapped(object? sender, RoutedEventArgs e)
{
//if (string.IsNullOrEmpty(FileExtensions) || FileExtensions == "*")
//{
// fileTypes = new ValueTuple<string, string[]>[] { ("All Files", new[] { "*" }) };
//}
//else
//{
// fileTypes = new ValueTuple<string, string[]>[] {
// ("Required Files", FileExtensions.Split(",")),
// ("All Files", new[] { "*" }),
// };
//}
var result = await FilePicker2.PickAsync(PickOptions.Images);
if (result != null)
{
FileName = result.FullPath;
}
else
{
Toast.Show(ToastIcon.Warning, Strings.PleaseSelect);
}
//else
//{
// Toast.Show(ToastIcon.Warning, Strings.PleaseSelect);
//}
}
}
@@ -3,6 +3,9 @@
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:generic="using:System.Collections.Generic"
xmlns:i="using:Avalonia.Xaml.Interactivity"
xmlns:ia="using:Avalonia.Xaml.Interactions.Core"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:spp="https://steampp.net/ui"
xmlns:ui="using:FluentAvalonia.UI.Controls"
@@ -32,7 +35,7 @@
ClipToBounds="True"
CornerRadius="8">
<Panel>
<Carousel Name="Carousel" Grid.Column="1">
<Carousel Name="CarouselControl" Grid.Column="1">
<Carousel.PageTransition>
<PageSlide Orientation="Horizontal" Duration="0.25" />
</Carousel.PageTransition>
@@ -68,15 +71,43 @@
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<DataTemplate>
<Button Padding="0" Classes="Plain">
<DataTemplate.DataType>
<x:Type x:TypeArguments="x:Int32, x:String" TypeName="generic:KeyValuePair" />
</DataTemplate.DataType>
<Button
Padding="0"
Classes="Plain"
Click="CarouselBannerIndexButton_Click"
Tag="{Binding Key}">
<Ellipse
Name="IndexEllipse"
Width="10"
Height="10"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Fill="{ReflectionBinding}"
Fill="{Binding Value}"
Opacity="0.6"
StrokeThickness="0" />
<!--<i:Interaction.Behaviors>
<ia:DataTriggerBehavior
Binding="{Binding}"
ComparisonCondition="Equal"
Value="{Binding #Carousel.SelectedIndex}">
<ia:ChangePropertyAction
PropertyName="Fill"
TargetObject="IndexEllipse"
Value="White" />
</ia:DataTriggerBehavior>
<ia:DataTriggerBehavior
Binding="{Binding}"
ComparisonCondition="NotEqual"
Value="{Binding #Carousel.SelectedIndex}">
<ia:ChangePropertyAction
PropertyName="Fill"
TargetObject="IndexEllipse"
Value="Gray" />
</ia:DataTriggerBehavior>
</i:Interaction.Behaviors>-->
</Button>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
@@ -73,14 +73,14 @@ namespace BD.WTTS.UI.Views.Controls
Left.Click += (s, e) => SwiperPrevious();
Right.Click += (s, e) => SwiperNext();
//Carousel[!Carousel.Items] = this[!Items];
Carousel[!Carousel.ItemsSourceProperty] = this[!ItemsSourceProperty];
Carousel[!Carousel.ItemTemplateProperty] = this[!ItemTemplateProperty];
//CarouselControl[!Carousel.Items] = this[!Items];
CarouselControl[!Carousel.ItemsSourceProperty] = this[!ItemsSourceProperty];
CarouselControl[!Carousel.ItemTemplateProperty] = this[!ItemTemplateProperty];
this.GetObservable(ItemsSourceProperty)
.Subscribe(_ => SwipersLoad());
Carousel.GetObservable(Carousel.SelectedIndexProperty)
CarouselControl.GetObservable(Carousel.SelectedIndexProperty)
.Subscribe(x => SwipersLoad());
this.GetObservable(AutoScrollProperty)
@@ -107,14 +107,22 @@ namespace BD.WTTS.UI.Views.Controls
});
}
private void CarouselBannerIndexButton_Click(object? sender, RoutedEventArgs e)
{
if (sender is Button button && button.Tag is int index)
{
CarouselControl.SelectedIndex = index;
}
}
private void SwipersLoad()
{
if (Carousel.ItemCount <= 0)
if (CarouselControl.ItemCount <= 0)
{
Swiper.ItemsSource = null;
return;
}
if (Carousel.ItemCount == 1)
if (CarouselControl.ItemCount == 1)
{
Left.IsVisible = Right.IsVisible = Swiper.IsVisible = false;
return;
@@ -122,12 +130,12 @@ namespace BD.WTTS.UI.Views.Controls
else
{
Left.IsVisible = Right.IsVisible = Swiper.IsVisible = true;
var arr = new string[Carousel.ItemCount];
for (var i = 0; i < arr.Length; i++)
var arr = new Dictionary<int, string>();
for (var i = 0; i < CarouselControl.ItemCount; i++)
{
arr[i] = "#ADADAD";
arr.Add(i, "#ADADAD");
}
var index = Carousel.SelectedIndex < 0 ? 0 : Carousel.SelectedIndex;
var index = CarouselControl.SelectedIndex < 0 ? 0 : CarouselControl.SelectedIndex;
arr[index] = "#FFFFFF";
Swiper.ItemsSource = arr;
@@ -136,29 +144,29 @@ namespace BD.WTTS.UI.Views.Controls
private void SwiperNext()
{
if (Carousel.ItemCount < 1)
if (CarouselControl.ItemCount < 1)
return;
if (Carousel.SelectedIndex < Carousel.ItemCount - 1)
if (CarouselControl.SelectedIndex < CarouselControl.ItemCount - 1)
{
Carousel.Next();
CarouselControl.Next();
}
else
{
Carousel.SelectedIndex = 0;
CarouselControl.SelectedIndex = 0;
}
}
private void SwiperPrevious()
{
if (Carousel.ItemCount < 1)
if (CarouselControl.ItemCount < 1)
return;
if (Carousel.SelectedIndex > 0)
if (CarouselControl.SelectedIndex > 0)
{
Carousel.Previous();
CarouselControl.Previous();
}
else
{
Carousel.SelectedIndex = Carousel.ItemCount - 1;
CarouselControl.SelectedIndex = CarouselControl.ItemCount - 1;
}
}
}
@@ -67,166 +67,166 @@
</StackPanel>
</spp:PageBase.ActionContent>-->
<ScrollViewer Padding="20">
<spp:ContentLoader IsLoading="False">
<StackPanel
x:Name="HomeRoot"
MaxWidth="1080"
Spacing="20">
<spp:Snackbar
Title="{Binding Path=Res.Notice_Tray_Title, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
VerticalAlignment="Top"
IsClosable="False"
IsOpen="True"
IsVisible="{spp:OnPlatform !GA}"
Message="当前使用的程序版本为测试版本,可能会有各种各样不可言明的 Bug,遇到问题请理性反馈,谢谢。"
Severity="Warning" />
<spp:Snackbar
Title="{Binding Path=Res.Notice_Tray_Title, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
VerticalAlignment="Top"
IsClosable="False"
IsOpen="True"
IsVisible="{Binding !!!MainWindow2.PluginCount, Mode=OneWay, Source={x:Static s:IViewModelManager.Instance}}"
Message="检测到你没有安装插件,请去下载插件即可使用更多功能。"
Severity="Warning" />
<!--<spp:ContentLoader IsLoading="False">-->
<StackPanel
x:Name="HomeRoot"
MaxWidth="1080"
Spacing="20">
<spp:Snackbar
Title="{Binding Path=Res.Notice_Tray_Title, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
VerticalAlignment="Top"
IsClosable="False"
IsOpen="True"
IsVisible="{spp:OnPlatform !GA}"
Message="当前使用的程序版本为测试版本,可能会有各种各样不可言明的 Bug,遇到问题请理性反馈,谢谢。"
Severity="Warning" />
<spp:Snackbar
Title="{Binding Path=Res.Notice_Tray_Title, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
VerticalAlignment="Top"
IsClosable="False"
IsOpen="True"
IsVisible="{Binding !!!MainWindow2.PluginCount, Mode=OneWay, Source={x:Static s:IViewModelManager.Instance}}"
Message="检测到你没有安装插件,请去下载插件即可使用更多功能。"
Severity="Warning" />
<WrapPanel Margin="5,0">
<WrapPanel IsVisible="{Binding Source={x:Static s:SteamConnectService.Current}, Path=CurrentSteamUser, Mode=OneWay, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}">
<spp:Image2
Width="36"
Height="36"
Margin="0,0,5,0"
VerticalAlignment="Center"
DecodeWidth="36"
Source="{Binding Source={x:Static s:SteamConnectService.Current}, Path=CurrentSteamUser.AvatarMedium, Mode=OneWay}"
Stretch="Uniform">
<spp:Image2.Clip>
<EllipseGeometry Rect="0,0,36,36" />
</spp:Image2.Clip>
</spp:Image2>
<TextBlock
VerticalAlignment="Center"
Text="{Binding Source={x:Static s:SteamConnectService.Current}, Path=CurrentSteamUser.SteamNickName, Mode=OneWay}"
Theme="{StaticResource SubtitleTextBlockStyle}" />
<TextBlock
VerticalAlignment="Center"
IsVisible="{Binding Source={x:Static s:SteamConnectService.Current}, Path=CurrentSteamUser.IPCountry, Mode=OneWay, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}"
Text="{Binding Source={x:Static s:SteamConnectService.Current}, Path=CurrentSteamUser.IPCountry, Mode=OneWay, StringFormat={}({0})}"
Theme="{StaticResource SubtitleTextBlockStyle}" />
<TextBlock
Margin="0,0,10,0"
VerticalAlignment="Center"
Text=","
Theme="{StaticResource SubtitleTextBlockStyle}" />
</WrapPanel>
<TextBlock VerticalAlignment="Center" Theme="{StaticResource SubtitleTextBlockStyle}">
<Run Text="{Binding Path=Res.Welcome_User_, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
</TextBlock>
<WrapPanel Margin="5,0">
<WrapPanel IsVisible="{Binding Source={x:Static s:SteamConnectService.Current}, Path=CurrentSteamUser, Mode=OneWay, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}">
<spp:Image2
Width="36"
Height="36"
Margin="0,0,5,0"
VerticalAlignment="Center"
DecodeWidth="36"
Source="{Binding Source={x:Static s:SteamConnectService.Current}, Path=CurrentSteamUser.AvatarMedium, Mode=OneWay}"
Stretch="Uniform">
<spp:Image2.Clip>
<EllipseGeometry Rect="0,0,36,36" />
</spp:Image2.Clip>
</spp:Image2>
<TextBlock
VerticalAlignment="Center"
Text="{Binding Source={x:Static s:SteamConnectService.Current}, Path=CurrentSteamUser.SteamNickName, Mode=OneWay}"
Theme="{StaticResource SubtitleTextBlockStyle}" />
<TextBlock
VerticalAlignment="Center"
IsVisible="{Binding Source={x:Static s:SteamConnectService.Current}, Path=CurrentSteamUser.IPCountry, Mode=OneWay, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}"
Text="{Binding Source={x:Static s:SteamConnectService.Current}, Path=CurrentSteamUser.IPCountry, Mode=OneWay, StringFormat={}({0})}"
Theme="{StaticResource SubtitleTextBlockStyle}" />
<TextBlock
Margin="0,0,10,0"
VerticalAlignment="Center"
Text=","
Theme="{StaticResource SubtitleTextBlockStyle}" />
</WrapPanel>
<TextBlock VerticalAlignment="Center" Theme="{StaticResource SubtitleTextBlockStyle}">
<Run Text="{Binding Path=Res.Welcome_User_, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
</TextBlock>
</WrapPanel>
<Grid Margin="0,-10,0,0" RowDefinitions="Auto,*">
<spp:CarouselBanner
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
ItemsSource="{Binding NavigationBanners}">
<spp:CarouselBanner.ItemTemplate>
<DataTemplate DataType="spp:AdvertisementDTO">
<spp:AppItem
Title="{Binding Describe}"
Height="350"
Classes="Banner Scale"
ClickCommand="{Binding OpenBrowserCommand, Source={x:Static spp:App.Instance}}"
ClickCommandParameter="{Binding Url}"
Description="{Binding Name}">
<spp:AppItem.Status>
<Border
Padding="20,10"
Background="{DynamicResource AccentFillColorSelectedTextBackgroundBrush}"
ClipToBounds="True"
CornerRadius="{StaticResource ControlCornerRadius}">
<TextBlock FontSize="16" Text="阅读更多" />
</Border>
</spp:AppItem.Status>
<spp:AppItem.Image>
<spp:Image2 Source="{Binding ImageUrl}" />
</spp:AppItem.Image>
</spp:AppItem>
</DataTemplate>
</spp:CarouselBanner.ItemTemplate>
</spp:CarouselBanner>
</Grid>
<Grid Margin="0,-10,0,0" RowDefinitions="Auto,*">
<spp:CarouselBanner
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
ItemsSource="{Binding NavigationBanners}">
<spp:CarouselBanner.ItemTemplate>
<DataTemplate DataType="spp:AdvertisementDTO">
<spp:AppItem
Title="{Binding Describe}"
Height="350"
Classes="Banner Scale"
ClickCommand="{Binding OpenBrowserCommand, Source={x:Static spp:App.Instance}}"
ClickCommandParameter="{Binding Url}"
Description="{Binding Name}">
<spp:AppItem.Status>
<Border
Padding="20,10"
Background="{DynamicResource AccentFillColorSelectedTextBackgroundBrush}"
ClipToBounds="True"
CornerRadius="{StaticResource ControlCornerRadius}">
<TextBlock FontSize="16" Text="阅读更多" />
</Border>
</spp:AppItem.Status>
<spp:AppItem.Image>
<spp:Image2 Source="{Binding ImageUrl}" />
</spp:AppItem.Image>
</spp:AppItem>
</DataTemplate>
</spp:CarouselBanner.ItemTemplate>
</spp:CarouselBanner>
</Grid>
<!--<Viewbox Stretch="UniformToFill">
<!--<Viewbox Stretch="UniformToFill">
<spp:AdControl
MaxWidth="{Binding #HomeRoot.MaxWidth}"
MaxHeight="200"
Standard="Horizontal" />
</Viewbox>-->
<StackPanel
Grid.Row="2"
Margin="0,10"
Spacing="10">
<DockPanel>
<TextBlock
VerticalAlignment="Center"
Text="最新消息"
Theme="{StaticResource TitleTextBlockStyle}" />
<Button
HorizontalAlignment="Right"
VerticalAlignment="Center"
Command="{Binding OpenBrowserCommand, Source={x:Static spp:App.Instance}}"
CommandParameter="{x:Static spp:HomePageViewModel.OfficialWebsite_Article}"
Content="查看更多"
DockPanel.Dock="Right"
Theme="{StaticResource HyperlinkButton}" />
</DockPanel>
<StackPanel
Grid.Row="2"
Margin="0,10"
Spacing="10">
<DockPanel>
<TextBlock
VerticalAlignment="Center"
Text="最新消息"
Theme="{StaticResource TitleTextBlockStyle}" />
<Button
HorizontalAlignment="Right"
VerticalAlignment="Center"
Command="{Binding OpenBrowserCommand, Source={x:Static spp:App.Instance}}"
CommandParameter="{x:Static spp:HomePageViewModel.OfficialWebsite_Article}"
Content="查看更多"
DockPanel.Dock="Right"
Theme="{StaticResource HyperlinkButton}" />
</DockPanel>
<Grid Margin="0,0,0,20" ColumnDefinitions="*,10,*,10,*">
<Grid.Styles>
<Style x:DataType="spp:ArticleItemDTO" Selector="spp|AppItem">
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Title" Value="{Binding Title}" />
<Setter Property="Description" Value="{Binding Introduction}" />
<Setter Property="Tags" Value="{Binding AuthorName}" />
<Setter Property="ClickCommand" Value="{Binding OpenBrowserCommand, Source={x:Static spp:App.Instance}}" />
<Setter Property="ClickCommandParameter">
<Setter.Value>
<MultiBinding Converter="{StaticResource StringFormatConverter}">
<CompiledBinding Path="." Source="{x:Static spp:HomePageViewModel.OfficialWebsite_Article_Detail_}" />
<CompiledBinding Path="Id" />
</MultiBinding>
</Setter.Value>
</Setter>
<Setter Property="Image">
<Setter.Value>
<Template>
<spp:Image2 RenderOptions.BitmapInterpolationMode="HighQuality" Source="{Binding CoverUrl}" />
</Template>
</Setter.Value>
</Setter>
<Setter Property="Status">
<Setter.Value>
<Template>
<Border Classes="Status">
<TextBlock Text="{Binding CreationTime, StringFormat={}{0:yyyy-MM-dd}}" />
</Border>
</Template>
</Setter.Value>
</Setter>
</Style>
</Grid.Styles>
<spp:AppItem Classes="Vertical Scale" DataContext="{Binding Articles[0]}" />
<spp:AppItem
Grid.Column="2"
Classes="Vertical Scale"
DataContext="{Binding Articles[1]}" />
<spp:AppItem
Grid.Column="4"
Classes="Vertical Scale"
DataContext="{Binding Articles[2]}" />
</Grid>
<Grid Margin="0,0,0,20" ColumnDefinitions="*,10,*,10,*">
<Grid.Styles>
<Style x:DataType="spp:ArticleItemDTO" Selector="spp|AppItem">
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Title" Value="{Binding Title}" />
<Setter Property="Description" Value="{Binding Introduction}" />
<Setter Property="Tags" Value="{Binding AuthorName}" />
<Setter Property="ClickCommand" Value="{Binding OpenBrowserCommand, Source={x:Static spp:App.Instance}}" />
<Setter Property="ClickCommandParameter">
<Setter.Value>
<MultiBinding Converter="{StaticResource StringFormatConverter}">
<CompiledBinding Path="." Source="{x:Static spp:HomePageViewModel.OfficialWebsite_Article_Detail_}" />
<CompiledBinding Path="Id" />
</MultiBinding>
</Setter.Value>
</Setter>
<Setter Property="Image">
<Setter.Value>
<Template>
<spp:Image2 RenderOptions.BitmapInterpolationMode="HighQuality" Source="{Binding CoverUrl}" />
</Template>
</Setter.Value>
</Setter>
<Setter Property="Status">
<Setter.Value>
<Template>
<Border Classes="Status">
<TextBlock Text="{Binding CreationTime, StringFormat={}{0:yyyy-MM-dd}}" />
</Border>
</Template>
</Setter.Value>
</Setter>
</Style>
</Grid.Styles>
<spp:AppItem Classes="Vertical Scale" DataContext="{Binding Articles[0]}" />
<spp:AppItem
Grid.Column="2"
Classes="Vertical Scale"
DataContext="{Binding Articles[1]}" />
<spp:AppItem
Grid.Column="4"
Classes="Vertical Scale"
DataContext="{Binding Articles[2]}" />
</Grid>
<!--<ItemsControl ItemsSource="{Binding Articles}">
<!--<ItemsControl ItemsSource="{Binding Articles}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid ColumnDefinitions="*,*,*" />
@@ -252,149 +252,149 @@
</ItemsControl.ItemTemplate>
</ItemsControl>-->
<DockPanel>
<TextBlock
VerticalAlignment="Center"
Text="精选"
Theme="{StaticResource TitleTextBlockStyle}" />
<Button
HorizontalAlignment="Right"
VerticalAlignment="Center"
Command="{Binding OpenBrowserCommand, Source={x:Static spp:App.Instance}}"
CommandParameter="{x:Static spp:HomePageViewModel.WattGameUrl}"
Content="访问 WattGame 商城"
DockPanel.Dock="Right"
Theme="{StaticResource HyperlinkButton}" />
</DockPanel>
<ScrollViewer
Name="ShopsScrollViewer"
Margin="0,3,0,20"
Padding="0,0,0,15"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Disabled">
<ItemsControl ItemsSource="{Binding Shops}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Spacing="10" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="spp:ShopRecommendGoodItem">
<spp:AppItem
Title="{Binding Name}"
MaxWidth="260"
Classes="Vertical Scale"
ClickCommand="{Binding OpenBrowserCommand, Source={x:Static spp:App.Instance}}"
Cursor="Hand"
Tags="{Binding GoodsAllCategorysText}"
ToolTip.Tip="{Binding Brief}">
<spp:AppItem.ClickCommandParameter>
<MultiBinding Converter="{StaticResource StringFormatConverter}">
<CompiledBinding Path="." Source="{x:Static spp:HomePageViewModel.WattGame_Goods_Detail_}" />
<CompiledBinding Path="Id" />
</MultiBinding>
</spp:AppItem.ClickCommandParameter>
<spp:AppItem.Image>
<spp:Image2 RenderOptions.BitmapInterpolationMode="HighQuality" Source="{Binding Image}" />
</spp:AppItem.Image>
<spp:AppItem.Status>
<Border Classes="Status">
<StackPanel Orientation="Horizontal">
<TextBlock
VerticalAlignment="Center"
FontSize="12"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
IsVisible="{Binding !!DiscountValue}"
Text="{Binding Mktprice, Converter={StaticResource StringFormatConverter}, ConverterParameter={x:Static spp:CurrencyCode.CNY}}"
TextDecorations="Strikethrough" />
<TextBlock
VerticalAlignment="Center"
FontSize="14"
Text="{Binding Price, Converter={StaticResource StringFormatConverter}, ConverterParameter={x:Static spp:CurrencyCode.CNY}}" />
</StackPanel>
</Border>
</spp:AppItem.Status>
<spp:AppItem.ActionButton>
<Border
Height="24"
Padding="8,0"
Background="#4c6b22"
ClipToBounds="True"
CornerRadius="4"
IsVisible="{Binding !!DiscountValue}">
<TextBlock
VerticalAlignment="Center"
Foreground="#beee11"
Text="{Binding DiscountValue, StringFormat={}-{0}%}" />
</Border>
</spp:AppItem.ActionButton>
</spp:AppItem>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<DockPanel>
<TextBlock
Margin="-2,0,0,0"
Text="已安装功能"
VerticalAlignment="Center"
Text="精选"
Theme="{StaticResource TitleTextBlockStyle}" />
<Button
HorizontalAlignment="Right"
VerticalAlignment="Center"
Command="{Binding OpenBrowserCommand, Source={x:Static spp:App.Instance}}"
CommandParameter="{x:Static spp:HomePageViewModel.WattGameUrl}"
Content="访问 WattGame 商城"
DockPanel.Dock="Right"
Theme="{StaticResource HyperlinkButton}" />
</DockPanel>
<ItemsControl ItemsSource="{Binding MainWindow2.TabItems, Mode=OneWay, Source={x:Static s:IViewModelManager.Instance}}">
<ItemsControl.Resources>
<ControlTheme
x:Key="NavButtonStyle"
BasedOn="{StaticResource {x:Type Button}}"
TargetType="Button">
<Setter Property="Width" Value="120" />
<Setter Property="Padding" Value="0" />
<Setter Property="Margin" Value="6" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="ClipToBounds" Value="True" />
</Style>
</ControlTheme>
</ItemsControl.Resources>
<ScrollViewer
Name="ShopsScrollViewer"
Margin="0,3,0,20"
Padding="0,0,0,15"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Disabled">
<ItemsControl ItemsSource="{Binding Shops}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
<StackPanel Orientation="Horizontal" Spacing="10" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="spp:TabItemViewModel">
<Border spp:Animations.EnableAnimations="True">
<Button
Command="{Binding $parent[spp:HomePage].((spp:HomePageViewModel)DataContext).NavgationToMenuPageCommand}"
CommandParameter="{Binding}"
Theme="{StaticResource NavButtonStyle}">
<Grid RowDefinitions="3*,*">
<Border
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
CornerRadius="4 4 0 0"
RenderOptions.BitmapInterpolationMode="HighQuality">
<spp:Image2
Width="96"
Height="96"
Margin="0,10,0,0"
Source="{Binding IconKey}"
Stretch="Uniform" />
</Border>
<DataTemplate DataType="spp:ShopRecommendGoodItem">
<spp:AppItem
Title="{Binding Name}"
MaxWidth="260"
Classes="Vertical Scale"
ClickCommand="{Binding OpenBrowserCommand, Source={x:Static spp:App.Instance}}"
Cursor="Hand"
Tags="{Binding GoodsAllCategorysText}"
ToolTip.Tip="{Binding Brief}">
<spp:AppItem.ClickCommandParameter>
<MultiBinding Converter="{StaticResource StringFormatConverter}">
<CompiledBinding Path="." Source="{x:Static spp:HomePageViewModel.WattGame_Goods_Detail_}" />
<CompiledBinding Path="Id" />
</MultiBinding>
</spp:AppItem.ClickCommandParameter>
<spp:AppItem.Image>
<spp:Image2 RenderOptions.BitmapInterpolationMode="HighQuality" Source="{Binding Image}" />
</spp:AppItem.Image>
<spp:AppItem.Status>
<Border Classes="Status">
<StackPanel Orientation="Horizontal">
<TextBlock
VerticalAlignment="Center"
FontSize="12"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
IsVisible="{Binding !!DiscountValue}"
Text="{Binding Mktprice, Converter={StaticResource StringFormatConverter}, ConverterParameter={x:Static spp:CurrencyCode.CNY}}"
TextDecorations="Strikethrough" />
<TextBlock
VerticalAlignment="Center"
FontSize="14"
Text="{Binding Price, Converter={StaticResource StringFormatConverter}, ConverterParameter={x:Static spp:CurrencyCode.CNY}}" />
</StackPanel>
</Border>
</spp:AppItem.Status>
<spp:AppItem.ActionButton>
<Border
Height="24"
Padding="8,0"
Background="#4c6b22"
ClipToBounds="True"
CornerRadius="4"
IsVisible="{Binding !!DiscountValue}">
<TextBlock
Grid.Row="1"
Margin="12"
FontWeight="SemiBold"
Text="{Binding Name}" />
</Grid>
</Button>
</Border>
VerticalAlignment="Center"
Foreground="#beee11"
Text="{Binding DiscountValue, StringFormat={}-{0}%}" />
</Border>
</spp:AppItem.ActionButton>
</spp:AppItem>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<!--<TextBlock Text="联系我们" Theme="{StaticResource TitleTextBlockStyle}" />
<TextBlock
Margin="-3,0,0,0"
Text="已安装功能"
Theme="{StaticResource TitleTextBlockStyle}" />
<ItemsControl ItemsSource="{Binding MainWindow2.TabItems, Mode=OneWay, Source={x:Static s:IViewModelManager.Instance}}">
<ItemsControl.Resources>
<ControlTheme
x:Key="NavButtonStyle"
BasedOn="{StaticResource {x:Type Button}}"
TargetType="Button">
<Setter Property="Width" Value="120" />
<Setter Property="Padding" Value="0" />
<Setter Property="Margin" Value="6" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="ClipToBounds" Value="True" />
</Style>
</ControlTheme>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="spp:TabItemViewModel">
<Border spp:Animations.EnableAnimations="True">
<Button
Command="{Binding $parent[spp:HomePage].((spp:HomePageViewModel)DataContext).NavgationToMenuPageCommand}"
CommandParameter="{Binding}"
Theme="{StaticResource NavButtonStyle}">
<Grid RowDefinitions="3*,*">
<Border
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
CornerRadius="4 4 0 0"
RenderOptions.BitmapInterpolationMode="HighQuality">
<spp:Image2
Width="96"
Height="96"
Margin="0,10,0,0"
Source="{Binding IconKey}"
Stretch="Uniform" />
</Border>
<TextBlock
Grid.Row="1"
Margin="12"
FontWeight="SemiBold"
Text="{Binding Name}" />
</Grid>
</Button>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!--<TextBlock Text="联系我们" Theme="{StaticResource TitleTextBlockStyle}" />
<Grid Margin="0,0,0,20" ColumnDefinitions="*,10,*,10,*,10,*,10,*">
<spp:AppItem
@@ -449,9 +449,9 @@
</spp:AppItem>
</Grid>-->
</StackPanel>
</StackPanel>
<!--<TabControl Grid.Row="3" Padding="0">
<!--<TabControl Grid.Row="3" Padding="0">
<TabItem Header="1111">
<StackPanel Spacing="5">
<spp:AppItem
@@ -523,13 +523,13 @@
</TabItem>
</TabControl>-->
<TextBlock
Margin="0,30"
HorizontalAlignment="Center"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
Text="不忘初心,方得始终。"
Theme="{StaticResource SubtitleTextBlockStyle}" />
</StackPanel>
</spp:ContentLoader>
<TextBlock
Margin="0,30"
HorizontalAlignment="Center"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
Text="不忘初心,方得始终。"
Theme="{StaticResource SubtitleTextBlockStyle}" />
</StackPanel>
<!--</spp:ContentLoader>-->
</ScrollViewer>
</UserControl>
@@ -9,34 +9,34 @@ public partial class HomePage : ReactiveUserControl<HomePageViewModel>
InitializeComponent();
this.SetViewModel<HomePageViewModel>(false);
ShopsScrollViewer.PointerWheelChanged += ShopsScrollViewer_PointerWheelChanged;
//ShopsScrollViewer.PointerWheelChanged += ShopsScrollViewer_PointerWheelChanged;
}
private void ShopsScrollViewer_PointerWheelChanged(object? sender, PointerWheelEventArgs e)
{
if (sender is ScrollViewer scroll)
if (scroll.IsPointerOver)
if (scroll.Extent.Height > scroll.Viewport.Height || scroll.Extent.Width > scroll.Viewport.Width)
{
var delta = e.Delta;
//private void ShopsScrollViewer_PointerWheelChanged(object? sender, PointerWheelEventArgs e)
//{
// if (sender is ScrollViewer scroll)
// if (scroll.IsPointerOver)
// if (scroll.Extent.Height > scroll.Viewport.Height || scroll.Extent.Width > scroll.Viewport.Width)
// {
// var delta = e.Delta;
var isScrollStart = scroll.Offset.X == 0;
var isScrollEnd = scroll.Offset.X + scroll.Bounds.Size.Width >= scroll.Extent.Width;
if (isScrollStart && MathUtilities.IsOne(e.Delta.Y))
{
return;
}
if (isScrollEnd && e.Delta.Y == -1)
{
return;
}
if (MathUtilities.IsZero(delta.X))
{
var horizontalOffset = scroll.Offset.X;
horizontalOffset -= delta.Y * 50; // 根据事件参数来调整滚动的距离
scroll.Offset = new Vector(horizontalOffset, scroll.Offset.Y);
e.Handled = true;
}
}
}
// var isScrollStart = scroll.Offset.X == 0;
// var isScrollEnd = scroll.Offset.X + scroll.Bounds.Size.Width >= scroll.Extent.Width;
// if (isScrollStart && MathUtilities.IsOne(e.Delta.Y))
// {
// return;
// }
// if (isScrollEnd && e.Delta.Y == -1)
// {
// return;
// }
// if (MathUtilities.IsZero(delta.X))
// {
// var horizontalOffset = scroll.Offset.X;
// horizontalOffset -= delta.Y * 50; // 根据事件参数来调整滚动的距离
// scroll.Offset = new Vector(horizontalOffset, scroll.Offset.Y);
// e.Handled = true;
// }
// }
//}
}
@@ -180,7 +180,7 @@
ClipToBounds="True"
CornerRadius="30">
<spp:Image2
DecodeWidth="32"
DecodeWidth="36"
FallbackSource="{StaticResource DefaultAvatar}"
RenderOptions.BitmapInterpolationMode="HighQuality"
Source="{Binding Path=AvatarPath, Mode=OneWay, Source={x:Static s:UserService.Current}}" />
@@ -97,8 +97,7 @@
Header="{Binding Path=Res.Settings_General_StorageSpace, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
IconSource="Globe"
IsClickEnabled="False"
IsExpanded="True"
IsVisible="{spp:OnPlatform Windows}">
IsExpanded="True">
<ui:SettingsExpander.IconSource>
<ui:FontIconSource FontFamily="Segoe Fluent Icons" Glyph="&#xE7F1;" />
</ui:SettingsExpander.IconSource>
@@ -30,10 +30,22 @@
<TextBlock Margin="0,10,0,5" Theme="{StaticResource BodyStrongTextBlockStyle}">
<Run Text="{Binding Path=Res.Plugin_InstalledPlugins, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}({1})">
<CompiledBinding
Mode="OneWay"
Path="Res.Plugin_InstalledPlugins"
Source="{x:Static s:ResourceService.Current}" />
<CompiledBinding
Mode="OneWay"
Path="MainWindow2.PluginCount"
Source="{x:Static s:IViewModelManager.Instance}" />
</MultiBinding>
</TextBlock.Text>
<!--<Run Text="{Binding Path=Res.Plugin_InstalledPlugins, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<Run Text="(" />
<Run Text="{Binding MainWindow2.PluginCount, Mode=OneWay, Source={x:Static s:IViewModelManager.Instance}}" />
<Run Text=")" />
<Run Text=")" />-->
</TextBlock>
<ItemsControl Classes="DraggableOrder" ItemsSource="{Binding Plugins}">
@@ -35,6 +35,16 @@ public partial class LoginOrRegisterPage : ReactiveUserControl<LoginOrRegisterWi
{
base.OnLoaded(e);
this.SetViewModel<LoginOrRegisterWindowViewModel>(false);
if (this.ViewModel != null)
{
this.ViewModel.LoginState = 0;
if (UserService.Current.IsAuthenticated)
{
Toast.Show(ToastIcon.Info, "当前已是登录状态");
this.ViewModel.Close();
}
}
}
protected override void OnDataContextChanged(EventArgs e)
@@ -148,6 +148,7 @@ public sealed class ScriptManager : GeneralHttpClientFactory, IScriptManager
info.LocalId = oldInfo.LocalId;
info.Id = oldInfo.Id;
info.Order = oldInfo.Order;
info.IconUrl = oldInfo.IconUrl;
if (isNoRepeat)
{
var state = await DeleteScriptAsync(oldInfo, false);
@@ -164,13 +165,10 @@ public sealed class ScriptManager : GeneralHttpClientFactory, IScriptManager
info.UpdateLink = oldInfo.UpdateLink;
info.DownloadLink = oldInfo.DownloadLink;
info.IconUrl = oldInfo.IconUrl;
info.AuthorName = oldInfo.AuthorName;
info.Describe = oldInfo.Describe;
info.UpdateTime = oldInfo.UpdateTime;
info.AccelerateProjects = oldInfo.AccelerateProjects;
info.Version = oldInfo.Version;
info.ExcludeDomainNames = oldInfo.ExcludeDomainNames;
info.MatchDomainNames = oldInfo.MatchDomainNames;
info.Name = oldInfo.Name;
}
}
@@ -17,7 +17,7 @@ partial class ProxyService
if (!proxyDomains.Any_Nullable())
{
Toast.Show(ToastIcon.Warning, "你没有启用任何加速项!!");
Toast.Show(ToastIcon.Warning, Strings.CommunityFix_AccEmpty);
}
IReadOnlyCollection<ScriptIPCDTO>? scripts = default;
@@ -297,7 +297,11 @@ partial class ProxyService
break;
}
StopTimer(); // 停止 UI 计时器
#if MACOS
reverseProxyService.StopProxyAsync().GetAwaiter(); // 停止代理服务
#else
await reverseProxyService.StopProxyAsync(); // 停止代理服务
#endif
return default;
}
@@ -15,24 +15,18 @@ public partial class ScriptPageViewModel : TabItemViewModel
//AllEnableScriptCommand = ReactiveCommand.Create(AllEnableScript);
AddNewScriptCommand = ReactiveCommand.CreateFromTask(async () =>
{
FilePickerFileType? fileTypes;
if (IApplication.IsDesktop())
{
fileTypes = new ValueTuple<string, string[]>[]
{
("JavaScript Files", new[] { $"*{FileEx.JS}", }),
("Text Files", new[] { $"*{FileEx.TXT}", }),
//("All Files", new[] { "*", }),
};
}
else if (OperatingSystem2.IsAndroid())
{
fileTypes = new[] { MediaTypeNames.TXT, MediaTypeNames.JS };
}
else
{
fileTypes = null;
}
AvaloniaFilePickerFileTypeFilter fileTypes = new AvaloniaFilePickerFileTypeFilter.Item[] {
new("JavaScript Files") {
Patterns = new[] { "*.js", },
MimeTypes = new[] { MediaTypeNames.JS, },
//AppleUniformTypeIdentifiers =
},
new("Text Files") {
Patterns = new[] { "*.txt", },
MimeTypes = new[] { MediaTypeNames.TXT, },
//AppleUniformTypeIdentifiers =
},
};
await FilePicker2.PickAsync(ProxyService.Current.AddNewScriptAsync, fileTypes);
});
@@ -140,19 +140,18 @@ public static class AuthenticatorHelper
SaveFileResult? exportFile = null;
if (Essentials.IsSupportedSaveFileDialog)
{
FilePickerFileType? fileTypes;
if (IApplication.IsDesktop())
{
fileTypes = new ValueTuple<string, string[]>[]
{
("MsgPack Files", new[] { $"*{FileEx.MPO}", }), ("Data Files", new[] { $"*{FileEx.DAT}", }),
//("All Files", new[] { "*", }),
};
}
else
{
fileTypes = null;
}
AvaloniaFilePickerFileTypeFilter fileTypes = new AvaloniaFilePickerFileTypeFilter.Item[] {
new("MsgPack Files") {
Patterns = new[] { $"*.{FileEx.MPO}", },
//MimeTypes
//AppleUniformTypeIdentifiers =
},
new("Data Files") {
Patterns = new[] { $"*.{FileEx.DAT}", },
//MimeTypes
//AppleUniformTypeIdentifiers =
},
};
exportFile = await FilePicker2.SaveAsync(new PickOptions
{
FileTypes = fileTypes,
@@ -462,12 +461,18 @@ public static class AuthenticatorHelper
var options = new PickOptions();
if (!string.IsNullOrEmpty(fileExtension))
{
FilePickerFileType fileTypes = new[] { ($"{fileExtension} Files", new[] { "*" + fileExtension, }), };
AvaloniaFilePickerFileTypeFilter fileTypes = new AvaloniaFilePickerFileTypeFilter.Item[] {
new($"{fileExtension} Files") {
Patterns = new[] { $"*.{fileExtension}", },
//MimeTypes
//AppleUniformTypeIdentifiers =
},
};
options.FileTypes = fileTypes;
}
var filePath = (await FilePicker2.PickAsync(options))?.FullPath;
if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
if (!File.Exists(filePath))
Toast.Show(ToastIcon.Warning, Strings.FilePathNotExist);
return filePath;
}
@@ -17,9 +17,11 @@ public partial class AuthenticatorItemModel : ReactiveObject, IDisposable
public async Task CopyCode()
{
//if (!IsShowCode) return;
await Clipboard2.SetTextAsync(AuthData.Value?.CurrentCode);
Toast.Show(ToastIcon.Success, Strings.LocalAuth_CopyAuthTip + AuthName);
if (AuthData.Value?.CurrentCode != null)
{
await Clipboard2.SetTextAsync(AuthData.Value?.CurrentCode);
Toast.Show(ToastIcon.Success, Strings.LocalAuth_CopyAuthTip + AuthName);
}
}
public AuthenticatorItemModel(IAuthenticatorDTO authenticatorDto)
@@ -207,8 +207,8 @@ internal sealed class AccountPlatformAuthenticatorRepository : Repository<Accoun
IsNotLocal = !isLocal,
IsNeedSecondaryPassword = !notSecondaryPassword,
Index = item.Index,
Created = item.Created,
LastUpdate = item.LastUpdate,
Created = item.Created == default ? DateTimeOffset.Now : item.Created,
LastUpdate = DateTimeOffset.Now,
};
return entity;
}
@@ -500,16 +500,13 @@ public sealed partial class AuthenticatorHomePageViewModel : ViewModelBase
if (Essentials.IsSupportedSaveFileDialog)
{
FilePickerFileType? fileTypes;
if (IApplication.IsDesktop())
{
fileTypes = new[] { ("maFile Files", new[] { FileEx.maFile, }), };
}
else
{
fileTypes = null;
}
AvaloniaFilePickerFileTypeFilter fileTypes = new AvaloniaFilePickerFileTypeFilter.Item[] {
new("maFile Files") {
Patterns = new[] { $"*.{FileEx.maFile}", },
//MimeTypes
//AppleUniformTypeIdentifiers =
},
};
var exportFile = await FilePicker2.SaveAsync(new PickOptions
{
FileTypes = fileTypes,
@@ -563,7 +560,7 @@ public sealed partial class AuthenticatorHomePageViewModel : ViewModelBase
{
if (sender is not AuthenticatorItemModel authenticatorItemModel) return;
var index = Auths.IndexOf(authenticatorItemModel);
if (index > Auths.Count)
if (index >= Auths.Count - 1)
return;
if (authenticatorItemModel.AuthData.ServerId != null)
{
@@ -9,7 +9,7 @@ public record AuthenticatorImportMethod(string Name, string Description, string?
public class AuthenticatorImportPageViewModel : ViewModelBase
{
public static string Name => Strings.PleaseSelect + Strings.AuthImport;
public static string Name => Strings.AuthImport;
public IReadOnlyCollection<AuthenticatorImportMethod> AuthenticatorImportMethods { get; }
@@ -142,6 +142,7 @@ public sealed partial class SteamTradePageViewModel : WindowViewModel
Toast.Show(ToastIcon.Success, string.Format(Strings.Success_, Strings.User_Login));
_steamAuthenticator.SessionData = RemenberLogin ? _steamClient.Session.ToString() : null;
await AuthenticatorHelper.SaveAuthenticator(_authenticatorDto!);
_steamClient = _steamAuthenticator.GetClient(ResourceService.GetCurrentCultureSteamLanguageName());
await GetConfirmations(_steamClient);
}
else
@@ -185,12 +186,14 @@ public sealed partial class SteamTradePageViewModel : WindowViewModel
public async Task Logout()
{
if (_steamClient == null) return;
if (_steamClient == null || _steamAuthenticator == null) return;
if (await IWindowManager.Instance.ShowTaskDialogAsync(
new MessageBoxWindowViewModel() { Content = Strings.LocalAuth_LogoutTip, }, AppResources.Logout, isCancelButton: true,
isDialog: false))
{
_steamClient.Logout();
_steamAuthenticator.SessionData = null;
await AuthenticatorHelper.SaveAuthenticator(_authenticatorDto!);
IsLogged = false;
}
}
@@ -34,30 +34,32 @@
</Viewbox>
</Button>-->
<Button
Padding="8"
Command="{Binding EditAuthNameAsync}"
Theme="{StaticResource TransparentButton}"
ToolTip.Tip="{Binding Path=Res.Auth_EditName, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
<Viewbox Width="20">
<Viewbox Width="16">
<ui:SymbolIcon Symbol="Edit" />
</Viewbox>
</Button>
<Button
Padding="8"
Command="{Binding ShowSteamTradeWindow}"
IsVisible="{Binding IsSteamAuthenticator, Mode=OneWay}"
Theme="{StaticResource TransparentButton}"
ToolTip.Tip="{Binding Path=Res.LocalAuth_AuthTrade, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
<Viewbox Width="20">
<Viewbox Width="16">
<ui:FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xE9D5;" />
</Viewbox>
</Button>
<Button
<!--<Button
Command="{Binding ShowDetailData}"
Theme="{StaticResource TransparentButton}"
ToolTip.Tip="{Binding Path=Res.ViewDetailedData, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
<Viewbox Width="20">
<ui:SymbolIcon Symbol="Calendar" />
</Viewbox>
</Button>
</Button>-->
<!--<Button
Command="{Binding ShowQrCode}"
Theme="{StaticResource TransparentButton}"
@@ -134,12 +134,12 @@
Source={x:Static s:ResourceService.Current}}" />-->
<!--<ui:MenuFlyoutItem Command="{Binding ShowRecoverWindow}" Text="{Binding Path=Res.Auth_Sync_Recover, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<ui:MenuFlyoutItem Command="{Binding ResetIndependentPassword}" Text="{Binding Path=Res.Auth_Sync_ResetPassword, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />-->
<ui:MenuFlyoutItem Text="{Binding Path=Res.Settings_Plugin, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<!--<ui:MenuFlyoutItem Text="{Binding Path=Res.Settings_Plugin, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />-->
<ui:MenuFlyoutSeparator />
<ui:MenuFlyoutItem IsEnabled="False" Text="{Binding Path=Res.Auth_Version, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<ui:MenuFlyoutItem Text="{Binding Path=Res.ViewInStore, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<!--<ui:MenuFlyoutItem Text="{Binding Path=Res.ViewInStore, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<ui:MenuFlyoutItem Text="{Binding Path=Res.UseHelp, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<ui:MenuFlyoutItem Text="{Binding Path=Res.AboutThisPlugin, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<ui:MenuFlyoutItem Text="{Binding Path=Res.AboutThisPlugin, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />-->
</ui:FAMenuFlyout>
</DropDownButton.Flyout>
</DropDownButton>
@@ -291,6 +291,14 @@
<ui:FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="{StaticResource QrCode}" />
</MenuItem.Icon>
</MenuItem>
<MenuItem
Command="{Binding ShowDetailData}"
CommandParameter="{Binding}"
Header="{Binding Path=Res.ViewDetailedData, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
<MenuItem.Icon>
<ui:SymbolIcon Symbol="Calendar" />
</MenuItem.Icon>
</MenuItem>
<MenuItem
Command="{Binding $parent[spp:PageBase].((spp:AuthenticatorHomePageViewModel)DataContext).DefaultExport}"
CommandParameter="{Binding}"
@@ -19,9 +19,7 @@
<TextBlock
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{Binding Source={x:Static s:ResourceService.Current},
Path=Res.LocalAuth_ShowAuthInfo,
Mode=OneWay}"
Text="{Binding Source={x:Static s:ResourceService.Current}, Path=Res.LocalAuth_ShowAuthInfo, Mode=OneWay}"
TextTrimming="CharacterEllipsis" />
<ToggleButton x:Name="ShowDetail" VerticalAlignment="Center">
<ToggleButton.Content>
@@ -40,8 +38,7 @@
VerticalAlignment="Center"
FontSize="12"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
Text="{Binding Source={x:Static s:ResourceService.Current},
Path=Res.LocalAuth_ShowSteamAuthTip2}"
Text="{Binding Source={x:Static s:ResourceService.Current}, Path=Res.LocalAuth_ShowSteamAuthTip2}"
TextWrapping="Wrap" />
</StackPanel>
</Border>
@@ -73,7 +70,6 @@
<TextBlock Text="{Binding Path=Res.LocalAuth_ShowSteamAuthTip1, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<TextBox
Height="250"
AcceptsReturn="True"
IsReadOnly="True"
PasswordChar="{StaticResource PasswordChar}"
RevealPassword="{Binding #ShowDetail.IsChecked}"
@@ -12,7 +12,7 @@
x:CompileBindings="True"
x:DataType="spp:SteamTradePageViewModel"
mc:Ignorable="d">
<spp:ContentLoader IsLoading="{Binding IsLoading}">
<spp:ContentLoader CustomLoadingText="提示:不要忘了先开加速" IsLoading="{Binding IsLoading}">
<Panel>
<!-- 登录 -->
<StackPanel
@@ -17,9 +17,12 @@ public class PlatformSettingsPageViewModel : ViewModelBase
if (Platform is null)
return;
FilePickerFileType fileTypes = new ValueTuple<string, string[]>[]
{
(Platform.FullName, new[] { Platform.ExeName ?? "*" }),
AvaloniaFilePickerFileTypeFilter fileTypes = new AvaloniaFilePickerFileTypeFilter.Item[] {
new(Platform.FullName) {
Patterns = new[] { Platform.ExeName ?? "*", },
//MimeTypes =
//AppleUniformTypeIdentifiers =
},
};
await FilePicker2.PickAsync((path) =>
@@ -258,6 +258,7 @@ public sealed class EditAppInfoPageViewModel : WindowViewModel
}
return;
}
Toast.Show(ToastIcon.Info, "图片下载需要一些时间,请稍后");
var imageHttpClientService = Ioc.Get<IImageHttpClientService>();
var stream = await imageHttpClientService.GetImageMemoryStreamAsync(SelectGrid.Url, default);
switch (type)
@@ -101,22 +101,22 @@
<TabItem Header="{Binding Path=Res.Media, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
<Panel>
<spp:ContentLoader
<DockPanel
x:Name="SteamGridDBContent"
MinWidth="300"
IsLoading="{Binding IsLoadingSteamGrid}"
IsShowNoResultText="{Binding IsSteamGridEmpty}"
IsVisible="False"
NoResultMessage="{Binding Path=Res.FailedGetImageFromSteamGridDB, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
<DockPanel>
<Button
Height="30"
Margin="5,5,5,10"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
Click="HideGridDialog_Click"
Content="{Binding Path=Res.Back, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
DockPanel.Dock="Top" />
IsVisible="False">
<Button
Height="30"
Margin="5,5,5,10"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
Click="HideGridDialog_Click"
Content="{Binding Path=Res.Back, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
DockPanel.Dock="Top" />
<spp:ContentLoader
IsLoading="{Binding IsLoadingSteamGrid}"
IsShowNoResultText="{Binding IsSteamGridEmpty}"
NoResultMessage="{Binding Path=Res.FailedGetImageFromSteamGridDB, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
<ScrollViewer DockPanel.Dock="Bottom">
<ItemsControl
ItemsSource="{Binding SteamGridItems}"
@@ -166,8 +166,8 @@
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</DockPanel>
</spp:ContentLoader>
</spp:ContentLoader>
</DockPanel>
<ScrollViewer x:Name="MediaContent">
<StackPanel Classes="InfoBox">
@@ -117,11 +117,19 @@ public sealed partial class IdleAppsPageViewModel : ViewModelBase
private async Task SteamAppsSort()
{
if (IdleSequentital == IdleSequentital.Mostvalue)
Badges = await IdleCard.GetBadgesAsync(SteamConnectService.Current.CurrentSteamUser!.SteamId64.ToString(), true);
else
Badges = await IdleCard.GetBadgesAsync(SteamConnectService.Current.CurrentSteamUser!.SteamId64.ToString());
Badges = Badges.Where(x => x.CardsRemaining != 0); // 过滤可掉落卡片的游戏
try
{
if (IdleSequentital == IdleSequentital.Mostvalue)
Badges = await IdleCard.GetBadgesAsync(SteamConnectService.Current.CurrentSteamUser!.SteamId64.ToString(), true);
else
Badges = await IdleCard.GetBadgesAsync(SteamConnectService.Current.CurrentSteamUser!.SteamId64.ToString());
Badges = Badges.Where(x => x.CardsRemaining != 0); // 过滤可掉落卡片的游戏
}
catch (Exception ex)
{
Toast.LogAndShowT(ex);
return;
}
var appid_sorts = Enumerable.Empty<int>();
if (IdleSequentital == IdleSequentital.Default)
@@ -163,7 +171,10 @@ public sealed partial class IdleAppsPageViewModel : ViewModelBase
private void StartIdle()
{
if (!IdleGameList.Any())
{
IdleComplete();
return;
}
if (IdleRule == IdleRule.OnlyOneGame)
{
@@ -392,7 +403,7 @@ public sealed partial class IdleAppsPageViewModel : ViewModelBase
/// </summary>
private void IdleComplete()
{
MessageBox.Show(Strings.Idle_Complete, button: MessageBox.Button.OK);
Toast.Show(ToastIcon.Success, Strings.Idle_Complete);
}
#endregion
@@ -0,0 +1,53 @@
namespace BD.WTTS.Models;
public sealed class AvaloniaFilePickerFileTypeFilter : IFilePickerFileType
{
public IEnumerable<Item> Values { get; }
public AvaloniaFilePickerFileTypeFilter(
IEnumerable<Item> values)
{
Values = values;
}
public AvaloniaFilePickerFileTypeFilter(
params Item[] values)
{
Values = values;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator AvaloniaFilePickerFileTypeFilter(Item[] values) => new(values);
IEnumerable<string>? IFilePickerFileType.GetPlatformFileType(Platform platform)
{
foreach (var value in Values)
{
if (value.Patterns != null)
foreach (var item in value.Patterns)
yield return item;
if (value.MimeTypes != null)
foreach (var item in value.MimeTypes)
yield return item;
if (value.AppleUniformTypeIdentifiers != null)
foreach (var item in value.AppleUniformTypeIdentifiers)
yield return item;
}
}
public readonly record struct Item
{
public Item(string? name)
{
Name = name ?? string.Empty;
}
public string Name { get; }
public IReadOnlyList<string>? Patterns { get; init; }
public IReadOnlyList<string>? MimeTypes { get; init; }
public IReadOnlyList<string>? AppleUniformTypeIdentifiers { get; init; }
}
}
@@ -24,4 +24,24 @@ public interface IRequestCacheRepository : IRequestCache
/// </summary>
/// <returns></returns>
Task<int> DeleteAllAsync(DateTimeOffset dateTimeOffset);
const string DefaultRequestUri = "/";
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static string GetOriginalRequestUri(HttpRequestMessage request)
{
string? originalRequestUri;
if (request is ImageHttpClientService.ImageHttpRequestMessage request2)
{
// 对于一些重定向的 Url 使用原始 Url 进行唯一性的计算
originalRequestUri = request2.OriginalRequestUri;
}
else
{
originalRequestUri = request.RequestUri?.ToString()!;
}
if (string.IsNullOrEmpty(originalRequestUri))
originalRequestUri = DefaultRequestUri;
return originalRequestUri;
}
}
@@ -6,7 +6,6 @@ namespace BD.WTTS.Repositories;
internal sealed class RequestCacheRepository : IRequestCacheRepository, IDisposable
{
const string DefaultRequestUri = "/";
const string CacheDirName = "Http";
const string TableName = "Fusillade_RequestCache";
const string DbFileName = "RequestCache.LiteDB";
@@ -49,17 +48,7 @@ internal sealed class RequestCacheRepository : IRequestCacheRepository, IDisposa
if (!bytes.Any_Nullable())
return;
var requestUri = response.RequestMessage?.RequestUri ?? request.RequestUri;
string requestUriString;
if (requestUri == null)
{
requestUriString = DefaultRequestUri;
}
else
{
requestUriString = requestUri.ToString();
}
var requestUriString = IRequestCacheRepository.GetOriginalRequestUri(request);
var fileTypeResult = FileFormat.AnalyzeFileType(bytes);
var hashKey = Hashs.String.SHA384(bytes, false);
var fileEx = fileTypeResult.FileEx;
@@ -116,6 +105,7 @@ internal sealed class RequestCacheRepository : IRequestCacheRepository, IDisposa
if (cancellationToken.IsCancellationRequested)
return;
key = UniqueKeyForRequest(requestUriString, request);
var entity = table.FindById(key);
bool isInsertOrUpdate;
if (entity == null)
@@ -158,17 +148,8 @@ internal sealed class RequestCacheRepository : IRequestCacheRepository, IDisposa
string key,
CancellationToken cancellationToken)
{
var requestUri = request.RequestUri;
string requestUriString;
if (requestUri == null)
{
requestUriString = DefaultRequestUri;
}
else
{
requestUriString = requestUri.ToString();
}
var requestUriString = IRequestCacheRepository.GetOriginalRequestUri(request);
key = UniqueKeyForRequest(requestUriString, request);
var entity = table.Query().Where(x => x.Id == key &&
x.HttpMethod == request.Method.Method &&
x.RequestUri == requestUriString).FirstOrDefault();
@@ -249,4 +230,49 @@ internal sealed class RequestCacheRepository : IRequestCacheRepository, IDisposa
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
static string UniqueKeyForRequest(string originalRequestUri, HttpRequestMessage request)
{
// https://github.com/reactiveui/Fusillade/blob/2.4.67/src/Fusillade/RateLimitedHttpMessageHandler.cs#L54-L89
using var s = new MemoryStream();
s.Write(Encoding.UTF8.GetBytes(originalRequestUri));
s.Write("\r\n"u8);
s.Write(Encoding.UTF8.GetBytes(request.Method.Method));
s.Write("\r\n"u8);
static void Write(Stream s, IEnumerable<object> items)
{
foreach (var item in items)
{
var str = item.ToString();
if (!string.IsNullOrEmpty(str))
s.Write(Encoding.UTF8.GetBytes(str));
s.Write("|"u8);
}
}
Write(s, request.Headers.Accept);
s.Write("\r\n"u8);
Write(s, request.Headers.AcceptEncoding);
s.Write("\r\n"u8);
var referrer = request.Headers.Referrer;
if (referrer == default)
s.Write("http://example"u8);
else
s.Write(Encoding.UTF8.GetBytes(referrer.ToString()));
s.Write("\r\n"u8);
Write(s, request.Headers.UserAgent);
s.Write("\r\n"u8);
if (request.Headers.Authorization != null)
{
var parameter = request.Headers.Authorization.Parameter;
if (!string.IsNullOrEmpty(parameter))
s.Write(Encoding.UTF8.GetBytes(parameter));
s.Write(Encoding.UTF8.GetBytes(request.Headers.Authorization.Scheme));
s.Write("\r\n"u8);
}
s.Position = 0;
var bytes = SHA384.HashData(s);
var str = bytes.ToHexString();
return str;
}
}
-9
View File
@@ -1,9 +0,0 @@
// ReSharper disable once CheckNamespace
namespace BD.WTTS;
#if DEBUG
[Obsolete("use ResourceService", true)]
public static class R
{
}
#endif
+9 -9
View File
@@ -1052,6 +1052,15 @@ namespace BD.WTTS.Client.Resources {
}
}
/// <summary>
/// 查找类似 没有启用任何加速项!! 的本地化字符串。
/// </summary>
public static string CommunityFix_AccEmpty {
get {
return ResourceManager.GetString("CommunityFix_AccEmpty", resourceCulture);
}
}
/// <summary>
/// 查找类似 已加速 的本地化字符串。
/// </summary>
@@ -4838,15 +4847,6 @@ namespace BD.WTTS.Client.Resources {
}
}
/// <summary>
/// 查找类似 请选择 的本地化字符串。
/// </summary>
public static string PleaseSelect {
get {
return ResourceManager.GetString("PleaseSelect", resourceCulture);
}
}
/// <summary>
/// 查找类似 作者:{0} 的本地化字符串。
/// </summary>
+3 -3
View File
@@ -241,6 +241,9 @@
</data>
<data name="CommunityFix_ItemsEmpty" xml:space="preserve">
<value>获取加速信息失败,请检查程序是否能正常联网</value>
</data>
<data name="CommunityFix_AccEmpty" xml:space="preserve">
<value>没有启用任何加速项!!</value>
</data>
<data name="CommunityFix_AutoRunProxy" xml:space="preserve">
<value>启动时自动启动加速</value>
@@ -726,9 +729,6 @@
<data name="PleaseEnterNickName" xml:space="preserve">
<value>请输入昵称</value>
</data>
<data name="PleaseSelect" xml:space="preserve">
<value>请选择</value>
</data>
<data name="RecoveryCode" xml:space="preserve">
<value>恢复代码</value>
</data>
@@ -175,7 +175,9 @@ public sealed partial class IPCMainProcessServiceImpl : IPCMainProcessService
psi.ArgumentList.Add(pid.ToString());
psi.ArgumentList.Add(mSubProcessArgumentIndex2Model.Value);
configure?.Invoke(psi);
#if !MACOS
DotNetRuntimeHelper.AddEnvironment(psi);
#endif
var nativeLibraryPath = Startup.NativeLibraryPath;
if (!string.IsNullOrWhiteSpace(nativeLibraryPath))
{
@@ -26,6 +26,8 @@ sealed class SteamServiceImpl2 : SteamServiceBaseImpl, ISteamConnectService
set => SteamConnectService.Current.IsConnectToSteam = value;
}
string? ISteamConnectService.SteamLanguageString => ResourceService.GetCurrentCultureSteamLanguageName();
SourceCache<SteamApp, uint> ISteamConnectService.SteamApps => SteamConnectService.Current.SteamApps;
SourceCache<SteamApp, uint> ISteamConnectService.DownloadApps => SteamConnectService.Current.DownloadApps;
@@ -55,7 +55,7 @@ public sealed class NoticeService : ReactiveObject
item.Unread = true;
//只弹最新的一条通知
if (UnreadNotificationsCount == 0 && GeneralSettings.MessagePopupNotification)
if (UnreadNotificationsCount == 0 && GeneralSettings.MessagePopupNotification.Value)
INotificationService.Instance.Notify(item.Content, NotificationType.Announcement, title: item.Title);
UnreadNotificationsCount++;
@@ -9,8 +9,6 @@ partial interface IPlatformService
/// 获取 排除代理地址
/// </summary>
protected static string[] GetNoProxyHostName => new string[] {
"localhost",
"127.*",
"10.*",
"172.16.*",
"172.17.*",
@@ -2,17 +2,17 @@ namespace BD.WTTS.Services;
public interface INavigationService
{
public static INavigationService Instance { get; } = Ioc.Get<INavigationService>();
static INavigationService Instance { get; } = Ioc.Get<INavigationService>();
public object? GetViewModelToPageContent(object viewModel, bool isCreateInstance = true);
object? GetViewModelToPageContent(object viewModel, bool isCreateInstance = true);
public void Navigate(Type? t, NavigationTransitionEffect effect = NavigationTransitionEffect.None);
void Navigate(Type? t, NavigationTransitionEffect effect = NavigationTransitionEffect.None, bool useCache = true);
public void GoBack();
void GoBack(Type? t = null);
public void NavigateFromContext(object dataContext, NavigationTransitionEffect transitionInfo = NavigationTransitionEffect.None);
void NavigateFromContext(object dataContext, NavigationTransitionEffect transitionInfo = NavigationTransitionEffect.None);
public void ShowControlDefinitionOverlay(Type targetType);
void ShowControlDefinitionOverlay(Type targetType);
public void ClearOverlay();
void ClearOverlay();
}
@@ -27,7 +27,9 @@ public sealed class HomePageViewModel : TabItemViewModel
public HomePageViewModel()
{
Articles = new ObservableCollection<ArticleItemDTO>();
#pragma warning disable CS8625 // 初始化3个null 为解决调试报错中断
Articles = new ObservableCollection<ArticleItemDTO>() { null, null, null };
#pragma warning restore CS8625 // 无法将 null 字面量转换为非 null 的引用类型。
NavigationBanners = new ObservableCollection<AdvertisementDTO>();
Shops = new ObservableCollection<ShopRecommendGoodItem>();
@@ -41,8 +43,7 @@ public sealed class HomePageViewModel : TabItemViewModel
var result = await Instance.Article.Order(null, ArticleOrderBy.DateTime);
if (result.IsSuccess && result.Content != null)
{
Articles.Clear();
Articles.Add(result.Content.DataSource);
Articles = new ObservableCollection<ArticleItemDTO>(result.Content.DataSource);
}
var result2 = await Instance.Shop.RecommendGoods();
@@ -34,12 +34,6 @@ public sealed partial class SettingsPageViewModel : TabItemViewModel
SelectImage_Click = ReactiveCommand.CreateFromTask(async () =>
{
//FilePickerFileType fileTypes = new ValueTuple<string, string[]>[]
//{
// ("Image Files", FileEx.Images.Select(s => $"*{s}").ToArray()),
// //("All Files", new[] { "*", }),
//};
//await FilePicker2.PickAsync(SetBackgroundImagePath, fileTypes);
await FilePicker2.PickAsync(SetBackgroundImagePath, IFilePickerFileType.Images());
});
@@ -67,9 +61,12 @@ public sealed partial class SettingsPageViewModel : TabItemViewModel
#if (WINDOWS || MACCATALYST || MACOS || LINUX) && !(IOS || ANDROID)
public async void SelectSteamProgramLocation()
{
FilePickerFileType fileTypes = new ValueTuple<string, string[]>[]
{
("Steam", new[] { "steam.exe" }),
AvaloniaFilePickerFileTypeFilter fileTypes = new AvaloniaFilePickerFileTypeFilter.Item[] {
new("Steam") {
Patterns = new[] { "steam.exe", },
//MimeTypes =
//AppleUniformTypeIdentifiers =
},
};
await FilePicker2.PickAsync((path) =>
{
@@ -10,7 +10,7 @@ public partial class LoginOrRegisterWindowViewModel : WindowViewModel, SendSmsUI
{
Title = DisplayName;
Close = INavigationService.Instance.GoBack;
Close = () => INavigationService.Instance.GoBack(typeof(LoginOrRegisterWindowViewModel));
ChooseChannel = ReactiveCommand.CreateFromTask<string>(async channel_ =>
{