Compare commits

..

1 Commits

Author SHA1 Message Date
lxy829 42464db1bc 🎨 ResxXamlBinding 2023-12-12 10:29:41 +08:00
462 changed files with 3363 additions and 23427 deletions
+5 -5
View File
@@ -68,19 +68,19 @@ jobs:
run: dotnet --info
- name: Build BD.WTTS.Client.AppHost
run: dotnet build -c Release src\BD.WTTS.Client.AppHost\BD.WTTS.Client.AppHost.csproj --nologo -v q --property:WarningLevel=1 --property:DebugType=pdbonly
run: dotnet build -c Release src\BD.WTTS.Client.AppHost\BD.WTTS.Client.AppHost.csproj --nologo -v q /property:WarningLevel=1
- name: Build BD.WTTS.Client.Plugins.Accelerator.ReverseProxy
run: dotnet build -c Release src\BD.WTTS.Client.Plugins.Accelerator.ReverseProxy\BD.WTTS.Client.Plugins.Accelerator.ReverseProxy.csproj --nologo -v q --property:WarningLevel=1 --property:DebugType=pdbonly
run: dotnet build -c Release src\BD.WTTS.Client.Plugins.Accelerator.ReverseProxy\BD.WTTS.Client.Plugins.Accelerator.ReverseProxy.csproj --nologo -v q /property:WarningLevel=1
- name: Build BD.WTTS.Client.Avalonia.App
run: dotnet build -c Release src\BD.WTTS.Client.Avalonia.App\BD.WTTS.Client.Avalonia.App.csproj --nologo -v q --property:WarningLevel=1 --property:DebugType=pdbonly
run: dotnet build -c Release src\BD.WTTS.Client.Avalonia.App\BD.WTTS.Client.Avalonia.App.csproj --nologo -v q /property:WarningLevel=1
- name: Build BD.WTTS.Client.Avalonia.Designer.HostApp
run: dotnet build -c Release src\BD.WTTS.Client.Avalonia.Designer.HostApp\BD.WTTS.Client.Avalonia.Designer.HostApp.csproj --nologo -v q --property:WarningLevel=1 --property:DebugType=pdbonly
run: dotnet build -c Release src\BD.WTTS.Client.Avalonia.Designer.HostApp\BD.WTTS.Client.Avalonia.Designer.HostApp.csproj --nologo -v q /property:WarningLevel=1
- name: Test
run: dotnet test src/BD.WTTS.UnitTest/BD.WTTS.UnitTest.csproj -c Release -p:GeneratePackageOnBuild=false --nologo -v q --property:WarningLevel=1 --property:DebugType=pdbonly
run: dotnet test src/BD.WTTS.UnitTest/BD.WTTS.UnitTest.csproj -c Release -p:GeneratePackageOnBuild=false --nologo -v q /property:WarningLevel=1
# release:
# name: Release
+1 -1
View File
@@ -16,7 +16,7 @@
[![NET 7.0](https://img.shields.io/badge/dotnet-7.0-purple.svg?style=flat-square&color=512bd4)](https://learn.microsoft.com/zh-cn/dotnet/core/whats-new/dotnet-7)
[![C# 11](https://img.shields.io/badge/c%23-11-brightgreen.svg?style=flat-square&color=6da86a)](https://learn.microsoft.com/zh-cn/dotnet/csharp/whats-new/csharp-11)
[![爱发电](https://img.shields.io/badge/爱发电-软妹币玩家-blue.svg?style=flat-square&color=ea4aaa&logo=github-sponsors)](https://afdian.com/@rmbgame)
[![爱发电](https://img.shields.io/badge/爱发电-软妹币玩家-blue.svg?style=flat-square&color=ea4aaa&logo=github-sponsors)](https://afdian.net/@rmbgame)
[![Kofi](https://img.shields.io/badge/Kofi-RMBGAME-orange.svg?style=flat-square&logo=kofi)](https://ko-fi.com/rmbgame)
[![Patreon](https://img.shields.io/badge/Patreon-RMBGAME-red.svg?style=flat-square&logo=patreon)](https://www.patreon.com/rmbgame)
+6 -6
View File
@@ -40,14 +40,14 @@ else
fi
}
certutil_Init() {
certutil -d $HOME/.pki/nssdb -L
certutil -d sql:$HOME/.pki/nssdb -L
ret=$?
if [ $ret -ne 0 ]; then
echo "即将初始化 certutil \$HOME/.pki/nssdb"
mkdir -p $HOME/.pki
mkdir -p $HOME/.pki/nssdb
chmod 700 $HOME/.pki/nssdb
certutil -d $HOME/.pki/nssdb -N --empty-password
echo "即将初始化 certutil sql:\$HOME/.pki/nssdb"
mkdir -p sql:$HOME/.pki
mkdir -p sql:$HOME/.pki/nssdb
chmod 700 sql:$HOME/.pki/nssdb
certutil -d sql:$HOME/.pki/nssdb -N --empty-password
else
echo "certutil nssdb 正常"
fi
-208
View File
@@ -1,208 +0,0 @@
#!/bin/bash
run_path=$(dirname "$0")
base_path="$(dirname "$run_path")"
mkdir -p "$base_path"
cd "$base_path" || exit 1
appVer_path="$base_path/WattToolkit.AppVer"
exec_name="Steam++"
tar_name="WattToolkit.tgz"
tar_path="$base_path/$tar_name"
app_name="Watt Toolkit"
PROCESS_NAMES=("$exec_name" "$app_name")
export LC_ALL=en_US.UTF-8
Install_certutil() {
# 判断发行版类型
if command -v certutil &>/dev/null; then
echo "certutil 工具已安装。"
else
echo "证书导入以及验证需要使用 certutil 工具。"
# 判断包管理器
if command -v apt &>/dev/null; then
# 使用 apt (Debian/Ubuntu)
sudo apt update
sudo apt install -y libnss3-tools
elif command -v dnf &>/dev/null; then
# 使用 dnf (Fedora)
sudo dnf install -y nss-tools
elif command -v yum &>/dev/null; then
# 使用 yum (CentOS/Red Hat)
sudo yum install -y nss-tools
elif command -v pacman &>/dev/null; then
# 使用 pacman (Arch Linux)
# sudo pacman -S nss
echo "请手动安装 certutil 工具。"
exit 1
else
echo "请手动安装 certutil 工具。"
exit 1
fi
echo "certutil 工具已安装。"
fi
}
certutil_Init() {
certutil -d $HOME/.pki/nssdb -L
ret=$?
if [ $ret -ne 0 ]; then
echo "即将初始化 certutil \$HOME/.pki/nssdb"
mkdir -p $HOME/.pki
mkdir -p $HOME/.pki/nssdb
chmod 700 $HOME/.pki/nssdb
certutil -d $HOME/.pki/nssdb -N --empty-password
else
echo "certutil nssdb 正常"
fi
}
Install_jq() {
# Check if jq is already installed
if command -v jq &>/dev/null; then
echo "jq 工具已安装。"
else
echo "jq 用来解析版本更新。"
# Check the package manager
if command -v apt &>/dev/null; then
# Using apt (Debian/Ubuntu)
sudo apt update
sudo apt install -y jq
elif command -v dnf &>/dev/null; then
# Using dnf (Fedora)
sudo dnf install -y jq
elif command -v yum &>/dev/null; then
# Using yum (CentOS/Red Hat)
sudo yum install -y jq
elif command -v pacman &>/dev/null; then
# Using pacman (Arch Linux)
sudo pacman -S jq
else
echo "请手动安装 jq 工具。"
exit 1
fi
echo "请手动安装 jq 工具。"
fi
}
Install_zenity() {
# 判断发行版类型
if command -v zenity &>/dev/null; then
echo "zenity 工具已安装。"
else
echo "安装过程需要 zenity 工具。"
# 判断包管理器
if command -v apt &>/dev/null; then
# 使用 apt (Debian/Ubuntu)
sudo apt update
sudo apt install -y zenity
elif command -v dnf &>/dev/null; then
# 使用 dnf (Fedora)
sudo dnf install -y zenity
elif command -v yum &>/dev/null; then
# 使用 yum (CentOS/Red Hat)
sudo yum install -y zenity
elif command -v pacman &>/dev/null; then
# 使用 pacman (Arch Linux)
# sudo pacman -S zenity
echo "请手动安装 zenity 工具。"
exit 1
else
echo "请手动安装 zenity 工具。"
exit 1
fi
echo "zenity 工具已安装。"
fi
}
Show_Run() {
local param1=$1
# 显示提示框,询问是否运行程序
zenity --question --text="$1" --width=400
# 获取上一个命令的退出码
response=$?
if [ $response -eq 0 ]; then
echo "程序已启动。"
exit 0 &
# 用户点击了 "运行" 按钮,启动程序
/bin/sh -c "$base_path/$exec_name.sh"
else
# 用户点击了 "关闭" 按钮,退出脚本
exit 0
fi
}
Kill_Process() {
# 尝试的次数
Kill_MAX_RETRIES=3
# 循环尝试终止进程
for process_name in "${PROCESS_NAMES[@]}"; do
kill_retry=1
while [ $kill_retry -le $Kill_MAX_RETRIES ]; do
pid=$(pgrep "$process_name")
if [ -n "$pid" ]; then
echo "尝试 $kill_retry: 进程 $process_name 正在运行中。正在终止..."
kill $pid
sleep 2
else
break
fi
kill_retry=$((kill_retry + 1))
done
done
for process_name in "${PROCESS_NAMES[@]}"; do
# 检查是否成功终止进程
if pgrep -x "$process_name" >/dev/null; then
echo "无法终止程序 $process_name。尝试次数已达上限。"
exit 1
else
echo "程序 $process_name 已成功终止。"
fi
done
}
Install_certutil
Install_zenity
Install_jq
certutil_Init
Kill_Process
dotnet_exec="$dotnet_path/dotnet/dotnet"
if [ -x "$dotnet_exec" ]; then
echo "文件具有执行权限。"
else
chmod +x "$dotnet_exec"
fi
chmod +x "$base_path/$exec_name.sh"
# xdg-icon-resource install "$base_path/Icons/Watt-Toolkit.png" --size 128 Watt-Toolkit
InitDesktop() {
while true; do
# 使用 zenity 提示用户选择安装路径或使用默认路径
choice=$(zenity --list --radiolist --title="请选择要添加到的位置" --column="选择" --column="路径" TRUE "$HOME/.local/share/applications/" FALSE "$HOME/Desktop")
# 检查用户输入
if [ "$choice" == "$HOME/.local/share/applications/" ]; then
target_dir="$HOME/.local/share/applications/"
break
elif [ "$choice" == "$HOME/Desktop" ]; then
target_dir="$HOME/Desktop/"
break
else
echo "无效选项,请输入 1 或 2。"
fi
done
#添加桌面文件
rm -rf "$target_dir/Watt Toolkit.desktop" 2>/dev/null
echo "#!/usr/bin/env xdg-open
[Desktop Entry]
Name=Watt Toolkit
Exec=$base_path/$exec_name.sh
Icon=$base_path/Icons/Watt-Toolkit.png
Terminal=false
Type=Application
StartupNotify=false" >"$target_dir/Watt Toolkit.desktop"
chmod +x "$target_dir/Watt Toolkit.desktop"
}
InitDesktop
# update-desktop-database ~/.local/share/applications
#运行程序
Show_Run "下载安装完成,是否启动程序?"
exit 0
+16 -122
View File
@@ -1,44 +1,7 @@
#!/bin/bash
# 设置默认的 base_path 参数
default_base_path="$HOME/WattToolkit"
base_path="$default_base_path"
# 检查是否以root身份执行
if [ "$EUID" -eq 0 ]; then
echo "此脚本不能以root身份执行。"
exit 1
fi
# 循环直到用户输入有效路径或直接回车
while true; do
# 使用 zenity 提示用户选择安装路径或使用默认路径
custom_base_path=$(zenity --entry --title="安装路径" --text="请输入安装路径(默认为 $default_base_path,不输入则使用默认路径)")
# 如果用户提供了自定义路径,则使用该路径
if [ -n "$custom_base_path" ]; then
base_path="$custom_base_path"
break
elif [ -z "$custom_base_path" ]; then
# 用户直接回车,使用默认路径
break
else
# 用户输入无效路径,重新提示
echo "无效路径,请重新输入。"
fi
done
# 创建安装路径
mkdir -p "$base_path" || {
echo "无法创建安装路径 $base_path,请检查权限或路径是否正确。"
exit 1
}
# 切换到安装路径
cd "$base_path" || {
echo "无法切换到安装路径 $base_path,请检查权限或路径是否正确。"
exit 1
}
base_path="$HOME/WattToolkit"
mkdir -p "$base_path"
cd "$base_path" || exit 1
appVer_path="$base_path/WattToolkit.AppVer"
exec_name="Steam++"
tar_name="WattToolkit.tgz"
@@ -47,45 +10,7 @@ base_url="https://api.steampp.net"
architecture=1
app_name="Watt Toolkit"
PROCESS_NAMES=("$exec_name" "$app_name")
Check_LC_Code() {
# 检查当前 LANG 环境变量
current_lang="${LC_ALL:-$LANG}"
echo "当前语言环境: $current_lang"
# 检查是否为 C 或 C.UTF-8
if [ "$current_lang" = "C" ] || [ "$current_lang" = "C.UTF-8" ]; then
echo "当前语言环境是 C 或 C.UTF-8,需要修改。"
# 列出系统支持的语言环境
supported_locales=$(locale -a)
if [ -z "$supported_locales" ]; then
echo "未能获取到支持的语言环境列表。请检查系统配置。"
return 1
fi
# 遍历支持的语言环境列表,找到第一个不是 C 或 C.UTF-8 的项
first_non_c_locale=""
for locale in $supported_locales; do
if [ "$locale" != "C" ] && [ "$locale" != "C.UTF-8" ]; then
first_non_c_locale="$locale"
break
fi
done
# 检查是否找到了非 C/C.UTF-8 的语言环境
if [ -n "$first_non_c_locale" ]; then
echo "修改语言环境为支持列表中的第一个非 C/C.UTF-8 项:$first_non_c_locale"
export LC_ALL="$first_non_c_locale"
echo "语言环境已修改为 $first_non_c_locale。"
else
echo "未能找到非 C/C.UTF-8 的语言环境。请检查系统配置。"
return 1
fi
else
echo "当前语言环境不是 C 或 C.UTF-8,无需修改。"
fi
}
Check_LC_Code
export LC_ALL=en_US.UTF-8
Install_certutil() {
# 判断发行版类型
if command -v certutil &>/dev/null; then
@@ -116,14 +41,14 @@ Install_certutil() {
fi
}
certutil_Init() {
certutil -d $HOME/.pki/nssdb -L
certutil -d sql:$HOME/.pki/nssdb -L
ret=$?
if [ $ret -ne 0 ]; then
echo "即将初始化 certutil \$HOME/.pki/nssdb"
mkdir -p $HOME/.pki
mkdir -p $HOME/.pki/nssdb
chmod 700 $HOME/.pki/nssdb
certutil -d $HOME/.pki/nssdb -N --empty-password
echo "即将初始化 certutil sql:\$HOME/.pki/nssdb"
mkdir -p sql:$HOME/.pki
mkdir -p sql:$HOME/.pki/nssdb
chmod 700 sql:$HOME/.pki/nssdb
certutil -d sql:$HOME/.pki/nssdb -N --empty-password
else
echo "certutil nssdb 正常"
fi
@@ -257,9 +182,7 @@ Get_NewVer() {
sleep 1
#本地版本 Hash
if [ -f "AppVer" ]; then
o_sha384=$(cat "AppVer")
fi
o_sha384=$(cat "AppVer")
if [ -e "AppVer" ]; then
if [ "${o_sha384,,}" = "${n_sha384,,}" ]; then
Show_Run "已是最新版本,是否启动程序?"
@@ -403,46 +326,17 @@ Kill_Process
#解压
Decompression
# xdg-icon-resource install "$base_path/Icons/Watt-Toolkit.png" --size 128 Watt-Toolkit
InitDesktop() {
# 检查XDG_DESKTOP_DIR环境变量,如果未设置则使用默认值
XDG_DESKTOP_DIR="${XDG_DESKTOP_DIR:-$HOME/Desktop}"
while true; do
# 使用 zenity 提示用户选择安装路径或使用默认路径
choice=$(zenity --list --radiolist --title="请选择要添加到的位置" \
--column="选择" --column="路径" \
TRUE "$XDG_DESKTOP_DIR" \
FALSE "$HOME/.local/share/applications/")
# 检查用户输入
if [ "$choice" == "$HOME/.local/share/applications/" ]; then
target_dir="$HOME/.local/share/applications/"
break
elif [ "$choice" == "$XDG_DESKTOP_DIR" ]; then
target_dir="$XDG_DESKTOP_DIR"
break
else
# 无效选项时给出提示,并继续循环
zenity --info --text="无效选项,请重新选择。"
fi
done
# 添加桌面文件
rm -rf "$target_dir/Watt Toolkit.desktop" 2>/dev/null
cat <<EOT > "$target_dir/Watt Toolkit.desktop"
#添加桌面文件
rm -rf "$HOME/Desktop/Watt Toolkit.desktop" 2>/dev/null
echo "#!/usr/bin/env xdg-open
[Desktop Entry]
Name=Watt Toolkit
Exec=$base_path/$exec_name.sh
Icon=$base_path/Icons/Watt-Toolkit.png
Terminal=false
Type=Application
StartupNotify=false
EOT
chmod +x "$target_dir/Watt Toolkit.desktop"
}
InitDesktop
StartupNotify=false" >"$HOME/Desktop/Watt Toolkit.desktop"
chmod +x "$HOME/Desktop/Watt Toolkit.desktop"
# update-desktop-database ~/.local/share/applications
#运行程序
Show_Run "下载安装完成,是否启动程序?"
+11 -50
View File
@@ -1,6 +1,6 @@
#!/bin/bash
run_path=$(dirname "$0")
base_path="$(dirname "$run_path")"
base_path="$HOME/WattToolkit"
export LC_ALL=en_US.UTF-8
exec_name="Steam++"
app_name="Watt Toolkit"
AppData="$XDG_DATA_HOME/Steam++"
@@ -8,37 +8,7 @@ AppData_t="$HOME/.local/share/Steam++"
Cache="$XDG_CACHE_HOME/Steam++"
Cache_t="$HOME/.cache/Steam+"
PROCESS_NAMES=("$exec_name" "$app_name")
export LC_ALL=en_US.UTF-8
#检查是否存在 Steam++.sh 避免卸载错误
file_to_check="$base_path/Steam++.sh"
folders_to_check=("dotnet" "modules" "native" "script" "assemblies")
if [ -e "$file_to_check" ]; then
echo "文件 $file_to_check 存在"
else
echo "文件 $file_to_check 不存在"
exit 1
fi
for folder in "${folders_to_check[@]}"; do
folder_path="$base_path/$folder"
if [ -d "$folder_path" ]; then
echo "文件夹 $folder_path 存在"
else
echo "文件夹 $folder_path 不存在"
exit 1
fi
done
echo "验证该文件夹是 $app_name 安装目录,请确认是否卸载。"
read -p "所有文件和文件夹都存在,确认卸载吗? (输入 'y' 确认): " confirmation
if [ "${confirmation,,}" == "y" ]; then
echo "开始执行卸载操作"
# 在这里添加您的卸载操作
else
echo "用户取消卸载操作"
exit 0
fi
Kill_Process() {
# 尝试的次数
Kill_MAX_RETRIES=3
@@ -72,28 +42,19 @@ Kill_Process() {
}
Kill_Process
zenity --question --text="是否删除证书?" --width=400
zenity --question --text="是否删除用户数据" --width=400
# 获取上一个命令的退出码
delCer=$?
response=$?
if [ $delCer -eq 0 ]; then
certutil -D -d $HOME/.pki/nssdb -n "SteamTools"
fi
zenity --question --text="是否删除用户数据?" --width=400
# 获取上一个命令的退出码
delUserData=$?
if [ $delUserData -eq 0 ]; then
rm -rf $AppData 2>/dev/null
rm -rf $AppData_t 2>/dev/null
certutil -D -d $HOME/.pki/nssdb -n "SteamTools"
if [ $response -eq 0 ]; then
rm -rfq "$AppData" 2>/dev/null
rm -rfq "$AppData_t" 2>/dev/null
else
echo "保留用户数据方便下次安装。"
echo "如需删除可手动删除该目录:$AppData 或者 $AppData_t"
fi
rm -rf $Cache 2>/dev/null
rm -rf $Cache_t 2>/dev/null
rm -rf $base_path 2>/dev/null
rm -rf "$HOME/Desktop/Watt Toolkit.desktop" 2>/dev/null
rm -rfq "$Cache" 2>/dev/null
rm -rfq "$Cache_t" 2>/dev/null
rm -rfq "$base_path" 2>/dev/null
rm -rfq "$HOME/Desktop/Watt Toolkit.desktop" 2>/dev/null
zenity --info --text="卸载完成!" --width=300
+19 -19
View File
@@ -14,7 +14,7 @@ CodesignKey_Name="mossimo code"
App_Modules_Path="$App_Path/$Publish_Path/modules"
echo "编译主程序"
cd "$App_Path"
dotnet publish -c Release -p:PublishDir="$Publish_Path" -f net8.0-macos -p:CreatePackage=false -p:EnableCodeSigning=true -p:CodesignKey="$CodesignKey_Name"
dotnet publish -c Release -p:PublishDir="$Publish_Path" -f net7.0-macos -p:CreatePackage=false -p:EnableCodeSigning=true -p:CodesignKey="$CodesignKey_Name"
rm -r "$App_Modules_Path"
mkdir -p "$App_Modules_Path"
@@ -30,59 +30,59 @@ Copy_Plugins() {
echo "编译加速插件"
Plugins_Accelerator_Path="$Base_Path/src/BD.WTTS.Client.Plugins.Accelerator"
cd "$Plugins_Accelerator_Path"
dotnet publish -c Release -p:PublishDir="$Publish_Path" -f net8.0-macos
Copy_Plugins "$Plugins_Release_Path/net8.0-macos" "Accelerator" "BD.WTTS.Client.Plugins.Accelerator.dll"
dotnet publish -c Release -p:PublishDir="$Publish_Path" -f net7.0-macos
Copy_Plugins "$Plugins_Release_Path/net7.0-macos" "Accelerator" "BD.WTTS.Client.Plugins.Accelerator.dll"
Plugins_Accelerator_ReverseProxy_Path="$Base_Path/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy"
cd "$Plugins_Accelerator_ReverseProxy_Path"
# 根据 Build_Mode 执行不同逻辑
if [ "$Build_Mode" = "any" ]; then
dotnet publish -c Release -p:PublishDir="$Publish_Path/arm64" -f net8.0 -r osx-arm64 -p:PublishSingleFile=true --self-contained -p:EnableCodeSigning=true -p:CodesignKey="$CodesignKey_Name"
dotnet publish -c Release -p:PublishDir="$Publish_Path/x64" -f net8.0 -r osx-x64 -p:PublishSingleFile=true --self-contained -p:EnableCodeSigning=true -p:CodesignKey="$CodesignKey_Name"
dotnet publish -c Release -p:PublishDir="$Publish_Path/arm64" -f net7.0 -r osx-arm64 -p:PublishSingleFile=true --self-contained -p:EnableCodeSigning=true -p:CodesignKey="$CodesignKey_Name"
dotnet publish -c Release -p:PublishDir="$Publish_Path/x64" -f net7.0 -r osx-x64 -p:PublishSingleFile=true --self-contained -p:EnableCodeSigning=true -p:CodesignKey="$CodesignKey_Name"
lipo -create "$Publish_Path/arm64/Steam++.Accelerator" "$Publish_Path/x64/Steam++.Accelerator" -output "$Publish_Path/Steam++.Accelerator"
Copy_Plugins "$Publish_Path" "Accelerator" "Steam++.Accelerator"
elif [ "$Build_Mode" = "arm64" ]; then
dotnet publish -c Release -p:PublishDir="$Publish_Path/arm64" -f net8.0 -r osx-arm64 -p:PublishSingleFile=true --self-contained -p:EnableCodeSigning=true -p:CodesignKey="$CodesignKey_Name"
dotnet publish -c Release -p:PublishDir="$Publish_Path/arm64" -f net7.0 -r osx-arm64 -p:PublishSingleFile=true --self-contained -p:EnableCodeSigning=true -p:CodesignKey="$CodesignKey_Name"
Copy_Plugins "$Publish_Path/arm64" "Accelerator" "Steam++.Accelerator"
elif [ "$Build_Mode" = "x64" ]; then
dotnet publish -c Release -p:PublishDir="$Publish_Path/x64" -f net8.0 -r osx-x64 -p:PublishSingleFile=true --self-contained -p:EnableCodeSigning=true -p:CodesignKey="$CodesignKey_Name"
dotnet publish -c Release -p:PublishDir="$Publish_Path/x64" -f net7.0 -r osx-x64 -p:PublishSingleFile=true --self-contained -p:EnableCodeSigning=true -p:CodesignKey="$CodesignKey_Name"
Copy_Plugins "$Publish_Path/x64" "Accelerator" "Steam++.Accelerator"
fi
echo "编译令牌插件"
Plugins_Authenticator_Path="$Base_Path/src/BD.WTTS.Client.Plugins.Authenticator"
cd "$Plugins_Authenticator_Path"
dotnet publish -c Release -p:PublishDir="$Publish_Path" -f net8.0-macos -p:EnableCodeSigning=true -p:CodesignKey="$CodesignKey_Name"
Copy_Plugins "$Plugins_Release_Path/net8.0-macos" "Authenticator" "BD.WTTS.Client.Plugins.Authenticator.dll"
dotnet publish -c Release -p:PublishDir="$Publish_Path" -f net7.0-macos -p:EnableCodeSigning=true -p:CodesignKey="$CodesignKey_Name"
Copy_Plugins "$Plugins_Release_Path/net7.0-macos" "Authenticator" "BD.WTTS.Client.Plugins.Authenticator.dll"
echo "编译账户插件"
Plugins_GameAccount_Path="$Base_Path/src/BD.WTTS.Client.Plugins.GameAccount"
cd "$Plugins_GameAccount_Path"
dotnet publish -c Release -p:PublishDir="$Publish_Path" -f net8.0-macos -p:EnableCodeSigning=true -p:CodesignKey="$CodesignKey_Name"
Copy_Plugins "$Plugins_Release_Path/net8.0-macos" "GameAccount" "BD.WTTS.Client.Plugins.GameAccount.dll"
dotnet publish -c Release -p:PublishDir="$Publish_Path" -f net7.0-macos -p:EnableCodeSigning=true -p:CodesignKey="$CodesignKey_Name"
Copy_Plugins "$Plugins_Release_Path/net7.0-macos" "GameAccount" "BD.WTTS.Client.Plugins.GameAccount.dll"
echo "编译游戏库插件"
Plugins_GameList_Path="$Base_Path/src/BD.WTTS.Client.Plugins.GameList"
cd "$Plugins_GameList_Path"
dotnet publish -c Release -p:PublishDir="$Publish_Path" -f net8.0-macos -p:EnableCodeSigning=true -p:CodesignKey="$CodesignKey_Name"
Copy_Plugins "$Plugins_Release_Path/net8.0-macos" "GameList" "BD.WTTS.Client.Plugins.GameList.dll"
dotnet publish -c Release -p:PublishDir="$Publish_Path" -f net7.0-macos -p:EnableCodeSigning=true -p:CodesignKey="$CodesignKey_Name"
Copy_Plugins "$Plugins_Release_Path/net7.0-macos" "GameList" "BD.WTTS.Client.Plugins.GameList.dll"
echo "复制插件到程序目录"
cd "$App_Path"
# 根据 Build_Mode 执行不同逻辑
if [ "$Build_Mode" = "any" ]; then
cp -r "$App_Modules_Path" "$Plugins_Release_Path/net8.0-macos/Steam++.app/Contents/MonoBundle"
cp -r "$App_Modules_Path" "$Plugins_Release_Path/net7.0-macos/Steam++.app/Contents/MonoBundle"
elif [ "$Build_Mode" = "arm64" ]; then
cp -r "$App_Modules_Path" "$Plugins_Release_Path/net8.0-macos/osx-arm64/Steam++.app/Contents/MonoBundle"
cp -r "$Plugins_Release_Path/net8.0-macos/Steam++.app/Contents/Resources" "$Plugins_Release_Path/net8.0-macos/Steam++.app/Contents"
cp -r "$App_Modules_Path" "$Plugins_Release_Path/net7.0-macos/osx-arm64/Steam++.app/Contents/MonoBundle"
cp -r "$Plugins_Release_Path/net7.0-macos/Steam++.app/Contents/Resources" "$Plugins_Release_Path/net7.0-macos/Steam++.app/Contents"
elif [ "$Build_Mode" = "x64" ]; then
cp -r "$App_Modules_Path" "$Plugins_Release_Path/net8.0-macos/osx-x64/Steam++.app/Contents/MonoBundle"
cp -r "$Plugins_Release_Path/net8.0-macos/Steam++.app/Contents/Resources" "$Plugins_Release_Path/net8.0-macos/Steam++.app/Contents"
cp -r "$App_Modules_Path" "$Plugins_Release_Path/net7.0-macos/osx-x64/Steam++.app/Contents/MonoBundle"
cp -r "$Plugins_Release_Path/net7.0-macos/Steam++.app/Contents/Resources" "$Plugins_Release_Path/net7.0-macos/Steam++.app/Contents"
fi
echo "代码签名重新手动签名"
App_Publish_Path="$App_Path/bin/Release/net8.0-macos/Steam++.app"
App_Publish_Path="$App_Path/bin/Release/net7.0-macos/Steam++.app"
# #代码签名重新手动签名
codesign --remove-signature "$App_Publish_Path"
codesign --remove-signature "$App_Publish_Path/Contents/MacOS/Steam++"
+1 -240
View File
@@ -212,15 +212,6 @@
"Summary": "菜单排序",
"IsRegionOrEndregion": null,
"IsValueType": null
},
{
"TypeName": "string",
"PropertyName": "StartDefaultPageName",
"DefaultValue": "null",
"DefaultValueIsConst": true,
"Summary": "程序启动时默认页",
"IsRegionOrEndregion": null,
"IsValueType": null
}
],
"Usings": ""
@@ -496,15 +487,6 @@
"Summary": "账号平台设置集合",
"IsRegionOrEndregion": null,
"IsValueType": null
},
{
"TypeName": "bool",
"PropertyName": "IsShowAccountName",
"DefaultValue": "false",
"DefaultValueIsConst": false,
"Summary": "是否显示账号用户名",
"IsRegionOrEndregion": null,
"IsValueType": null
}
],
"Usings": ""
@@ -973,233 +955,12 @@
},
{
"TypeName": "string",
"PropertyName": "CustomDohAddres2",
"PropertyName": "CustomDohAddres",
"DefaultValue": "null",
"DefaultValueIsConst": true,
"Summary": "自定义 DNS over HTTPS 地址",
"IsRegionOrEndregion": null,
"IsValueType": null
},
{
"TypeName": "int",
"PropertyName": "AcceleratorTabsSelectedIndex",
"DefaultValue": "0",
"DefaultValueIsConst": false,
"Summary": "加速页面 Tab 选项卡选中下标",
"IsRegionOrEndregion": null,
"IsValueType": null
},
{
"TypeName": "bool",
"PropertyName": "AutoShowWattAcceleratorWindow",
"DefaultValue": "true",
"DefaultValueIsConst": true,
"Summary": "加速后自动唤起 Watt 加速器界面",
"IsRegionOrEndregion": null,
"IsValueType": null
}
],
"Usings": ""
},
"SteamIdleSettings": {
"ClassFilePath": "..\\src\\BD.WTTS.Client.Plugins.SteamIdleCard\\Settings",
"InterfaceFilePath": "..\\src\\BD.WTTS.Client.Plugins.SteamIdleCard\\Settings\\Abstractions",
"Properties": [
{
"TypeName": "TimeSpan",
"PropertyName": "IdleTime",
"DefaultValue": "TimeSpan.FromMinutes(6)",
"DefaultValueIsConst": false,
"Summary": "挂卡状态更新时间",
"IsRegionOrEndregion": null,
"IsValueType": true
},
{
"TypeName": "IdleRule",
"PropertyName": "IdleRule",
"DefaultValue": "IdleRule.FastMode",
"DefaultValueIsConst": false,
"Summary": "运行规则",
"IsRegionOrEndregion": null,
"IsValueType": true
},
{
"TypeName": "IdleSequentital",
"PropertyName": "IdleSequentital",
"DefaultValue": "IdleSequentital.Default",
"DefaultValueIsConst": false,
"Summary": "运行顺序",
"IsRegionOrEndregion": null,
"IsValueType": true
},
{
"TypeName": "int",
"PropertyName": "MaxIdleCount",
"DefaultValue": "30",
"DefaultValueIsConst": false,
"Summary": "最大并行运行游戏数量",
"IsRegionOrEndregion": null,
"IsValueType": true
},
{
"TypeName": "double",
"PropertyName": "MinRunTime",
"DefaultValue": "2",
"DefaultValueIsConst": false,
"Summary": "最少游戏时间 hours",
"IsRegionOrEndregion": null,
"IsValueType": true
},
{
"TypeName": "double",
"PropertyName": "SwitchTime",
"DefaultValue": "5000",
"DefaultValueIsConst": false,
"Summary": "自动切换游戏时间间隔 ms",
"IsRegionOrEndregion": null,
"IsValueType": true
},
{
"TypeName": "double",
"PropertyName": "RefreshBadgesTime",
"DefaultValue": "6",
"DefaultValueIsConst": false,
"Summary": "自动刷新徽章数据时间间隔 min",
"IsRegionOrEndregion": null,
"IsValueType": true
}
],
"Usings": ""
},
"ASFSettings": {
"ClassFilePath": "..\\src\\BD.WTTS.Client.Plugins.ArchiSteamFarmPlus\\Settings",
"InterfaceFilePath": "..\\src\\BD.WTTS.Client.Plugins.ArchiSteamFarmPlus\\Settings\\Abstractions",
"Properties": [
{
"TypeName": "string",
"PropertyName": "ArchiSteamFarmExePath",
"DefaultValue": "string.Empty",
"DefaultValueIsConst": false,
"Summary": "ASF 路径",
"IsRegionOrEndregion": null,
"IsValueType": false
},
{
"TypeName": "bool",
"PropertyName": "AutoRunArchiSteamFarm",
"DefaultValue": "false",
"DefaultValueIsConst": false,
"Summary": "程序启动时自动运行 ASF",
"IsRegionOrEndregion": null,
"IsValueType": true
},
{
"TypeName": "bool",
"PropertyName": "CheckArchiSteamFarmExe",
"DefaultValue": "false",
"DefaultValueIsConst": false,
"Summary": "检查文件安全性",
"IsRegionOrEndregion": null,
"IsValueType": true
},
{
"TypeName": "int",
"PropertyName": "ConsoleMaxLineDefault",
"DefaultValue": "200",
"DefaultValueIsConst": true,
"Summary": "控制台默认最大行数",
"IsRegionOrEndregion": null,
"IsValueType": true
},
{
"TypeName": "int",
"PropertyName": "MinRangeConsoleMaxLine",
"DefaultValue": "DefaultConsoleMaxLineDefault",
"DefaultValueIsConst": true,
"Summary": "控制台默认最大行数范围最小值",
"IsRegionOrEndregion": null,
"IsValueType": true
},
{
"TypeName": "int",
"PropertyName": "MaxRangeConsoleMaxLine",
"DefaultValue": "5000",
"DefaultValueIsConst": true,
"Summary": "控制台默认最大行数范围最大值",
"IsRegionOrEndregion": null,
"IsValueType": true
},
{
"TypeName": "int",
"PropertyName": "ConsoleMaxLine",
"DefaultValue": "DefaultConsoleMaxLineDefault",
"DefaultValueIsConst": false,
"Summary": "控制台最大行数",
"IsRegionOrEndregion": null,
"IsValueType": true
},
{
"TypeName": "int",
"PropertyName": "ConsoleFontSizeDefault",
"DefaultValue": "14",
"DefaultValueIsConst": true,
"Summary": "",
"IsRegionOrEndregion": null,
"IsValueType": true
},
{
"TypeName": "int",
"PropertyName": "MinRangeConsoleFontSize",
"DefaultValue": "8",
"DefaultValueIsConst": true,
"Summary": "",
"IsRegionOrEndregion": null,
"IsValueType": true
},
{
"TypeName": "int",
"PropertyName": "MaxRangeConsoleFontSize",
"DefaultValue": "24",
"DefaultValueIsConst": true,
"Summary": "",
"IsRegionOrEndregion": null,
"IsValueType": true
},
{
"TypeName": "int",
"PropertyName": "ConsoleFontSize",
"DefaultValue": "DefaultConsoleFontSizeDefault",
"DefaultValueIsConst": false,
"Summary": "控制台字体大小",
"IsRegionOrEndregion": null,
"IsValueType": true
},
{
"TypeName": "int",
"PropertyName": "IPCPortIdValue",
"DefaultValue": "6242",
"DefaultValueIsConst": true,
"Summary": "",
"IsRegionOrEndregion": null,
"IsValueType": null
},
{
"TypeName": "int",
"PropertyName": "IPCPortId",
"DefaultValue": "DefaultIPCPortIdValue",
"DefaultValueIsConst": false,
"Summary": "IPC 端口号,默认值为 <see cref=\"DefaultIPCPortIdValue\" />",
"IsRegionOrEndregion": null,
"IsValueType": true
},
{
"TypeName": "bool",
"PropertyName": "IPCPortOccupiedRandom",
"DefaultValue": "true",
"DefaultValueIsConst": false,
"Summary": "IPC 端口号被占用时是否随机一个未使用的端口号,默认值 <see langword=\"true\" />",
"IsRegionOrEndregion": null,
"IsValueType": true
}
],
"Usings": ""
-5
View File
@@ -1,5 +0,0 @@
<Project>
<PropertyGroup>
<CheckEolWorkloads>false</CheckEolWorkloads>
</PropertyGroup>
</Project>
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
-11
View File
@@ -1,11 +0,0 @@
static void WinDivert()
{
var dllWinDivert = Path.Combine(ProjectUtils.ProjPath, "ref", "WinDivert.dll");
var sysWinDivert64 = Path.Combine(ProjectUtils.ProjPath, "ref", "WinDivert64.sys");
byte[][] data = [File.ReadAllBytes(dllWinDivert), File.ReadAllBytes(sysWinDivert64)];
var bytes = MemoryPackSerializer.Serialize(data);
bytes.AsSpan().Reverse();
File.WriteAllBytes(Path.Combine(ProjectUtils.ProjPath, "ref", "WinDivert.mpo"), bytes);
}
Binary file not shown.
+3 -3
View File
@@ -16,14 +16,14 @@ public static partial class AssemblyInfo
/// <summary>
/// 预览版本号,范围 1~9,只增不减
/// </summary>
const string ver_for_preview = "9";
const string ver_for_preview = "7";
/// <summary>
/// RC 版本号,范围 0~9,只增不减
/// </summary>
const string ver_for_rc = "12";
const string ver_for_rc = "3";
public const string FileVersion = $"{Version2}.{ver_for_rc}1{ver_for_preview}.0";
public const string FileVersion = $"{Version2}.{ver_for_rc}0{ver_for_preview}.0";
//public const string InformationalVersion = Version;
//public const string InformationalVersion = $"{Version}-preview.{ver_for_preview}";
-3
View File
@@ -22,9 +22,6 @@ global using Avalonia.Metadata;
[assembly: XmlnsDefinition("https://steampp.net/ui", "BD.WTTS.Converters")]
[assembly: XmlnsDefinition("https://steampp.net/ui", "BD.WTTS.Markup")]
[assembly: XmlnsDefinition("https://steampp.net/ui", "BD.WTTS.Client.Resources")]
[assembly: XmlnsDefinition("https://steampp.net/ui", "Mobius.Models")]
[assembly: XmlnsDefinition("https://steampp.net/ui", "Mobius")]
[assembly: XmlnsDefinition("https://steampp.net/services", "BD.WTTS.Services")]
[assembly: XmlnsDefinition("https://steampp.net/services", "BD.WTTS.Plugins")]
[assembly: XmlnsDefinition("https://steampp.net/services", "BD.WTTS.Plugins.Abstractions")]
@@ -7,7 +7,6 @@
<DelaySign>false</DelaySign>
<AssemblyOriginatorKeyFile>$(MSBuildProjectDirectory)\..\..\avalonia.snk</AssemblyOriginatorKeyFile>
<!--https://github.com/AvaloniaUI/Avalonia/blob/0.10.10/build/SharedVersion.props#L18-->
<AvaloniaAccessUnstablePrivateApis>true</AvaloniaAccessUnstablePrivateApis>
</PropertyGroup>
<ItemGroup>
@@ -38,9 +38,9 @@ public interface IFontManagerImpl2 : IFontManagerImpl
return Impl.TryCreateGlyphTypeface(familyName, style, weight, stretch, out glyphTypeface);
}
bool IFontManagerImpl.TryCreateGlyphTypeface(Stream stream, FontSimulations fontSimulations, [NotNullWhen(returnValue: true)] out IGlyphTypeface? glyphTypeface)
bool IFontManagerImpl.TryCreateGlyphTypeface(Stream stream, [NotNullWhen(returnValue: true)] out IGlyphTypeface? glyphTypeface)
{
return Impl.TryCreateGlyphTypeface(stream, fontSimulations, out glyphTypeface);
return Impl.TryCreateGlyphTypeface(stream, out glyphTypeface);
}
//IGlyphTypeface IFontManagerImpl.CreateGlyphTypeface(Typeface typeface)
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
@@ -8,76 +8,70 @@
xmlns:desktop2="http://schemas.microsoft.com/appx/manifest/desktop/windows10/2"
IgnorableNamespaces="uap rescap desktop desktop2">
<Identity
Name="4651ED44255E.47979655102CE"
Publisher="CN=A90E406B-B2D3-4A23-B061-0FA1D65C4F66"
Version="3.0.207.0" />
<Identity
Name="4651ED44255E.47979655102CE"
Publisher="CN=A90E406B-B2D3-4A23-B061-0FA1D65C4F66"
Version="3.0.207.0" />
<Properties>
<DisplayName>Watt Toolkit</DisplayName>
<PublisherDisplayName>软妹币玩家</PublisherDisplayName>
<Logo>Images\StoreLogo.png</Logo>
</Properties>
<Properties>
<DisplayName>Watt Toolkit</DisplayName>
<PublisherDisplayName>软妹币玩家</PublisherDisplayName>
<Logo>Images\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
</Dependencies>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="Watt Toolkit"
Description="「Watt Toolkit」是一个开源跨平台的多功能游戏工具箱,此工具的大部分功能都是需要您下载安装 Steam 才能使用。"
BackgroundColor="transparent"
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png">
<uap:DefaultTile Wide310x150Logo="Images\Wide310x150Logo.png" Square71x71Logo="Images\SmallTile.png" Square310x310Logo="Images\LargeTile.png" ShortName="Steam++">
<uap:ShowNameOnTiles>
<uap:ShowOn Tile="square150x150Logo"/>
<uap:ShowOn Tile="wide310x150Logo"/>
<uap:ShowOn Tile="square310x310Logo"/>
</uap:ShowNameOnTiles>
</uap:DefaultTile >
<uap:SplashScreen Image="Images\SplashScreen.png" />
<uap:InitialRotationPreference>
<uap:Rotation Preference="landscape"/>
</uap:InitialRotationPreference>
<uap:LockScreen BadgeLogo="Images\BadgeLogo.png" Notification="badgeAndTileText"/>
</uap:VisualElements>
<Extensions>
<desktop:Extension Category="windows.fullTrustProcess" Executable="Steam++\Steam++.exe" />
<desktop:Extension Category="windows.startupTask" Executable="Steam++\Steam++.exe" EntryPoint="Windows.FullTrustApplication">
<desktop:StartupTask TaskId="BootAutoStartTask" Enabled="true" DisplayName="Steam++ System Boot Run" />
</desktop:Extension>
<uap:Extension Category="windows.protocol">
<uap:Protocol Name="spp">
<uap:Logo>Images\Square44x44Logo.png</uap:Logo>
<uap:DisplayName>Steam++ URI Scheme</uap:DisplayName>
</uap:Protocol>
</uap:Extension>
</Extensions>
</Application>
</Applications>
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="Watt Toolkit"
Description="「Watt Toolkit」是一个开源跨平台的多功能游戏工具箱,此工具的大部分功能都是需要您下载安装 Steam 才能使用。"
BackgroundColor="transparent"
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png">
<uap:DefaultTile Wide310x150Logo="Images\Wide310x150Logo.png" Square71x71Logo="Images\SmallTile.png" Square310x310Logo="Images\LargeTile.png" ShortName="Steam++">
<uap:ShowNameOnTiles>
<uap:ShowOn Tile="square150x150Logo"/>
<uap:ShowOn Tile="wide310x150Logo"/>
<uap:ShowOn Tile="square310x310Logo"/>
</uap:ShowNameOnTiles>
</uap:DefaultTile >
<uap:SplashScreen Image="Images\SplashScreen.png" />
<uap:InitialRotationPreference>
<uap:Rotation Preference="landscape"/>
</uap:InitialRotationPreference>
<uap:LockScreen BadgeLogo="Images\BadgeLogo.png" Notification="badgeAndTileText"/>
</uap:VisualElements>
<Extensions>
<desktop:Extension Category="windows.fullTrustProcess" Executable="Steam++\Steam++.exe" />
<desktop:Extension Category="windows.startupTask" Executable="Steam++\Steam++.exe" EntryPoint="Windows.FullTrustApplication">
<desktop:StartupTask TaskId="BootAutoStartTask" Enabled="true" DisplayName="Steam++ System Boot Run" />
</desktop:Extension>
</Extensions>
</Application>
</Applications>
<Extensions>
<desktop2:Extension Category="windows.firewallRules">
<desktop2:FirewallRules Executable="Steam++\modules\Accelerator\Steam++.Accelerator.exe">
<desktop2:Rule Direction="in" IPProtocol="TCP" Profile="all"/>
<desktop2:Rule Direction="in" IPProtocol="UDP" Profile="all"/>
</desktop2:FirewallRules>
</desktop2:Extension>
</Extensions>
<Extensions>
<desktop2:Extension Category="windows.firewallRules">
<desktop2:FirewallRules Executable="Steam++\modules\Accelerator\Steam++.Accelerator.exe">
<desktop2:Rule Direction="in" IPProtocol="TCP" Profile="all"/>
<desktop2:Rule Direction="in" IPProtocol="UDP" Profile="all"/>
</desktop2:FirewallRules>
</desktop2:Extension>
</Extensions>
<Capabilities>
<Capability Name="internetClient" />
<rescap:Capability Name="runFullTrust" />
<rescap:Capability Name="allowElevation" />
</Capabilities>
<Capabilities>
<Capability Name="internetClient" />
<rescap:Capability Name="runFullTrust" />
<rescap:Capability Name="allowElevation" />
</Capabilities>
</Package>
+1 -1
View File
@@ -10,6 +10,6 @@
<legacyCorruptedStateExceptionsPolicy enabled="true"/>
</runtime>
<appSettings>
<add key="d" value="8.0.0"/>
<add key="d" value="7.0.11"/>
</appSettings>
</configuration>
+2 -2
View File
@@ -16,9 +16,9 @@ static unsafe partial class Program
{
static Program()
{
dotnet_version_major = "8";
dotnet_version_major = "7";
dotnet_version_minor = "0";
dotnet_version_build = "0";
dotnet_version_build = "11";
dotnet_version = $"{dotnet_version_major}.{dotnet_version_minor}.{dotnet_version_build}";
}
@@ -1 +1 @@
<?xml version="1.0" encoding="utf-8"?><assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"><assemblyIdentity version="1.0.0.0" name="BeyondDimension.WattToolkit.AppHost"/><trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"><security><requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"><requestedExecutionLevel level="requireAdministrator" uiAccess="false" /></requestedPrivileges></security></trustInfo><compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"><application><supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" /><supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" /><supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" /><supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" /><supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" /></application></compatibility></assembly>
<?xml version="1.0" encoding="utf-8"?><assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"><assemblyIdentity version="1.0.0.0" name="BeyondDimension.WattToolkit.AppHost"/><trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"><security><requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"><requestedExecutionLevel level="asInvoker" uiAccess="false" /></requestedPrivileges></security></trustInfo><compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"><application><supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" /><supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" /><supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" /><supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" /><supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" /></application></compatibility></assembly>
@@ -91,18 +91,21 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="BD.Common.XmlnsDefinition.Avalonia">
<Aliases>BD_Common_XmlnsDefinition_Avalonia</Aliases>
</PackageReference>
<ProjectReference Include="..\BD.WTTS.Client.Avalonia\BD.WTTS.Client.Avalonia.csproj" />
<ProjectReference Include="..\BD.WTTS.Client\BD.WTTS.Client.csproj" />
</ItemGroup>
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows' AND Exists('$(NugetPackageRoot)\system.drawing.common\$(Version_System_Drawing_Common)\lib\net8.0\System.Drawing.Common.dll')">
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows' AND Exists('$(NugetPackageRoot)\system.drawing.common\$(Version_System_Drawing_Common)\runtimes\win\lib\net7.0\System.Drawing.Common.dll')">
<!-- Windows Only -->
<!-- 修复:存在 Microsoft.WindowsDesktop.App 依赖时不会将 System.Drawing.Common.dll 复制到输出目录-->
<None Include="$(NugetPackageRoot)\system.drawing.common\$(Version_System_Drawing_Common)\lib\net8.0\System.Drawing.Common.dll">
<None Include="$(NugetPackageRoot)\system.drawing.common\$(Version_System_Drawing_Common)\runtimes\win\lib\net7.0\System.Drawing.Common.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<Reference Include="System.Drawing.Common">
<HintPath>$(NugetPackageRoot)\system.drawing.common\$(Version_System_Drawing_Common)\lib\net8.0\System.Drawing.Common.dll</HintPath>
<HintPath>$(NugetPackageRoot)\system.drawing.common\$(Version_System_Drawing_Common)\runtimes\win\lib\net7.0\System.Drawing.Common.dll</HintPath>
</Reference>
</ItemGroup>
@@ -22,8 +22,6 @@
<string>NSApplication</string>
<key>XSAppIconAssets</key>
<string>Assets.xcassets/AppIcon.appiconset</string>
<key>CFBundleIconFile</key>
<string>AppIcon.icns</string>
<key>CFBundleIdentifier</key>
<string>net.steampp.app</string>
<key>CFBundleURLTypes</key>
@@ -1 +1 @@
<?xml version="1.0" encoding="utf-8"?><assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"><assemblyIdentity version="1.0.0.0" name="BeyondDimension.WattToolkit.App"/><trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"><security><requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"><requestedExecutionLevel level="requireAdministrator" uiAccess="false" /></requestedPrivileges></security></trustInfo><compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"><application><supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" /><supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" /><supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" /><supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" /><supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" /></application></compatibility></assembly>
<?xml version="1.0" encoding="utf-8"?><assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"><assemblyIdentity version="1.0.0.0" name="BeyondDimension.WattToolkit.App"/><trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"><security><requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"><requestedExecutionLevel level="asInvoker" uiAccess="false" /></requestedPrivileges></security></trustInfo><compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"><application><supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" /><supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" /><supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" /><supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" /><supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" /></application></compatibility></assembly>
@@ -68,6 +68,9 @@
<ItemGroup>
<PackageReference Include="Moq" />
<PackageReference Include="BD.Common.XmlnsDefinition.Avalonia">
<Aliases>BD_Common_XmlnsDefinition_Avalonia</Aliases>
</PackageReference>
<ProjectReference Include="..\BD.WTTS.Client.Avalonia\BD.WTTS.Client.Avalonia.csproj" />
<ProjectReference Include="..\BD.WTTS.Client.Plugins.Accelerator\BD.WTTS.Client.Plugins.Accelerator.csproj" />
<ProjectReference Include="..\BD.WTTS.Client.Plugins.ArchiSteamFarmPlus\BD.WTTS.Client.Plugins.ArchiSteamFarmPlus.csproj" />
@@ -4,7 +4,6 @@
<RootNamespace>BD.WTTS</RootNamespace>
<DefineConstants>AVALONIA;$(DefineConstants)</DefineConstants>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
<AvaloniaAccessUnstablePrivateApis>true</AvaloniaAccessUnstablePrivateApis>
</PropertyGroup>
<ItemGroup>
@@ -73,16 +72,17 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="BD.Common.XmlnsDefinition.Avalonia">
<Aliases>BD_Common_XmlnsDefinition_Avalonia</Aliases>
</PackageReference>
<PackageReference Include="BD.Common" />
<PackageReference Include="BD.Common.Primitives" />
<PackageReference Include="BD.Common.Essentials" />
<PackageReference Include="Avalonia" />
<PackageReference Include="Avalonia.ReactiveUI" />
<PackageReference Include="Avalonia.Controls.DataGrid" />
<PackageReference Include="Avalonia.Controls.ItemsRepeater" />
<PackageReference Include="Avalonia.Xaml.Behaviors" />
<PackageReference Include="Avalonia.AvaloniaEdit" />
<PackageReference Include="AvaloniaEdit.TextMate" />
<!--<PackageReference Include="Avalonia.AvaloniaEdit" />-->
<!--<PackageReference Include="Markdown.Avalonia" />-->
<PackageReference Include="FluentAvaloniaUI" />
<PackageReference Include="LiveChartsCore.SkiaSharpView.Avalonia" />
@@ -126,15 +126,6 @@
<ProjectReference Include="..\BD.WTTS.Client\BD.WTTS.Client.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="UI\Views\Controls\Widgets\CarouselItems.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<Compile Update="UI\Views\Pages\PluginStorePage.axaml.cs">
<DependentUpon>PluginStorePage.axaml</DependentUpon>
</Compile>
</ItemGroup>
<Import Project="..\TFM_NETX_WITH_DESKTOP.props" />
</Project>
@@ -1,203 +0,0 @@
using Avalonia.Reactive;
using Avalonia.Xaml.Interactions.Responsive;
using Avalonia.Xaml.Interactivity;
namespace BD.WTTS.Behaviors;
/// <summary>
/// Observes <see cref="Behavior{T}.AssociatedObject"/> control or <see cref="SourceControl"/> control <see cref="Visual.Bounds"/> property changes and if triggered sets or removes style classes when conditions from <see cref="AdaptiveClassSetter"/> are met.
/// </summary>
public class AdaptiveBehavior : Behavior<Control>
{
private IDisposable? _disposable;
private AvaloniaList<AdaptiveClassSetter>? _setters;
/// <summary>
/// Identifies the <seealso cref="SourceControl"/> avalonia property.
/// </summary>
public static readonly StyledProperty<Control?> SourceControlProperty =
AvaloniaProperty.Register<AdaptiveBehavior, Control?>(nameof(SourceControl));
/// <summary>
/// Identifies the <seealso cref="TargetControl"/> avalonia property.
/// </summary>
public static readonly StyledProperty<Control?> TargetControlProperty =
AvaloniaProperty.Register<AdaptiveBehavior, Control?>(nameof(TargetControl));
/// <summary>
/// Identifies the <seealso cref="Setters"/> avalonia property.
/// </summary>
public static readonly DirectProperty<AdaptiveBehavior, AvaloniaList<AdaptiveClassSetter>> SettersProperty =
AvaloniaProperty.RegisterDirect<AdaptiveBehavior, AvaloniaList<AdaptiveClassSetter>>(nameof(Setters), t => t.Setters);
/// <summary>
/// Gets or sets the the source control that <see cref="Visual.BoundsProperty"/> property are observed from, if not set <see cref="Behavior{T}.AssociatedObject"/> is used. This is a avalonia property.
/// </summary>
[ResolveByName]
public Control? SourceControl
{
get => GetValue(SourceControlProperty);
set => SetValue(SourceControlProperty, value);
}
/// <summary>
/// Gets or sets the target control that class name that should be added or removed when triggered, if not set <see cref="Behavior{T}.AssociatedObject"/> is used or <see cref="AdaptiveClassSetter.TargetControl"/> from <see cref="AdaptiveClassSetter"/>. This is a avalonia property.
/// </summary>
[ResolveByName]
public Control? TargetControl
{
get => GetValue(TargetControlProperty);
set => SetValue(TargetControlProperty, value);
}
/// <summary>
/// Gets adaptive class setters collection. This is a avalonia property.
/// </summary>
[Content]
public AvaloniaList<AdaptiveClassSetter> Setters => _setters ??= new AvaloniaList<AdaptiveClassSetter>();
/// <inheritdoc/>
protected override void OnAttachedToVisualTree()
{
base.OnAttachedToVisualTree();
StopObserving();
StartObserving();
}
/// <inheritdoc/>
protected override void OnDetachedFromVisualTree()
{
base.OnDetachedFromVisualTree();
StopObserving();
}
private void StartObserving()
{
var sourceControl = GetValue(SourceControlProperty) is not null
? SourceControl
: AssociatedObject;
if (sourceControl is not null)
{
_disposable = ObserveBounds(sourceControl);
}
}
private void StopObserving()
{
_disposable?.Dispose();
}
private IDisposable ObserveBounds(Control sourceControl)
{
if (sourceControl is null)
{
throw new ArgumentNullException(nameof(sourceControl));
}
return sourceControl.GetObservable(Visual.BoundsProperty)
.Subscribe(new AnonymousObserver<Rect>(bounds => ValueChanged(sourceControl, Setters, bounds)));
}
private void ValueChanged(Control? sourceControl, AvaloniaList<AdaptiveClassSetter>? setters, Rect bounds)
{
if (sourceControl is null || setters is null)
{
return;
}
foreach (var setter in setters)
{
var isMinOrMaxWidthSet = setter.IsSet(AdaptiveClassSetter.MinWidthProperty)
|| setter.IsSet(AdaptiveClassSetter.MaxWidthProperty);
var widthConditionTriggered = GetResult(setter.MinWidthOperator, bounds.Width, setter.MinWidth)
&& GetResult(setter.MaxWidthOperator, bounds.Width, setter.MaxWidth);
var isMinOrMaxHeightSet = setter.IsSet(AdaptiveClassSetter.MinHeightProperty)
|| setter.IsSet(AdaptiveClassSetter.MaxHeightProperty);
var heightConditionTriggered = GetResult(setter.MinHeightOperator, bounds.Height, setter.MinHeight)
&& GetResult(setter.MaxHeightOperator, bounds.Height, setter.MaxHeight);
var isAddClassTriggered = isMinOrMaxWidthSet switch
{
true when !isMinOrMaxHeightSet => widthConditionTriggered,
false when isMinOrMaxHeightSet => heightConditionTriggered,
true when isMinOrMaxHeightSet => widthConditionTriggered && heightConditionTriggered,
_ => false
};
var targetControl = setter.GetValue(AdaptiveClassSetter.TargetControlProperty) is not null
? setter.TargetControl
: GetValue(TargetControlProperty) is not null
? TargetControl
: AssociatedObject;
if (targetControl is not null)
{
var className = setter.ClassName;
var isPseudoClass = setter.IsPseudoClass;
if (isAddClassTriggered)
{
Add(targetControl, className, isPseudoClass);
}
else
{
Remove(targetControl, className, isPseudoClass);
}
}
}
}
private bool GetResult(ComparisonConditionType comparisonConditionType, double property, double value)
{
return comparisonConditionType switch
{
// ReSharper disable once CompareOfFloatsByEqualityOperator
ComparisonConditionType.Equal => property == value,
// ReSharper disable once CompareOfFloatsByEqualityOperator
ComparisonConditionType.NotEqual => property != value,
ComparisonConditionType.LessThan => property < value,
ComparisonConditionType.LessThanOrEqual => property <= value,
ComparisonConditionType.GreaterThan => property > value,
ComparisonConditionType.GreaterThanOrEqual => property >= value,
_ => throw new ArgumentOutOfRangeException()
};
}
private static void Add(Control targetControl, string? className, bool isPseudoClass)
{
if (className is null || string.IsNullOrEmpty(className) || targetControl.Classes.Contains(className))
{
return;
}
if (isPseudoClass)
{
((IPseudoClasses)targetControl.Classes).Add(className);
}
else
{
targetControl.Classes.Add(className);
}
}
private static void Remove(Control targetControl, string? className, bool isPseudoClass)
{
if (className is null || string.IsNullOrEmpty(className) || !targetControl.Classes.Contains(className))
{
return;
}
if (isPseudoClass)
{
((IPseudoClasses)targetControl.Classes).Remove(className);
}
else
{
targetControl.Classes.Remove(className);
}
}
}
@@ -18,8 +18,6 @@ public sealed class EnumLocalizationNameConverter : IValueConverter
else
{
text = Strings.ResourceManager.GetString(desc, Strings.Culture);
if (string.IsNullOrEmpty(text))
return desc;
}
if (!string.IsNullOrEmpty(text))
@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BD.WTTS.Converters;
public sealed class StringOmitConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string s = value.ToString();
int leng;
if (int.TryParse(parameter.ToString(), out leng))
{
if (s.Length <= leng)
return s;
else
return s[..leng] + "...";
}
else
return string.Empty;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
@@ -1,22 +1,18 @@
namespace BD.WTTS.Converters;
public sealed class VisibleStringConverter : IMultiValueConverter
public sealed class VisbleStringConverter : IMultiValueConverter
{
public object? Convert(IList<object?> values, Type targetType, object? parameter, CultureInfo culture)
{
if (values.Count >= 2 && values.FirstOrDefault() is bool isVisble)
if (values.Count >= 3 && values.FirstOrDefault() is bool isVisble)
{
if (isVisble)
{
return values[1];
}
else if (values.Count >= 3)
{
return values[2];
}
else
{
return null;
return values[2];
}
}
return values;
@@ -1,111 +0,0 @@
namespace BD.WTTS.Converters;
public sealed class WaveProgressValueConverter : IValueConverter
{
public static readonly WaveProgressValueConverter Instance = new();
/// <inheritdoc/>
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is not double i) return 0;
return 155 - (i * 2.1);
}
/// <inheritdoc/>
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return BindingOperations.DoNothing;
}
}
public class WaveProgressValueColorConverter : IValueConverter
{
public static readonly WaveProgressValueColorConverter Instance = new();
/// <inheritdoc/>
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is not double d) return Brushes.Black;
if (d > 50) return Brushes.GhostWhite;
return Application.Current?.ActualThemeVariant == ThemeVariant.Dark ? Brushes.GhostWhite : Brushes.Black;
}
/// <inheritdoc/>
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return BindingOperations.DoNothing;
}
}
public class WaveProgressValueTextConverter : IValueConverter
{
public static readonly WaveProgressValueTextConverter Instance = new();
/// <inheritdoc/>
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return value is not double d ? "0%" : $"{d:#0}%";
}
/// <inheritdoc/>
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return BindingOperations.DoNothing;
}
}
public class WaveProgressGradientOffsetConverter : IValueConverter
{
public static readonly WaveProgressGradientOffsetConverter Instance = new();
/// <inheritdoc/>
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is not double v)
return Brushes.Blue;
var app = Application.Current;
if (app == null)
return null;
Color primaryColor = Colors.DodgerBlue;
Color accentColor = Colors.Transparent;
try
{
if (app.FindResource("SystemAccentColor") is Color primaryColor2)
{
primaryColor = primaryColor2;
}
if (app.FindResource("SystemAccentColorLight2") is Color accentColor2)
{
accentColor = accentColor2;
}
}
catch { }
var isLight = app.RequestedThemeVariant == ThemeVariant.Light;
v /= 100;
v += isLight ? 0.2 : 0.4;
if (v > 1)
v = 1;
return new LinearGradientBrush()
{
EndPoint = new RelativePoint(0.5, 1, RelativeUnit.Relative),
StartPoint = new RelativePoint(0.5, 0, RelativeUnit.Relative),
GradientStops = new GradientStops()
{
new GradientStop() { Color = primaryColor, Offset = 0 },
new GradientStop() { Color = isLight ? Colors.Transparent : accentColor, Offset = v },
},
};
}
/// <inheritdoc/>
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return BindingOperations.DoNothing;
}
}
@@ -2,7 +2,7 @@ namespace BD.WTTS.UI;
public static class ControlExtensions
{
public static void SetViewModel<T>(this Control c, bool useCache = false) where T : ViewModelBase, new()
public static void SetViewModel<T>(this Control c, bool useCache = true) where T : ViewModelBase
{
if (c.DataContext == null || c.DataContext.GetType() != typeof(T))
{
@@ -11,7 +11,7 @@ public static class ControlExtensions
if (useCache)
cx = IViewModelManager.Instance.Get<T>();
else
cx = new T();
cx = Activator.CreateInstance<T>();
c.DataContext = cx;
}
@@ -1,31 +0,0 @@
namespace BD.WTTS;
/// <summary>
/// <see cref="IEnumerable"/> extensions methods
/// </summary>
public static class IEnumerableExtensions
{
public static IEnumerable<IEnumerable> Batch(this IEnumerable source, int size)
{
object[]? bucket = null;
var count = 0;
foreach (var item in source)
{
bucket ??= new object[size];
bucket[count++] = item;
if (count == size)
{
yield return bucket;
bucket = null;
count = 0;
}
}
if (bucket != null && count > 0)
yield return bucket.Take(count).ToArray();
}
}
@@ -13,7 +13,6 @@ public static class WindowTransparencyLevelExtensions
WindowBackgroundMaterial.Blur => WindowTransparencyLevel.Blur,
WindowBackgroundMaterial.AcrylicBlur => WindowTransparencyLevel.AcrylicBlur,
WindowBackgroundMaterial.Mica => WindowTransparencyLevel.Mica,
WindowBackgroundMaterial.Transparent => WindowTransparencyLevel.Transparent,
_ => WindowTransparencyLevel.None,
};
}
@@ -11,7 +11,6 @@
[assembly: XmlnsDefinition("https://steampp.net/ui", "BD.WTTS.UI.Views.Windows")]
[assembly: XmlnsDefinition("https://steampp.net/ui", "BD.WTTS.Converters")]
[assembly: XmlnsDefinition("https://steampp.net/ui", "BD.WTTS.Markup")]
[assembly: XmlnsDefinition("https://steampp.net/ui", "BD.WTTS.Behaviors")]
[assembly: XmlnsDefinition("https://steampp.net/services", "BD.WTTS.Services")]
[assembly: XmlnsDefinition("https://steampp.net/services", "BD.WTTS.Plugins")]
[assembly: XmlnsDefinition("https://steampp.net/services", "BD.WTTS.Plugins.Abstractions")]
@@ -4,7 +4,7 @@ using System.Collections.Immutable;
namespace BD.WTTS.Services.Implementation;
/// <inheritdoc cref="IWindowManager"/>
public sealed class AvaloniaWindowManagerImpl : IWindowManagerImpl
sealed class AvaloniaWindowManagerImpl : IWindowManagerImpl
{
Type? IWindowManagerImpl.WindowType => typeof(Window);
@@ -95,7 +95,7 @@ public sealed class AvaloniaWindowManagerImpl : IWindowManagerImpl
Func<bool>? cancelCloseAction = null,
bool disableScroll = false)
where TPageViewModel : ViewModelBase
{
{
var td = new TaskDialogEx
{
Title = title,
@@ -111,17 +111,12 @@ public sealed class AvaloniaWindowManagerImpl : IWindowManagerImpl
XamlRoot = GetWindowTopLevel(),
};
if (td.XamlRoot == null)
{
Toast.LogAndShowT(new Exception("在 AppWindow 为 Null 时,无法弹出 Taskdialog."));
return false;
}
if (viewModel != null)
{
if (viewModel is IWindowViewModel window)
{
window.Close = b => td?.Hide(b ? TaskDialogStandardResult.OK : TaskDialogStandardResult.Close);
window.Close = () => td?.Hide(TaskDialogStandardResult.Close);
}
td.DataContext = viewModel;
@@ -44,14 +44,12 @@ sealed class AvaloniaToastServiceImpl : IToastService
if (NotificationManager == null)
{
var host = AvaloniaWindowManagerImpl.GetWindowTopLevel();
if (host != null)
NotificationManager = new SnackbarManager(host)
{
NotificationManager = new SnackbarManager(host)
{
Position = NotificationPosition.BottomRight,
MaxItems = 5,
};
}
Position = NotificationPosition.BottomRight,
MaxItems = 5,
};
}
var notificationType = GetNotificationType(icon);
+4 -52
View File
@@ -63,50 +63,10 @@ partial class App
#else
s.HasTrayIcon ? ShutdownMode.OnExplicitShutdown : ShutdownMode.OnMainWindowClose;
#endif
#if MACOS
if (Current!.TryGetFeature<IActivatableLifetime>() is { } activatableLifetime)
{
activatableLifetime.Activated += ActivatableLifetimeOnActivated;
// macOS 中 右键隐藏 会触发目前不需要使用
//activatableLifetime.Deactivated += ActivatableLifetimeOnDeactivated;
}
#endif
}
}
#if MACOS
/// <summary>
/// 从 macOS Dock 栏恢复窗口显示
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ActivatableLifetimeOnActivated(object? sender, ActivatedEventArgs e)
{
switch (e.Kind)
{
case ActivationKind.Background:
case ActivationKind.Reopen:
RestoreMainWindow();
break;
}
}
///// <summary>
///// macOS 中 右键隐藏 会触发目前不需要使用
///// </summary>
///// <param name="sender"></param>
///// <param name="e"></param>
//private void ActivatableLifetimeOnDeactivated(object? sender, ActivatedEventArgs e)
//{
// switch (e.Kind)
// {
// case ActivationKind.Background:
// Console.WriteLine($"ActivatableLifetimeOnDeactivated {e.Kind}");
// break;
// }
//}
#endif
public void UpdateMenuItems()
{
MainThread2.BeginInvokeOnMainThread(() =>
@@ -128,7 +88,7 @@ partial class App
new Binding { Path = "Res.CloseSteam", Source = ResourceService.Current, Mode = BindingMode.OneWay },
new Binding { Path = "Res.StartSteam", Source = ResourceService.Current, Mode = BindingMode.OneWay },
},
Converter = (VisibleStringConverter)App.Instance.FindResource(nameof(VisibleStringConverter))!,
Converter = (VisbleStringConverter)App.Instance.FindResource("VisbleStringConverter")!,
},
Command = ReactiveCommand.Create(async () =>
{
@@ -165,20 +125,12 @@ partial class App
{
subMenu = new NativeMenu();
foreach (var sub in item.Value.Items)
{
var menu = new NativeMenuItem
subMenu.Add(new NativeMenuItem
{
Header = sub.Name,
Command = sub.Command,
CommandParameter = sub.CommandParameter,
};
if (sub.IsVisible is Avalonia.Data.IBinding v)
menu[!NativeMenuItem.IsVisibleProperty] = v;
if (sub.IsEnabled is Avalonia.Data.IBinding e)
menu[!NativeMenuItem.IsEnabledProperty] = e;
subMenu.Add(menu);
}
});
menus.Add(new NativeMenuItem
{
Header = item.Value.Name,
+2 -1
View File
@@ -17,7 +17,8 @@
<spp:EnumEqualValueConverter x:Key="EnumEqualValueConverter" />
<spp:StringEqualsConverter x:Key="StringEqualsConverter" />
<spp:EnumLocalizationNameConverter x:Key="EnumLocalizationNameConverter" />
<spp:VisibleStringConverter x:Key="VisibleStringConverter" />
<spp:VisbleStringConverter x:Key="VisbleStringConverter" />
<spp:StringOmitConverter x:Key="StringOmitConverter" />
</Application.Resources>
<Application.Styles>
<sty:FluentAvaloniaTheme PreferSystemTheme="False" PreferUserAccentColor="True" />
+6 -38
View File
@@ -11,12 +11,6 @@ public sealed partial class App : Application
{
const string TAG = "AvaApp";
public App()
{
OpenBrowserCommand = ReactiveCommand.Create<object?>(OpenBrowserCommandCore);
CopyToClipboardCommand = ReactiveCommand.Create<object?>(CopyToClipboardCommandCore);
}
/// <summary>
/// 获取当前主窗口
/// </summary>
@@ -52,7 +46,6 @@ public sealed partial class App : Application
#if WINDOWS || LINUX || MACOS
if (GeneralSettings.MinimizeOnStartup.Value)
Startup.Instance.IsMinimize = true;
if (Startup.Instance.IsSteamRun)
{
try
@@ -100,23 +93,16 @@ public sealed partial class App : Application
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
MainWindow = InitializeMainWindow?.Invoke(this) ?? new MainWindow();
desktop.MainWindow =
#if !UI_DEMO
Startup.Instance.IsMinimize && MainWindow is MainWindow ? null :
Startup.Instance.IsMinimize ? null :
#endif
MainWindow;
if (Startup.Instance.IsMinimize && MainWindow is AppWindow appWindow)
{
Task2.InBackground(() => appWindow.SplashScreen?.RunTasks(CancellationToken.None));
Task2.InBackground(() => appWindow.SplashScreen.RunTasks(CancellationToken.None));
}
IPlatformService.Instance.SetSystemSessionEnding(() =>
{
Log.Info("System Shutdown", "Application SafeExit...");
Shutdown();
});
}
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleView)
{
@@ -237,32 +223,16 @@ public sealed partial class App : Application
public static FontFamily DefaultFontFamily => _DefaultFontFamily.Value;
public ICommand OpenBrowserCommand { get; }
public async void OpenBrowserCommandCore(object? url)
public void OpenBrowserCommand(object url)
{
try
{
var urlString = url?.ToString();
if (string.IsNullOrEmpty(urlString))
if (url == null || string.IsNullOrEmpty(url.ToString()))
{
Toast.Show(ToastIcon.Warning, "打开链接失败");
return;
}
try
{
Uri uri = new(urlString);
if (uri.Host.EndsWith("steampp.net", StringComparison.OrdinalIgnoreCase) ||
uri.Host.EndsWith("mossimo.net", StringComparison.OrdinalIgnoreCase))
{
await UserService.Current.OpenAuthUrl(urlString);
return;
}
}
catch
{
}
Browser2.Open(urlString);
Browser2.Open(url.ToString());
}
catch (Exception ex)
{
@@ -270,9 +240,7 @@ public sealed partial class App : Application
}
}
public ICommand CopyToClipboardCommand { get; }
public async void CopyToClipboardCommandCore(object? text)
public async void CopyToClipboardCommand(object text)
{
try
{
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

@@ -1,21 +1,21 @@
<Styles
xmlns="https://github.com/avaloniaui"
xmlns:spp="https://steampp.net/ui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ms="https://steampp.net/settings"
xmlns:sys="using:System"
x:CompileBindings="True">
<Styles.Resources>
<ResourceDictionary>
<sys:Double x:Key="TitleBarHeight">50</sys:Double>
<Thickness x:Key="TitleBarAfterMargin">0,50,0,0</Thickness>
<sys:Double x:Key="TitleBarHeight">60</sys:Double>
<Thickness x:Key="TitleBarAfterMargin">0,60,0,0</Thickness>
<sys:Double x:Key="SplashScreenImageWidth">100</sys:Double>
<Thickness x:Key="PageMargin">10</Thickness>
<sys:Double x:Key="SettingsSpacing">3</sys:Double>
<sys:Char x:Key="PasswordChar">&#x25CF;</sys:Char>
<!--<sys:Char x:Key="PasswordChar">•</sys:Char>
<sys:Char x:Key="PasswordChar">·</sys:Char>-->
<!--<sys:Char x:Key="PasswordChar">&#x25CF;</sys:Char>-->
<sys:Char x:Key="PasswordChar">•</sys:Char>
<FontFamily x:Key="ContentControlThemeFontFamily">Null</FontFamily>
<BoxShadows x:Key="InfoBoxShadow">4 4 32 0 #66000000</BoxShadows>
@@ -45,7 +45,6 @@
<StyleInclude Source="/UI/Styling/InfoBox.axaml" />
<StyleInclude Source="/UI/Styling/Controls/PageBase.axaml" />
<StyleInclude Source="/UI/Styling/Controls/CarouselItems.axaml" />
<StyleInclude Source="/UI/Styling/Controls/OptionsDisplayItem.axaml" />
<StyleInclude Source="/UI/Styling/Controls/RippleEffect.axaml" />
<StyleInclude Source="/UI/Styling/Controls/Draggable.axaml" />
@@ -66,7 +65,6 @@
<StyleInclude Source="/UI/Styling/Controls/IconElement.axaml" />
<StyleInclude Source="/UI/Styling/Controls/CustomFilePicker.axaml" />
<StyleInclude Source="/UI/Styling/Controls/NumericUpDown.axaml" />
<StyleInclude Source="/UI/Styling/Controls/Skeleton.axaml" />
<Style Selector="FlyoutPresenter.NoPadding">
<Setter Property="Padding" Value="0" />
@@ -65,7 +65,7 @@
</spp:AppItem>
<spp:AppItem
Title="Wo Long: Fallen Dynasty (卧龙:苍天陨落)(卧龙:苍天陨落)(卧龙:苍天陨落)(卧龙:苍天陨落)"
Title="Wo Long: Fallen Dynasty (卧龙:苍天陨落)"
MaxHeight="120"
Description="This is a description of whatver this does"
Tags="111">
@@ -180,8 +180,7 @@
<TextBlock
Grid.Row="2"
Grid.Column="1"
Grid.ColumnSpan="2"
Margin="0,5,12,5"
Margin="0,5"
VerticalAlignment="Top"
Classes="CaptionTextBlockStyle"
FontSize="12"
@@ -1,5 +1,6 @@
<Styles
xmlns="https://github.com/avaloniaui"
xmlns:spp="https://steampp.net/ui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="https://steampp.net/services"
x:CompileBindings="True">
@@ -16,7 +17,7 @@
<!-- AutoCompleteBox -->
<Style Selector="AutoCompleteBox.Search /template/ TextBox#PART_TextBox">
<Setter Property="Watermark" Value="{Binding Path=Res.Search, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<Setter Property="Watermark" Value="{ReflectionBinding Path=Res.Search, Mode=OneWay, Source={x:Static spp:Strings.Search}}" />
<Setter Property="InnerRightContent">
<Template>
<StackPanel Orientation="Horizontal">
@@ -1,5 +1,6 @@
<Styles
xmlns="https://github.com/avaloniaui"
xmlns:spp="https://steampp.net/ui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:CompileBindings="True">
<Design.PreviewWith>
@@ -1,5 +1,6 @@
<Styles
xmlns="https://github.com/avaloniaui"
xmlns:spp="https://steampp.net/ui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="using:FluentAvalonia.UI.Controls"
x:CompileBindings="True">
@@ -7,13 +8,8 @@
<Border Padding="20">
<!-- Add Controls for Previewer Here -->
<StackPanel Spacing="10">
<HyperlinkButton Content="更新日志" />
<ui:HyperlinkButton Content="更新日志" />
<Button Content="更新日志" Theme="{StaticResource HyperlinkButton}" />
<Button Classes="TransparentAccent" Content="更新日志" />
<Button
Classes="TransparentAccent"
Content="更新日志"
IsEnabled="False" />
<Button
Content="更新日志"
IsEnabled="False"
@@ -92,7 +88,7 @@
<Setter Property="CornerRadius" Value="{DynamicResource ControlCornerRadius}" />
<Setter Property="Template">
<ControlTemplate>
<Border
<ui:FABorder
Name="Root"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
@@ -106,19 +102,19 @@
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
RecognizesAccessKey="True" />
</Border>
</ui:FABorder>
</ControlTemplate>
</Setter>
<Style Selector="^:pointerover">
<Style Selector="^ /template/ Border#Root">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorSecondaryBrush}" />
</Style>
</Style>
<Style Selector="^:pressed">
<Style Selector="^ /template/ Border#Root">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorTertiaryBrush}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -127,7 +123,7 @@
</Style>
<Style Selector="^:disabled">
<Style Selector="^ /template/ Border#Root">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorDisabledBrush}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -136,7 +132,7 @@
</Style>
<Style Selector="^:checked">
<Style Selector="^ /template/ Border#Root">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundChecked}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -145,7 +141,7 @@
<Style Selector="^:pointerover">
<Style Selector="^ /template/ Border#Root">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundCheckedPointerOver}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -154,7 +150,7 @@
</Style>
<Style Selector="^:pressed">
<Style Selector="^ /template/ Border#Root">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundCheckedPressed}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -163,7 +159,7 @@
</Style>
<Style Selector="^:disabled">
<Style Selector="^ /template/ Border#Root">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorDisabledBrush}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -173,19 +169,19 @@
</Style>
<Style Selector="^:indeterminate">
<Style Selector="^ /template/ Border#Root">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorTransparentBrush}" />
</Style>
<Style Selector="^:pointerover">
<Style Selector="^ /template/ Border#Root">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorSecondaryBrush}" />
</Style>
</Style>
<Style Selector="^:pressed">
<Style Selector="^ /template/ Border#Root">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorTertiaryBrush}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -194,7 +190,7 @@
</Style>
<Style Selector="^:disabled">
<Style Selector="^ /template/ Border#Root">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorDisabledBrush}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -219,22 +215,10 @@
<Style Selector="Button.Plain:pointerover">
<Setter Property="Background" Value="Transparent" />
</Style>
<Style Selector="Button.Plain:pointerover /template/ Border#Root">
<Style Selector="Button.Plain:pointerover /template/ ui|FABorder#Root">
<Setter Property="Background" Value="Transparent" />
</Style>
<Style Selector="Button.Plain:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="Transparent" />
</Style>
<Style Selector="Button.TransparentAccent /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource HyperlinkButtonForeground}" />
</Style>
<Style Selector="Button.TransparentAccent:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource HyperlinkButtonForegroundPointerOver}" />
</Style>
<Style Selector="Button.TransparentAccent:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource HyperlinkButtonForegroundPressed}" />
</Style>
</Styles>
@@ -1,5 +1,6 @@
<Styles
xmlns="https://github.com/avaloniaui"
xmlns:spp="https://steampp.net/ui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:CompileBindings="True">
<Design.PreviewWith>
@@ -1,111 +0,0 @@
<Styles
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:generic="using:System.Collections.Generic"
xmlns:spp="https://steampp.net/ui"
xmlns:sys="using:System"
xmlns:ui="using:FluentAvalonia.UI.Controls"
x:CompileBindings="True">
<Design.PreviewWith>
<Border Padding="20">
<spp:CarouselItems>
<spp:CarouselItems.Items>
<Border Background="Red" />
<Border Background="Blue" />
<Border Background="Black" />
<Border Background="Yellow" />
</spp:CarouselItems.Items>
</spp:CarouselItems>
</Border>
</Design.PreviewWith>
<Style Selector="spp|CarouselItems">
<Setter Property="Template">
<ControlTemplate>
<Border
BorderBrush="{DynamicResource CardStrokeColorDefaultBrush}"
BorderThickness="0"
ClipToBounds="True"
CornerRadius="8">
<Grid RowDefinitions="*,5,Auto">
<Carousel Name="CarouselControl" Classes="AnimeSlide">
<Carousel.ItemTemplate>
<DataTemplate DataType="sys:Object">
<ItemsControl ItemTemplate="{Binding $parent[spp:CarouselItems].ItemTemplate}" ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<spp:FixedWrapPanel ItemsPerLine="{Binding $parent[spp:CarouselItems].ItemsPerPage}" Spacing="5" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</Carousel.ItemTemplate>
</Carousel>
<Button
Name="Left"
HorizontalAlignment="Left"
Background="#80000000"
Classes="action"
IsVisible="False">
<ui:SymbolIcon FontSize="18" Symbol="ChevronLeft" />
</Button>
<Button
Name="Right"
HorizontalAlignment="Right"
Background="#80000000"
Classes="action"
IsVisible="False">
<ui:SymbolIcon FontSize="18" Symbol="ChevronRight" />
</Button>
<Panel
Grid.Row="2"
Height="10"
HorizontalAlignment="Center"
VerticalAlignment="Bottom">
<ItemsControl Name="Swiper" IsVisible="False">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Spacing="8" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataTemplate.DataType>
<x:Type x:TypeArguments="x:Int32, x:String" TypeName="generic:KeyValuePair" />
</DataTemplate.DataType>
<Button
Padding="0"
Classes="Plain"
Command="{Binding $parent[spp:CarouselItems].CarouselBannerIndexCommand}"
CommandParameter="{Binding Key}">
<Ellipse
Name="IndexEllipse"
Width="10"
Height="10"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Fill="{Binding Value}"
Opacity="0.6"
StrokeThickness="0" />
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Panel>
</Grid>
</Border>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="spp|CarouselItems /template/ Button.action">
<Setter Property="Width" Value="36" />
<Setter Property="Height" Value="64" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Foreground" Value="White" />
</Style>
</Styles>
@@ -18,15 +18,27 @@
HorizontalAlignment="Center"
VerticalAlignment="Center"
IsVisible="{TemplateBinding IsLoading}"
Spacing="10">
<!--<spp:Image2
Spacing="8">
<spp:Image2
Width="100"
Height="100"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
RenderOptions.BitmapInterpolationMode="HighQuality"
Source="avares://BD.WTTS.Client.Avalonia/UI/Assets/mona-loading-default.gif"
Stretch="UniformToFill" />-->
Stretch="UniformToFill" />
<TextBlock
HorizontalAlignment="Center"
Text="{Binding Path=Res.GameList_IsLoading, Mode=OneWay, Source={x:Static spp:Strings.GameList_IsLoading}}"
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"
@@ -39,18 +51,6 @@
Minimum="{TemplateBinding Minimum}"
Value="{TemplateBinding ProgressValue}" />
</Border>
<TextBlock
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}" />
</StackPanel>
<!--<TextBlock
@@ -75,34 +75,21 @@
</ContentPresenter.IsVisible>-->
</ContentPresenter>
<Panel HorizontalAlignment="Center" VerticalAlignment="Center">
<spp:Image2
Width="100"
Height="100"
Margin="0,0,0,120"
HorizontalAlignment="Center"
VerticalAlignment="Center"
RenderOptions.BitmapInterpolationMode="HighQuality"
Source="avares://BD.WTTS.Client.Avalonia/UI/Assets/Icons/empty.png"
Stretch="UniformToFill" />
<Panel.IsVisible>
<ContentPresenter
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{TemplateBinding NoResultMessage}"
Foreground="{TemplateBinding Foreground}"
Theme="{StaticResource SubtitleTextBlockStyle}">
<ContentPresenter.IsVisible>
<MultiBinding Converter="{x:Static BoolConverters.And}">
<Binding Path="IsShowNoResultText" RelativeSource="{RelativeSource TemplatedParent}" />
<Binding Path="!IsLoading" RelativeSource="{RelativeSource TemplatedParent}" />
</MultiBinding>
</Panel.IsVisible>
<ContentPresenter
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{TemplateBinding NoResultMessage}"
Foreground="{TemplateBinding Foreground}"
Theme="{StaticResource SubtitleTextBlockStyle}" />
</Panel>
</ContentPresenter.IsVisible>
</ContentPresenter>
</Panel>
</ControlTemplate>
</Setter>
<Style Selector="^:loading /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Effect" Value="blur(5)" />
</Style>
</ControlTheme>
</ResourceDictionary>
@@ -39,8 +39,8 @@
ContentTemplate="{TemplateBinding ContentTemplate}" />
<Panel
Name="FilePickerTipBorder"
MaxWidth="{Binding $parent.Bounds.Width}"
MaxHeight="{Binding $parent.Bounds.Height}">
MaxWidth="{ReflectionBinding $parent.Bounds.Width}"
MaxHeight="{ReflectionBinding $parent.Bounds.Height}">
<Border Background="{DynamicResource ControlOnImageFillColorSecondaryBrush}" Opacity="0.8">
<StackPanel
Margin="10,5"
@@ -49,7 +49,9 @@
<ui:SymbolIcon FontSize="30" Symbol="Download" />
<TextBlock
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
Text="{Binding Path=Res.CustomFilePicker_Tip, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
Text="{ReflectionBinding Path=Res.CustomFilePicker_Tip,
Mode=OneWay,
Source={x:Static spp:Strings.CustomFilePicker_Tip}}"
TextAlignment="Center"
Theme="{StaticResource BodyStrongTextBlockStyle}" />
</StackPanel>
@@ -74,4 +76,4 @@
<Style Selector="spp|CustomFilePicker:pointerover /template/ Panel#FilePickerTipBorder">
<Setter Property="IsVisible" Value="True" />
</Style>
</Styles>
</Styles>
@@ -1,5 +1,6 @@
<Styles
xmlns="https://github.com/avaloniaui"
xmlns:spp="https://steampp.net/ui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:CompileBindings="True">
<Design.PreviewWith>
@@ -1,5 +1,6 @@
<Styles
xmlns="https://github.com/avaloniaui"
xmlns:spp="https://steampp.net/ui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="using:FluentAvalonia.UI.Controls"
x:CompileBindings="True">
@@ -1,5 +1,6 @@
<Styles
xmlns="https://github.com/avaloniaui"
xmlns:spp="https://steampp.net/ui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:CompileBindings="True">
<Design.PreviewWith>
@@ -46,23 +46,25 @@
<Setter Property="Template">
<ControlTemplate>
<StackPanel>
<Border
<ui:FABorder
Name="LayoutRoot"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Border.Transitions>
<ui:FABorder.Transitions>
<Transitions>
<BrushTransition Property="Background" Duration="00:00:00.083" />
<BrushTransition Property="BorderBrush" Duration="00:00:00.083" />
</Transitions>
</Border.Transitions>
<Grid MinHeight="{TemplateBinding MinHeight}" ColumnDefinitions="Auto,*,Auto,Auto">
</ui:FABorder.Transitions>
<Grid
MinHeight="{TemplateBinding MinHeight}"
ColumnDefinitions="Auto,*,Auto,Auto"
RowDefinitions="*,Auto">
<Viewbox
Name="IconHost"
Grid.RowSpan="2"
Width="{DynamicResource SettingsExpanderItemIconSize}"
Height="{DynamicResource SettingsExpanderItemIconSize}"
HorizontalAlignment="Left"
@@ -74,31 +76,28 @@
Margin="{DynamicResource SettingsExpanderItemContentMargin}"
HorizontalAlignment="Left"
VerticalAlignment="Center">
<ContentPresenter
<TextBlock
Name="HeaderText"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Classes="BaseTextBlockStyle"
Content="{TemplateBinding Header}"
Text="{TemplateBinding Header}"
TextTrimming="CharacterEllipsis" />
<ContentPresenter
HorizontalAlignment="Stretch"
<TextBlock
VerticalAlignment="Top"
HorizontalContentAlignment="Stretch"
Classes="CaptionTextBlockStyle"
Content="{TemplateBinding Description}"
FontSize="12"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
IsVisible="{TemplateBinding Description,
Converter={StaticResource IsNullConverter},
ConverterParameter=invert}"
Text="{TemplateBinding Description}"
TextWrapping="Wrap" />
</StackPanel>
<ContentPresenter
Name="ActionButton"
Grid.RowSpan="2"
Grid.Column="2"
Margin="{DynamicResource SettingsExpanderItemFooterMargin}"
HorizontalAlignment="Right"
@@ -107,13 +106,12 @@
<ui:SymbolIcon
Name="Chevron"
Grid.RowSpan="2"
Grid.Column="3"
Margin="24,4,0,4"
VerticalAlignment="Center"
FontSize="18" />
</Grid>
</Border>
</ui:FABorder>
<ContentPresenter
Name="ExpandedContentPresenter"
@@ -144,10 +142,10 @@
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="spp|OptionsDisplayItem /template/ Border#LayoutRoot:pointerover">
<Style Selector="spp|OptionsDisplayItem /template/ ui|FABorder#LayoutRoot:pointerover">
<Setter Property="Background" Value="{DynamicResource ControlFillColorSecondaryBrush}" />
</Style>
<Style Selector="spp|OptionsDisplayItem:pressed /template/ Border#LayoutRoot:pointerover">
<Style Selector="spp|OptionsDisplayItem:pressed /template/ ui|FABorder#LayoutRoot:pointerover">
<Setter Property="Background" Value="{DynamicResource ControlFillColorTertiaryBrush}" />
</Style>
@@ -179,7 +177,7 @@
<Setter Property="CornerRadius" Value="{Binding CornerRadius, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BottomCornerRadiusFilterConverter}}" />
</Style>
<Style Selector="spp|OptionsDisplayItem:expanded /template/ Border#LayoutRoot">
<Style Selector="spp|OptionsDisplayItem:expanded /template/ ui|FABorder#LayoutRoot">
<Setter Property="CornerRadius" Value="{Binding CornerRadius, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource TopCornerRadiusFilterConverter}}" />
</Style>
@@ -195,19 +193,19 @@
<Style Selector="spp|OptionsDisplayItem.Vertical">
<Setter Property="Template">
<ControlTemplate>
<Border
<ui:FABorder
Name="LayoutRoot"
Padding="12"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Border.Transitions>
<ui:FABorder.Transitions>
<Transitions>
<BrushTransition Property="Background" Duration="00:00:00.083" />
<BrushTransition Property="BorderBrush" Duration="00:00:00.083" />
</Transitions>
</Border.Transitions>
</ui:FABorder.Transitions>
<Grid RowDefinitions="*,*">
<Border
Width="72"
@@ -241,7 +239,7 @@
TextWrapping="Wrap" />
</StackPanel>
</Grid>
</Border>
</ui:FABorder>
</ControlTemplate>
</Setter>
</Style>
@@ -97,7 +97,7 @@
</Design.PreviewWith>
<Styles.Resources>
<Thickness x:Key="AppPageMargin">20,10,20,20</Thickness>
<Thickness x:Key="AppPageMargin">20</Thickness>
</Styles.Resources>
<Style Selector="spp|PageBase">
@@ -313,7 +313,7 @@
<Setter Property="Grid.Row" Value="2" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="Margin" Value="0 12 0 0" />
<Setter Property="Margin" Value="0 12" />
</Style>
<Style Selector="^ /template/ Panel#PageDetails">
@@ -86,4 +86,4 @@
</Transitions>
</Setter>
</Style>
</Styles>
</Styles>
@@ -1,5 +1,6 @@
<Styles
xmlns="https://github.com/avaloniaui"
xmlns:spp="https://steampp.net/ui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:CompileBindings="True">
<Design.PreviewWith>
@@ -1,5 +1,6 @@
<ResourceDictionary
xmlns="https://github.com/avaloniaui"
xmlns:spp="https://steampp.net/ui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="using:FluentAvalonia.UI.Controls"
x:CompileBindings="True">
@@ -38,18 +39,18 @@
<Setter Property="MinHeight" Value="{DynamicResource SettingsExpanderItemMinHeight}" />
<Setter Property="Template">
<ControlTemplate>
<Border
<ui:FABorder
Name="Root"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Border.Transitions>
<ui:FABorder.Transitions>
<Transitions>
<BrushTransition Property="Background" Duration="00:00:00.083" />
<BrushTransition Property="BorderBrush" Duration="00:00:00.083" />
</Transitions>
</Border.Transitions>
</ui:FABorder.Transitions>
<Grid ColumnDefinitions="*,Auto,Auto" RowDefinitions="*,Auto">
<Viewbox
@@ -102,7 +103,7 @@
<ContentPresenter Name="ExpandChevronActionIconContainer" Content="{Binding TemplateSettings.ActionIcon, RelativeSource={RelativeSource TemplatedParent}}" />
</Viewbox>
</Grid>
</Border>
</ui:FABorder>
</ControlTemplate>
</Setter>
@@ -110,7 +111,7 @@
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^:nth-last-child(1) /template/ Border#Root">
<Style Selector="^:nth-last-child(1) /template/ ui|FABorder#Root">
<Setter Property="CornerRadius" Value="{Binding Source={StaticResource ControlCornerRadius}, Converter={StaticResource BottomCornerRadiusFilterConverter}}" />
</Style>
@@ -152,11 +153,11 @@
</Style>
<Style Selector="^:allowClick">
<Style Selector="^:pointerover /template/ Border#Root">
<Style Selector="^:pointerover /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource ControlFillColorSecondaryBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource ControlFillColorSecondaryBrush}" />
</Style>
<Style Selector="^:pressed /template/ Border#Root">
<Style Selector="^:pressed /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource ControlFillColorTertiaryBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource ControlStrokeColorDefaultBrush}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource TextFillColorSecondaryBrush}" />
@@ -164,7 +165,7 @@
</Style>
<Style Selector="^:disabled">
<Style Selector="^ /template/ Border#Root">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource ControlFillColorDisabledBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource ControlStrokeColorDefaultBrush}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource TextFillColorDisabledBrush}" />
@@ -1,111 +0,0 @@
<Styles
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:spp="https://steampp.net/ui"
x:CompileBindings="True">
<Design.PreviewWith>
<Border Padding="20">
<!-- Add Controls for Previewer Here -->
<StackPanel>
<ToggleSwitch Name="loading" Content="Loading" />
<ToggleSwitch Name="active" Content="Active" />
<Grid
MinWidth="400"
HorizontalAlignment="Left"
ColumnDefinitions="auto,*">
<spp:Skeleton
Width="100"
Height="100"
VerticalAlignment="Center"
CornerRadius="2"
IsActive="{Binding #active.IsChecked}"
IsLoading="{Binding #loading.IsChecked}">
<Image RenderOptions.BitmapInterpolationMode="HighQuality" Source="avares://BD.WTTS.Client.Avalonia/UI/Assets/ApplicationIcon.ico" />
</spp:Skeleton>
<UniformGrid
Grid.Column="1"
Margin="5,0"
Columns="1"
Rows="3">
<spp:Skeleton
Margin="0,0,200,0"
VerticalAlignment="Top"
CornerRadius="2"
IsActive="{Binding #active.IsChecked}"
IsLoading="{Binding #loading.IsChecked}">
<SelectableTextBlock Margin="0,2" Text="是先有鸡还是先有蛋" />
</spp:Skeleton>
<spp:Skeleton
Margin="0,0,100,0"
VerticalAlignment="Center"
CornerRadius="2"
IsActive="{Binding #active.IsChecked}"
IsLoading="{Binding #loading.IsChecked}">
<SelectableTextBlock Margin="0,2" Text="什么是工匠精神" />
</spp:Skeleton>
<spp:Skeleton
VerticalAlignment="Bottom"
CornerRadius="2"
IsActive="{Binding #active.IsChecked}"
IsLoading="{Binding #loading.IsChecked}">
<SelectableTextBlock Margin="0,2" Text="看山不是山,看水不是水,看山还是山,看水还是水" />
</spp:Skeleton>
</UniformGrid>
</Grid>
</StackPanel>
</Border>
</Design.PreviewWith>
<Styles.Resources>
<ControlTheme x:Key="{x:Type spp:Skeleton}" TargetType="spp:Skeleton">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<ControlTemplate TargetType="spp:Skeleton">
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
ClipToBounds="{TemplateBinding ClipToBounds}"
CornerRadius="{TemplateBinding CornerRadius}">
<Panel>
<ContentPresenter
x:Name="PART_ContentPresenter"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}" />
<spp:PureRectangle
x:Name="PART_LoadingBorder"
Background="{DynamicResource SkeletonDefaultBackground}"
Classes.Active="{Binding Path=IsActive, RelativeSource={RelativeSource TemplatedParent}}"
IsHitTestVisible="{TemplateBinding IsLoading}"
IsVisible="{TemplateBinding IsLoading}" />
<spp:PureRectangle
x:Name="PART_ActiveBorder"
IsHitTestVisible="{TemplateBinding IsLoading}"
IsVisible="{TemplateBinding IsLoading}" />
</Panel>
</Border>
</ControlTemplate>
</Setter>
</ControlTheme>
</Styles.Resources>
<Style Selector="spp|Skeleton[IsActive=True][IsLoading=True] /template/ spp|PureRectangle#PART_ActiveBorder">
<Style.Animations>
<Animation
Easing="CubicEaseInOut"
FillMode="None"
IterationCount="Infinite"
PlaybackDirection="Alternate"
Duration="0:0:1.4">
<KeyFrame Cue="0%">
<Setter Property="Background" Value="{DynamicResource SkeletonStartAnimationBackground}" />
</KeyFrame>
<KeyFrame Cue="100%">
<Setter Property="Background" Value="{DynamicResource SkeletonEndAnimationBackground}" />
</KeyFrame>
</Animation>
</Style.Animations>
</Style>
</Styles>
@@ -95,7 +95,7 @@
<Setter Property="Template">
<ControlTemplate>
<LayoutTransformControl Name="PART_LayoutTransformControl" UseRenderTransform="True">
<Border
<ui:FABorder
Name="ContentRoot"
VerticalAlignment="Top"
BorderBrush="{DynamicResource InfoBarBorderBrush}"
@@ -205,13 +205,13 @@
</Button>
</Grid>
</Panel>
</Border>
</ui:FABorder>
</LayoutTransformControl>
</ControlTemplate>
</Setter>
<Style Selector="^:informational">
<Style Selector="^ /template/ Border#ContentRoot">
<Style Selector="^ /template/ ui|FABorder#ContentRoot">
<!--<Setter Property="Background" Value="{DynamicResource InfoBarInformationalSeverityBackgroundBrush}" />-->
<Setter Property="Background" Value="{DynamicResource SolidBackgroundFillColorBaseBrush}" />
</Style>
@@ -226,7 +226,7 @@
</Style>
<Style Selector="^:error">
<Style Selector="^ /template/ Border#ContentRoot">
<Style Selector="^ /template/ ui|FABorder#ContentRoot">
<Setter Property="Background" Value="{DynamicResource InfoBarErrorSeverityBackgroundBrush}" />
</Style>
<Style Selector="^ /template/ Ellipse#IconBackground">
@@ -241,7 +241,7 @@
</Style>
<Style Selector="^:warning">
<Style Selector="^ /template/ Border#ContentRoot">
<Style Selector="^ /template/ ui|FABorder#ContentRoot">
<Setter Property="Background" Value="{DynamicResource InfoBarWarningSeverityBackgroundBrush}" />
</Style>
<Style Selector="^ /template/ Ellipse#IconBackground">
@@ -255,7 +255,7 @@
</Style>
<Style Selector="^:success">
<Style Selector="^ /template/ Border#ContentRoot">
<Style Selector="^ /template/ ui|FABorder#ContentRoot">
<Setter Property="Background" Value="{DynamicResource InfoBarSuccessSeverityBackgroundBrush}" />
</Style>
<Style Selector="^ /template/ Ellipse#IconBackground">
@@ -294,7 +294,7 @@
</Style>
<!-- Visible -->
<Style Selector="^:hidden /template/ Border#ContentRoot">
<Style Selector="^:hidden /template/ ui|FABorder#ContentRoot">
<Setter Property="IsVisible" Value="False" />
</Style>
@@ -1,5 +1,6 @@
<Styles
xmlns="https://github.com/avaloniaui"
xmlns:spp="https://steampp.net/ui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:CompileBindings="True">
<Design.PreviewWith>
@@ -75,7 +75,7 @@
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="Template">
<ControlTemplate>
<Border
<ui:FABorder
Name="Root"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
Background="{TemplateBinding Background}"
@@ -83,19 +83,19 @@
BorderThickness="1"
CornerRadius="{TemplateBinding CornerRadius}"
TemplatedControl.IsTemplateFocusTarget="True">
<Border.Transitions>
<ui:FABorder.Transitions>
<Transitions>
<BrushTransition Property="Background" Duration="00:00:00.083" />
</Transitions>
</Border.Transitions>
</ui:FABorder.Transitions>
<Panel>
<Border
<ui:FABorder
Name="Hover"
Margin="3"
Background="Transparent"
CornerRadius="{TemplateBinding CornerRadius}">
<Border.Transitions>
<ui:FABorder.Transitions>
<Transitions>
<BrushTransition Property="Background" Duration="00:00:00.083" />
<TransformOperationsTransition
@@ -103,8 +103,8 @@
Property="RenderTransform"
Duration="00:00:00.167" />
</Transitions>
</Border.Transitions>
</Border>
</ui:FABorder.Transitions>
</ui:FABorder>
<ContentPresenter
Name="PART_ContentPresenter"
@@ -139,19 +139,19 @@
</Rectangle>
</Panel>
</Border>
</ui:FABorder>
</ControlTemplate>
</Setter>
<Style Selector="^:pointerover">
<Style Selector="^ /template/ Border#Hover">
<Style Selector="^ /template/ ui|FABorder#Hover">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorSecondaryBrush}" />
</Style>
</Style>
<Style Selector="^:pressed">
<Style Selector="^ /template/ Border#Hover">
<Style Selector="^ /template/ ui|FABorder#Hover">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorTertiaryBrush}" />
<Setter Property="RenderTransform" Value="scale(0.96)" />
</Style>
@@ -161,10 +161,10 @@
</Style>
<Style Selector="^:selected">
<Style Selector="^ /template/ Border#Hover">
<Style Selector="^ /template/ ui|FABorder#Hover">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^ /template/ Border#Root">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource ControlFillColorDefaultBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource ControlElevationBorderBrush}" />
</Style>
@@ -181,10 +181,10 @@
</Style>
<Style Selector="^:disabled">
<Style Selector="^ /template/ Border#Hover">
<Style Selector="^ /template/ ui|FABorder#Hover">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^ /template/ Border#Root">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource ControlFillColorDisabledBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource ControlAltFillColorSecondaryBrush}" />
</Style>
@@ -1,5 +1,6 @@
<Styles
xmlns="https://github.com/avaloniaui"
xmlns:spp="https://steampp.net/ui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="using:FluentAvalonia.UI.Controls"
xmlns:uip="using:FluentAvalonia.UI.Controls.Primitives"
@@ -80,7 +80,7 @@
<Setter Property="Template">
<ControlTemplate>
<Panel Name="LayoutRoot" Background="{x:Null}">
<Border
<ui:FABorder
Name="ContentRoot"
MinWidth="{DynamicResource TaskDialogMinWidth}"
MinHeight="{DynamicResource TaskDialogMinHeight}"
@@ -216,7 +216,7 @@
</ItemsControl>
</Border>
</Grid>
</Border>
</ui:FABorder>
</Panel>
</ControlTemplate>
</Setter>
@@ -303,7 +303,7 @@
<Style Selector="^ /template/ Panel#LayoutRoot">
<Setter Property="Background" Value="{DynamicResource TaskDialogSmokeFill}" />
</Style>
<Style Selector="^ /template/ Border#ContentRoot">
<Style Selector="^ /template/ ui|FABorder#ContentRoot">
<Setter Property="BorderBrush" Value="{DynamicResource TaskDialogBorderBrush}" />
<Setter Property="CornerRadius" Value="{DynamicResource OverlayCornerRadius}" />
<Setter Property="BorderThickness" Value="{DynamicResource TaskDialogBorderWidth}" />
@@ -332,7 +332,7 @@
</Animation>
</Style.Animations>
</Style>
<Style Selector="^:hidden /template/ Border#ContentRoot">
<Style Selector="^:hidden /template/ ui|FABorder#ContentRoot">
<Style.Animations>
<Animation FillMode="Forward" Duration="00:00:00.167">
<KeyFrame Cue="0%">
@@ -368,7 +368,7 @@
</Animation>
</Style.Animations>
</Style>
<Style Selector="^:open /template/ Border#ContentRoot">
<Style Selector="^:open /template/ ui|FABorder#ContentRoot">
<Style.Animations>
<Animation FillMode="Forward" Duration="00:00:00.250">
<KeyFrame Cue="0%">
@@ -389,7 +389,7 @@
<Setter Property="Template">
<ControlTemplate>
<Panel Name="LayoutRoot" Background="{x:Null}">
<Border
<ui:FABorder
Name="ContentRoot"
MinWidth="{DynamicResource TaskDialogMinWidth}"
MinHeight="{DynamicResource TaskDialogMinHeight}"
@@ -521,7 +521,7 @@
</ItemsControl>
</Border>
</Grid>
</Border>
</ui:FABorder>
</Panel>
</ControlTemplate>
</Setter>
@@ -1,5 +1,6 @@
<ResourceDictionary
xmlns="https://github.com/avaloniaui"
xmlns:spp="https://steampp.net/ui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ms="https://steampp.net/settings"
x:CompileBindings="True">
@@ -1,5 +1,6 @@
<Styles
xmlns="https://github.com/avaloniaui"
xmlns:spp="https://steampp.net/ui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="https://steampp.net/services"
xmlns:ui="using:FluentAvalonia.UI.Controls"
@@ -27,26 +28,26 @@
<MenuItem
x:Name="TextBoxContextMenuCutItem"
Command="{Binding $parent[TextBox].Cut}"
Header="{Binding Path=Res.Cut, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
Header="{Binding Path=Res.Cut, Mode=OneWay, Source={x:Static spp:Strings.Cut}}"
InputGesture="{x:Static TextBox.CutGesture}"
IsEnabled="{Binding $parent[TextBox].CanCut}" />
<MenuItem
x:Name="TextBoxContextMenuCopyItem"
Command="{Binding $parent[TextBox].Copy}"
Header="{Binding Path=Res.Copy, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
Header="{Binding Path=Res.Copy, Mode=OneWay, Source={x:Static spp:Strings.Copy}}"
InputGesture="{x:Static TextBox.CopyGesture}"
IsEnabled="{Binding $parent[TextBox].CanCopy}" />
<MenuItem
x:Name="TextBoxContextMenuPasteItem"
Command="{Binding $parent[TextBox].Paste}"
Header="{Binding Path=Res.Paste, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
Header="{Binding Path=Res.Paste, Mode=OneWay, Source={x:Static spp:Strings.Paste}}"
InputGesture="{x:Static TextBox.PasteGesture}"
IsEnabled="{Binding $parent[TextBox].CanPaste}" />
<MenuItem Header="-" />
<MenuItem
x:Name="TextBoxContextMenuSelectAllItem"
Command="{Binding $parent[TextBox].SelectAll}"
Header="{Binding Path=Res.SelectAll, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
Header="{Binding Path=Res.SelectAll, Mode=OneWay, Source={x:Static spp:Strings.SelectAll}}"
InputGesture="Ctrl + A"
IsEnabled="{Binding $parent[TextBox].Text, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}" />
</MenuFlyout>
@@ -1,5 +1,6 @@
<Styles
xmlns="https://github.com/avaloniaui"
xmlns:spp="https://steampp.net/ui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="https://steampp.net/services"
xmlns:ui="using:FluentAvalonia.UI.Controls"
@@ -296,8 +297,8 @@
</Styles.Resources>
<Style Selector="ToggleSwitch">
<Setter Property="OffContent" Value="{Binding Path=Res.Off, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<Setter Property="OnContent" Value="{Binding Path=Res.On, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<Setter Property="OffContent" Value="{ReflectionBinding Path=Res.Off, Mode=OneWay, Source={x:Static spp:Strings.Off}}" />
<Setter Property="OnContent" Value="{ReflectionBinding Path=Res.On, Mode=OneWay, Source={x:Static spp:Strings.On}}" />
<Setter Property="MinWidth" Value="0" />
</Style>
@@ -1,5 +1,6 @@
<Styles
x:Class="BD.WTTS.UI.Styling.CustomTheme"
xmlns:spp="https://steampp.net/ui"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:CompileBindings="True">
@@ -14,5 +15,4 @@
</Styles.Resources>
<StyleInclude Source="/UI/Styling/Controls.axaml" />
<StyleInclude Source="avares://AvaloniaEdit/Themes/Fluent/AvaloniaEdit.xaml" />
</Styles>
@@ -1,5 +1,6 @@
<ResourceDictionary
xmlns="https://github.com/avaloniaui"
xmlns:spp="https://steampp.net/ui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="using:System"
xmlns:ui="https://steampp.net/ui"
@@ -1,5 +1,6 @@
<ResourceDictionary
xmlns="https://github.com/avaloniaui"
xmlns:spp="https://steampp.net/ui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="using:FluentAvalonia.UI.Controls"
x:CompileBindings="True">
@@ -38,7 +39,6 @@
<x:String x:Key="Back">&#xE112;</x:String>
<x:String x:Key="Sort">&#xE174;</x:String>
<x:String x:Key="Move">&#xE7C2;</x:String>
<x:String x:Key="Device">&#xE7FB;</x:String>
<ui:ImageIconSource x:Key="AppIcon" Source="avares://BD.WTTS.Client.Avalonia/UI/Assets/ApplicationIcon.ico" />
@@ -86,10 +86,4 @@
<StreamGeometry x:Key="Phone">
M15.75 2C16.9926 2 18 3.00736 18 4.25V19.75C18 20.9926 16.9926 22 15.75 22H8.25C7.00736 22 6 20.9926 6 19.75V4.25C6 3.00736 7.00736 2 8.25 2H15.75ZM13.25 18H10.75C10.3358 18 10 18.3358 10 18.75C10 19.1642 10.3358 19.5 10.75 19.5H13.25C13.6642 19.5 14 19.1642 14 18.75C14 18.3358 13.6642 18 13.25 18Z
</StreamGeometry>
<StreamGeometry x:Key="GOGGalaxy">
M304.99296 650.144H185.98496a17.12 17.12 0 0 0-16.992 17.184v85.344c0 8.992 7.68 16.992 16.992 16.992h119.52v56.32H156.16096a43.84 43.84 0 0 1-43.488-44v-144.512c0-23.968 19.68-43.488 44-43.488h148.32z m43.168-157.824c0 24.832-20 44.832-44.832 44.832H112.19296v-57.696h161.312a16.896 16.896 0 0 0 17.024-16.992V272.64a17.024 17.024 0 0 0-17.024-17.184H187.36096a17.152 17.152 0 0 0-17.536 17.184v86.144c0 9.856 7.68 17.024 17.024 17.024H256.00096v57.632H157.02496a44.544 44.544 0 0 1-44.832-44.32V242.304c0-24.352 20.192-44.32 44.832-44.32H303.04096c24.672 0 44.64 19.968 44.64 44.32v249.984z m563.168 333.664h-56.32v-175.84h-39.68a17.12 17.12 0 0 0-16.992 17.184v158.624h-56.832v-175.84h-39.68a17.12 17.12 0 0 0-16.992 17.184v158.624h-56.832v-188.512c0-23.968 19.68-43.488 44-43.488h239.328z m0.512-333.664c0 24.832-20.192 44.832-44.832 44.832h-191.136v-57.696h161.312a16.96 16.96 0 0 0 17.024-16.992V272.64a17.12 17.12 0 0 0-17.024-17.184h-86.656a17.024 17.024 0 0 0-17.024 17.184v86.144c0 9.856 7.68 17.024 17.024 17.024h69.152v57.632h-98.688a44.352 44.352 0 0 1-44.64-44.32V242.304c0-24.352 19.968-44.32 44.64-44.32h146.336c24.832 0 44.832 19.968 44.832 44.32v249.984zM585.34496 198.016h-146.688c-24.832 0-44.512 19.968-44.512 44.32v146.816a44.16 44.16 0 0 0 44.512 44.32h146.688a44.48 44.48 0 0 0 44.512-44.32V242.336c0-24.352-20.192-44.32-44.512-44.32z m-12.672 74.656v86.144c0 9.504-7.68 17.024-17.152 17.024h-86.688a16.96 16.96 0 0 1-16.992-17.024V272.96c0-9.312 7.328-16.992 16.992-16.992h85.856c9.824 0 16.992 7.68 16.992 16.992z m-33.824 321.344h-144.672c-24.16 0-43.808 19.488-43.808 43.488v144.512c0 24.32 19.68 44 43.808 44h144.672c24.32 0 44-19.68 44-44v-144.512c0-23.968-19.68-43.488-44-43.488z m-12.864 73.344v85.344a16.96 16.96 0 0 1-16.992 16.992v-0.352h-84.864a17.12 17.12 0 0 1-17.152-17.152v-84.832a17.28 17.28 0 0 1 17.152-17.184h85.344c9.344 0 17.024 7.84 17.024 17.184z m476.16-620.352A74.24 74.24 0 0 0 949.31296 24.64H74.65696A74.304 74.304 0 0 0 0.00096 99.296v825.344a74.304 74.304 0 0 0 74.656 74.656h874.656a74.304 74.304 0 0 0 74.656-74.656V99.296c0-20.32-8.48-39.168-21.856-52.832z m0 877.664a52.416 52.416 0 0 1-52.832 52.832H74.65696a52.576 52.576 0 0 1-53.344-52.832V99.328a52.672 52.672 0 0 1 52.832-52.832H948.80096c29.344 0 52.992 23.68 52.992 52.832v825.344z
</StreamGeometry>
<StreamGeometry x:Key="Discord">
M1049.062 139.672a3 3 0 0 0-1.528-1.4A970.13 970.13 0 0 0 808.162 64.06a3.632 3.632 0 0 0-3.846 1.82 674.922 674.922 0 0 0-29.8 61.2 895.696 895.696 0 0 0-268.852 0 619.082 619.082 0 0 0-30.27-61.2 3.78 3.78 0 0 0-3.848-1.82 967.378 967.378 0 0 0-239.376 74.214 3.424 3.424 0 0 0-1.576 1.352C78.136 367.302 36.372 589.38 56.86 808.708a4.032 4.032 0 0 0 1.53 2.75 975.332 975.332 0 0 0 293.65 148.378 3.8 3.8 0 0 0 4.126-1.352A696.4 696.4 0 0 0 416.24 860.8a3.72 3.72 0 0 0-2.038-5.176 642.346 642.346 0 0 1-91.736-43.706 3.77 3.77 0 0 1-0.37-6.252 502.094 502.094 0 0 0 18.218-14.274 3.638 3.638 0 0 1 3.8-0.512c192.458 87.834 400.82 87.834 591 0a3.624 3.624 0 0 1 3.848 0.466 469.066 469.066 0 0 0 18.264 14.32 3.768 3.768 0 0 1-0.324 6.252 602.814 602.814 0 0 1-91.78 43.66 3.75 3.75 0 0 0-2 5.222 782.11 782.11 0 0 0 60.028 97.63 3.728 3.728 0 0 0 4.126 1.4A972.096 972.096 0 0 0 1221.4 811.458a3.764 3.764 0 0 0 1.53-2.704c24.528-253.566-41.064-473.824-173.868-669.082zM444.982 675.16c-57.944 0-105.688-53.174-105.688-118.478s46.818-118.482 105.688-118.482c59.33 0 106.612 53.64 105.686 118.478 0 65.308-46.82 118.482-105.686 118.482z m390.76 0c-57.942 0-105.686-53.174-105.686-118.478s46.818-118.482 105.686-118.482c59.334 0 106.614 53.64 105.688 118.478 0 65.308-46.354 118.482-105.688 118.482z
</StreamGeometry>
</ResourceDictionary>
@@ -1,5 +1,6 @@
<Styles
xmlns="https://github.com/avaloniaui"
xmlns:spp="https://steampp.net/ui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="using:System"
xmlns:ui="using:FluentAvalonia.UI.Controls"
@@ -1,4 +1,6 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:spp="https://steampp.net/ui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Add Resources Here -->
<LinearGradientBrush x:Key="HeaderOpacityMaskBrush" StartPoint="0,0" EndPoint="0%,100%">
<GradientStop Offset="0" Color="#FF000000" />
@@ -21,16 +23,4 @@
</OnPlatform>
</RenderOptions.BitmapInterpolationMode>-->
</ImageBrush>
<LinearGradientBrush x:Key="SkeletonStartAnimationBackground" StartPoint="0%,100%" EndPoint="100%,100%">
<GradientStop Offset="0" Color="#FF1C1F23" />
<GradientStop Offset="0" Color="#FF2E3238" />
<GradientStop Offset="1" Color="#FF1C1F23" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="SkeletonEndAnimationBackground" StartPoint="0%,100%" EndPoint="100%,100%">
<GradientStop Offset="0" Color="#FF1C1F23" />
<GradientStop Offset="1" Color="#FF2E3238" />
<GradientStop Offset="1" Color="#FF1C1F23" />
</LinearGradientBrush>
<SolidColorBrush x:Key="SkeletonDefaultBackground" Color="#FF1C1F23" />
</ResourceDictionary>
@@ -1,4 +1,6 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:spp="https://steampp.net/ui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Add Resources Here -->
<LinearGradientBrush x:Key="HeaderOpacityMaskBrush" StartPoint="0,0" EndPoint="0%,100%">
<GradientStop Color="#00000000" />
@@ -1,4 +1,6 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:spp="https://steampp.net/ui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Add Resources Here -->
<LinearGradientBrush x:Key="HeaderOpacityMaskBrush" StartPoint="0,0" EndPoint="0%,100%">
<GradientStop Offset="0" Color="#FF000000" />
@@ -21,16 +23,4 @@
</OnPlatform>
</RenderOptions.BitmapInterpolationMode>-->
</ImageBrush>
<LinearGradientBrush x:Key="SkeletonStartAnimationBackground" StartPoint="0%,100%" EndPoint="100%,100%">
<GradientStop Offset="0" Color="#FFF9F9F9" />
<GradientStop Offset="0" Color="#FFE6E8EA" />
<GradientStop Offset="1" Color="#FFF9F9F9" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="SkeletonEndAnimationBackground" StartPoint="0%,100%" EndPoint="100%,100%">
<GradientStop Offset="0" Color="#FFF9F9F9" />
<GradientStop Offset="1" Color="#FFE6E8EA" />
<GradientStop Offset="1" Color="#FFF9F9F9" />
</LinearGradientBrush>
<SolidColorBrush x:Key="SkeletonDefaultBackground" Color="#FFF9F9F9" />
</ResourceDictionary>
@@ -97,27 +97,27 @@
Content="&#xE921;"
Theme="{StaticResource FA_SystemCaptionButton}"
ToolTip.Placement="Bottom"
ToolTip.Tip="{Binding Path=Res.Minimize, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
ToolTip.Tip="{Binding Path=Res.Minimize, Mode=OneWay, Source={x:Static spp:Strings.Minimize}}" />
<Button
Name="MaxRestoreButton"
Content="&#xE922;"
Theme="{StaticResource FA_SystemCaptionButton}"
ToolTip.Placement="Bottom"
ToolTip.Tip="{Binding Path=Res.Maximize, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
ToolTip.Tip="{Binding Path=Res.Maximize, Mode=OneWay, Source={x:Static spp:Strings.Maximize}}" />
<Button
Name="CloseButton"
Classes="Close"
Content="{StaticResource Close}"
Theme="{StaticResource FA_SystemCaptionButton}"
ToolTip.Placement="Bottom"
ToolTip.Tip="{Binding Path=Res.Close, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
ToolTip.Tip="{Binding Path=Res.Close, Mode=OneWay, Source={x:Static spp:Strings.Close}}" />
</StackPanel>
</ControlTemplate>
</Setter>
<Style Selector="^:maximized /template/ Button#MaxRestoreButton">
<Setter Property="Content" Value="&#xE923;" />
<Setter Property="ToolTip.Tip" Value="{Binding Path=Res.Restore, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<Setter Property="ToolTip.Tip" Value="{Binding Path=Res.Restore, Mode=OneWay, Source={x:Static spp:Strings.Restore}}" />
</Style>
</ControlTheme>
@@ -210,7 +210,7 @@
<wnd:MinMaxCloseControl
Name="SystemCaptionButtons"
Height="{Binding TemplateSettings.TitleBarHeight, RelativeSource={RelativeSource TemplatedParent}}"
Margin="14,0"
Margin="18,0"
HorizontalAlignment="Right"
VerticalAlignment="Top" />
@@ -1,7 +1,5 @@
using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Rendering.Composition;
using FluentAvalonia.UI.Controls.Experimental;
using FluentAvalonia.UI.Navigation;
namespace BD.WTTS.UI.Views.Pages;
@@ -9,8 +7,6 @@ public class PageBase : UserControl
{
public PageBase() : base()
{
_disposables = new();
SizeChanged += PageBaseSizeChanged;
if (HeaderBackground == null)
@@ -18,8 +14,6 @@ public class PageBase : UserControl
this[!HeaderBackgroundProperty] = new DynamicResourceExtension("PageHeaderBackgroundBrush");
}
_disposables.Add(UISettings.WindowBackgroundCustomImage.Subscribe(x => IsShowBackgroundImage = !x));
//AddHandler(Frame.NavigatingFromEvent, FrameNavigatingFrom, RoutingStrategies.Direct);
//AddHandler(Frame.NavigatedToEvent, FrameNavigatedTo, RoutingStrategies.Direct);
}
@@ -145,7 +139,6 @@ public class PageBase : UserControl
//_previewImageHost = e.NameScope.Find<IconSourceElement>("PreviewImageElement");
//_detailsHost = e.NameScope.Find<StackPanel>("DetailsTextHost");
_optionsHost = e.NameScope.Find<Panel>("OptionsRegion");
_tabsHost = e.NameScope.Find<Border>("TabRegion");
_detailsPanel = e.NameScope.Find<Panel>("PageDetails");
@@ -164,7 +157,6 @@ public class PageBase : UserControl
{
base.OnUnloaded(e);
_hasLoaded = false;
_disposables.Dispose();
}
private void PageBaseSizeChanged(object? sender, SizeChangedEventArgs e)
@@ -274,28 +266,33 @@ public class PageBase : UserControl
ec.ImplicitAnimations = ani;
}
//private void FrameNavigatingFrom(object? sender, NavigatingCancelEventArgs e)
//private void FrameNavigatingFrom(object sender, NavigatingCancelEventArgs e)
//{
// // If TargetType is not set, we know we're currently on a CoreControls page since those
// // are grouped pages - whereas, FA controls only display one control per page and
// // set all the extra properties
// bool isFAControlPage = TargetType != null;
// // Only setup the ConnectedAnimation if it makes sense
// if ((e.SourcePageType == typeof(HomePageViewModel)) ||
// (e.SourcePageType == typeof(PluginStorePageViewModel)))
// if ((!isFAControlPage && e.SourcePageType == typeof(CoreControlsPageViewModel)) ||
// (isFAControlPage && e.SourcePageType == typeof(FAControlsOverviewPageViewModel)))
// {
// // Only setup the Back connected animation if we're going back to the
// // controls list pages
// var svc = ConnectedAnimationService.GetForView(TopLevel.GetTopLevel(this));
// svc.PrepareToAnimate("BackAnimation", (Control)_previewImageHost.Parent);
// //NavigationService.Instance.PreviousPage = this;
// NavigationService.Instance.PreviousPage = this;
// }
//}
//private void FrameNavigatedTo(object? sender, NavigationEventArgs e)
//private void FrameNavigatedTo(object sender, NavigationEventArgs e)
//{
// var svc = ConnectedAnimationService.GetForView(TopLevel.GetTopLevel(this));
// var animation = svc.GetAnimation("ForwardAnimation");
// if (animation != null)
// {
// var coordinated = new List<Visual?>
// var coordinated = new List<Visual>
// {
// _optionsHost,
// _detailsHost,
@@ -318,7 +315,6 @@ public class PageBase : UserControl
//private IconSourceElement? _previewImageHost;
//private StackPanel? _detailsHost;
private ScrollViewer? _scroller;
private CompositeDisposable _disposables;
}
public class PageBase<TViewModel> : PageBase, IViewFor<TViewModel> where TViewModel : class
@@ -328,14 +324,13 @@ public class PageBase<TViewModel> : PageBase, IViewFor<TViewModel> where TViewMo
/// <summary>
/// Initializes a new instance of the <see cref="PageBase{TViewModel}"/> class.
/// </summary>
public PageBase() : base()
public PageBase()
{
// This WhenActivated block calls ViewModel's WhenActivated
// block if the ViewModel implements IActivatableViewModel.
this.WhenActivated(disposables =>
{
//disposables.Add(UISettings.WindowBackgroundCustomImage.Subscribe(x => IsShowBackgroundImage = !x));
disposables.Add(UISettings.WindowBackgroundCustomImage.Subscribe(x => IsShowBackgroundImage = !x));
});
this.GetObservable(ViewModelProperty).Subscribe(OnViewModelChanged);
}
@@ -14,8 +14,6 @@ public class ReactiveAppWindow<TViewModel> : AppWindow, IViewFor<TViewModel>, IV
public static readonly StyledProperty<bool> IsSaveWindowSizeProperty = AvaloniaProperty
.Register<ReactiveAppWindow<TViewModel>, bool>(nameof(IsSaveWindowSize), true);
private bool _isInitialize;
/// <summary>
/// Initializes a new instance of the <see cref="ReactiveAppWindow{TViewModel}"/> class.
/// </summary>
@@ -54,7 +52,7 @@ public class ReactiveAppWindow<TViewModel> : AppWindow, IViewFor<TViewModel>, IV
//SystemDecorations = SystemDecorations.BorderOnly;
Background = null;
TransparencyBackgroundFallback = OperatingSystem2.IsMacOS() ? Brushes.Black : Brushes.Transparent;
TransparencyBackgroundFallback = Brushes.Transparent;
TransparencyLevelHint = new WindowTransparencyLevel[] { UISettings.WindowBackgroundMaterial.Value.ToWindowTransparencyLevel() };
if (IsSaveWindowSize)
@@ -129,32 +127,27 @@ public class ReactiveAppWindow<TViewModel> : AppWindow, IViewFor<TViewModel>, IV
{
var primaryScreenBounds = screen.Bounds;
if (CanResize && !_isInitialize && !IsVisible)
if (CanResize && !IsVisible)
{
WindowStartupLocation = WindowStartupLocation.Manual;
var scalingOffset = 31 - ((screen.Scaling - 1) / 0.5); // appwindow偏移量
if (SizePosition.Width > 0 &&
primaryScreenBounds.Width >= SizePosition.Width)
Width = SizePosition.Width;
if (SizePosition.Height > 0 &&
primaryScreenBounds.Height >= SizePosition.Height)
Height = SizePosition.Height - scalingOffset;
Height = SizePosition.Height;
if (SizePosition.X > 0 && SizePosition.Y > 0)
{
var offsetY = (int)Math.Round(scalingOffset * screen.Scaling);
//var offsetY = scalingOffset;
var leftTopPoint = new PixelPoint(SizePosition.X, SizePosition.Y + offsetY);
var leftTopPoint = new PixelPoint(SizePosition.X, SizePosition.Y);
var rightBottomPoint = new PixelPoint(SizePosition.X + (int)Width, SizePosition.Y + (int)Height);
if (primaryScreenBounds.Contains(leftTopPoint) &&
primaryScreenBounds.Contains(rightBottomPoint))
{
Position = leftTopPoint;
WindowStartupLocation = WindowStartupLocation.Manual;
}
}
_isInitialize = true;
}
}
}
@@ -8,7 +8,9 @@
xmlns:spp="https://steampp.net/ui"
d:DesignHeight="450"
d:DesignWidth="800"
IsVisible="{Binding IsShowAdvertise, Mode=OneWay, Source={x:Static s:AdvertiseService.Current}}"
IsVisible="{ReflectionBinding IsShowAdvertise,
Mode=OneWay,
Source={x:Static s:AdvertiseService.Current}}"
mc:Ignorable="d">
<Border ClipToBounds="True" CornerRadius="{DynamicResource ControlCornerRadius}">
<Panel>
@@ -18,14 +20,15 @@
<Button
Padding="0"
Classes="Plain"
Command="{Binding ClickAdvertisementCommand, Mode=OneWay, Source={x:Static s:AdvertiseService.Current}}"
Command="{ReflectionBinding ClickAdvertisementCommand,
Mode=OneWay,
Source={x:Static s:AdvertiseService.Current}}"
CommandParameter="{Binding}"
Cursor="Hand"
ToolTip.Tip="{Binding Describe}">
<spp:Image2
Width="{Binding $parent[UserControl].Bounds.Width}"
Height="{Binding $parent[UserControl].Bounds.Height}"
EnableCancelToken="False"
Source="{Binding ImageUrl}"
Stretch="UniformToFill" />
</Button>
@@ -36,13 +39,17 @@
Margin="10"
FontSize="10"
Foreground="White"
Text="{Binding Path=Res.Advertisement, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
Text="{ReflectionBinding Path=Res.Advertisement,
Mode=OneWay,
Source={x:Static spp:Strings.Advertisement}}" />
<Button
Name="CloseAdBtn"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="Transparent"
Content="{Binding Path=Res.Advertisement_Close, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
Content="{ReflectionBinding Path=Res.Advertisement_Close,
Mode=OneWay,
Source={x:Static spp:Strings.Advertisement_Close}}"
Cursor="Hand"
Foreground="White" />
</Panel>
@@ -1,13 +0,0 @@
namespace BD.WTTS.UI.Views.Controls;
public enum AlignContent
{
FlexStart,
FlexEnd,
Center,
Stretch,
SpaceBetween,
SpaceAround,
SpaceEvenly
}
@@ -1,10 +0,0 @@
namespace BD.WTTS.UI.Views.Controls;
[SuppressMessage("Naming", "CA1717:Only FlagsAttribute enums should have plural names")]
public enum AlignItems
{
FlexStart,
FlexEnd,
Center,
Stretch
}
@@ -1,183 +0,0 @@
namespace BD.WTTS.UI.Views.Controls;
public static class Flex
{
/// <summary>
/// Defines an attached property to control the alignment of a specific child in a flex layout.
/// </summary>
public static readonly AttachedProperty<AlignItems?> AlignSelfProperty =
AvaloniaProperty.RegisterAttached<Layoutable, AlignItems?>("AlignSelf", typeof(Flex));
/// <summary>
/// Defines an attached property to control the order of a specific child in a flex layout.
/// </summary>
public static readonly AttachedProperty<int> OrderProperty =
AvaloniaProperty.RegisterAttached<Layoutable, int>("Order", typeof(Flex));
public static readonly AttachedProperty<FlexBasis> BasisProperty =
AvaloniaProperty.RegisterAttached<Layoutable, FlexBasis>("Basis", typeof(Flex), FlexBasis.Auto);
public static readonly AttachedProperty<double> ShrinkProperty =
AvaloniaProperty.RegisterAttached<Layoutable, double>("Shrink", typeof(Flex), 1.0, validate: v => v >= 0.0);
public static readonly AttachedProperty<double> GrowProperty =
AvaloniaProperty.RegisterAttached<Layoutable, double>("Grow", typeof(Flex), 0.0, validate: v => v >= 0.0);
internal static readonly AttachedProperty<double> BaseLengthProperty =
AvaloniaProperty.RegisterAttached<Layoutable, double>("BaseLength", typeof(Flex), 0.0);
internal static readonly AttachedProperty<double> CurrentLengthProperty =
AvaloniaProperty.RegisterAttached<Layoutable, double>("CurrentLength", typeof(Flex), 0.0);
/// <summary>
/// Gets the child alignment in a flex layout
/// </summary>
public static AlignItems? GetAlignSelf(Layoutable layoutable)
{
if (layoutable is null)
{
throw new ArgumentNullException(nameof(layoutable));
}
return layoutable.GetValue(AlignSelfProperty);
}
/// <summary>
/// Sets the child alignment in a flex layout
/// </summary>
public static void SetAlignSelf(Layoutable layoutable, AlignItems? value)
{
if (layoutable is null)
{
throw new ArgumentNullException(nameof(layoutable));
}
layoutable.SetValue(AlignSelfProperty, value);
}
/// <summary>
/// Gets the child order in a flex layout
/// </summary>
public static int GetOrder(Layoutable layoutable)
{
if (layoutable is null)
{
throw new ArgumentNullException(nameof(layoutable));
}
return layoutable.GetValue(OrderProperty);
}
/// <summary>
/// Sets the child order in a flex layout
/// </summary>
public static void SetOrder(Layoutable layoutable, int value)
{
if (layoutable is null)
{
throw new ArgumentNullException(nameof(layoutable));
}
layoutable.SetValue(OrderProperty, value);
}
public static FlexBasis GetBasis(Layoutable layoutable)
{
if (layoutable is null)
{
throw new ArgumentNullException(nameof(layoutable));
}
return layoutable.GetValue(BasisProperty);
}
public static void SetBasis(Layoutable layoutable, FlexBasis value)
{
if (layoutable is null)
{
throw new ArgumentNullException(nameof(layoutable));
}
layoutable.SetValue(BasisProperty, value);
}
public static double GetShrink(Layoutable layoutable)
{
if (layoutable is null)
{
throw new ArgumentNullException(nameof(layoutable));
}
return layoutable.GetValue(ShrinkProperty);
}
public static void SetShrink(Layoutable layoutable, double value)
{
if (layoutable is null)
{
throw new ArgumentNullException(nameof(layoutable));
}
layoutable.SetValue(ShrinkProperty, value);
}
public static double GetGrow(Layoutable layoutable)
{
if (layoutable is null)
{
throw new ArgumentNullException(nameof(layoutable));
}
return layoutable.GetValue(GrowProperty);
}
public static void SetGrow(Layoutable layoutable, double value)
{
if (layoutable is null)
{
throw new ArgumentNullException(nameof(layoutable));
}
layoutable.SetValue(GrowProperty, value);
}
internal static double GetBaseLength(Layoutable layoutable)
{
if (layoutable is null)
{
throw new ArgumentNullException(nameof(layoutable));
}
return layoutable.GetValue(BaseLengthProperty);
}
internal static void SetBaseLength(Layoutable layoutable, double value)
{
if (layoutable is null)
{
throw new ArgumentNullException(nameof(layoutable));
}
layoutable.SetValue(BaseLengthProperty, value);
}
internal static double GetCurrentLength(Layoutable layoutable)
{
if (layoutable is null)
{
throw new ArgumentNullException(nameof(layoutable));
}
return layoutable.GetValue(CurrentLengthProperty);
}
internal static void SetCurrentLength(Layoutable layoutable, double value)
{
if (layoutable is null)
{
throw new ArgumentNullException(nameof(layoutable));
}
layoutable.SetValue(CurrentLengthProperty, value);
}
}
@@ -1,66 +0,0 @@
namespace BD.WTTS.UI.Views.Controls;
public readonly struct FlexBasis : IEquatable<FlexBasis>
{
public double Value { get; }
public FlexBasisKind Kind { get; }
public FlexBasis(double value, FlexBasisKind kind)
{
if (value < 0 || double.IsNaN(value) || double.IsInfinity(value))
throw new ArgumentException($"Invalid basis value: {value}", nameof(value));
if (kind < FlexBasisKind.Auto || kind > FlexBasisKind.Relative)
throw new ArgumentException($"Invalid basis kind: {kind}", nameof(kind));
Value = value;
Kind = kind;
}
public FlexBasis(double value) : this(value, FlexBasisKind.Absolute) { }
public static FlexBasis Auto => new(0.0, FlexBasisKind.Auto);
public bool IsAuto => Kind == FlexBasisKind.Auto;
public bool IsAbsolute => Kind == FlexBasisKind.Absolute;
public bool IsRelative => Kind == FlexBasisKind.Relative;
[SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator")]
public bool Equals(FlexBasis other) =>
(IsAuto && other.IsAuto) || (Value == other.Value && Kind == other.Kind);
public override bool Equals(object? obj) =>
obj is FlexBasis other && Equals(other);
public override int GetHashCode() =>
HashCode.Combine(Value, (int)Kind);
public static bool operator ==(FlexBasis left, FlexBasis right) =>
left.Equals(right);
public static bool operator !=(FlexBasis left, FlexBasis right) =>
!left.Equals(right);
public override string ToString()
{
return Kind switch
{
FlexBasisKind.Auto => "Auto",
FlexBasisKind.Absolute => FormattableString.Invariant($"{Value:G17}"),
FlexBasisKind.Relative => FormattableString.Invariant($"{Value * 100:G17}%"),
_ => throw new InvalidOperationException(),
};
}
public static FlexBasis Parse(string str)
{
return str.ToUpperInvariant() switch
{
"AUTO" => Auto,
var s when s.EndsWith("%") => new FlexBasis(ParseDouble(s[..^1].Trim()) / 100, FlexBasisKind.Relative),
_ => new FlexBasis(ParseDouble(str), FlexBasisKind.Absolute),
};
double ParseDouble(string s) => double.Parse(s, CultureInfo.InvariantCulture);
}
}
@@ -1,8 +0,0 @@
namespace BD.WTTS.UI.Views.Controls;
public enum FlexBasisKind
{
Auto,
Absolute,
Relative,
}
@@ -1,9 +0,0 @@
namespace BD.WTTS.UI.Views.Controls;
public enum FlexDirection
{
Row,
RowReverse,
Column,
ColumnReverse
}
@@ -1,468 +0,0 @@
namespace BD.WTTS.UI.Views.Controls;
public sealed class FlexPanel : Panel
{
private static readonly Func<Layoutable, int> s_getOrder = x => x is { } y ? Flex.GetOrder(y) : 0;
private static readonly Func<Layoutable, bool> s_isVisible = x => x.IsVisible;
/// <summary>
/// Defines the <see cref="Direction"/> property.
/// </summary>
public static readonly StyledProperty<FlexDirection> DirectionProperty =
AvaloniaProperty.Register<FlexPanel, FlexDirection>(nameof(Direction));
/// <summary>
/// Defines the <see cref="JustifyContent"/> property.
/// </summary>
public static readonly StyledProperty<JustifyContent> JustifyContentProperty =
AvaloniaProperty.Register<FlexPanel, JustifyContent>(nameof(JustifyContent));
/// <summary>
/// Defines the <see cref="AlignItems"/> property.
/// </summary>
public static readonly StyledProperty<AlignItems> AlignItemsProperty =
AvaloniaProperty.Register<FlexPanel, AlignItems>(nameof(AlignItems));
/// <summary>
/// Defines the <see cref="AlignContent"/> property.
/// </summary>
public static readonly StyledProperty<AlignContent> AlignContentProperty =
AvaloniaProperty.Register<FlexPanel, AlignContent>(nameof(AlignContent));
/// <summary>
/// Defines the <see cref="Wrap"/> property.
/// </summary>
public static readonly StyledProperty<FlexWrap> WrapProperty =
AvaloniaProperty.Register<FlexPanel, FlexWrap>(nameof(Wrap), FlexWrap.Wrap);
/// <summary>
/// Defines the <see cref="ColumnSpacing"/> property.
/// </summary>
public static readonly StyledProperty<double> ColumnSpacingProperty =
AvaloniaProperty.Register<FlexPanel, double>(nameof(ColumnSpacing));
/// <summary>
/// Defines the <see cref="RowSpacing"/> property.
/// </summary>
public static readonly StyledProperty<double> RowSpacingProperty =
AvaloniaProperty.Register<FlexPanel, double>(nameof(RowSpacing));
private FlexLayoutState? _state;
static FlexPanel()
{
AffectsMeasure<FlexPanel>(
DirectionProperty,
JustifyContentProperty,
WrapProperty,
ColumnSpacingProperty,
RowSpacingProperty);
AffectsArrange<FlexPanel>(
AlignItemsProperty,
AlignContentProperty);
AffectsParentMeasure<FlexPanel>(
HorizontalAlignmentProperty,
VerticalAlignmentProperty,
Flex.OrderProperty,
Flex.BasisProperty,
Flex.ShrinkProperty,
Flex.GrowProperty);
AffectsParentArrange<FlexPanel>(
Flex.AlignSelfProperty);
}
/// <summary>
/// Gets or sets the flex direction
/// </summary>
public FlexDirection Direction
{
get => GetValue(DirectionProperty);
set => SetValue(DirectionProperty, value);
}
/// <summary>
/// Gets or sets the flex justify content mode
/// </summary>
public JustifyContent JustifyContent
{
get => GetValue(JustifyContentProperty);
set => SetValue(JustifyContentProperty, value);
}
/// <summary>
/// Gets or sets the flex align items mode
/// </summary>
public AlignItems AlignItems
{
get => GetValue(AlignItemsProperty);
set => SetValue(AlignItemsProperty, value);
}
/// <summary>
/// Gets or sets the flex align content mode
/// </summary>
public AlignContent AlignContent
{
get => GetValue(AlignContentProperty);
set => SetValue(AlignContentProperty, value);
}
/// <summary>
/// Gets or sets the flex wrap mode
/// </summary>
public FlexWrap Wrap
{
get => GetValue(WrapProperty);
set => SetValue(WrapProperty, value);
}
/// <summary>
/// Gets or sets the column spacing
/// </summary>
public double ColumnSpacing
{
get => GetValue(ColumnSpacingProperty);
set => SetValue(ColumnSpacingProperty, value);
}
/// <summary>
/// Gets or sets the row spacing
/// </summary>
public double RowSpacing
{
get => GetValue(RowSpacingProperty);
set => SetValue(RowSpacingProperty, value);
}
/// <inheritdoc />
protected override Size MeasureOverride(Size availableSize)
{
var children = (IReadOnlyList<Layoutable>)Children;
var isColumn = Direction is FlexDirection.Column or FlexDirection.ColumnReverse;
var max = Uv.FromSize(availableSize, isColumn);
var spacing = Uv.FromSize(ColumnSpacing, RowSpacing, isColumn);
var (lineU, lineV, lineShrink, lineGrow, lineAutoMargins) = (0.0, 0.0, 0.0, 0.0, 0);
var (childIndex, firstChildIndex, itemIndex, lineIndex) = (0, 0, 0, 0);
var lines = new List<FlexLine>();
children = children.Where(s_isVisible).OrderBy(s_getOrder).ToArray();
foreach (var element in children)
{
var basis = Flex.GetBasis(element);
var flexConstraint = basis.Kind switch
{
FlexBasisKind.Auto => max.U,
FlexBasisKind.Absolute => basis.Value,
FlexBasisKind.Relative => max.U * basis.Value / 100,
_ => throw new InvalidOperationException()
};
element.Measure(Uv.ToSize(max.WithU(flexConstraint), isColumn));
var size = Uv.FromSize(element.DesiredSize, isColumn);
var flexLength = basis.Kind switch
{
FlexBasisKind.Auto => size.U,
FlexBasisKind.Absolute or FlexBasisKind.Relative => Math.Max(size.U, flexConstraint),
_ => throw new InvalidOperationException()
};
size = size.WithU(flexLength);
Flex.SetBaseLength(element, flexLength);
Flex.SetCurrentLength(element, flexLength);
if (Wrap != FlexWrap.NoWrap && lineU + size.U + itemIndex * spacing.U > max.U)
{
lines.Add(new FlexLine(firstChildIndex, childIndex - 1,
lineU, lineV, lineShrink, lineGrow, lineAutoMargins));
(lineU, lineV, lineShrink, lineGrow, lineAutoMargins) = (0.0, 0.0, 0.0, 0.0, 0);
firstChildIndex = childIndex;
itemIndex = 0;
lineIndex++;
}
lineU += size.U;
lineV = Math.Max(lineV, size.V);
lineShrink += Flex.GetShrink(element);
lineGrow += Flex.GetGrow(element);
lineAutoMargins += GetItemAutoMargins(element, isColumn);
itemIndex++;
childIndex++;
}
if (itemIndex != 0)
{
lines.Add(new FlexLine(firstChildIndex, firstChildIndex + itemIndex - 1,
lineU, lineV, lineShrink, lineGrow, lineAutoMargins));
}
var state = new FlexLayoutState(children, lines, Wrap);
var totalSpacingV = (lines.Count - 1) * spacing.V;
var panelSizeU = lines.Count > 0 ? lines.Max(line => line.U + (line.Count - 1) * spacing.U) : 0.0;
// Reizing along main axis using grow and shrink factors can affect cross axis, so remeasure affected items and lines.
foreach (var line in lines)
{
var (itemsCount, totalSpacingU, totalU, freeU) = GetLineMeasureU(line, max.U, spacing.U);
var (lineMult, autoMargins, remainingFreeU) = GetLineMultInfo(line, freeU);
if (lineMult != 0.0 && remainingFreeU != 0.0)
{
foreach (var element in state.GetLineItems(line))
{
var baseLength = Flex.GetBaseLength(element);
var mult = GetItemMult(element, freeU);
if (mult != 0.0)
{
var length = Math.Max(0.0, baseLength + remainingFreeU * mult / lineMult);
element.Measure(Uv.ToSize(max.WithU(length), isColumn));
}
}
line.V = state.GetLineItems(line).Max(i => Uv.FromSize(i.DesiredSize, isColumn).V);
}
}
_state = state;
var totalLineV = lines.Sum(l => l.V);
var panelSize = lines.Count == 0 ? default : new Uv(panelSizeU, totalLineV + totalSpacingV);
return Uv.ToSize(panelSize, isColumn);
}
/// <inheritdoc />
protected override Size ArrangeOverride(Size finalSize)
{
var state = _state ?? throw new InvalidOperationException();
var isColumn = Direction is FlexDirection.Column or FlexDirection.ColumnReverse;
var isReverse = Direction is FlexDirection.RowReverse or FlexDirection.ColumnReverse;
var panelSize = Uv.FromSize(finalSize, isColumn);
var spacing = Uv.FromSize(ColumnSpacing, RowSpacing, isColumn);
var linesCount = state.Lines.Count;
var totalLineV = state.Lines.Sum(s => s.V);
var totalSpacingV = (linesCount - 1) * spacing.V;
var totalV = totalLineV + totalSpacingV;
var freeV = panelSize.V - totalV;
var alignContent = freeV >= 0.0 ? AlignContent : AlignContent switch
{
AlignContent.FlexStart or AlignContent.Stretch or AlignContent.SpaceBetween => AlignContent.FlexStart,
AlignContent.Center or AlignContent.SpaceAround or AlignContent.SpaceEvenly => AlignContent.Center,
AlignContent.FlexEnd => AlignContent.FlexEnd,
_ => throw new InvalidOperationException()
};
var (spacingV, v) = alignContent switch
{
AlignContent.FlexStart => (spacing.V, 0.0),
AlignContent.FlexEnd => (spacing.V, freeV),
AlignContent.Center => (spacing.V, freeV / 2),
AlignContent.Stretch => (spacing.V, 0.0),
AlignContent.SpaceBetween => (spacing.V + freeV / (linesCount - 1), 0.0),
AlignContent.SpaceAround => (spacing.V + freeV / linesCount, freeV / linesCount / 2),
AlignContent.SpaceEvenly => (spacing.V + freeV / (linesCount + 1), freeV / (linesCount + 1)),
_ => throw new InvalidOperationException()
};
var scaleV = alignContent == AlignContent.Stretch ? (panelSize.V - totalSpacingV) / totalLineV : 1.0;
foreach (var line in state.Lines)
{
var lineV = scaleV * line.V;
var (itemsCount, totalSpacingU, totalU, freeU) = GetLineMeasureU(line, panelSize.U, spacing.U);
var (lineMult, lineAutoMargins, remainingFreeU) = GetLineMultInfo(line, freeU);
var currentFreeU = remainingFreeU;
if (lineMult != 0.0 && remainingFreeU != 0.0)
{
foreach (var element in state.GetLineItems(line))
{
var baseLength = Flex.GetBaseLength(element);
var mult = GetItemMult(element, freeU);
if (mult != 0.0)
{
var length = Math.Max(0.0, baseLength + remainingFreeU * mult / lineMult);
Flex.SetCurrentLength(element, length);
currentFreeU -= length - baseLength;
}
}
}
remainingFreeU = currentFreeU;
if (lineAutoMargins != 0 && remainingFreeU != 0.0)
{
foreach (var element in state.GetLineItems(line))
{
var baseLength = Flex.GetCurrentLength(element);
var autoMargins = GetItemAutoMargins(element, isColumn);
if (autoMargins != 0)
{
var length = Math.Max(0.0, baseLength + remainingFreeU * autoMargins / lineAutoMargins);
Flex.SetCurrentLength(element, length);
currentFreeU -= length - baseLength;
}
}
}
remainingFreeU = currentFreeU;
var (spacingU, u) = line.Grow > 0 ? (spacing.U, 0.0) : JustifyContent switch
{
JustifyContent.FlexStart => (spacing.U, 0.0),
JustifyContent.FlexEnd => (spacing.U, remainingFreeU),
JustifyContent.Center => (spacing.U, remainingFreeU / 2),
JustifyContent.SpaceBetween => (spacing.U + remainingFreeU / (itemsCount - 1), 0.0),
JustifyContent.SpaceAround => (spacing.U + remainingFreeU / itemsCount, remainingFreeU / itemsCount / 2),
JustifyContent.SpaceEvenly => (spacing.U + remainingFreeU / (itemsCount + 1), remainingFreeU / (itemsCount + 1)),
_ => throw new InvalidOperationException()
};
foreach (var element in state.GetLineItems(line))
{
var size = Uv.FromSize(element.DesiredSize, isColumn).WithU(Flex.GetCurrentLength(element));
var align = Flex.GetAlignSelf(element) ?? AlignItems;
var positionV = align switch
{
AlignItems.FlexStart => v,
AlignItems.FlexEnd => v + lineV - size.V,
AlignItems.Center => v + (lineV - size.V) / 2,
AlignItems.Stretch => v,
_ => throw new InvalidOperationException()
};
size = size.WithV(align == AlignItems.Stretch ? lineV : size.V);
var position = new Uv(isReverse ? panelSize.U - size.U - u : u, positionV);
element.Arrange(new Rect(Uv.ToPoint(position, isColumn), Uv.ToSize(size, isColumn)));
u += size.U + spacingU;
}
v += lineV + spacingV;
}
return finalSize;
}
private static (int ItemsCount, double TotalSpacingU, double TotalU, double FreeU) GetLineMeasureU(
FlexLine line, double panelSizeU, double spacingU)
{
var itemsCount = line.Count;
var totalSpacingU = (itemsCount - 1) * spacingU;
var totalU = line.U + totalSpacingU;
var freeU = panelSizeU - totalU;
return (itemsCount, totalSpacingU, totalU, freeU);
}
private static (double LineMult, double LineAutoMargins, double RemainingFreeU) GetLineMultInfo(FlexLine line, double freeU)
{
var lineMult = freeU switch
{
< 0 => line.Shrink,
> 0 => line.Grow,
_ => 0.0,
};
// https://www.w3.org/TR/css-flexbox-1/#remaining-free-space
// Sum of flex factors less than 1 reduces remaining free space to be distributed.
return lineMult is > 0 and < 1
? (lineMult, line.AutoMargins, freeU * lineMult)
: (lineMult, line.AutoMargins, freeU);
}
private static double GetItemMult(Layoutable element, double freeU)
{
var mult = freeU switch
{
< 0 => Flex.GetShrink(element),
> 0 => Flex.GetGrow(element),
_ => 0.0,
};
return mult;
}
private static int GetItemAutoMargins(Layoutable element, bool isColumn)
{
return isColumn
? element.VerticalAlignment switch
{
VerticalAlignment.Stretch => 0,
VerticalAlignment.Top or VerticalAlignment.Bottom => 1,
VerticalAlignment.Center => 2,
_ => throw new InvalidOperationException()
}
: element.HorizontalAlignment switch
{
HorizontalAlignment.Stretch => 0,
HorizontalAlignment.Left or HorizontalAlignment.Right => 1,
HorizontalAlignment.Center => 2,
_ => throw new InvalidOperationException()
};
}
private readonly struct FlexLayoutState
{
private readonly IReadOnlyList<Layoutable> _children;
public IReadOnlyList<FlexLine> Lines { get; }
public FlexLayoutState(IReadOnlyList<Layoutable> children, List<FlexLine> lines, FlexWrap wrap)
{
if (wrap == FlexWrap.WrapReverse)
{
lines.Reverse();
}
_children = children;
Lines = lines;
}
public IEnumerable<Layoutable> GetLineItems(FlexLine line)
{
for (var i = line.First; i <= line.Last; i++)
yield return _children[i];
}
}
private class FlexLine
{
public FlexLine(int first, int last, double u, double v, double shrink, double grow, int autoMargins)
{
First = first;
Last = last;
U = u;
V = v;
Shrink = shrink;
Grow = grow;
AutoMargins = autoMargins;
}
/// <summary>First item index.</summary>
public int First { get; }
/// <summary>Last item index.</summary>
public int Last { get; }
/// <summary>Sum of main sizes of items.</summary>
public double U { get; }
/// <summary>Max of cross sizes of items.</summary>
public double V { get; set; }
/// <summary>Sum of shrink factors of flexible items.</summary>
public double Shrink { get; }
/// <summary>Sum of grow factors of flexible items.</summary>
public double Grow { get; }
/// <summary>Number of "auto margins" along main axis.</summary>
public int AutoMargins { get; }
/// <summary>Number of items.</summary>
public int Count => Last - First + 1;
}
}
@@ -1,8 +0,0 @@
namespace BD.WTTS.UI.Views.Controls;
public enum FlexWrap
{
NoWrap,
Wrap,
WrapReverse
}
@@ -1,11 +0,0 @@
namespace BD.WTTS.UI.Views.Controls;
public enum JustifyContent
{
FlexStart,
FlexEnd,
Center,
SpaceBetween,
SpaceAround,
SpaceEvenly
}
@@ -1,29 +0,0 @@
namespace BD.WTTS.UI.Views.Controls;
internal readonly struct Uv(double u, double v)
{
public double U { get; } = u;
public double V { get; } = v;
public static Uv FromSize(double width, double height, bool swap) =>
new Uv(swap ? height : width, swap ? width : height);
public static Uv FromSize(Size size, bool swap) =>
FromSize(size.Width, size.Height, swap);
public static Point ToPoint(Uv uv, bool swap) =>
new Point(swap ? uv.V : uv.U, swap ? uv.U : uv.V);
public static Size ToSize(Uv uv, bool swap) =>
new Size(swap ? uv.V : uv.U, swap ? uv.U : uv.V);
public Uv WithU(double u) =>
new Uv(u, V);
public Uv WithV(double v) =>
new Uv(U, v);
public override string ToString() =>
$"U: {U}, V: {V}";
}
@@ -1,14 +1,12 @@
using Avalonia.Controls;
namespace BD.WTTS.UI.Views.Controls;
public class OptionsDisplayItem : TemplatedControl
{
public static readonly StyledProperty<object?> HeaderProperty =
AvaloniaProperty.Register<OptionsDisplayItem, object?>(nameof(Header));
public static readonly StyledProperty<string> HeaderProperty =
AvaloniaProperty.Register<OptionsDisplayItem, string>(nameof(Header));
public static readonly StyledProperty<object?> DescriptionProperty =
AvaloniaProperty.Register<OptionsDisplayItem, object?>(nameof(Description));
public static readonly StyledProperty<string> DescriptionProperty =
AvaloniaProperty.Register<OptionsDisplayItem, string>(nameof(Description));
public static readonly StyledProperty<object?> IconProperty =
AvaloniaProperty.Register<OptionsDisplayItem, object?>(nameof(Icon));
@@ -31,13 +29,13 @@ public class OptionsDisplayItem : TemplatedControl
public static readonly StyledProperty<ICommand> NavigationCommandProperty =
AvaloniaProperty.Register<OptionsDisplayItem, ICommand>(nameof(NavigationCommand));
public object? Header
public string Header
{
get => GetValue(HeaderProperty);
set => SetValue(HeaderProperty, value);
}
public object? Description
public string Description
{
get => GetValue(DescriptionProperty);
set => SetValue(DescriptionProperty, value);
@@ -114,7 +112,7 @@ public class OptionsDisplayItem : TemplatedControl
}
else if (change.Property == DescriptionProperty)
{
PseudoClasses.Set(":desc", change.GetNewValue<object?>() != null);
PseudoClasses.Set(":desc", !string.IsNullOrEmpty(change.GetNewValue<string>()));
}
else if (change.Property == IsExpandedProperty)
PseudoClasses.Set(":expanded", change.GetNewValue<bool>());
@@ -126,7 +124,7 @@ public class OptionsDisplayItem : TemplatedControl
{
base.OnApplyTemplate(e);
_layoutRoot = e.NameScope.Find<Border>("LayoutRoot");
_layoutRoot = e.NameScope.Find<FABorder>("LayoutRoot");
if (_layoutRoot != null)
{
_layoutRoot.PointerPressed += OnLayoutRootPointerPressed;
@@ -172,5 +170,5 @@ public class OptionsDisplayItem : TemplatedControl
private bool _isPressed;
private bool _isExpanded;
private Border? _layoutRoot;
private FABorder? _layoutRoot;
}
@@ -1,47 +0,0 @@
namespace BD.WTTS.UI.Views.Controls;
public class PureCircle : Control
{
public static readonly StyledProperty<double> DiameterProperty = AvaloniaProperty.Register<PureCircle, double>(
nameof(Diameter));
public double Diameter
{
get => GetValue(DiameterProperty);
set => SetValue(DiameterProperty, value);
}
public static readonly StyledProperty<IBrush?>
BackgroundProperty = Border.BackgroundProperty.AddOwner<PureCircle>();
public IBrush? Background
{
get => GetValue(BackgroundProperty);
set => SetValue(BackgroundProperty, value);
}
static PureCircle()
{
AffectsMeasure<PureCircle>(DiameterProperty);
AffectsArrange<PureCircle>(DiameterProperty);
AffectsRender<PureCircle>(BackgroundProperty, DiameterProperty);
}
protected override Size MeasureOverride(Size availableSize)
{
double diameter = Math.Max(0, Diameter);
return new Size(diameter, diameter);
}
protected override Size ArrangeOverride(Size finalSize)
{
double diameter = Math.Max(0, Diameter);
return new Size(diameter, diameter);
}
public override void Render(DrawingContext context)
{
double radius = Math.Max(0, Diameter) / 2;
context.DrawEllipse(Background, null, new(radius, radius), radius, radius);
}
}
@@ -1,27 +0,0 @@
namespace BD.WTTS.UI.Views.Controls;
/// <summary>
/// Provide the most simplified shape implementation. This is a rectangle with a background, without border and corner radius.
/// </summary>
public class PureRectangle : Control
{
public static readonly StyledProperty<IBrush?> BackgroundProperty =
Border.BackgroundProperty.AddOwner<PureRectangle>();
public IBrush? Background
{
get => GetValue(BackgroundProperty);
set => SetValue(BackgroundProperty, value);
}
static PureRectangle()
{
AffectsRender<PureRectangle>(BackgroundProperty);
}
public override void Render(DrawingContext context)
{
base.Render(context);
context.DrawRectangle(Background, null, new Rect(Bounds.Size));
}
}
@@ -1,30 +0,0 @@
namespace BD.WTTS.UI.Views.Controls;
public class PureRing : PureCircle
{
public static readonly StyledProperty<double> InnerDiameterProperty = AvaloniaProperty.Register<PureRing, double>(
nameof(InnerDiameter));
public double InnerDiameter
{
get => GetValue(InnerDiameterProperty);
set => SetValue(InnerDiameterProperty, value);
}
static PureRing()
{
AffectsRender<PureCircle>(InnerDiameterProperty);
}
public override void Render(DrawingContext context)
{
double outer = Diameter / 2;
double inner = InnerDiameter / 2;
double thickness = outer - inner;
context.DrawEllipse(null,
new Pen(Background, outer - inner),
new Point(outer, outer),
outer - thickness / 2,
outer - thickness / 2);
}
}

Some files were not shown because too many files have changed in this diff Show More