Compare commits

..
155 Commits
Author SHA1 Message Date
Aigio Liu 96a14d69bd 🚧 Misc 2024-08-06 17:09:13 +08:00
Aigio Liu c79fba98d3 🚧 Misc 2024-07-04 17:51:15 +08:00
Aigio Liu 4160bb43c5 🚧 Misc 2024-06-29 00:57:23 +08:00
RMBGAME 67209f3861 🚧 Misc 2024-06-25 14:16:31 +08:00
RMBGAME 110c92d909 🐛⬆️ Avalonia 11.0-rc1 2024-06-24 14:26:48 +08:00
Aigio Liu cdc773ba74 📝 System.ArgumentException: Decoded string is not a valid IDN name. (Parameter 'unicode') 2024-06-16 00:48:32 +08:00
Aigio Liu 8ea8b73aab 🐛 System.ArgumentException: Decoded string is not a valid IDN name. (Parameter 'unicode')
at System.Globalization.IdnMapping.IcuGetAsciiCore(String unicodeString, Char* unicode, Int32 count)
   at System.Globalization.IdnMapping.GetAscii(String unicode, Int32 index, Int32 count)
   at System.Security.Cryptography.X509Certificates.SubjectAlternativeNameBuilder.AddDnsName(String dnsName)
   at BD.WTTS.Services.Implementation.CertGenerator.Add(SubjectAlternativeNameBuilder builder, String name)
2024-06-16 00:46:51 +08:00
RMBGAME 0614e172b8 ✨ 账号切换新增显示用户名设置项 2024-06-07 23:58:49 +08:00
yingpanwang 4c73a5b622 Feautre/joinsteamauthenticator (#3362)
* ✨ 导入steam令牌 新增添加 联合steam 令牌方式
2024-06-06 15:01:15 +08:00
RMBGAME 34341172b8 🚧 ItemsRepeater 2024-05-29 19:15:59 +08:00
RMBGAME 6813ed9ece ⬆️ FA 2.1.0-preview5 2024-05-27 18:23:02 +08:00
RMBGAME 3eb916e78a 🐛 蒸汽平台切换账号支持 2024-05-18 21:37:25 +08:00
RMBGAME 7424d05f54 💄 Avalonia_Edit 2024-05-17 20:27:04 +08:00
RMBGAME 76829b0ca2 🐛 fixed 挂时长启动暂停按钮显示问题 2024-05-10 17:24:43 +08:00
RMBGAME bbe98f68f6 🐛 游戏已加速情况下启动程序闪退问题修复 2024-05-06 19:04:46 +08:00
john.jiang 96025c9ef5 🎨 fixs 2024-05-06 17:12:18 +08:00
john.jiang 2fb12f1b7f 🎨 修复快速掉卡模式剩最后一个游戏闪退Bug 2024-05-06 17:07:07 +08:00
Mossimo 542b528b93 🐛 修复 Ubuntu 版本文件不存在中断问题 2024-04-30 16:28:23 +08:00
RMBGAME 0a4326924d 💄 修复加速模式文本显示错误 2024-04-30 16:13:49 +08:00
john.jiang e8a9990354 🎨 挂卡列表虚拟化缓存加长 2024-04-30 15:25:43 +08:00
Aigio Liu 4e72f9ccf9 🐛 ClickAdvertisement 2024-04-30 13:54:13 +08:00
Aigio Liu 6df6ed93cb 🐛 ClickAdvertisement 2024-04-30 13:42:09 +08:00
Aigio Liu 605beeb918 🐛 CopyToClipboardCommand 2024-04-30 13:38:13 +08:00
Aigio Liu 2bdfbefda9 🐛 OpenAuthUrl 2024-04-30 13:30:34 +08:00
Aigio Liu 6747549cbc 🐛 App.OpenBrowserCommand & IPartialGameAccountSettings null 2024-04-30 12:43:47 +08:00
Mossimo 0d4c0b27f7 🐛 fix 修复2月与新版本差异 2024-04-30 11:58:31 +08:00
Mossimo c501066a3d 🐛 fix 回退 websocket macos 使用 url 协议 2024-04-30 11:47:02 +08:00
john.jiang 57a6b24dad 🎨 修复挂卡价格显示 2024-04-30 11:40:37 +08:00
john.jiang 143011fbd0 🎨 挂卡帐号不一致 Toast 警告,账号登录页登陆成功先跳转主页再获取数据 2024-04-30 11:23:34 +08:00
RMBGAME 11bc9cd440 💄 略微缩减标题栏高度 2024-04-30 00:02:06 +08:00
RMBGAME 72e9068571 💄 简单的加速疑难解答 2024-04-29 19:28:28 +08:00
yingpanwang 5842d5f80f Merge pull request #3321 from BeyondDimension/fix/authenticator-ui
🐛 修复替换令牌时恢复代码不显示的问题
2024-04-29 18:08:06 +08:00
wangyingpan bc19a02f4f 🐛 修复替换令牌时恢复代码不显示的问题
调整添加令牌时的提示信息
2024-04-29 18:07:05 +08:00
Aigio Liu d59d63d57e 🎨 vipEndTimeString 2024-04-29 16:13:40 +08:00
yingpanwang 9ad6e8fa8d Fix/authenticator verifycode UI (#3313)
* 🐛 修复添加令牌邮箱/短信验证ui显示

* 🎨 删除绑定手机号步骤
🐛 修复替换令牌逻辑验证码信息展示错误的问题

* 🐛 修复添加令牌邮箱/短信验证ui显示

* 🎨 删除绑定手机号步骤
🐛 修复替换令牌逻辑验证码信息展示错误的问题

* ✨ 替换令牌中添加绑定手机号窜哦做
2024-04-29 15:27:28 +08:00
Aigio Liu 45ef15b220 🎨 VipEndTimeString 2024-04-29 15:04:47 +08:00
Aigio Liu 25dfd1f888 🐛 VipEndTimeString 2024-04-29 15:01:57 +08:00
Aigio Liu 0495cd3079 💚 CI 2024-04-29 13:14:45 +08:00
Aigio Liu ea9c45d78b 🎨 VipEndTimeString 2024-04-29 13:11:51 +08:00
Aigio Liu 4427fd1a5f 🐛 VipEndTimeString 2024-04-29 12:18:03 +08:00
RMBGAME edf3c3a72c ⬆️ SteamClient 2024-04-29 12:10:10 +08:00
Aigio Liu 55490d2351 🐛 VipEndTimeString 2024-04-29 11:59:22 +08:00
Aigio Liu 17ae6655b4 🐛 VipEndTimeString 2024-04-29 11:55:34 +08:00
john.jiang 342d25deac 🎨 受限账户徽章页处理 2024-04-29 10:59:58 +08:00
RMBGAME f5616dac2e 🐛💄 UI改进,修复加速可能导致的循环修改hosts问题 2024-04-28 22:15:29 +08:00
john.jiang 28914c53f6 🎨 fixs 2024-04-28 19:24:41 +08:00
john.jiang f0cbe8ef88 🎨 会员时长文本显示调整 2024-04-28 19:11:01 +08:00
RMBGAME e0b45bf8af 💄🐛 修复可能导致启动加速无限修改hosts的错误 2024-04-28 17:43:30 +08:00
RMBGAME 854fe420fd 🐛💄 Misc 2024-04-28 17:43:30 +08:00
Aigio Liu c95ce1087a 🐛 Shortcut 2024-04-28 17:29:44 +08:00
Aigio Liu 14ae662675 ✨ URI 激活 2024-04-28 16:18:58 +08:00
RMBGAME 1594bd250e 🐛💄 UI错误修复 2024-04-28 16:09:32 +08:00
Aigio Liu c83ab4fb08 🐛 VipEndTime 2024-04-28 15:35:45 +08:00
Aigio Liu e690454e0c 🐛 VipEndTime 2024-04-28 15:29:13 +08:00
john.jiang 27b4f4bb10 🎨 会员时间显示格式调整 2024-04-28 15:03:42 +08:00
john.jiang 70315c3a99 🎨 fixs 2024-04-28 11:13:45 +08:00
Aigio Liu b8e49a5332 🎨 XY.GetVipEndTime 2024-04-28 10:38:15 +08:00
RMBGAME 1374dc52b8 🐛 2024-04-27 17:40:46 +08:00
RMBGAME 150f93e7b7 ⬆️ Avalonia 11.1.0-beta2 2024-04-27 16:17:59 +08:00
RMBGAME d1aea71f67 🐛 修复一些图片加载问题 2024-04-25 18:51:36 +08:00
RMBGAME 37a522ec7f ⬆️ Image2 2024-04-25 17:43:03 +08:00
RMBGAME 8b816b9787 💄 UI调整优化
现在不需要赞助也可以设置启动默认页
2024-04-25 17:41:49 +08:00
Aigio Liu 4f487a5ca8 🐛 OpenBrowserCommand 2024-04-22 17:03:53 +08:00
Aigio Liu 6c7a547a83 🎨 GetVipEndTime 2024-04-22 17:00:47 +08:00
Aigio Liu bde5751d69 ✨ 会员时间显示与联系客服 2024-04-22 16:45:37 +08:00
Aigio Liu 23544b6c39 🎨 XunYouSDK.GetVipEndTime 2024-04-22 16:13:12 +08:00
RMBGAME 2c60a9fb69 💄 feedback 2024-04-22 16:03:10 +08:00
RMBGAME 4ce67c8f1a 💄 Misc 2024-04-22 11:22:35 +08:00
Aigio Liu e8a1a6153e 🎨 OpenBrowserCommand 2024-04-22 10:26:58 +08:00
ff m 452fa2ac84 🐛 离线安装也支持选择初始化位置 2024-04-20 18:51:23 +08:00
ff m 60e6d71d48 ✨ 安装脚本支持安装到指定目录,支持选择desktop创建至 $HOME/.local/share/applications/ or $HOME/Desktop
The most significant changes to the `online_install.sh` script involve the addition of user prompts for customization of the installation path and the location of the desktop file. The script now includes a loop to allow the user to input a custom installation path or use the default one. If the user provides an invalid path, they are prompted to input again. The script also creates the installation path and switches to it, outputting an error message and exiting with status 1 if it fails to do so. A new function, `InitDesktop`, has been added to prompt the user to choose where to add the desktop file. The user can choose between `$HOME/.local/share/applications/` and `$HOME/Desktop`. The script then removes any existing desktop file in the chosen location and creates a new one. If the user provides an invalid option, they are prompted to input again.

List of changes:

1. A loop has been added to prompt the user to input a custom installation path or use the default path. If the user provides an invalid path, they are prompted to input again (online_install.sh).

2. The script now creates the installation path and switches to it. If it fails to do either, it outputs an error message and exits with status 1 (online_install.sh).

3. A function `InitDesktop` has been added to prompt the user to choose where to add the desktop file. The user can choose between `$HOME/.local/share/applications/` and `$HOME/Desktop`. The script then removes any existing desktop file in the chosen location and creates a new one. If the user provides an invalid option, they are prompted to input again (online_install.sh).

4. The function `InitDesktop` is called to execute the above changes (online_install.sh).
2024-04-20 18:39:43 +08:00
RMBGAME ae0e2349e7 🐛 fix Errors caused by testing modifications 2024-04-20 17:28:47 +08:00
Aigio Liu 3a0f2a4950 🐛 ShowStart 2024-04-19 21:26:22 +08:00
Aigio Liu 5263863c23 🐛 ShowStart 2024-04-19 20:22:41 +08:00
RMBGAME c52f3c3e00 💄 测试加速项 Beta徽章 2024-04-18 20:39:51 +08:00
RMBGAME be61df890e 🐛 修复 隔行扫描gif图 动态头像显示错误 2024-04-17 23:05:49 +08:00
Aigio Liu 6a7c9113a0 ✨ XunYouState.启动游戏成功/启动游戏失败 2024-04-16 19:15:26 +08:00
Aigio Liu ac953af7a1 🎨 hosts mark duplicate auto reset 2024-04-16 14:15:31 +08:00
john.jiang 147a6b911f 🎨 家庭监护账号Cookie取消本地储存,有效期太短 2024-04-16 13:29:30 +08:00
wangyingpan 972054ca7c ⬆️ 更新 ClientSDK 2024-04-15 17:13:03 +08:00
RMBGAME 0cea809b40 🐛 fix 2024-04-15 16:24:23 +08:00
lxy829 7ec34e59a7 🎨 切换提示 2024-04-12 16:12:36 +08:00
RMBGAME 00d41dfbc8 🚧 Misc 2024-04-12 14:52:07 +08:00
RMBGAME 0272a34e5c ✨ 游戏加速 启动游戏按钮 2024-04-12 12:21:15 +08:00
wangyingpan d450753c92 添加代理token 缓存 2024-04-11 14:29:30 +08:00
wangyingpan 1e6263c241 🎨 调整尝试获取服务端代理token 方法 2024-04-11 13:51:41 +08:00
RMBGAME a4602d29a7 🐛 fix background img 2024-04-10 16:40:00 +08:00
john.jiang 7623788991 🎨 Idle挂卡家庭监护账号处理 2024-04-09 15:27:57 +08:00
Aigio Liu 8075183be1 ✨ XYSDK 2024-04-09 15:20:39 +08:00
ff m 058f1a9bf2 🐛 屏蔽 IPC 脚本内容优化 2024-04-08 20:52:09 +08:00
wangyingpan 196b7f0f5e 🐛 回撤ForwarderRequestConfig的错误修改 2024-04-03 18:29:14 +08:00
wangyingpan 99d24b2513 Merge branch 'develop' of https://github.com/BeyondDimension/SteamTools into develop 2024-04-03 18:26:35 +08:00
wangyingpan 7e3fb6cf06 ✨ 启动加速时请求服务端代理token,代理设置添加服务端代理token属性 2024-04-03 18:26:29 +08:00
lxy829 a0a0dd9bc7 🎨 fix 2024-04-03 16:37:21 +08:00
lxy829 81f75e61ca 🎨 Shortcut 指向协议 2024-04-03 16:08:16 +08:00
john.jiang 11890c68a8 🎨 修复挂卡顺序切换图片不显示 2024-04-03 11:20:32 +08:00
RMBGAME be8621d4d5 ✨ 增加代理http3支持
修复twitch登录失效
修复twitch直播聊天失效
修复twtich面板内图片加载失败
修复Github Docs网站代理无效且异常重定向
修复Github education网站代理无效且异常重定向
修复Gravatar加速失效
新增Open Spotify加速
新增Github Dev加速
2024-04-02 19:07:16 +08:00
wangyingpan 511c84b2ba 添加服务端代理转发头 2024-04-02 18:31:07 +08:00
john.jiang 9e75da9e46 🎨 fixs 2024-04-02 10:57:53 +08:00
john.jiang 547b360db8 🎨 Idle 启动失败提示 2024-04-02 10:56:37 +08:00
john.jiang 9be21a8e0a 🎨 挂卡完成提示完善 2024-04-01 17:00:46 +08:00
john.jiang efbb41bf3f 🎨 快速挂卡模式优化 2024-04-01 14:31:45 +08:00
RMBGAME c2220359dd 🐛 fix 2024-03-29 22:16:46 +08:00
lxy829 a788afdeeb 🎨 Steam 账号加载方式优化 2024-03-28 11:19:34 +08:00
BuknSS b543a889a0 🎨 Remove temporary test code. 2024-03-27 16:08:52 +08:00
lxy829 478950b75f 🎨 GameAccountShortcut 2024-03-26 19:13:07 +08:00
Aigio Liu 27b4114d7d 🔖 3.0.0-rc.8 2024-03-26 15:30:41 +08:00
Aigio Liu 6ead1f3666 🐛 |Error|HostsFileS|TryReadHosts fail, methodName: ContainsHostsByTag. | System.IO.IOException: The process cannot access the file 'C:\WINDOWS\system32\drivers\etc\hosts' because it is being used by another process.
at Microsoft.Win32.SafeHandles.SafeFileHandle.CreateFile(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options)
   at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
   at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
   at System.IO.Strategies.FileStreamHelpers.ChooseStrategyCore(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
   at System.IO.StreamReader.ValidateArgsAndOpenPath(String path, Encoding encoding, Int32 bufferSize)
   at System.IO.File.ReadAllLines(String path, Encoding encoding)
2024-03-26 14:24:36 +08:00
Aigio Liu 22a015d8b9 ✨ hosts 文件监听 2024-03-26 12:02:59 +08:00
BuknSS f5b7cd6db8 🐛 Fix not regenerating a valid certificate after the certificate expires. 2024-03-26 11:02:33 +08:00
lxy829 5a397d1311 🎨 SteamSwitchShortcut 2024-03-25 18:59:03 +08:00
Aigio Liu 0c1bedaeb1 🔥 iotest 2024-03-22 21:50:32 +08:00
Aigio Liu e959dcc017 ✨ 查看证书信息 2024-03-22 19:05:31 +08:00
RMBGAME 41610453a0 🐛 fix 挂卡首次登录后数据加载问题 2024-03-20 20:10:21 +08:00
ff m adf3e0ca9d 🐛 UrlsOpened 11.1 使用新 API 2024-03-20 00:21:00 +08:00
Aigio Liu 21e80a5b7b 🎨 XunYouSDK.GetGameInfo 2024-03-18 13:57:58 +08:00
Aigio Liu 9a78f387cf 🔖 3.0.0-rc.7 2024-03-16 19:20:17 +08:00
Aigio Liu 8a091cee0c 🐛 tabItems 2024-03-16 19:01:32 +08:00
RMBGAME 28f9dde2a4 Revert "🐛 PluginCount"
This reverts commit 01e8478ce0.
2024-03-16 18:44:34 +08:00
RMBGAME aa88832d09 🐛 账号切换备注 ToolTip 显示 2024-03-16 18:44:17 +08:00
ff m 3da18b39ac 🐛 HttpUtility.UrlEncode 特定日期下无法格式 下午 这个中文
2024%2f4%2f15+下午4%3a13%3a52+%2b00%3a00
2024-03-16 14:54:33 +08:00
Aigio Liu 01e8478ce0 🐛 PluginCount 2024-03-16 14:45:04 +08:00
RMBGAME 0de026257a 🐛 fix 登录窗口登录成功后未正常关闭 2024-03-15 22:33:08 +08:00
Aigio Liu 5ff097d7d6 🐛 UISettings.StartDefaultPageName 在最小化启动时无效 x2 2024-03-15 19:14:48 +08:00
Aigio Liu 59effc34a3 🐛 UISettings.StartDefaultPageName 在最小化启动时无效 2024-03-15 17:25:36 +08:00
Aigio Liu afd21a3285 ✨ 加速页面 Tab 选项框下标记住选择 2024-03-15 14:14:04 +08:00
Aigio Liu c7ffeb6046 🔖 3.0.0-rc.6 2024-03-15 13:12:02 +08:00
Aigio Liu e659e3d502 ✨ Visual Studio App Center Retirement
https://learn.microsoft.com/en-us/appcenter/retirement
2024-03-15 11:44:02 +08:00
Aigio Liu 077a333d49 🎨 改进主窗口数据加载 2024-03-15 11:32:50 +08:00
Aigio Liu 056a73e3f0 🐛 起始页数据加载 2024-03-15 11:32:50 +08:00
RMBGAME db5095c205 🐛 显示加速模式与脚本状态 2024-03-13 18:11:55 +08:00
RMBGAME a1789cec16 🐛 fix挂时长在游戏列表未加载完成时进入错误的标注了游戏所属 2024-03-13 17:44:28 +08:00
Aigio Liu 9a234ae84f 🐛 MvvmService thread safe 2024-03-13 16:41:15 +08:00
Aigio Liu 8692eaef7c 🐛 ProxyService thread safe 2024-03-13 16:09:30 +08:00
lxy829 cb6516ce53 🎨 EpicSwitch 2024-03-13 11:35:20 +08:00
RMBGAME d8362ce9ea ✨ 支持设置启动时默认页(仍有一些问题) 2024-03-13 05:17:01 +08:00
RMBGAME 0cfdff80cd 🐛 修复加速项目勾选三级菜单启动加速没生效问题
修复账号切换首次打开没有读取缓存依然加载问题
2024-03-12 20:43:11 +08:00
RMBGAME 15c67bcd52 🐛 fix Steam账号切换删除时缓存没有正常清理问题 2024-03-10 21:42:12 +08:00
RMBGAME 3ebe7de3d7 💄 Misc 2024-03-10 21:12:57 +08:00
Aigio Liu deee8d056f 🎨 FileVersion 2024-03-08 17:57:36 +08:00
ff m 3016469c7f 🐛 Fix macOs Icons 2024-03-08 17:44:38 +08:00
Aigio Liu 526fb7a78d 🐛 图片加载缓存 2024-03-08 15:56:13 +08:00
RMBGAME 2790ffc5f1 🐛 Carousel CancelToken 2024-03-08 15:14:14 +08:00
RMBGAME e22897e2ae 🐛 挂卡登录异常处理 2024-03-08 15:03:46 +08:00
RMBGAME 00b8c4dfcf 💄 插件设置的一些样式 2024-03-08 14:54:10 +08:00
Aigio Liu 9a2d2c6c94 🐛 PublishTool 2024-03-08 14:36:19 +08:00
Aigio Liu 29fb43fc38 ⬆️ 3.0.0 rc.5 2024-03-08 11:30:22 +08:00
Aigio Liu 4ca3066644 🐛 https://github.com/BeyondDimension/SteamTools/issues/3213 https://github.com/BeyondDimension/SteamTools/issues/3214 2024-03-08 11:04:23 +08:00
RMBGAME 890f2fab37 🐛 fix最小化启动失效问题 2024-03-07 19:50:38 +08:00
Aigio Liu f561f841e3 🐛 MSStore DNS Mode x3 2024-03-07 18:59:45 +08:00
Aigio Liu a016631d68 🐛 MSStore DNS Mode x2 2024-03-07 18:24:46 +08:00
ff m 367c97b480 Script 文件存在强制替换 Delete 后未移动文件导致丢失。 2024-03-07 18:21:59 +08:00
Aigio L 6367bc5ed1 🐛 MSStore DNS Mode (#3211) 2024-03-07 17:07:59 +08:00
lxy829 2b69b98f3c 🎨 Riot Games and Rockstar switch 2024-03-06 16:28:47 +08:00
Aigio L a6010ba5f4 Merge pull request #3198 from BeyondDimension/develop
v3.0.0-rc.4_win_x64_240306_1204508630992
2024-03-06 13:42:14 +08:00
358 changed files with 6753 additions and 3914 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
run: dotnet build -c Release src\BD.WTTS.Client.AppHost\BD.WTTS.Client.AppHost.csproj --nologo -v q --property:WarningLevel=1;DebugType=pdbonly
- 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
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;DebugType=pdbonly
- 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
run: dotnet build -c Release src\BD.WTTS.Client.Avalonia.App\BD.WTTS.Client.Avalonia.App.csproj --nologo -v q --property:WarningLevel=1;DebugType=pdbonly
- 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
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;DebugType=pdbonly
- name: Test
run: dotnet test src/BD.WTTS.UnitTest/BD.WTTS.UnitTest.csproj -c Release -p:GeneratePackageOnBuild=false --nologo -v q /property:WarningLevel=1
run: dotnet test src/BD.WTTS.UnitTest/BD.WTTS.UnitTest.csproj -c Release -p:GeneratePackageOnBuild=false --nologo -v q --property:WarningLevel=1;DebugType=pdbonly
# release:
# name: Release
+24 -5
View File
@@ -172,17 +172,36 @@ else
fi
chmod +x "$base_path/$exec_name.sh"
# xdg-icon-resource install "$base_path/Icons/Watt-Toolkit.png" --size 128 Watt-Toolkit
#添加桌面文件
rm -rf "$HOME/Desktop/Watt Toolkit.desktop" 2>/dev/null
echo "#!/usr/bin/env xdg-open
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" >"$HOME/Desktop/Watt Toolkit.desktop"
chmod +x "$HOME/Desktop/Watt Toolkit.desktop"
StartupNotify=false" >"$target_dir/Watt Toolkit.desktop"
chmod +x "$target_dir/Watt Toolkit.desktop"
}
InitDesktop
# update-desktop-database ~/.local/share/applications
#运行程序
Show_Run "下载安装完成,是否启动程序?"
+61 -9
View File
@@ -1,7 +1,38 @@
#!/bin/bash
base_path="$HOME/WattToolkit"
mkdir -p "$base_path"
cd "$base_path" || exit 1
# 设置默认的 base_path 参数
default_base_path="$HOME/WattToolkit"
base_path="$default_base_path"
# 循环直到用户输入有效路径或直接回车
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
}
appVer_path="$base_path/WattToolkit.AppVer"
exec_name="Steam++"
tar_name="WattToolkit.tgz"
@@ -182,7 +213,9 @@ Get_NewVer() {
sleep 1
#本地版本 Hash
o_sha384=$(cat "AppVer")
if [ -f "AppVer" ]; then
o_sha384=$(cat "AppVer")
fi
if [ -e "AppVer" ]; then
if [ "${o_sha384,,}" = "${n_sha384,,}" ]; then
Show_Run "已是最新版本,是否启动程序?"
@@ -326,17 +359,36 @@ Kill_Process
#解压
Decompression
# xdg-icon-resource install "$base_path/Icons/Watt-Toolkit.png" --size 128 Watt-Toolkit
#添加桌面文件
rm -rf "$HOME/Desktop/Watt Toolkit.desktop" 2>/dev/null
echo "#!/usr/bin/env xdg-open
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" >"$HOME/Desktop/Watt Toolkit.desktop"
chmod +x "$HOME/Desktop/Watt Toolkit.desktop"
StartupNotify=false" >"$target_dir/Watt Toolkit.desktop"
chmod +x "$target_dir/Watt Toolkit.desktop"
}
InitDesktop
# update-desktop-database ~/.local/share/applications
#运行程序
Show_Run "下载安装完成,是否启动程序?"
+27
View File
@@ -212,6 +212,15 @@
"Summary": "菜单排序",
"IsRegionOrEndregion": null,
"IsValueType": null
},
{
"TypeName": "string",
"PropertyName": "StartDefaultPageName",
"DefaultValue": "null",
"DefaultValueIsConst": true,
"Summary": "程序启动时默认页",
"IsRegionOrEndregion": null,
"IsValueType": null
}
],
"Usings": ""
@@ -487,6 +496,15 @@
"Summary": "账号平台设置集合",
"IsRegionOrEndregion": null,
"IsValueType": null
},
{
"TypeName": "bool",
"PropertyName": "IsShowAccountName",
"DefaultValue": "false",
"DefaultValueIsConst": false,
"Summary": "是否显示账号用户名",
"IsRegionOrEndregion": null,
"IsValueType": null
}
],
"Usings": ""
@@ -961,6 +979,15 @@
"Summary": "自定义 DNS over HTTPS 地址",
"IsRegionOrEndregion": null,
"IsValueType": null
},
{
"TypeName": "int",
"PropertyName": "AcceleratorTabsSelectedIndex",
"DefaultValue": "0",
"DefaultValueIsConst": false,
"Summary": "加速页面 Tab 选项卡选中下标",
"IsRegionOrEndregion": null,
"IsValueType": null
}
],
"Usings": ""
+26 -2
View File
@@ -3,6 +3,14 @@ namespace BD.WTTS;
/// <summary>
/// 提供用来获取应用程序信息(如版本号、说明、加载的程序集等)的属性。
/// </summary>
[Mobius3(
"""
Mobius.AssemblyInfo
AssemblyInfo.cs
AssemblyInfo.Version.cs
AssemblyInfo.Version.NativeHost.cs
AssemblyInfo.Version.Setup.Windows.cs
""")]
public static partial class AssemblyInfo
{
const string Version2 = "3.0";
@@ -16,12 +24,12 @@ public static partial class AssemblyInfo
/// <summary>
/// 预览版本号,范围 1~9,只增不减
/// </summary>
const string ver_for_preview = "7";
const string ver_for_preview = "8";
/// <summary>
/// RC 版本号,范围 0~9,只增不减
/// </summary>
const string ver_for_rc = "4";
const string ver_for_rc = "8";
public const string FileVersion = $"{Version2}.{ver_for_rc}0{ver_for_preview}.0";
@@ -146,4 +154,20 @@ false
#endif
}
[AttributeUsage(AttributeTargets.All, Inherited = false)]
sealed class Mobius3Attribute : Attribute
{
public Mobius3Attribute()
{
}
public Mobius3Attribute(string str)
{
}
public bool Obsolete { get; set; }
}
+1
View File
@@ -1,3 +1,4 @@
// Mobius Properties\XmlnsDefinition.cs
#if (WINDOWS || MACCATALYST || MACOS || LINUX) && !(IOS || ANDROID)
// C# 10 定义全局 using
@@ -38,9 +38,9 @@ public interface IFontManagerImpl2 : IFontManagerImpl
return Impl.TryCreateGlyphTypeface(familyName, style, weight, stretch, out glyphTypeface);
}
bool IFontManagerImpl.TryCreateGlyphTypeface(Stream stream, [NotNullWhen(returnValue: true)] out IGlyphTypeface? glyphTypeface)
bool IFontManagerImpl.TryCreateGlyphTypeface(Stream stream, FontSimulations fontSimulations, [NotNullWhen(returnValue: true)] out IGlyphTypeface? glyphTypeface)
{
return Impl.TryCreateGlyphTypeface(stream, out glyphTypeface);
return Impl.TryCreateGlyphTypeface(stream, fontSimulations, out glyphTypeface);
}
//IGlyphTypeface IFontManagerImpl.CreateGlyphTypeface(Typeface typeface)
File diff suppressed because it is too large Load Diff
@@ -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,70 +8,67 @@
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.999.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>
</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>
<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>
<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>
@@ -22,6 +22,8 @@
<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>
@@ -81,8 +81,10 @@
<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="Avalonia.AvaloniaEdit" />
<PackageReference Include="AvaloniaEdit.TextMate" />
<!--<PackageReference Include="Markdown.Avalonia" />-->
<PackageReference Include="FluentAvaloniaUI" />
<PackageReference Include="LiveChartsCore.SkiaSharpView.Avalonia" />
@@ -130,6 +132,9 @@
<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" />
@@ -0,0 +1,111 @@
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,11 +2,18 @@ namespace BD.WTTS.UI;
public static class ControlExtensions
{
public static void SetViewModel<T>(this Control c) where T : ViewModelBase, new()
public static void SetViewModel<T>(this Control c, bool useCache = false) where T : ViewModelBase, new()
{
if (c.DataContext == null || c.DataContext.GetType() != typeof(T))
{
c.DataContext = new T();
T cx;
if (useCache)
cx = IViewModelManager.Instance.Get<T>();
else
cx = new T();
c.DataContext = cx;
}
}
}
@@ -113,7 +113,6 @@ public sealed class AvaloniaWindowManagerImpl : IWindowManagerImpl
if (viewModel != null)
{
if (viewModel is IWindowViewModel window)
{
window.Close = b => td?.Hide(b ? TaskDialogStandardResult.OK : TaskDialogStandardResult.Close);
@@ -7,12 +7,28 @@ namespace BD.WTTS.UI;
partial class App
{
[Mobius(
"""
App.DefaultActualTheme
""")]
const AppTheme _DefaultActualTheme = AppTheme.FollowingSystem;
[Mobius(
"""
App.DefaultActualTheme
""")]
AppTheme IApplication.DefaultActualTheme => _DefaultActualTheme;
[Mobius(
"""
App.mTheme
""")]
AppTheme mTheme = _DefaultActualTheme;
[Mobius(
"""
App.Theme
""")]
public AppTheme Theme
{
get => mTheme;
@@ -50,6 +66,10 @@ partial class App
}
}
[Mobius(
"""
App.SetThemeNotChangeValue
""")]
public void SetThemeNotChangeValue(AppTheme value)
{
var mode = value switch
@@ -71,6 +91,10 @@ partial class App
}
}
[Mobius(
"""
App.SetThemeAccent
""")]
public static void SetThemeAccent(string? colorHex)
{
if (colorHex == null)
+38 -2
View File
@@ -9,14 +9,34 @@ namespace BD.WTTS.UI;
partial class App
{
[Mobius(
"""
App.TrayMenus
""")]
public Dictionary<string, TrayMenuItem> TrayMenus { get; } = new Dictionary<string, TrayMenuItem>();
[Mobius(
"""
App.TrayIcons
""")]
public TrayIcons TrayIcons { get; init; } = new TrayIcons();
[Mobius(
"""
App.trayIconMenus
""")]
readonly Dictionary<string, ICommand> trayIconMenus = new();
[Mobius(
"""
App.TrayIconMenus
""")]
public IReadOnlyDictionary<string, ICommand> TrayIconMenus => trayIconMenus;
[Mobius(
"""
App.InitTrayIcon
""")]
void InitTrayIcon()
{
if (ApplicationLifetime is not
@@ -67,6 +87,10 @@ partial class App
}
}
[Mobius(
"""
App.UpdateMenuItems
""")]
public void UpdateMenuItems()
{
MainThread2.BeginInvokeOnMainThread(() =>
@@ -125,12 +149,20 @@ partial class App
{
subMenu = new NativeMenu();
foreach (var sub in item.Value.Items)
subMenu.Add(new NativeMenuItem
{
var menu = 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,
@@ -158,6 +190,10 @@ partial class App
});
}
[Mobius(
"""
App.UpdateMenuItems
""")]
public void UpdateMenuItems(string menuKey, TrayMenuItem trayMenuItem)
{
if (TrayMenus != null)
+32 -7
View File
@@ -11,6 +11,12 @@ public sealed partial class App : Application
{
const string TAG = "AvaApp";
public App()
{
OpenBrowserCommand = ReactiveCommand.Create<object?>(OpenBrowserCommandCore);
CopyToClipboardCommand = ReactiveCommand.Create<object?>(CopyToClipboardCommandCore);
}
/// <summary>
/// 获取当前主窗口
/// </summary>
@@ -44,9 +50,9 @@ public sealed partial class App : Application
AvaloniaXamlLoader.Load(this);
#if WINDOWS || LINUX || MACOS
//非主窗口不执行启动时最小化逻辑
if (GeneralSettings.MinimizeOnStartup.Value && MainWindow is MainWindow)
if (GeneralSettings.MinimizeOnStartup.Value)
Startup.Instance.IsMinimize = true;
if (Startup.Instance.IsSteamRun)
{
try
@@ -94,9 +100,10 @@ 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 ? null :
Startup.Instance.IsMinimize && MainWindow is MainWindow ? null :
#endif
MainWindow;
@@ -224,16 +231,32 @@ public sealed partial class App : Application
public static FontFamily DefaultFontFamily => _DefaultFontFamily.Value;
public void OpenBrowserCommand(object url)
public ICommand OpenBrowserCommand { get; }
public async void OpenBrowserCommandCore(object? url)
{
try
{
if (url == null || string.IsNullOrEmpty(url.ToString()))
var urlString = url?.ToString();
if (string.IsNullOrEmpty(urlString))
{
Toast.Show(ToastIcon.Warning, "打开链接失败");
return;
}
Browser2.Open(url.ToString());
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);
}
catch (Exception ex)
{
@@ -241,7 +264,9 @@ public sealed partial class App : Application
}
}
public async void CopyToClipboardCommand(object text)
public ICommand CopyToClipboardCommand { get; }
public async void CopyToClipboardCommandCore(object? text)
{
try
{
Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

@@ -6,8 +6,8 @@
x:CompileBindings="True">
<Styles.Resources>
<ResourceDictionary>
<sys:Double x:Key="TitleBarHeight">60</sys:Double>
<Thickness x:Key="TitleBarAfterMargin">0,60,0,0</Thickness>
<sys:Double x:Key="TitleBarHeight">50</sys:Double>
<Thickness x:Key="TitleBarAfterMargin">0,50,0,0</Thickness>
<sys:Double x:Key="SplashScreenImageWidth">100</sys:Double>
<Thickness x:Key="PageMargin">10</Thickness>
@@ -66,6 +66,7 @@
<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" />
@@ -7,7 +7,7 @@
<Border Padding="20">
<!-- Add Controls for Previewer Here -->
<StackPanel Spacing="10">
<ui:HyperlinkButton Content="更新日志" />
<HyperlinkButton Content="更新日志" />
<Button Content="更新日志" Theme="{StaticResource HyperlinkButton}" />
<Button
Content="更新日志"
@@ -87,7 +87,7 @@
<Setter Property="CornerRadius" Value="{DynamicResource ControlCornerRadius}" />
<Setter Property="Template">
<ControlTemplate>
<ui:FABorder
<Border
Name="Root"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
@@ -101,19 +101,19 @@
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
RecognizesAccessKey="True" />
</ui:FABorder>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:pointerover">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorSecondaryBrush}" />
</Style>
</Style>
<Style Selector="^:pressed">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorTertiaryBrush}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -122,7 +122,7 @@
</Style>
<Style Selector="^:disabled">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorDisabledBrush}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -131,7 +131,7 @@
</Style>
<Style Selector="^:checked">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundChecked}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -140,7 +140,7 @@
<Style Selector="^:pointerover">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundCheckedPointerOver}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -149,7 +149,7 @@
</Style>
<Style Selector="^:pressed">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundCheckedPressed}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -158,7 +158,7 @@
</Style>
<Style Selector="^:disabled">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorDisabledBrush}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -168,19 +168,19 @@
</Style>
<Style Selector="^:indeterminate">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorTransparentBrush}" />
</Style>
<Style Selector="^:pointerover">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorSecondaryBrush}" />
</Style>
</Style>
<Style Selector="^:pressed">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorTertiaryBrush}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -189,7 +189,7 @@
</Style>
<Style Selector="^:disabled">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorDisabledBrush}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -214,10 +214,13 @@
<Style Selector="Button.Plain:pointerover">
<Setter Property="Background" Value="Transparent" />
</Style>
<Style Selector="Button.Plain:pointerover /template/ ui|FABorder#Root">
<Style Selector="Button.Plain:pointerover /template/ Border#Root">
<Setter Property="Background" Value="Transparent" />
</Style>
<Style Selector="Button.Plain:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="Transparent" />
</Style>
</Styles>
@@ -63,14 +63,13 @@
Height="10"
HorizontalAlignment="Center"
VerticalAlignment="Bottom">
<ItemsRepeater Name="Swiper" IsVisible="False">
<ItemsRepeater.Layout>
<StackLayout
DisableVirtualization="True"
Orientation="Horizontal"
Spacing="8" />
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<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" />
@@ -91,8 +90,8 @@
StrokeThickness="0" />
</Button>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Panel>
</Grid>
</Border>
@@ -18,27 +18,15 @@
HorizontalAlignment="Center"
VerticalAlignment="Center"
IsVisible="{TemplateBinding IsLoading}"
Spacing="8">
<spp:Image2
Spacing="10">
<!--<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" />
<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}" />
Stretch="UniformToFill" />-->
<Border
Width="35"
Height="35"
@@ -51,6 +39,18 @@
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
@@ -101,5 +101,8 @@
</Panel>
</ControlTemplate>
</Setter>
<Style Selector="^:loading /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Effect" Value="blur(5)" />
</Style>
</ControlTheme>
</ResourceDictionary>
@@ -46,19 +46,19 @@
<Setter Property="Template">
<ControlTemplate>
<StackPanel>
<ui:FABorder
<Border
Name="LayoutRoot"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<ui:FABorder.Transitions>
<Border.Transitions>
<Transitions>
<BrushTransition Property="Background" Duration="00:00:00.083" />
<BrushTransition Property="BorderBrush" Duration="00:00:00.083" />
</Transitions>
</ui:FABorder.Transitions>
</Border.Transitions>
<Grid MinHeight="{TemplateBinding MinHeight}" ColumnDefinitions="Auto,*,Auto,Auto">
<Viewbox
Name="IconHost"
@@ -113,7 +113,7 @@
VerticalAlignment="Center"
FontSize="18" />
</Grid>
</ui:FABorder>
</Border>
<ContentPresenter
Name="ExpandedContentPresenter"
@@ -144,10 +144,10 @@
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="spp|OptionsDisplayItem /template/ ui|FABorder#LayoutRoot:pointerover">
<Style Selector="spp|OptionsDisplayItem /template/ Border#LayoutRoot:pointerover">
<Setter Property="Background" Value="{DynamicResource ControlFillColorSecondaryBrush}" />
</Style>
<Style Selector="spp|OptionsDisplayItem:pressed /template/ ui|FABorder#LayoutRoot:pointerover">
<Style Selector="spp|OptionsDisplayItem:pressed /template/ Border#LayoutRoot:pointerover">
<Setter Property="Background" Value="{DynamicResource ControlFillColorTertiaryBrush}" />
</Style>
@@ -179,7 +179,7 @@
<Setter Property="CornerRadius" Value="{Binding CornerRadius, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BottomCornerRadiusFilterConverter}}" />
</Style>
<Style Selector="spp|OptionsDisplayItem:expanded /template/ ui|FABorder#LayoutRoot">
<Style Selector="spp|OptionsDisplayItem:expanded /template/ Border#LayoutRoot">
<Setter Property="CornerRadius" Value="{Binding CornerRadius, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource TopCornerRadiusFilterConverter}}" />
</Style>
@@ -195,19 +195,19 @@
<Style Selector="spp|OptionsDisplayItem.Vertical">
<Setter Property="Template">
<ControlTemplate>
<ui:FABorder
<Border
Name="LayoutRoot"
Padding="12"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<ui:FABorder.Transitions>
<Border.Transitions>
<Transitions>
<BrushTransition Property="Background" Duration="00:00:00.083" />
<BrushTransition Property="BorderBrush" Duration="00:00:00.083" />
</Transitions>
</ui:FABorder.Transitions>
</Border.Transitions>
<Grid RowDefinitions="*,*">
<Border
Width="72"
@@ -241,7 +241,7 @@
TextWrapping="Wrap" />
</StackPanel>
</Grid>
</ui:FABorder>
</Border>
</ControlTemplate>
</Setter>
</Style>
@@ -38,18 +38,18 @@
<Setter Property="MinHeight" Value="{DynamicResource SettingsExpanderItemMinHeight}" />
<Setter Property="Template">
<ControlTemplate>
<ui:FABorder
<Border
Name="Root"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ui:FABorder.Transitions>
<Border.Transitions>
<Transitions>
<BrushTransition Property="Background" Duration="00:00:00.083" />
<BrushTransition Property="BorderBrush" Duration="00:00:00.083" />
</Transitions>
</ui:FABorder.Transitions>
</Border.Transitions>
<Grid ColumnDefinitions="*,Auto,Auto" RowDefinitions="*,Auto">
<Viewbox
@@ -102,7 +102,7 @@
<ContentPresenter Name="ExpandChevronActionIconContainer" Content="{Binding TemplateSettings.ActionIcon, RelativeSource={RelativeSource TemplatedParent}}" />
</Viewbox>
</Grid>
</ui:FABorder>
</Border>
</ControlTemplate>
</Setter>
@@ -110,7 +110,7 @@
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^:nth-last-child(1) /template/ ui|FABorder#Root">
<Style Selector="^:nth-last-child(1) /template/ Border#Root">
<Setter Property="CornerRadius" Value="{Binding Source={StaticResource ControlCornerRadius}, Converter={StaticResource BottomCornerRadiusFilterConverter}}" />
</Style>
@@ -152,11 +152,11 @@
</Style>
<Style Selector="^:allowClick">
<Style Selector="^:pointerover /template/ ui|FABorder#Root">
<Style Selector="^:pointerover /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource ControlFillColorSecondaryBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource ControlFillColorSecondaryBrush}" />
</Style>
<Style Selector="^:pressed /template/ ui|FABorder#Root">
<Style Selector="^:pressed /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource ControlFillColorTertiaryBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource ControlStrokeColorDefaultBrush}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource TextFillColorSecondaryBrush}" />
@@ -164,7 +164,7 @@
</Style>
<Style Selector="^:disabled">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource ControlFillColorDisabledBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource ControlStrokeColorDefaultBrush}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource TextFillColorDisabledBrush}" />
@@ -0,0 +1,111 @@
<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">
<ui:FABorder
<Border
Name="ContentRoot"
VerticalAlignment="Top"
BorderBrush="{DynamicResource InfoBarBorderBrush}"
@@ -205,13 +205,13 @@
</Button>
</Grid>
</Panel>
</ui:FABorder>
</Border>
</LayoutTransformControl>
</ControlTemplate>
</Setter>
<Style Selector="^:informational">
<Style Selector="^ /template/ ui|FABorder#ContentRoot">
<Style Selector="^ /template/ Border#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/ ui|FABorder#ContentRoot">
<Style Selector="^ /template/ Border#ContentRoot">
<Setter Property="Background" Value="{DynamicResource InfoBarErrorSeverityBackgroundBrush}" />
</Style>
<Style Selector="^ /template/ Ellipse#IconBackground">
@@ -241,7 +241,7 @@
</Style>
<Style Selector="^:warning">
<Style Selector="^ /template/ ui|FABorder#ContentRoot">
<Style Selector="^ /template/ Border#ContentRoot">
<Setter Property="Background" Value="{DynamicResource InfoBarWarningSeverityBackgroundBrush}" />
</Style>
<Style Selector="^ /template/ Ellipse#IconBackground">
@@ -255,7 +255,7 @@
</Style>
<Style Selector="^:success">
<Style Selector="^ /template/ ui|FABorder#ContentRoot">
<Style Selector="^ /template/ Border#ContentRoot">
<Setter Property="Background" Value="{DynamicResource InfoBarSuccessSeverityBackgroundBrush}" />
</Style>
<Style Selector="^ /template/ Ellipse#IconBackground">
@@ -294,7 +294,7 @@
</Style>
<!-- Visible -->
<Style Selector="^:hidden /template/ ui|FABorder#ContentRoot">
<Style Selector="^:hidden /template/ Border#ContentRoot">
<Setter Property="IsVisible" Value="False" />
</Style>
@@ -75,7 +75,7 @@
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="Template">
<ControlTemplate>
<ui:FABorder
<Border
Name="Root"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
Background="{TemplateBinding Background}"
@@ -83,19 +83,19 @@
BorderThickness="1"
CornerRadius="{TemplateBinding CornerRadius}"
TemplatedControl.IsTemplateFocusTarget="True">
<ui:FABorder.Transitions>
<Border.Transitions>
<Transitions>
<BrushTransition Property="Background" Duration="00:00:00.083" />
</Transitions>
</ui:FABorder.Transitions>
</Border.Transitions>
<Panel>
<ui:FABorder
<Border
Name="Hover"
Margin="3"
Background="Transparent"
CornerRadius="{TemplateBinding CornerRadius}">
<ui:FABorder.Transitions>
<Border.Transitions>
<Transitions>
<BrushTransition Property="Background" Duration="00:00:00.083" />
<TransformOperationsTransition
@@ -103,8 +103,8 @@
Property="RenderTransform"
Duration="00:00:00.167" />
</Transitions>
</ui:FABorder.Transitions>
</ui:FABorder>
</Border.Transitions>
</Border>
<ContentPresenter
Name="PART_ContentPresenter"
@@ -139,19 +139,19 @@
</Rectangle>
</Panel>
</ui:FABorder>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:pointerover">
<Style Selector="^ /template/ ui|FABorder#Hover">
<Style Selector="^ /template/ Border#Hover">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorSecondaryBrush}" />
</Style>
</Style>
<Style Selector="^:pressed">
<Style Selector="^ /template/ ui|FABorder#Hover">
<Style Selector="^ /template/ Border#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/ ui|FABorder#Hover">
<Style Selector="^ /template/ Border#Hover">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#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/ ui|FABorder#Hover">
<Style Selector="^ /template/ Border#Hover">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource ControlFillColorDisabledBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource ControlAltFillColorSecondaryBrush}" />
</Style>
@@ -80,7 +80,7 @@
<Setter Property="Template">
<ControlTemplate>
<Panel Name="LayoutRoot" Background="{x:Null}">
<ui:FABorder
<Border
Name="ContentRoot"
MinWidth="{DynamicResource TaskDialogMinWidth}"
MinHeight="{DynamicResource TaskDialogMinHeight}"
@@ -216,7 +216,7 @@
</ItemsControl>
</Border>
</Grid>
</ui:FABorder>
</Border>
</Panel>
</ControlTemplate>
</Setter>
@@ -303,7 +303,7 @@
<Style Selector="^ /template/ Panel#LayoutRoot">
<Setter Property="Background" Value="{DynamicResource TaskDialogSmokeFill}" />
</Style>
<Style Selector="^ /template/ ui|FABorder#ContentRoot">
<Style Selector="^ /template/ Border#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/ ui|FABorder#ContentRoot">
<Style Selector="^:hidden /template/ Border#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/ ui|FABorder#ContentRoot">
<Style Selector="^:open /template/ Border#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}">
<ui:FABorder
<Border
Name="ContentRoot"
MinWidth="{DynamicResource TaskDialogMinWidth}"
MinHeight="{DynamicResource TaskDialogMinHeight}"
@@ -521,7 +521,7 @@
</ItemsControl>
</Border>
</Grid>
</ui:FABorder>
</Border>
</Panel>
</ControlTemplate>
</Setter>
@@ -14,4 +14,5 @@
</Styles.Resources>
<StyleInclude Source="/UI/Styling/Controls.axaml" />
<StyleInclude Source="avares://AvaloniaEdit/Themes/Fluent/AvaloniaEdit.xaml" />
</Styles>
@@ -38,6 +38,7 @@
<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" />
@@ -21,4 +21,16 @@
</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>
@@ -21,4 +21,16 @@
</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>
@@ -210,7 +210,7 @@
<wnd:MinMaxCloseControl
Name="SystemCaptionButtons"
Height="{Binding TemplateSettings.TitleBarHeight, RelativeSource={RelativeSource TemplatedParent}}"
Margin="18,0"
Margin="14,0"
HorizontalAlignment="Right"
VerticalAlignment="Top" />
@@ -1,5 +1,7 @@
using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Rendering.Composition;
using FluentAvalonia.UI.Controls.Experimental;
using FluentAvalonia.UI.Navigation;
namespace BD.WTTS.UI.Views.Pages;
@@ -7,6 +9,8 @@ public class PageBase : UserControl
{
public PageBase() : base()
{
_disposables = new();
SizeChanged += PageBaseSizeChanged;
if (HeaderBackground == null)
@@ -14,6 +18,8 @@ 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);
}
@@ -139,6 +145,7 @@ 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");
@@ -157,6 +164,7 @@ public class PageBase : UserControl
{
base.OnUnloaded(e);
_hasLoaded = false;
_disposables.Dispose();
}
private void PageBaseSizeChanged(object? sender, SizeChangedEventArgs e)
@@ -266,33 +274,28 @@ 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 ((!isFAControlPage && e.SourcePageType == typeof(CoreControlsPageViewModel)) ||
// (isFAControlPage && e.SourcePageType == typeof(FAControlsOverviewPageViewModel)))
// if ((e.SourcePageType == typeof(HomePageViewModel)) ||
// (e.SourcePageType == typeof(PluginStorePageViewModel)))
// {
// // 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,
@@ -315,6 +318,7 @@ 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
@@ -324,13 +328,14 @@ public class PageBase<TViewModel> : PageBase, IViewFor<TViewModel> where TViewMo
/// <summary>
/// Initializes a new instance of the <see cref="PageBase{TViewModel}"/> class.
/// </summary>
public PageBase()
public PageBase() : base()
{
// 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);
}
@@ -25,6 +25,7 @@
<spp:Image2
Width="{Binding $parent[UserControl].Bounds.Width}"
Height="{Binding $parent[UserControl].Bounds.Height}"
EnableCancelToken="False"
Source="{Binding ImageUrl}"
Stretch="UniformToFill" />
</Button>
@@ -126,7 +126,7 @@ public class OptionsDisplayItem : TemplatedControl
{
base.OnApplyTemplate(e);
_layoutRoot = e.NameScope.Find<FABorder>("LayoutRoot");
_layoutRoot = e.NameScope.Find<Border>("LayoutRoot");
if (_layoutRoot != null)
{
_layoutRoot.PointerPressed += OnLayoutRootPointerPressed;
@@ -172,5 +172,5 @@ public class OptionsDisplayItem : TemplatedControl
private bool _isPressed;
private bool _isExpanded;
private FABorder? _layoutRoot;
private Border? _layoutRoot;
}
@@ -0,0 +1,47 @@
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);
}
}
@@ -0,0 +1,27 @@
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));
}
}
@@ -0,0 +1,30 @@
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);
}
}
@@ -62,14 +62,13 @@
Margin="0,0,0,5"
HorizontalAlignment="Center"
VerticalAlignment="Bottom">
<ItemsRepeater Name="Swiper" IsVisible="False">
<ItemsRepeater.Layout>
<StackLayout
DisableVirtualization="True"
Orientation="Horizontal"
Spacing="8" />
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<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" />
@@ -110,8 +109,8 @@
</i:Interaction.Behaviors>-->
</Button>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Panel>
</Panel>
</Border>
@@ -55,7 +55,7 @@ public class CarouselItems : ItemsControl
Carousel? _carouselControl;
Button? _leftButton;
Button? _rightButton;
ItemsRepeater? _swiper;
ItemsControl? _swiper;
Timer? _timer;
public ICommand? CarouselBannerIndexCommand { get; }
@@ -72,7 +72,7 @@ public class CarouselItems : ItemsControl
_carouselControl = e.NameScope.Find<Carousel>("CarouselControl");
_leftButton = e.NameScope.Find<Button>("Left");
_rightButton = e.NameScope.Find<Button>("Right");
_swiper = e.NameScope.Find<ItemsRepeater>("Swiper");
_swiper = e.NameScope.Find<Avalonia.Controls.ItemsControl>("Swiper");
if (_leftButton != null)
{
@@ -0,0 +1,22 @@
namespace BD.WTTS.UI.Views.Controls;
public class Skeleton : ContentControl
{
public static readonly StyledProperty<bool> IsActiveProperty =
AvaloniaProperty.Register<Skeleton, bool>(nameof(IsActive));
public bool IsActive
{
get { return GetValue(IsActiveProperty); }
set { SetValue(IsActiveProperty, value); }
}
public static readonly StyledProperty<bool> IsLoadingProperty =
AvaloniaProperty.Register<Skeleton, bool>(nameof(IsLoading));
public bool IsLoading
{
get => GetValue(IsLoadingProperty);
set => SetValue(IsLoadingProperty, value);
}
}
@@ -0,0 +1,141 @@
<UserControl
x:Class="BD.WTTS.UI.Views.Controls.WaveProgress"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:spp="https://steampp.net/ui"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<UserControl.Styles>
<Style Selector="spp|WaveProgress">
<Setter Property="Template">
<ControlTemplate>
<Border
Canvas.Left="20"
Canvas.Top="20"
Canvas.Right="20"
Canvas.Bottom="20"
Width="200"
Height="200"
Margin="20"
Background="Transparent"
BorderBrush="{DynamicResource ControlElevationBorderBrush}"
BorderThickness="1.2"
BoxShadow="{DynamicResource LowShadow}"
ClipToBounds="False"
CornerRadius="100">
<Border.Resources>
<spp:WaveProgressValueConverter x:Key="WValueConvert" />
<spp:WaveProgressValueTextConverter x:Key="WValueTextConvert" />
<spp:WaveProgressValueColorConverter x:Key="WValueColorConvert" />
<spp:WaveProgressGradientOffsetConverter x:Key="WGradientConverter" />
</Border.Resources>
<Border
Width="200"
Height="200"
HorizontalAlignment="Center"
VerticalAlignment="Center"
ClipToBounds="True"
CornerRadius="100">
<Panel>
<Canvas Width="200" Height="200">
<Path
Canvas.Top="{TemplateBinding Value,
Converter={StaticResource WValueConvert}}"
Classes="WaveAnimatedFast"
Data="M 0,50 H 700 V 350 H 0 M 0,50 C 25,55 75,45 100,50 S 175,55 200,50 S 275,45 300,50 S 375,55 400,50 S 475,45 500,50 S 575,55 600,50 S 675,45 700,50"
Fill="{TemplateBinding Value,
Converter={StaticResource WGradientConverter}}"
Opacity="0.45"
StrokeThickness="0">
<Path.Transitions>
<Transitions>
<DoubleTransition Property="Canvas.Top" Duration="0:0:1.5">
<DoubleTransition.Easing>
<CircularEaseOut />
</DoubleTransition.Easing>
</DoubleTransition>
</Transitions>
</Path.Transitions>
</Path>
<Path
Canvas.Top="{TemplateBinding Value,
Converter={StaticResource WValueConvert}}"
Classes="WaveAnimated"
Data="M 0,50 H 700 V 350 H 0 M 0,50 C 25,55 75,45 100,50 S 175,55 200,50 S 275,45 300,50 S 375,55 400,50 S 475,45 500,50 S 575,55 600,50 S 675,45 700,50"
Fill="{TemplateBinding Value,
Converter={StaticResource WGradientConverter}}"
Opacity="0.8"
StrokeThickness="0">
<Path.Transitions>
<Transitions>
<DoubleTransition Property="Canvas.Top" Duration="0:0:2.5">
<DoubleTransition.Easing>
<CircularEaseOut />
</DoubleTransition.Easing>
</DoubleTransition>
</Transitions>
</Path.Transitions>
</Path>
</Canvas>
<TextBlock
Name="PART_Text"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="{TemplateBinding Value,
Converter={StaticResource WValueColorConvert}}"
Text="{TemplateBinding Value,
Converter={StaticResource WValueTextConvert}}"
Theme="{StaticResource TitleTextBlockStyle}">
<TextBlock.Transitions>
<Transitions>
<DoubleTransition Property="Opacity" Duration="0:0:0.3" />
</Transitions>
</TextBlock.Transitions>
</TextBlock>
</Panel>
</Border>
</Border>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="spp|WaveProgress[IsTextVisible=True] /template/ TextBlock#PART_Text">
<Setter Property="Opacity" Value="1" />
</Style>
<Style Selector="spp|WaveProgress[IsTextVisible=False] /template/ TextBlock#PART_Text">
<Setter Property="Opacity" Value="0" />
</Style>
<Style Selector="Path.WaveAnimated">
<Style.Animations>
<Animation IterationCount="INFINITE" Duration="0:0:6">
<KeyFrame Cue="0%">
<Setter Property="Canvas.Left" Value="-100" />
</KeyFrame>
<KeyFrame Cue="100%">
<Setter Property="Canvas.Left" Value="-500" />
</KeyFrame>
</Animation>
</Style.Animations>
</Style>
<Style Selector="Path.WaveAnimatedFast">
<Style.Animations>
<Animation IterationCount="INFINITE" Duration="0:0:3">
<KeyFrame Cue="0%">
<Setter Property="Canvas.Left" Value="-100" />
</KeyFrame>
<KeyFrame Cue="100%">
<Setter Property="Canvas.Left" Value="-500" />
</KeyFrame>
</Animation>
</Style.Animations>
</Style>
</UserControl.Styles>
</UserControl>
@@ -0,0 +1,63 @@
namespace BD.WTTS.UI.Views.Controls;
public sealed partial class WaveProgress : UserControl
{
public static readonly DirectProperty<WaveProgress, double> ValueProperty =
AvaloniaProperty.RegisterDirect<WaveProgress, double>(
nameof(Value),
o => o.Value,
(o, v) => o.Value = v,
defaultBindingMode: BindingMode.TwoWay,
enableDataValidation: true);
public static readonly StyledProperty<bool> IsTextVisibleProperty =
AvaloniaProperty.Register<WaveProgress, bool>(nameof(IsTextVisible), defaultValue: true);
public WaveProgress()
{
InitializeComponent();
//var theme = App.Current.thm;
//theme.OnBaseThemeChanged += _ =>
//{
// Value++;
// Value--;
//};
//theme.OnColorThemeChanged += _ =>
//{
// Value++;
// Value--;
//};
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
private double _value = 65;
public double Value
{
get => _value;
set
{
if (value is < 0 or > 100)
return;
SetAndRaise(ValueProperty, ref _value, value);
}
}
public bool IsTextVisible
{
get
{
return GetValue(IsTextVisibleProperty);
}
set
{
SetValue(IsTextVisibleProperty, value);
}
}
}
@@ -139,20 +139,24 @@
VerticalAlignment="Center"
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
Text="{Binding Path=Res.Link, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<ItemsRepeater Margin="0,0,6,6" ItemsSource="{Binding Hyperlinks, Mode=OneTime}">
<ItemsRepeater.Layout>
<UniformGridLayout MinItemWidth="166" />
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<ItemsControl Margin="0,0,6,6" ItemsSource="{Binding Hyperlinks, Mode=OneTime}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="spp:HyperlinkModel">
<Button
Command="{Binding Command, Mode=OneWay}"
Content="{Binding Text, Mode=OneWay}"
Cursor="Hand"
Theme="{StaticResource HyperlinkButton}" />
<Border MinWidth="166">
<Button
Command="{Binding Command, Mode=OneWay}"
Content="{Binding Text, Mode=OneWay}"
Cursor="Hand"
Theme="{StaticResource HyperlinkButton}" />
</Border>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Border
Height="1"
Margin="-50,0"
@@ -162,20 +166,24 @@
VerticalAlignment="Center"
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
Text="{Binding Path=Res.OpenSourceLibrary, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<ItemsRepeater Margin="0,0,6,6" ItemsSource="{Binding OSL, Mode=OneTime}">
<ItemsRepeater.Layout>
<UniformGridLayout MinItemWidth="290" />
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<ItemsControl Margin="0,0,6,6" ItemsSource="{Binding OSL, Mode=OneTime}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="spp:HyperlinkModel">
<Button
Command="{Binding Command, Mode=OneWay}"
Content="{Binding Text, Mode=OneWay}"
Cursor="Hand"
Theme="{StaticResource HyperlinkButton}" />
<Border MinWidth="290">
<Button
Command="{Binding Command, Mode=OneWay}"
Content="{Binding Text, Mode=OneWay}"
Cursor="Hand"
Theme="{StaticResource HyperlinkButton}" />
</Border>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</spp:OptionsDisplayItem.Content>
</spp:OptionsDisplayItem>
@@ -12,6 +12,7 @@
d:DesignWidth="800"
x:CompileBindings="True"
x:DataType="spp:DebugPageViewModel"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
mc:Ignorable="d">
<Design.DataContext>
<spp:DebugPageViewModel />
@@ -149,7 +150,53 @@
</Panel>
<Panel>
<TextBlock Text="Test Control" />
<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>
</Panel>
</Carousel>
</spp:PageBase>
@@ -9,7 +9,7 @@
d:DesignWidth="800"
mc:Ignorable="d">
<Panel>
<Image Source="/UI/Assets/back.png" Stretch="UniformToFill" />
<!--<Image Source="/UI/Assets/back.png" Stretch="UniformToFill" />-->
<!--<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
@@ -150,7 +150,7 @@
</Border>
</spp:AppItem.Status>
<spp:AppItem.Image>
<spp:Image2 Source="{Binding ImageUrl}" />
<spp:Image2 EnableCancelToken="False" Source="{Binding ImageUrl}" />
</spp:AppItem.Image>
</spp:AppItem>
</DataTemplate>
@@ -279,57 +279,60 @@
ItemsSource="{Binding Shops}">
<spp:CarouselItems.ItemTemplate>
<DataTemplate x:DataType="spp:ShopRecommendGoodItem">
<Border spp:Animations.EnableAnimations="True">
<spp:AppItem
Title="{Binding Name}"
MaxWidth="260"
Classes="Vertical Scale"
ClickCommand="{Binding OpenBrowserCommand, Source={x:Static spp:App.Instance}}"
Cursor="Hand"
Tags="{Binding GoodsAllCategorysText}"
ToolTip.Tip="{Binding Brief}">
<spp:AppItem.ClickCommandParameter>
<MultiBinding Converter="{StaticResource StringFormatConverter}">
<CompiledBinding Path="." Source="{x:Static spp:HomePageViewModel.WattGame_Goods_Detail_}" />
<CompiledBinding Path="Id" />
</MultiBinding>
</spp:AppItem.ClickCommandParameter>
<spp:AppItem.Image>
<spp:Image2 RenderOptions.BitmapInterpolationMode="HighQuality" Source="{Binding Image}" />
</spp:AppItem.Image>
<spp:AppItem.Status>
<Border Classes="Status">
<StackPanel Orientation="Horizontal">
<TextBlock
VerticalAlignment="Center"
FontSize="12"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
IsVisible="{Binding !!DiscountValue}"
Text="{Binding Mktprice, Converter={StaticResource StringFormatConverter}, ConverterParameter={x:Static spp:CurrencyCode.CNY}}"
TextDecorations="Strikethrough" />
<TextBlock
VerticalAlignment="Center"
FontSize="14"
Text="{Binding Price, Converter={StaticResource StringFormatConverter}, ConverterParameter={x:Static spp:CurrencyCode.CNY}}" />
</StackPanel>
</Border>
</spp:AppItem.Status>
<spp:AppItem.ActionButton>
<Border
Height="24"
Padding="8,0"
Background="#4c6b22"
ClipToBounds="True"
CornerRadius="4"
IsVisible="{Binding !!DiscountValue}">
<!--<Border spp:Animations.EnableAnimations="True">-->
<spp:AppItem
Title="{Binding Name}"
MaxWidth="260"
Classes="Vertical Scale"
ClickCommand="{Binding OpenBrowserCommand, Source={x:Static spp:App.Instance}}"
Cursor="Hand"
Tags="{Binding GoodsAllCategorysText}"
ToolTip.Tip="{Binding Brief}">
<spp:AppItem.ClickCommandParameter>
<MultiBinding Converter="{StaticResource StringFormatConverter}">
<CompiledBinding Path="." Source="{x:Static spp:HomePageViewModel.WattGame_Goods_Detail_}" />
<CompiledBinding Path="Id" />
</MultiBinding>
</spp:AppItem.ClickCommandParameter>
<spp:AppItem.Image>
<spp:Image2
EnableCancelToken="False"
RenderOptions.BitmapInterpolationMode="HighQuality"
Source="{Binding Image}" />
</spp:AppItem.Image>
<spp:AppItem.Status>
<Border Classes="Status">
<StackPanel Orientation="Horizontal">
<TextBlock
VerticalAlignment="Center"
Foreground="#beee11"
Text="{Binding DiscountValue, StringFormat={}-{0}%}" />
</Border>
</spp:AppItem.ActionButton>
</spp:AppItem>
</Border>
FontSize="12"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
IsVisible="{Binding !!DiscountValue}"
Text="{Binding Mktprice, Converter={StaticResource StringFormatConverter}, ConverterParameter={x:Static spp:CurrencyCode.CNY}}"
TextDecorations="Strikethrough" />
<TextBlock
VerticalAlignment="Center"
FontSize="14"
Text="{Binding Price, Converter={StaticResource StringFormatConverter}, ConverterParameter={x:Static spp:CurrencyCode.CNY}}" />
</StackPanel>
</Border>
</spp:AppItem.Status>
<spp:AppItem.ActionButton>
<Border
Height="24"
Padding="8,0"
Background="#4c6b22"
ClipToBounds="True"
CornerRadius="4"
IsVisible="{Binding !!DiscountValue}">
<TextBlock
VerticalAlignment="Center"
Foreground="#beee11"
Text="{Binding DiscountValue, StringFormat={}-{0}%}" />
</Border>
</spp:AppItem.ActionButton>
</spp:AppItem>
<!--</Border>-->
</DataTemplate>
</spp:CarouselItems.ItemTemplate>
</spp:CarouselItems>
@@ -7,7 +7,7 @@ public partial class HomePage : ReactiveUserControl<HomePageViewModel>
public HomePage()
{
InitializeComponent();
this.SetViewModel<HomePageViewModel>();
this.SetViewModel<HomePageViewModel>(useCache: true);
//ShopsScrollViewer.PointerWheelChanged += ShopsScrollViewer_PointerWheelChanged;
}
@@ -24,10 +24,10 @@
</Style>
<Style Selector="ui|NavigationView.AppNav[IsBackButtonVisible=False] SplitView /template/ ContentPresenter#PART_PanePresenter">
<Setter Property="Margin" Value="0 50 0 0" />
<Setter Property="Margin" Value="0 42 0 0" />
</Style>
<Style Selector="ui|NavigationView.AppNav[IsBackButtonVisible=True] SplitView /template/ ContentPresenter#PART_PanePresenter">
<Setter Property="Margin" Value="0 10 0 0" />
<Setter Property="Margin" Value="0 2 0 0" />
</Style>
<Style Selector="ui|NavigationViewItem.AppNav">
@@ -216,9 +216,22 @@
<StackPanel VerticalAlignment="Center" IsVisible="{Binding Path=User, Mode=OneWay, Source={x:Static s:UserService.Current}, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}">
<TextBlock Text="{Binding Path=User.NickName, Mode=OneWay, Source={x:Static s:UserService.Current}}" />
<Border VerticalAlignment="Center" IsVisible="{Binding Path=User.UserType, Mode=OneWay, Source={x:Static s:UserService.Current}, Converter={StaticResource EnumEqualValueConverter}, ConverterParameter={x:Static enum:UserType.Sponsor}}">
<TextBlock FontSize="10" Text="{Binding Path=Res.User_Sponsor, Mode=OneWay, Source={x:Static s:ResourceService.Current}, StringFormat={}❤️{0}}" />
<Border
Padding="5,1"
VerticalAlignment="Center"
CornerRadius="2"
IsVisible="{Binding Path=User.UserType, Mode=OneWay, Source={x:Static s:UserService.Current}, Converter={StaticResource EnumEqualValueConverter}, ConverterParameter={x:Static enum:UserType.Sponsor}}">
<Border.Background>
<LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
<GradientStop Offset="0.0" Color="#453a94" />
<GradientStop Offset="1.0" Color="#f43b47" />
</LinearGradientBrush>
</Border.Background>
<TextBlock
VerticalAlignment="Center"
FontSize="10"
Foreground="White"
Text="{Binding Path=Res.User_Sponsor, Mode=OneWay, Source={x:Static s:ResourceService.Current}, StringFormat={}❤️{0}}" />
</Border>
</StackPanel>
@@ -263,18 +276,18 @@
</MenuItem.Header>
</MenuItem>
<MenuItem Header="-" IsVisible="{Binding Path=User, Mode=OneWay, Source={x:Static s:UserService.Current}, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}" />
<MenuItem
<MenuItem
Command="{Binding Path=OpenAuthOfficialCommand, Source={x:Static s:UserService.Current}}"
CommandParameter="https://steampp.net/account/center/info"
Header="{Binding Path=Res.PersonalCenter, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
IsVisible="{Binding Path=User, Mode=OneWay, Source={x:Static s:UserService.Current}, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}" />
<!--<MenuItem Header="{Binding Path=Res.MyOrder, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" IsVisible="{Binding Path=User, Mode=OneWay, Source={x:Static s:UserService.Current}, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}" />-->
<MenuItem
<!--<MenuItem Header="{Binding Path=Res.MyOrder, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" IsVisible="{Binding Path=User, Mode=OneWay, Source={x:Static s:UserService.Current}, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}" />-->
<MenuItem
Command="{Binding Path=OpenAuthOfficialCommand, Source={x:Static s:UserService.Current}}"
CommandParameter="https://steampp.net/account/center/bind"
Header="{Binding Path=Res.BindThirdPartyAccount, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
IsVisible="{Binding Path=User, Mode=OneWay, Source={x:Static s:UserService.Current}, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}" />
<MenuItem
<MenuItem
Command="{Binding Path=OpenAuthOfficialCommand, Source={x:Static s:UserService.Current}}"
CommandParameter="https://steampp.net/account/center/safe"
Header="{Binding Path=Res.PersonalSafe, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
@@ -318,7 +331,7 @@
PaneDisplayMode="Left">
<ui:NavigationView.Resources>
<!-- Override this -->
<Thickness x:Key="NavigationViewContentMargin">0,60,0,0</Thickness>
<Thickness x:Key="NavigationViewContentMargin">0,50,0,0</Thickness>
</ui:NavigationView.Resources>
<ui:NavigationView.Styles>
<Style Selector="Button#NavigationViewBackButton">
@@ -329,7 +342,7 @@
<Setter Property="Content" Value="&#xF0D5;" />
</Style>
<Style Selector="Grid#PaneToggleButtonGrid">
<Setter Property="Margin" Value="5 5 0 0" />
<Setter Property="Margin" Value="5 0 0 0" />
<Setter Property="ToolTip.Tip" Value="{Binding Path=Res.Back, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<Setter Property="ToolTip.Placement" Value="Bottom" />
</Style>
@@ -0,0 +1,88 @@
<UserControl
x:Class="BD.WTTS.UI.Views.Pages.PluginStorePage"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:s="https://steampp.net/services"
xmlns:spp="https://steampp.net/ui"
xmlns:ui="using:FluentAvalonia.UI.Controls"
d:DesignHeight="450"
d:DesignWidth="800"
x:CompileBindings="True"
x:DataType="spp:PluginStorePageViewModel"
mc:Ignorable="d">
<ScrollViewer Padding="20">
<!--<spp:ContentLoader IsLoading="False">-->
<StackPanel
x:Name="HomeRoot"
MaxWidth="1080"
Spacing="20">
<TextBlock
Margin="-3,0,0,0"
Text="插件商店是什么?"
Theme="{StaticResource TitleTextBlockStyle}" />
<TextBlock Text="3.0 版本的计划是将所有功能插件化,拆分后按需下载安装,每个人都可以只下载自己需要的插件功能使用,并且支持所有人都可以开发插件,等等还有许多暂时不方便说的内容,因为计划的过于异想天开,且遇到的问题有点多,所以开发难度有点点大,这个功能上线还需要一点时间,上线后 3.0 也将正式发布正式版,对一直等待的大家说声抱歉麻烦在多等等了 😭,如果您不习惯启动后是插件商店页面也可以在界面设置中修改启动默认页。" TextWrapping="WrapWithOverflow" />
<TextBlock
Margin="-3,0,0,0"
Text="已安装功能"
Theme="{StaticResource TitleTextBlockStyle}" />
<ItemsControl ItemsSource="{Binding MainWindow2.TabItems, Mode=OneWay, Source={x:Static s:IViewModelManager.Instance}}">
<ItemsControl.Resources>
<ControlTheme
x:Key="NavButtonStyle"
BasedOn="{StaticResource {x:Type Button}}"
TargetType="Button">
<Setter Property="Width" Value="120" />
<Setter Property="Padding" Value="0" />
<Setter Property="Margin" Value="6" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="ClipToBounds" Value="True" />
</Style>
</ControlTheme>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="spp:TabItemViewModel">
<Border spp:Animations.EnableAnimations="True">
<Button
Command="{Binding $parent[spp:PluginStorePage].((spp:PluginStorePageViewModel)DataContext).NavgationToMenuPageCommand}"
CommandParameter="{Binding}"
Theme="{StaticResource NavButtonStyle}">
<Grid RowDefinitions="3*,*">
<Border
Name="IconHost"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
CornerRadius="4 4 0 0"
RenderOptions.BitmapInterpolationMode="HighQuality">
<spp:Image2
Width="96"
Height="96"
Margin="0,10,0,0"
Source="{Binding IconKey}"
Stretch="Uniform" />
</Border>
<TextBlock
Grid.Row="1"
Margin="12"
FontWeight="SemiBold"
Text="{Binding Name}" />
</Grid>
</Button>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</UserControl>
@@ -0,0 +1,92 @@
using FluentAvalonia.UI.Controls.Experimental;
using FluentAvalonia.UI.Navigation;
namespace BD.WTTS.UI.Views.Pages;
public partial class PluginStorePage : UserControl
{
public PluginStorePage()
{
InitializeComponent();
this.SetViewModel<PluginStorePageViewModel>(useCache: true);
// Use the frame events here to ensure ConnectedAnimations still work with
// Back/Forward navigation and not just explicit page invokes
//AddHandler(Frame.NavigatingFromEvent, OnNavigatingFrom, RoutingStrategies.Direct);
//AddHandler(Frame.NavigatedToEvent, OnNavigatedTo, RoutingStrategies.Direct);
}
//private void PluginStorePage_Click(object? sender, RoutedEventArgs e)
//{
// if (sender != null && sender is Button b && b.DataContext is TabItemViewModel fci)
// {
// _animationPage = fci;
// //NavigationService.Instance.NavigateFromContext(fci);
// }
//}
//private void OnNavigatedTo(object? sender, NavigationEventArgs e)
//{
// if (_animationPage == null)
// return;
// var svc = ConnectedAnimationService.GetForView(TopLevel.GetTopLevel(this));
// var anim = svc.GetAnimation("BackAnimation");
// if (anim == null)
// return;
// var item = this.GetVisualDescendants()
// ?.Where(x => x is Button && x.DataContext == _animationPage)
// ?.FirstOrDefault()
// ?.GetVisualDescendants()
// .Where(x => x is Border && x.Name == "IconHost")
// .FirstOrDefault();
// var presenter = item;// GetAnimationSource();
// // In WinUI, ConnectedAnimation is somehow exempt from all clipping behaviors
// // Here, we are not, so disable ClipToBounds on all elements in the SettingsExpander
// // The rest are taken care of in the xaml.
// // NOTE: The ScrollViewer is not changed here as that's important for scrolling - thus
// // the animation will be cut off, but the back animation is pretty fast and mostly is
// // only visible closer to the element so we're ok, I think
// var x = presenter?.GetVisualParent();
// while (!(x is ScrollContentPresenter) && x != null)
// {
// x.ClipToBounds = false;
// x = x.GetVisualParent();
// }
// anim.Configuration = new DirectConnectedAnimationConfiguration();
// anim.TryStart(presenter);
//}
//private void OnNavigatingFrom(object? sender, NavigatingCancelEventArgs e)
//{
// if (_animationPage == null)
// return;
// // We're not navigating to a control page, don't set up the animation & clear
// // the previous animation source
// if (!e.SourcePageType.Name.Equals(nameof(TabItemViewModel)))
// {
// _animationPage = null;
// _animationPage = null;
// return;
// }
// var item = this.GetVisualDescendants()
// ?.Where(x => x is ListBoxItem && x.DataContext == _animationPage)
// ?.FirstOrDefault()
// ?.GetVisualDescendants()
// .Where(x => x is Viewbox && x.Name == "IconHost")
// .FirstOrDefault();
// var svc = ConnectedAnimationService.GetForView(TopLevel.GetTopLevel(this));
// svc.PrepareToAnimate("ForwardAnimation", item);
//}
//private TabItemViewModel? _animationPage;
}
@@ -102,6 +102,7 @@
Command="{Binding $parent[spp:Settings_Plugin].((spp:SettingsPageViewModel)DataContext).DeletePlugin_Click}"
CommandParameter="{Binding Data}"
Content="{Binding Path=Res.Plugin_Delete, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
Foreground="{DynamicResource SystemFillColorCriticalBrush}"
IsClickEnabled="True" />
</ui:SettingsExpander>
</DataTemplate>
@@ -22,6 +22,23 @@
Text="{Binding Path=Res.Settings_UI, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
Theme="{StaticResource SubtitleTextBlockStyle}" />
<Border>
<ui:SettingsExpander Header="{Binding Path=Res.Settings_UI_StartDefaultPage, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
<ui:SettingsExpander.IconSource>
<ui:FontIconSource FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="{StaticResource Device}" />
</ui:SettingsExpander.IconSource>
<ui:SettingsExpander.Footer>
<ComboBox ItemsSource="{Binding Path=MainWindow2.TabItems, Mode=OneWay, Source={x:Static s:IViewModelManager.Instance}}" SelectedItem="{Binding SelectDefaultPage, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate DataType="spp:TabItemViewModel">
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</ui:SettingsExpander.Footer>
</ui:SettingsExpander>
</Border>
<Border IsEnabled="{Binding Path=User, Mode=OneWay, Source={x:Static s:UserService.Current}, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}">
<ui:SettingsExpander
Description="{Binding Path=Res.Advertisement_NoShow_Tip, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
@@ -172,13 +172,13 @@
<WrapPanel Margin="0,20" HorizontalAlignment="Center">
<TextBlock Text="{Binding Path=Res.User_LoginUnexpectedPrompt, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Theme="{StaticResource CaptionTextBlockStyle}" />
<ui:HyperlinkButton
<HyperlinkButton
Margin="5,0"
Padding="0"
HorizontalContentAlignment="Center"
Command="{Binding ManualLogin}">
<TextBlock Text="{Binding Path=Res.Login_ManualLogin, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Theme="{StaticResource CaptionTextBlockStyle}" />
</ui:HyperlinkButton>
</HyperlinkButton>
</WrapPanel>
<ProgressBar
@@ -222,23 +222,23 @@
FontSize="12"
Text="{Binding Path=Res.User_RegisterAgreed, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
Theme="{StaticResource CaptionTextBlockStyle}" />
<ui:HyperlinkButton
<HyperlinkButton
Margin="5,0"
Padding="0"
Command="{Binding OpenHyperlink}"
CommandParameter="Agreement"
Cursor="Hand">
<TextBlock Text="{Binding Path=Res.User_Agreement, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Theme="{StaticResource CaptionTextBlockStyle}" />
</ui:HyperlinkButton>
</HyperlinkButton>
<TextBlock Text="{Binding Path=Res.And, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Theme="{StaticResource CaptionTextBlockStyle}" />
<ui:HyperlinkButton
<HyperlinkButton
Margin="5,0"
Padding="0"
Command="{Binding OpenHyperlink}"
CommandParameter="Privacy"
Cursor="Hand">
<TextBlock Text="{Binding Path=Res.User_Privacy, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Theme="{StaticResource CaptionTextBlockStyle}" />
</ui:HyperlinkButton>
</HyperlinkButton>
</WrapPanel>
<StackPanel
@@ -45,6 +45,17 @@ public partial class LoginOrRegisterPage : ReactiveUserControl<LoginOrRegisterWi
this.ViewModel.Close(false);
}
}
// 11.1 使用新 API https://docs.avaloniaui.net/docs/concepts/services/activatable-lifetime#handling-uri-activation
//if (Application.Current.TryGetFeature<IActivatableLifetime>() is { } activatableLifetime)
//{
// activatableLifetime.Activated += (s, a) =>
// {
// if (a is ProtocolActivatedEventArgs protocolArgs && protocolArgs.Kind == ActivationKind.OpenUri)
// {
// Console.WriteLine($"App activated via Uri: {protocolArgs.Uri}");
// }
// };
//}
Application.Current!.UrlsOpened += Current_UrlsOpened;
}
@@ -37,7 +37,36 @@ public sealed partial class MainWindow : ReactiveAppWindow<MainWindowViewModel>
}
}
protected override void OnOpened(EventArgs e)
DateTime lastOpenedTime;
internal bool SetStartDefaultPageName()
{
if (NavigationService.Instance.CurrnetPage != null)
return false;
var mw2 = IViewModelManager.Instance.MainWindow2;
if (mw2 == null)
return false;
Type? pageType = null;
if (!string.IsNullOrEmpty(UISettings.StartDefaultPageName.Value))
{
var tabItems = mw2?.TabItems;
if (tabItems == null)
return false;
var page = tabItems.OfType<MenuTabItemViewModel>()
.FirstOrDefault(s => s.Id == UISettings.StartDefaultPageName.Value);
if (page != null)
{
pageType = page.PageType;
}
}
INavigationService.Instance.Navigate(pageType ?? typeof(PluginStorePage));
return true;
}
protected override async void OnOpened(EventArgs e)
{
base.OnOpened(e);
if (Steamworks.SteamClient.IsValid)
@@ -46,24 +75,23 @@ public sealed partial class MainWindow : ReactiveAppWindow<MainWindowViewModel>
}
if (AppSplashScreen.IsInitialized)
{
if (NavigationService.Instance.CurrnetPage == null)
{
INavigationService.Instance.Navigate(typeof(HomePage));
}
Task2.InBackground(async () =>
{
IViewModelManager.Instance.Get<HomePageViewModel>().GetServerContent();
await AdvertiseService.Current.RefrshAdvertiseAsync();
NoticeService.Current.GetNewsAsync();
});
try // 在主窗口显示时调用此函数检查是否需要显示新版本通知窗口
{
Ioc.Get_Nullable<IAppUpdateService>()?.OnMainOpenTryShowNewVersionWindow();
}
catch
{
SetStartDefaultPageName();
}
if (lastOpenedTime == default ||
(DateTime.Now - lastOpenedTime) > TimeSpan.FromMinutes(30))
{
lastOpenedTime = DateTime.Now;
await IViewModelManager.Instance.Get<HomePageViewModel>().GetServerContent();
await AdvertiseService.Current.RefrshAdvertiseAsync();
await NoticeService.Current.GetNewsAsync();
}
try // 在主窗口显示时调用此函数检查是否需要显示新版本通知窗口
{
Ioc.Get_Nullable<IAppUpdateService>()?.OnMainOpenTryShowNewVersionWindow();
}
catch
{
}
}
}
}
@@ -72,7 +100,7 @@ public sealed class AppSplashScreen : IApplicationSplashScreen
{
public static bool IsInitialized = false;
public WindowViewModel? ViewModel { get; }
//public WindowViewModel? ViewModel { get; }
public string? AppName { get; }
@@ -162,7 +190,7 @@ public sealed class AppSplashScreen : IApplicationSplashScreen
});
AdvertiseService.Current.InitAdvertise();
NoticeService.Current.GetNewsAsync();
await NoticeService.Current.GetNewsAsync();
var mainWindow = App.Instance.MainWindow;
mainWindow.ThrowIsNull();
@@ -188,7 +216,7 @@ public sealed class AppSplashScreen : IApplicationSplashScreen
#endif
new MenuTabItemViewModel("Plugin_Store")
{
PageType = null,
PageType = typeof(PluginStorePage),
IsResourceGet = true,
IconKey = "avares://BD.WTTS.Client.Avalonia/UI/Assets/Icons/store.ico",
},
@@ -205,8 +233,10 @@ public sealed class AppSplashScreen : IApplicationSplashScreen
{
mainWindow.DataContext = IViewModelManager.Instance.MainWindow;
s.InitSettingSubscribe();
INavigationService.Instance.Navigate(typeof(HomePage));
if (mainWindow is MainWindow mainWindow1)
{
mainWindow1.SetStartDefaultPageName();
}
});
#if STARTUP_WATCH_TRACE || DEBUG
WatchTrace.Record("InitMainWindowViewModel");
@@ -0,0 +1,17 @@
namespace BD;
[AttributeUsage(AttributeTargets.All, Inherited = false)]
public sealed class MobiusAttribute : Attribute
{
public MobiusAttribute()
{
}
public MobiusAttribute(string str)
{
}
public bool Obsolete { get; set; }
}
@@ -6,6 +6,7 @@ namespace BD.WTTS.Services;
/// <summary>
/// 子进程的 IPC 服务实现
/// </summary>
[Mobius(Obsolete = true)]
public interface IPCSubProcessService : IDisposable
{
/// <summary>
@@ -93,6 +94,9 @@ public interface IPCSubProcessService : IDisposable
var nativeLibraryPath = Environment.GetEnvironmentVariable(EnvKey_NativeLibraryPath);
if (!string.IsNullOrWhiteSpace(nativeLibraryPath))
{
var nativeLibraryPaths = nativeLibraryPath.Split(';',
StringSplitOptions.RemoveEmptyEntries);
// 监听当前应用程序域的程序集加载
AppDomain.CurrentDomain.AssemblyLoad += (_, args)
=> CurrentDomain_AssemblyLoad(args.LoadedAssembly);
@@ -119,23 +123,34 @@ public interface IPCSubProcessService : IDisposable
return libraryName;
}
var libraryFileName = GetLibraryFileName(libraryName);
var libraryPath = Path.Combine(nativeLibraryPath, libraryFileName);
if (File.Exists(libraryPath) &&
NativeLibrary.TryLoad(libraryPath, out var handle))
string libraryPath = libraryName;
try
{
return handle;
}
else if (!OperatingSystem.IsWindows() && !libraryFileName.StartsWith("lib", StringComparison.OrdinalIgnoreCase))
{
libraryFileName = $"lib{libraryFileName}";
libraryPath = Path.Combine(nativeLibraryPath, libraryFileName);
if (File.Exists(libraryPath) &&
NativeLibrary.TryLoad(libraryPath, out handle))
foreach (var nativeLibraryPath in nativeLibraryPaths)
{
return handle;
libraryPath = Path.Combine(nativeLibraryPath, libraryFileName);
if (File.Exists(libraryPath) &&
NativeLibrary.TryLoad(libraryPath, out var handle))
{
return handle;
}
else if (!OperatingSystem.IsWindows() && !libraryFileName.StartsWith("lib", StringComparison.OrdinalIgnoreCase))
{
libraryFileName = $"lib{libraryFileName}";
libraryPath = Path.Combine(nativeLibraryPath, libraryFileName);
if (File.Exists(libraryPath) &&
NativeLibrary.TryLoad(libraryPath, out handle))
{
return handle;
}
}
}
return NativeLibrary.Load(libraryName, assembly, searchPath);
}
catch (Exception ex)
{
throw new FileNotFoundException(null, libraryPath, ex);
}
return NativeLibrary.Load(libraryName, assembly, searchPath);
}
NativeLibrary.SetDllImportResolver(loadedAssembly, Delegate);
}
@@ -123,6 +123,7 @@ public static class KestrelServerOptionsExtensions
var httpsPort = IReverseProxyConfig.HttpsPort;
options.Listen(IReverseProxyService.Constants.Instance.ProxyIp, httpsPort, listen =>
{
listen.Protocols = HttpProtocols.Http1AndHttp2;
listen.UseFlowAnalyze();
listen.UseTls();
});
@@ -0,0 +1,17 @@
namespace BD;
[AttributeUsage(AttributeTargets.All, Inherited = false)]
public sealed class MobiusAttribute : Attribute
{
public MobiusAttribute()
{
}
public MobiusAttribute(string str)
{
}
public bool Obsolete { get; set; }
}
@@ -155,7 +155,21 @@ public static class CertGenerator
}
else
{
builder.AddDnsName(name);
try
{
builder.AddDnsName(name);
}
catch
{
/* name = Environment.MachineName
* System.ArgumentException: Decoded string is not a valid IDN name. (Parameter 'unicode')
* at System.Globalization.IdnMapping.IcuGetAsciiCore(String unicodeString, Char* unicode, Int32 count)
* at System.Globalization.IdnMapping.GetAscii(String unicode, Int32 index, Int32 count)
* at System.Security.Cryptography.X509Certificates.SubjectAlternativeNameBuilder.AddDnsName(String dnsName)
* at BD.WTTS.Services.Implementation.CertGenerator.Add(SubjectAlternativeNameBuilder builder, String name)
* at BD.WTTS.Services.Implementation.CertGenerator.CreateEndCertificate(X509Certificate2 issuerCertificate, X500DistinguishedName subjectName, IEnumerable`1 extraDnsNames, Nullable`1 notBefore, Nullable`1 notAfter, Int32 rsaKeySizeInBits)
*/
}
}
}
@@ -450,4 +450,36 @@ sealed partial class CertificateManagerImpl : ICertificateManager
var result = ICertificateManager.Constants.IsCertificateInstalled(platformService, packable);
return result;
}
public string GetCertificateInfo()
{
var rootCert = RootCertificate;
if (rootCert == null)
{
GenerateCertificate();
}
rootCert = RootCertificate;
if (rootCert == null)
{
return "";
}
StringBuilder b = new();
b.AppendLine("Subject:");
b.AppendLine(rootCert.Subject);
b.AppendLine("SerialNumber:");
b.AppendLine(rootCert.SerialNumber);
b.AppendLine("PeriodValidity:");
b.Append(rootCert.GetEffectiveDateString());
b.Append(" ~ ");
b.Append(rootCert.GetExpirationDateString());
b.AppendLine();
b.AppendLine("SHA256:");
b.AppendLine(rootCert.GetCertHashStringCompat(HashAlgorithmName.SHA256));
b.AppendLine("SHA1:");
b.AppendLine(rootCert.GetCertHashStringCompat(HashAlgorithmName.SHA1));
return b.ToString();
}
}
@@ -46,4 +46,9 @@ sealed class LazyCertificateManager : ICertificateManager
{
return impl().DeleteRootCertificate();
}
public string GetCertificateInfo()
{
return impl().GetCertificateInfo();
}
}
@@ -32,7 +32,7 @@ sealed class ReverseProxyHttpClientHandler : DelegatingHandler
var tlsSniValue = domainConfig.GetTlsSniPattern().WithDomain(uri.Host).WithRandom();
request.SetRequestContext(new RequestContext(isHttps, tlsSniValue));
// 设置请求头 host,修改协议为 http
// 设置请求头 host,因为连接中已带端口号故 修改协议为 http
request.Headers.Host = uri.Host;
request.RequestUri = new UriBuilder(uri) { Scheme = Uri.UriSchemeHttp }.Uri;
@@ -80,7 +80,15 @@ sealed partial class HttpReverseProxyMiddleware
return;
}
var destinationPrefix = GetDestinationPrefix(context.Request.Scheme, context.Request.Host, domainConfig.Destination);
var destination = domainConfig.Destination;
if (domainConfig.Destination?.AbsoluteUri.Contains("@") == true)
{
var newUrl = domainConfig.Destination.AbsoluteUri.Replace("@domain", context.Request.Host.Host);
newUrl = newUrl.Replace("@uri", context.Request.RawUrl());
destination = new Uri(newUrl);
}
var destinationPrefix = GetDestinationPrefix(context.Request.Scheme, context.Request.Host, destination);
var httpClient = httpClientFactory.CreateHttpClient(context.Request.Host.Host, domainConfig);
if (!string.IsNullOrEmpty(domainConfig.UserAgent))
{
@@ -89,9 +97,19 @@ sealed partial class HttpReverseProxyMiddleware
var forwarderRequestConfig = new ForwarderRequestConfig()
{
Version = context.Request.Protocol.StartsWith("HTTP/2") ? System.Net.HttpVersion.Version20 : System.Net.HttpVersion.Version11,
Version = context.Request.Protocol switch
{
var protocol when protocol.StartsWith("HTTP/2") => System.Net.HttpVersion.Version20,
var protocol when protocol.StartsWith("HTTP/3") => System.Net.HttpVersion.Version30,
_ => System.Net.HttpVersion.Version11,
},
};
if (domainConfig.IsServerSideProxy)
{
SetWattHeaders(context, reverseProxyConfig.Service.ServerSideProxyToken);
}
var error = await httpForwarder.SendAsync(context, destinationPrefix, httpClient, forwarderRequestConfig, HttpTransformer.Empty);
if (error != ForwarderError.None)
@@ -393,6 +411,15 @@ sealed partial class HttpReverseProxyMiddleware
return false;
}
static void SetWattHeaders(HttpContext context, string? token)
{
context.Request.Headers.TryAdd("X-Watt-Origin-Dest-Scheme", context.Request.Scheme);
context.Request.Headers.TryAdd("X-Watt-Origin-Dest-Host", context.Request.Host.ToString());
context.Request.Headers.TryAdd("X-Watt-Origin-Dest-PathAndQuery", context.Request.GetEncodedPathAndQuery());
context.Request.Headers.TryAdd("X-Watt-Token", token ?? string.Empty);
}
const int UTF8PreambleLength = 3;
const byte UTF8PreambleByte2 = 0xBF;
const int UTF8PreambleFirst2Bytes = 0xEFBB;
@@ -89,6 +89,8 @@ abstract class ReverseProxyServiceImpl : IReverseProxySettings
public string? CustomDohAddres { get; set; }
public string? ServerSideProxyToken { get; set; }
/// <summary>
/// 获取一个随机的未使用的端口
/// </summary>
@@ -157,7 +159,7 @@ abstract class ReverseProxyServiceImpl : IReverseProxySettings
return StartProxyResultCode.DeserializeReverseProxySettingsFail;
}
// Linux 如果是443 需要验证 是否允许使用
// Linux 如果是443 需要验证 是否允许使用
if (OperatingSystem.IsLinux())
{
if (string.IsNullOrWhiteSpace(reverseProxySettings.ProxyIp))
@@ -178,7 +180,6 @@ abstract class ReverseProxyServiceImpl : IReverseProxySettings
protected virtual void CheckRootCertificate()
{
}
protected abstract Task<StartProxyResult> StartProxyImpl();
@@ -193,6 +193,9 @@ public interface ICertificateManager
var isRootCertificateInstalled = IsCertificateInstalled();
if (!isRootCertificateInstalled)
{
// 生成证书
certificateManager.GenerateCertificate();
// 安装证书
ICertificateManager.Constants.TrustRootCertificate(
GetCerFilePath, platformService, certificate2);
@@ -271,4 +274,10 @@ public interface ICertificateManager
/// <param name="filePath"></param>
/// <returns></returns>
bool? GenerateCertificate();
/// <summary>
/// 获取证书信息
/// </summary>
/// <returns></returns>
string GetCertificateInfo();
}
@@ -1,6 +1,9 @@
using dotnetCampus.Ipc.CompilerServices.Attributes;
#if APP_REVERSE_PROXY
using InstanceReverseProxyService = BD.WTTS.Services.Implementation.YarpReverseProxyServiceImpl;
#else
using InstanceReverseProxyService = BD.WTTS.Services.IReverseProxyService;
#endif
@@ -59,6 +62,7 @@ public partial interface IReverseProxyService : IDisposable
Task StopProxyAsync();
#if DEBUG
string GetDebugString()
{
return $"Pid: {Environment.ProcessId}, Exe: {Environment.ProcessPath}, Asm: {Assembly.GetAssembly(GetType())?.FullName}";
@@ -69,6 +73,7 @@ public partial interface IReverseProxyService : IDisposable
StartProxyResult r = new(StartProxyResultCode.Exception, new Exception("aaaa"));
return Task.FromResult(r);
}
#endif
}
@@ -139,7 +144,7 @@ public partial interface IReverseProxySettings
/// </summary>
ushort Socks5ProxyPortId { get; set; }
#endregion
#endregion Socks5
#region TwoLevelAgent(二级代理)
@@ -155,7 +160,7 @@ public partial interface IReverseProxySettings
string? TwoLevelAgentPassword { get; set; }
#endregion
#endregion TwoLevelAgent(二级代理)
IPAddress? ProxyDNS { get; set; }
@@ -167,6 +172,11 @@ public partial interface IReverseProxySettings
bool UseDoh { get; set; }
string? CustomDohAddres { get; set; }
/// <summary>
/// 服务端代理令牌
/// </summary>
string? ServerSideProxyToken { get; set; }
}
[MP2Obj(SerializeLayout.Explicit)]
@@ -214,7 +224,9 @@ public readonly partial record struct ReverseProxySettings(
[property:MP2Key(20)]
bool UseDoh,
[property:MP2Key(21)]
string? CustomDohAddres)
string? CustomDohAddres,
[property:MP2Key(22)]
string? ServerSideProxyToken)
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal IPAddress GetProxyIp() => GetProxyIp(ProxyIp);
@@ -267,6 +279,7 @@ public readonly partial record struct ReverseProxySettings(
settings.IsSupportIpv6 = IsSupportIpv6;
settings.UseDoh = UseDoh;
settings.CustomDohAddres = CustomDohAddres;
settings.ServerSideProxyToken = ServerSideProxyToken;
}
#endif
}
@@ -123,8 +123,8 @@ static class WinDivertInitHelper
//case Architecture.X86:
case Architecture.X64:
IsSupported = true;
libraryDirPath = Path.Combine(AppContext.BaseDirectory, "native", "win-x64");
libraryPath = Path.Combine(libraryDirPath, "WinDivert.dll");
libraryPath = GlobalDllImportResolver.GetLibraryPath("WinDivert.dll");
libraryDirPath = Path.GetDirectoryName(libraryPath);
break;
}
}
@@ -7,6 +7,13 @@ public partial class XunYouGameViewModel : ReactiveSerializationObject, IReactiv
[MP2Key(0), JsonPropertyOrder(0)]
public XunYouGame Model { get; set; } = model;
/// <summary>
/// PicInfo
/// </summary>
[Reactive]
[XmlIgnore, IgnoreDataMember, SystemTextJsonIgnore, NewtonsoftJsonIgnore, MPIgnore, MP2Ignore]
public XunYouPicInfo? PicInfo { get; set; }
/// <summary>
/// 加速延迟
/// </summary>
@@ -41,12 +48,26 @@ public partial class XunYouGameViewModel : ReactiveSerializationObject, IReactiv
[XmlIgnore, IgnoreDataMember, SystemTextJsonIgnore, NewtonsoftJsonIgnore, MPIgnore, MP2Ignore]
public float PingSpeedLoss { get; set; }
XunYouGameInfo? _GameInfo;
/// <summary>
/// 游戏信息
/// </summary>
[Reactive]
[XmlIgnore, IgnoreDataMember, SystemTextJsonIgnore, NewtonsoftJsonIgnore, MPIgnore, MP2Ignore]
public XunYouGameInfo? GameInfo { get; set; }
public XunYouGameInfo? GameInfo
{
get => _GameInfo;
set
{
_GameInfo = value;
this.RaisePropertyChanged();
this.RaisePropertyChanged(nameof(ShowStart));
}
}
/// <inheritdoc cref="XunYouGameInfo.ShowStart"/>
[XmlIgnore, IgnoreDataMember, SystemTextJsonIgnore, NewtonsoftJsonIgnore, MPIgnore, MP2Ignore]
public bool ShowStart => IsAccelerated && (GameInfo != null && GameInfo.ShowStart);
/// <summary>
/// 是否正在加速等待
@@ -62,12 +83,25 @@ public partial class XunYouGameViewModel : ReactiveSerializationObject, IReactiv
[MP2Ignore, SystemTextJsonIgnore]
public int AcceleratingProgress { get; set; }
bool _IsAccelerated;
/// <summary>
/// 是否已加速
/// </summary>
[Reactive]
[MP2Ignore, SystemTextJsonIgnore]
public bool IsAccelerated { get; set; }
public bool IsAccelerated
{
get => _IsAccelerated;
set
{
if (_IsAccelerated != value)
{
_IsAccelerated = value;
this.RaisePropertyChanged();
this.RaisePropertyChanged(nameof(ShowStart));
}
}
}
/// <summary>
/// 是否正在停止加速等待
@@ -151,7 +151,7 @@ public sealed class Plugin : PluginBase<Plugin>, IPlugin
//if (ResourceService.IsChineseSimplified)
//{
await ProxyService.Current.InitializeAsync();
await MainThread2.InvokeOnMainThreadAsync(ProxyService.Current.InitializeAsync);
//}
}
}
@@ -189,4 +189,12 @@ partial class BackendAcceleratorServiceImpl
await Task.CompletedTask;
return result;
}
/// <inheritdoc/>
public async Task<ApiRsp<XunYouStartGameCode>> XY_StartGame(CancellationToken cancellationToken = default)
{
var result = XunYouSDK.StartGame();
await Task.CompletedTask;
return result;
}
}
@@ -134,7 +134,10 @@ public sealed class ScriptManager : GeneralHttpClientFactory, IScriptManager
if (jsSaveInfo.Exists)
{
if (isNoRepeat)
{
jsSaveInfo.Delete();
fileInfo.CopyTo(jsSavePath);
}
}
else
{
@@ -404,7 +407,7 @@ public sealed class ScriptManager : GeneralHttpClientFactory, IScriptManager
}
await TryReadFileAsync(item, true);
//清理 脚本内容 后续 IPC 传递 插件进程读取。
item.Content = string.Empty;
//item.Content = string.Empty;
await scriptRepository.SaveScriptCachePathAsync(item, default);
}
else
@@ -419,9 +422,15 @@ public sealed class ScriptManager : GeneralHttpClientFactory, IScriptManager
file.Delete();
await TryReadFileAsync(item, true);
//清理 脚本内容 后续 IPC 传递 插件进程读取。
item.Content = string.Empty;
//item.Content = string.Empty;
}
}
else
{
await TryReadFileAsync(item, true);
//item.Content = string.Empty;
}
}
}
return scripts;
@@ -443,7 +452,7 @@ public sealed class ScriptManager : GeneralHttpClientFactory, IScriptManager
var cachePath = Path.Combine(Plugin.Instance.CacheDirectory, item.CachePath);
if (File.Exists(cachePath))
{
//item.Content = File.ReadAllText(cachePath);
item.Content = File.ReadAllText(cachePath);
}
else
{
@@ -81,6 +81,12 @@ partial interface IAcceleratorService // XunYou
/// </summary>
/// <returns></returns>
Task<ApiRsp<XunYouIsRunningCode>> XY_IsRunning(CancellationToken cancellationToken = default);
/// <summary>
/// 迅游加速器启动游戏
/// </summary>
/// <returns></returns>
Task<ApiRsp<XunYouStartGameCode>> XY_StartGame(CancellationToken cancellationToken = default);
}
partial interface IXunYouAccelStateToFrontendCallback
@@ -13,9 +13,9 @@ public sealed partial class GameAcceleratorService
: ReactiveObject
#endif
{
static GameAcceleratorService? mCurrent;
static readonly Lazy<GameAcceleratorService> mCurrent = new(() => new(), LazyThreadSafetyMode.ExecutionAndPublication);
public static GameAcceleratorService Current => mCurrent ??= new();
public static GameAcceleratorService Current => mCurrent.Value;
public SourceCache<XunYouGameViewModel, int> Games { get; }
@@ -38,12 +38,25 @@ public sealed partial class GameAcceleratorService
public ICommand GameAcceleratorCommand { get; }
public ICommand GameLaunchCommand { get; }
public ICommand InstallAcceleratorCommand { get; }
public ICommand UninstallAcceleratorCommand { get; }
public ICommand AcceleratorChangeAreaCommand { get; }
/// <summary>
/// VIP 到期时间
/// </summary>
[Reactive]
public DateTime? VipEndTime { get; set; }
const string VipEndTimeStringDef = "新用户免费试用 2 天";
[Reactive]
public string? VipEndTimeString { get; set; } = VipEndTimeStringDef;
GameAcceleratorService()
{
Ioc.Get<IAcceleratorService>().InitStateSubscribe(); // 仅旧项目(WattToolkit)上监听
@@ -52,6 +65,7 @@ public sealed partial class GameAcceleratorService
DeleteMyGameCommand = ReactiveCommand.Create<XunYouGameViewModel>(DeleteMyGame);
GameAcceleratorCommand = ReactiveCommand.CreateFromTask<XunYouGameViewModel>(GameAccelerator);
GameLaunchCommand = ReactiveCommand.CreateFromTask<XunYouGameViewModel>(GameLaunch);
InstallAcceleratorCommand = ReactiveCommand.CreateFromTask(InstallAccelerator);
UninstallAcceleratorCommand = ReactiveCommand.Create(UninstallAccelerator);
AcceleratorChangeAreaCommand = ReactiveCommand.Create<XunYouGameViewModel>(AcceleratorChangeArea);
@@ -139,6 +153,12 @@ public sealed partial class GameAcceleratorService
case XunYouState.启动中:
case XunYouState.启动成功:
break;
case XunYouState.启动游戏成功:
Toast.Show(ToastIcon.Success, "启动游戏成功");
break;
case XunYouState.启动游戏失败:
Toast.Show(ToastIcon.Error, "启动游戏失败");
break;
default:
Games.Items.Where(s => s.IsAccelerating || s.IsAccelerated).ForEach(s =>
{
@@ -155,6 +175,58 @@ public sealed partial class GameAcceleratorService
}
});
UserService.Current.WhenAnyValue(static x => x.User)
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(async x =>
{
string vipEndTimeString = VipEndTimeStringDef;
try
{
if (string.IsNullOrWhiteSpace(x?.WattOpenId))
{
return;
}
var vipEndTimeResult = await IMicroServiceClient.Instance.Manage.GetXunYouVipEndTime();
if (vipEndTimeResult == null)
{
Log.Error(nameof(GameAcceleratorService),
"XunYouSDK.GetVipEndTime is null.");
return;
}
if (!vipEndTimeResult.IsSuccess || vipEndTimeResult.Content == null)
{
Toast.Show(ToastIcon.Error, "获取会员时间失败");
return;
}
if (vipEndTimeResult.Content.Code == XunYouBaseResponseCode.成功)
{
var etime = vipEndTimeResult.Content.Data?.ExpireTime;
if (etime.HasValue)
{
VipEndTime = etime.Value.ToDateTime(UnixTimestampType.Seconds);
if (VipEndTime.Value > DateTime.Now)
{
vipEndTimeString = $"游戏加速会员有效期 {VipEndTime.Value:yyyy-MM-dd}";
}
}
}
else
{
Log.Error(nameof(GameAcceleratorService),
"XunYouSDK.GetVipEndTime is fail, message: {message}, code: {code}.",
vipEndTimeResult.Content.Message,
vipEndTimeResult.Content.Code);
}
}
finally
{
VipEndTimeString = vipEndTimeString;
}
});
RefreshAllGames();
LoadGames();
}
@@ -183,6 +255,10 @@ public sealed partial class GameAcceleratorService
CurrentAcceleratorGame.IsAccelerated = true;
CurrentAcceleratorGame.LastAccelerateTime = DateTimeOffset.Now;
if (CurrentAcceleratorGame.PicInfo == null)
{
CurrentAcceleratorGame.PicInfo = XunYouSDK.GetPicInfo(CurrentAcceleratorGame.Id);
}
if (CurrentAcceleratorGame.SelectedArea?.Id != areaId)
{
var gameInfo = XunYouSDK.GetGameInfo(game.Id);
@@ -205,6 +281,7 @@ public sealed partial class GameAcceleratorService
var gameInfo = XunYouSDK.GetGameInfo(game.Id);
cApp.SelectedArea = gameInfo?.Areas?.FirstOrDefault(s => s.Id == areaId);
cApp.SelectedServer = cApp.SelectedArea?.Servers?.FirstOrDefault(s => s.Id == serverId);
cApp.PicInfo = XunYouSDK.GetPicInfo(game.Id);
CurrentAcceleratorGame = cApp;
}
@@ -403,6 +480,8 @@ public sealed partial class GameAcceleratorService
GameAcceleratorSettings.MyGames.Remove(app.Id);
if (GameAcceleratorSettings.MyGames.TryAdd(app.Id, app))
{
if (app.PicInfo == null)
app.PicInfo = XunYouSDK.GetPicInfo(app.Id);
Current.Games.AddOrUpdate(app);
Toast.Show(ToastIcon.Success, "已添加到游戏列表");
}
@@ -424,6 +503,12 @@ public sealed partial class GameAcceleratorService
if (GameAcceleratorSettings.MyGames.Any_Nullable())
{
Games.Clear();
var temp = GameAcceleratorSettings.MyGames.Value!.Values.ToArray();
foreach (var item in temp)
{
if (item.PicInfo == null)
item.PicInfo = XunYouSDK.GetPicInfo(item.Id);
}
Games.AddOrUpdate(GameAcceleratorSettings.MyGames.Value!.Values);
}
else
@@ -433,6 +518,12 @@ public sealed partial class GameAcceleratorService
{
Games.Clear();
GameAcceleratorSettings.MyGames.AddRange(games.Select(s => new KeyValuePair<int, XunYouGameViewModel>(s.Id, new XunYouGameViewModel(s))));
var temp = GameAcceleratorSettings.MyGames.Value!.Values.ToArray();
foreach (var item in temp)
{
if (item.PicInfo == null)
item.PicInfo = XunYouSDK.GetPicInfo(item.Id);
}
Games.AddOrUpdate(GameAcceleratorSettings.MyGames.Value!.Values);
}
}
@@ -643,4 +734,16 @@ public sealed partial class GameAcceleratorService
XYAccelState = content;
}
}
public async Task GameLaunch(XunYouGameViewModel app)
{
var result = await Ioc.Get<IAcceleratorService>().XY_StartGame();
if (result.HandleUI(out var r))
{
if (r == XunYouStartGameCode.失败)
{
Toast.Show(ToastIcon.Error, $"启动 {app.Name} 失败");
}
}
}
}
@@ -7,6 +7,8 @@ partial class ProxyService
const ushort httpsPort = 443;
ProxyMode proxyMode = defaultProxyMode;
static string? proxyTokenCache = null;
/// <summary>
/// 启动代理服务
/// </summary>
@@ -126,7 +128,6 @@ partial class ProxyService
//{
// //if (string.IsNullOrWhiteSpace(Plugin.Instance.SubProcessPath))
// //{
// //}
// // var processPath = Environment.ProcessPath;
// // processPath.ThrowIsNull();
@@ -156,6 +157,7 @@ partial class ProxyService
}
}
break;
case ProxyMode.System:
if (OperatingSystem.IsWindows() &&
proxyIp_.Value.Equals(IPAddress.Any))
@@ -170,6 +172,7 @@ partial class ProxyService
return Strings.CommunityFix_SetAsSystemProxyFail;
}
break;
case ProxyMode.PAC:
if (OperatingSystem.IsWindows() &&
proxyIp_.Value.Equals(IPAddress.Any))
@@ -203,12 +206,15 @@ partial class ProxyService
}
}
string? proxyToken = proxyDomains.Any_Nullable(s => s.ProxyType == ProxyType.ServerAccelerate) ?
await TryRequestServerSideProxyToken() : null;
ReverseProxySettings reverseProxySettings = new(proxyDomains, scripts,
isEnableScript, isOnlyWorkSteamBrowser, proxyPort,
proxyIp, proxyMode, isProxyGOG, onlyEnableProxyScript,
enableHttpProxyToHttps, socks5ProxyEnable, socks5ProxyPortId,
twoLevelAgentEnable, twoLevelAgentProxyType, twoLevelAgentIp,
twoLevelAgentPortId, twoLevelAgentUserName, twoLevelAgentPassword, proxyDNS, isSupportIpv6, useDoh, customDohAddres);
twoLevelAgentPortId, twoLevelAgentUserName, twoLevelAgentPassword, proxyDNS, isSupportIpv6, useDoh, customDohAddres, proxyToken);
byte[] reverseProxySettings_ = Serializable.SMP2(reverseProxySettings);
var startProxyResult = await reverseProxyService.StartProxyAsync(reverseProxySettings_);
if (startProxyResult)
@@ -331,12 +337,14 @@ partial class ProxyService
}
}
break;
case ProxyMode.System:
if (callSet)
{
await platformService.SetAsSystemProxyAsync(false);
}
break;
case ProxyMode.PAC:
if (callSet)
{
@@ -361,6 +369,34 @@ partial class ProxyService
return default;
}
/// <summary>
/// 尝试获取服务端代理token
/// </summary>
/// <returns></returns>
static async Task<string?> TryRequestServerSideProxyToken()
{
try
{
if (!string.IsNullOrEmpty(proxyTokenCache))
return proxyTokenCache;
var resp = await IMicroServiceClient.Instance.Account
.GenerateServerSideProxyToken();
if (resp != null && !string.IsNullOrEmpty(resp.Content?.AccessToken))
{
proxyTokenCache = resp.Content.AccessToken;
}
return proxyTokenCache;
}
catch (Exception ex)
{
ex.LogAndShowT();
return null;
}
}
/// <summary>
/// 操作代理服务返回结果
/// </summary>
@@ -1,8 +1,6 @@
using BD.Common;
using System.Linq;
using KeyValuePair = System.Collections.Generic.KeyValuePair;
// ReSharper disable once CheckNamespace
using Avalonia.Data;
namespace BD.WTTS.Services;
public sealed partial class ProxyService
@@ -10,9 +8,9 @@ public sealed partial class ProxyService
: ReactiveObject, IProxyService
#endif
{
static ProxyService? mCurrent;
static readonly Lazy<ProxyService> mCurrent = new(() => new(), LazyThreadSafetyMode.ExecutionAndPublication);
public static ProxyService Current => mCurrent ??= new();
public static ProxyService Current => mCurrent.Value;
readonly IReverseProxyService reverseProxyService = IReverseProxyService.Constants.Instance;
readonly IScriptManager scriptManager = IScriptManager.Instance;
@@ -31,37 +29,38 @@ public sealed partial class ProxyService
.Bind(out _ProxyDomainsList)
.Subscribe(_ => SelectGroup = ProxyDomains.Items.FirstOrDefault());
this.WhenValueChanged(x => x.ProxyStatus, false)
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(async proxyStatusLeft =>
{
bool proxyStatusRight;
if (proxyStatusLeft)
{
var reuslt = await StartProxyServiceAsync();
proxyStatusRight = reuslt.OnStartedShowToastReturnProxyStatus();
}
else
{
var reuslt = await StopProxyServiceAsync();
proxyStatusRight = reuslt.OnStopedShowToastReturnProxyStatus();
}
if (proxyStatusLeft != proxyStatusRight)
{
ProxyStatus = proxyStatusRight;
//this.WhenValueChanged(x => x.ProxyStatus, false)
// .ObserveOn(RxApp.MainThreadScheduler)
// .Subscribe(async proxyStatusLeft =>
// {
// bool proxyStatusRight;
// if (proxyStatusLeft)
// {
// var reuslt = await StartProxyServiceAsync();
// proxyStatusRight = reuslt.OnStartedShowToastReturnProxyStatus();
// }
// else
// {
// var reuslt = await StopProxyServiceAsync();
// proxyStatusRight = reuslt.OnStopedShowToastReturnProxyStatus();
// }
// if (proxyStatusLeft != proxyStatusRight)
// {
// ProxyStatus = proxyStatusRight;
//UpdateProxyTrayMenuItems();
//if (Steamworks.SteamClient.IsValid)
//{
// if (ProxyStatus)
// Steamworks.SteamFriends.SetRichPresence("steam_display", "#Status_Accelerator");
// else
// Steamworks.SteamFriends.ClearRichPresence();
//}
}
});
// //UpdateProxyTrayMenuItems();
// //if (Steamworks.SteamClient.IsValid)
// //{
// // if (ProxyStatus)
// // Steamworks.SteamFriends.SetRichPresence("steam_display", "#Status_Accelerator");
// // else
// // Steamworks.SteamFriends.ClearRichPresence();
// //}
// }
// });
this.WhenAnyValue(v => v.ProxyDomainsList)
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(domain => domain?
.ToObservableChangeSet()
.AutoRefresh(x => x.ObservableItems)
@@ -75,6 +74,7 @@ public sealed partial class ProxyService
}));
this.WhenAnyValue(v => v.ProxyScripts)
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(script => script?
.Connect()
.AutoRefresh(x => x.Disable)
@@ -111,13 +111,54 @@ public sealed partial class ProxyService
public SourceList<ScriptDTO> ProxyScripts { get; }
public async Task StartOrStopProxyService(bool startOrStop)
{
if (startOrStop == ProxyStatus)
{
return;
}
if (!ProxyStarting)
{
ProxyStarting = true;
bool proxyStatusRight;
if (startOrStop)
{
var reuslt = await StartProxyServiceAsync();
proxyStatusRight = reuslt.OnStartedShowToastReturnProxyStatus();
}
else
{
var reuslt = await StopProxyServiceAsync();
proxyStatusRight = reuslt.OnStopedShowToastReturnProxyStatus();
}
if (startOrStop != proxyStatusRight)
{
startOrStop = proxyStatusRight;
}
//UpdateProxyTrayMenuItems();
//if (Steamworks.SteamClient.IsValid)
//{
// if (startOrStop)
// Steamworks.SteamFriends.SetRichPresence("steam_display", "#Status_Accelerator");
// else
// Steamworks.SteamFriends.ClearRichPresence();
//}
ProxyStarting = false;
ProxyStatus = startOrStop;
}
}
public IEnumerable<AccelerateProjectDTO>? GetEnableProxyDomains()
{
if (!ProxyDomains.Items.Any_Nullable())
return null;
var data = ProxyDomains.Items
.Where(x => x.Items != null)
.SelectMany(s => s.Items!.Where(w => w.Checked));
.SelectMany(s => s.Items!.Where(w => w.ThreeStateEnable != false));
//return data.Concat(data.SelectMany(s => GetProxyDomainsItems(s)));
return data;
}
@@ -204,17 +245,20 @@ public sealed partial class ProxyService
// return r;
//}
#endregion
#endregion HOSTS_PROXY_RUNNING_STATUS
#region 代理状态启动退出
private bool _ProxyStatus;
public bool ProxyStatus
{
get { return _ProxyStatus; }
set => this.RaiseAndSetIfChanged(ref _ProxyStatus, value);
}
#endregion
/// <summary>
/// 代理启动中
/// </summary>
[Reactive]
public bool ProxyStarting { get; set; }
[Reactive]
public bool ProxyStatus { get; set; }
#endregion 代理状态启动退出
static bool IsProgramStartupRunProxy()
{
@@ -273,7 +317,8 @@ public sealed partial class ProxyService
}
else
{
ProxyStatus = true;
//ProxyStatus = true;
await StartOrStopProxyService(true);
}
}
}
@@ -298,10 +343,30 @@ public sealed partial class ProxyService
{
new TrayMenuItem
{
Name = "启动/停止",
Command = ReactiveCommand.Create(() =>
Name = "启动",
//IsEnabled = new Binding()
//{
// Source = ProxyService.Current,
// Mode = BindingMode.OneWay,
// Path = "!" + nameof(ProxyStatus),
//},
Command = ReactiveCommand.CreateFromTask(async () =>
{
ProxyStatus = !ProxyStatus;
await StartOrStopProxyService(true);
}),
},
new TrayMenuItem
{
Name = "停止",
//IsEnabled = new Binding()
//{
// Source = ProxyService.Current,
// Mode = BindingMode.OneWay,
// Path = nameof(ProxyStatus),
//},
Command = ReactiveCommand.CreateFromTask(async () =>
{
await StartOrStopProxyService(false);
}),
},
},
@@ -630,7 +695,8 @@ public sealed partial class ProxyService
}
}
}
#endregion
#endregion 脚本相关
public async void FixNetwork()
{
@@ -652,7 +718,6 @@ public sealed partial class ProxyService
}
catch
{
}
}
#endif
@@ -155,6 +155,11 @@ public partial interface IProxySettings
/// </summary>
string? CustomDohAddres { get; set; }
/// <summary>
/// 加速页面 Tab 选项卡选中下标
/// </summary>
int AcceleratorTabsSelectedIndex { get; set; }
/// <summary>
/// 启用脚本自动检查更新的默认值
/// </summary>
@@ -270,4 +275,9 @@ public partial interface IProxySettings
/// </summary>
const string? DefaultCustomDohAddres = null;
/// <summary>
/// 加速页面 Tab 选项卡选中下标的默认值
/// </summary>
static readonly int DefaultAcceleratorTabsSelectedIndex = 0;
}
@@ -197,6 +197,12 @@ public sealed partial class ProxySettings_ : IProxySettings, ISettings, ISetting
[MPKey(22), MP2Key(22), JsonPropertyOrder(22)]
public string? CustomDohAddres { get; set; } = IProxySettings.DefaultCustomDohAddres;
/// <summary>
/// 加速页面 Tab 选项卡选中下标
/// </summary>
[MPKey(23), MP2Key(23), JsonPropertyOrder(23)]
public int AcceleratorTabsSelectedIndex { get; set; } = IProxySettings.DefaultAcceleratorTabsSelectedIndex;
}
public static partial class ProxySettings
@@ -359,4 +365,10 @@ public static partial class ProxySettings
public static SettingsProperty<string, ProxySettings_> CustomDohAddres { get; }
= new(DefaultCustomDohAddres);
/// <summary>
/// 加速页面 Tab 选项卡选中下标
/// </summary>
public static SettingsStructProperty<int, ProxySettings_> AcceleratorTabsSelectedIndex { get; }
= new(DefaultAcceleratorTabsSelectedIndex);
}
@@ -15,12 +15,13 @@ public sealed partial class AcceleratorPageViewModel
public AcceleratorPageViewModel()
{
StartProxyCommand = ReactiveCommand.Create(() =>
StartProxyCommand = ReactiveCommand.CreateFromTask(async _ =>
{
#if LINUX
if (!EnvironmentCheck()) return;
#endif
ProxyService.Current.ProxyStatus = !ProxyService.Current.ProxyStatus;
//ProxyService.Current.ProxyStatus = !ProxyService.Current.ProxyStatus;
await ProxyService.Current.StartOrStopProxyService(!ProxyService.Current.ProxyStatus);
});
RefreshCommand = ReactiveCommand.Create(async () =>
@@ -58,6 +59,7 @@ public sealed partial class AcceleratorPageViewModel
ResetHostsFileCommand = ReactiveCommand.CreateFromTask(hostsFileService.ResetFile);
NetworkFixCommand = ReactiveCommand.Create(ProxyService.Current.FixNetwork);
TrustCerCommand = ReactiveCommand.Create(TrustCer_OnClick);
ShowCertificateCommand = ReactiveCommand.Create(ShowCertificate_OnClick);
OpenCertificateDirCommand = ReactiveCommand.Create(() =>
{
certificateManager.GetCerFilePathGeneratedWhenNoFileExists();
@@ -125,4 +127,10 @@ public sealed partial class AcceleratorPageViewModel
Toast.Show(ToastIcon.Error, Strings.CommunityFix_DeleteCertificate_Fail);
}
}
void ShowCertificate_OnClick()
{
var certInfo = certificateManager.GetCertificateInfo();
MessageBox.Show(certInfo, "证书信息");
}
}
@@ -15,6 +15,8 @@ public sealed partial class AcceleratorPageViewModel : TabItemViewModel
public ICommand? DeleteCertificateCommand { get; }
public ICommand? ShowCertificateCommand { get; }
public ICommand? OpenCertificateDirCommand { get; }
public ICommand? EditHostsFileCommand { get; }
@@ -93,13 +93,13 @@
Grid.ColumnSpan="2"
Stretch="UniformToFill">
<spp:Image2
DecodeWidth="600"
DecodeWidth="300"
FallbackSource="avares://BD.WTTS.Client.Plugins.Accelerator/UI/Assets/defaultBackground.png"
Source="{Binding PicUrl}"
Source="{Binding PicInfo.Small.Url}"
Stretch="UniformToFill" />
</Viewbox>
<spp:Image2
<!--<spp:Image2
Grid.RowSpan="2"
Grid.ColumnSpan="2"
Margin="10,0,50,0"
@@ -107,7 +107,7 @@
VerticalAlignment="Bottom"
DecodeWidth="250"
Source="{Binding LogoUrl}"
Stretch="Uniform" />
Stretch="Uniform" />-->
<Border
Name="ShadowBox"
@@ -180,7 +180,7 @@
VerticalAlignment="Center"
DecodeWidth="20"
IsVisible="{Binding !$self.IsFailed}"
Source="{Binding IconUrl}">
Source="{Binding PicInfo.Icon.Url}">
<spp:Image2.Transitions>
<Transitions>
<DoubleTransition
@@ -36,7 +36,7 @@
Classes="Scale"
DecodeWidth="800"
FallbackSource="avares://BD.WTTS.Client.Plugins.Accelerator/UI/Assets/defaultBackground.png"
Source="{Binding PicUrl}" />
Source="{Binding PicInfo.Large.Url}" />
</Viewbox>
<spp:Image2
@@ -46,7 +46,7 @@
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
DecodeWidth="400"
Source="{Binding LogoUrl}"
Source="{Binding PicInfo.Logo.Url}"
Stretch="Uniform" />
<Panel
@@ -68,7 +68,7 @@
VerticalAlignment="Center"
DecodeWidth="36"
IsVisible="{Binding !$self.IsFailed}"
Source="{Binding IconUrl}">
Source="{Binding PicInfo.Icon.Url}">
<spp:Image2.Transitions>
<Transitions>
<DoubleTransition
@@ -163,15 +163,28 @@
Foreground="White"
Text="KB" />-->
</Grid>
<Button
<StackPanel
Grid.Row="2"
Width="150"
Height="42"
Classes="accent"
Command="{Binding GameAcceleratorCommand, Source={x:Static s:GameAcceleratorService.Current}}"
CommandParameter="{Binding}"
Content="停止加速"
FontSize="18" />
Orientation="Horizontal"
Spacing="10">
<Button
Width="150"
Height="42"
Classes="accent"
Command="{Binding GameLaunchCommand, Source={x:Static s:GameAcceleratorService.Current}}"
CommandParameter="{Binding}"
Content="启动游戏"
FontSize="18"
IsVisible="{Binding ShowStart}" />
<Button
Width="150"
Height="42"
Command="{Binding GameAcceleratorCommand, Source={x:Static s:GameAcceleratorService.Current}}"
CommandParameter="{Binding}"
Content="停止加速"
FontSize="18" />
</StackPanel>
</Grid>
</Panel>
@@ -297,6 +297,10 @@
HorizontalAlignment="Stretch"
Command="{Binding DeleteCertificateCommand}"
Content="{Binding Path=Res.CommunityFix_DeleteCertificate, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<Button
HorizontalAlignment="Stretch"
Command="{Binding ShowCertificateCommand}"
Content="查看证书信息" />
<Button
HorizontalAlignment="Stretch"
Command="{Binding OpenCertificateDirCommand}"
@@ -7,6 +7,6 @@ public partial class AcceleratorPage : PageBase<AcceleratorPageViewModel>
public AcceleratorPage()
{
InitializeComponent();
this.SetViewModel<AcceleratorPageViewModel>();
this.SetViewModel<AcceleratorPageViewModel>(true);
}
}
@@ -3,6 +3,7 @@
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:enum="using:BD.WTTS.Enums"
xmlns:i="using:Avalonia.Xaml.Interactivity"
xmlns:ia="using:Avalonia.Xaml.Interactions.Core"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@@ -25,26 +26,25 @@
</spp:PageBase.PreviewImage>
<spp:PageBase.ActionContent>
<StackPanel Orientation="Horizontal" Spacing="2">
<Button
<SplitButton
Padding="8,4"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Command="{Binding StartProxyCommand}"
DockPanel.Dock="Right"
IsVisible="{Binding Source={x:Static s:ProxyService.Current}, Path=!ProxyStatus, Mode=OneWay}"
Theme="{StaticResource TransparentButton}">
<!--<SplitButton.Flyout>
<ui:FAMenuFlyout>
<ui:MenuFlyoutSubItem ItemsSource="{Binding Source={x:Static ms:ProxySettings.ProxyModes}, Path=., Mode=OneWay}" Text="加速模式">
IsVisible="{Binding Source={x:Static s:ProxyService.Current}, Path=!ProxyStatus, Mode=OneWay}">
<SplitButton.Flyout>
<ui:FAMenuFlyout Placement="BottomEdgeAlignedRight">
<!--<ui:MenuFlyoutSubItem ItemsSource="{Binding Source={x:Static ms:ProxySettings.ProxyModes}, Path=., Mode=OneWay}" Text="加速模式">
<ui:MenuFlyoutSubItem.ItemTemplate>
<DataTemplate>
<ui:RadioMenuFlyoutItem GroupName="ProxyMode" Text="{Binding}" />
</DataTemplate>
</ui:MenuFlyoutSubItem.ItemTemplate>
</ui:MenuFlyoutSubItem>
<ui:ToggleMenuFlyoutItem Text="启用脚本" />
</ui:MenuFlyoutSubItem>-->
<ui:ToggleMenuFlyoutItem IsChecked="{Binding Source={x:Static s:ProxyService.Current}, Path=IsEnableScript, Mode=TwoWay}" Text="启用脚本" />
</ui:FAMenuFlyout>
</SplitButton.Flyout>-->
</SplitButton.Flyout>
<Panel>
<Viewbox
Width="16"
@@ -52,13 +52,34 @@
HorizontalAlignment="Left">
<ui:FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="{StaticResource SpeedHigh}" />
</Viewbox>
<TextBlock
<ContentControl
Margin="28,4,0,4"
HorizontalAlignment="Left"
VerticalAlignment="Center">
<ContentControl.Content>
<MultiBinding Converter="{StaticResource VisibleStringConverter}">
<CompiledBinding
Mode="OneWay"
Path="ProxyStarting"
Source="{x:Static s:ProxyService.Current}" />
<CompiledBinding
Mode="OneWay"
Path="Res.CommunityFix_Starting"
Source="{x:Static s:ResourceService.Current}" />
<CompiledBinding
Mode="OneWay"
Path="Res.CommunityFix_StartProxy"
Source="{x:Static s:ResourceService.Current}" />
</MultiBinding>
</ContentControl.Content>
</ContentControl>
<!--<TextBlock
Margin="28,4,0,4"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{x:Static spp:Strings.CommunityFix_StartProxy}" />
Text="{x:Static spp:Strings.CommunityFix_StartProxy}" />-->
</Panel>
</Button>
</SplitButton>
<Button
Padding="8,4"
@@ -291,6 +312,10 @@
HorizontalAlignment="Stretch"
Command="{Binding DeleteCertificateCommand}"
Content="{x:Static spp:Strings.CommunityFix_DeleteCertificate}" />
<Button
HorizontalAlignment="Stretch"
Command="{Binding ShowCertificateCommand}"
Content="查看证书信息" />
<Button
HorizontalAlignment="Stretch"
Command="{Binding OpenCertificateDirCommand}"
@@ -353,10 +378,52 @@
VerticalAlignment="Top"
ItemContainerTheme="{StaticResource TabItemStyle}"
Theme="{StaticResource TabStripStyle}">
<TabStripItem Name="GameAccTab" Content="游戏加速" />
<TabStripItem Content="平台加速 (免费)" IsVisible="{Binding Source={x:Static s:ProxyService.Current}, Path=!ProxyStatus, Mode=OneWay}" />
<TabStripItem Content="平台加速" IsVisible="{Binding Source={x:Static s:ProxyService.Current}, Path=!ProxyStatus, Mode=OneWay}">
<WrapPanel>
<TextBlock Text="平台加速" />
<Border
Margin="5,0,0,0"
Padding="5,1"
VerticalAlignment="Center"
CornerRadius="2">
<Border.Background>
<LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
<GradientStop Offset="0.0" Color="#48C6EF" />
<GradientStop Offset="1.0" Color="#6F86D6" />
</LinearGradientBrush>
</Border.Background>
<TextBlock
VerticalAlignment="Center"
FontSize="10"
Foreground="White"
Text="免费" />
</Border>
</WrapPanel>
</TabStripItem>
<TabStripItem Content="{x:Static spp:Strings.CommunityFix_FlowStatistics}" IsVisible="{Binding Source={x:Static s:ProxyService.Current}, Path=ProxyStatus, Mode=OneWay}" />
<TabStripItem Content="{x:Static spp:Strings.CommunityFix_Services}" IsVisible="{Binding Source={x:Static s:ProxyService.Current}, Path=ProxyStatus, Mode=OneWay}" />
<TabStripItem Name="GameAccTab">
<WrapPanel>
<TextBlock Text="游戏加速" />
<Border
Margin="5,0,0,0"
Padding="5,1"
VerticalAlignment="Center"
CornerRadius="2">
<Border.Background>
<LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
<GradientStop Offset="0.0" Color="#EEAD92" />
<GradientStop Offset="1.0" Color="#6018DC" />
</LinearGradientBrush>
</Border.Background>
<TextBlock
VerticalAlignment="Center"
FontSize="10"
Foreground="White"
Text="收费" />
</Border>
</WrapPanel>
</TabStripItem>
</TabStrip>
<Carousel
Grid.Row="1"
@@ -364,66 +431,6 @@
Classes="AnimeSlide"
SelectedIndex="{Binding #AcceleratorTabs.SelectedIndex}">
<!-- 游戏加速 -->
<Panel x:DataType="spp:GameAcceleratorPageViewModel">
<Panel.DataContext>
<spp:GameAcceleratorPageViewModel />
</Panel.DataContext>
<spp:ContentLoader
IsLoading="{Binding Source={x:Static s:GameAcceleratorService.Current}, Path=IsLoadingGames, Mode=OneWay}"
IsShowNoResultText="{Binding !!!Games.Count}"
IsVisible="{Binding Source={x:Static s:GameAcceleratorService.Current}, Path=!CurrentAcceleratorGame.IsAccelerated}"
NoResultMessage="{x:Static spp:Strings.GameAccelerator_GamesEmptyTip}}">
<ScrollViewer
Name="GameScrollViewer"
Padding="0,0,10,0"
HorizontalScrollBarVisibility="Disabled"
IsVisible="{Binding !!Games.Count}"
VerticalScrollBarVisibility="Auto">
<StackPanel>
<ItemsRepeater ItemsSource="{Binding Games}" VerticalCacheLength="50">
<ItemsRepeater.Layout>
<UniformGridLayout
ItemsJustification="Start"
ItemsStretch="Uniform"
MinColumnSpacing="10"
MinItemHeight="180"
MinItemWidth="200"
MinRowSpacing="10" />
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<DataTemplate DataType="spp:XunYouGameViewModel">
<spp:GameAppItem ButtonCommand="{Binding GameAcceleratorCommand, Source={x:Static s:GameAcceleratorService.Current}}" />
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
<StackPanel
Margin="0,30"
HorizontalAlignment="Center"
Spacing="10">
<spp:Image2
Width="100"
Height="100"
HorizontalAlignment="Center"
VerticalAlignment="Center"
RenderOptions.BitmapInterpolationMode="HighQuality"
Source="avares://BD.WTTS.Client.Avalonia/UI/Assets/Icons/empty.png"
Stretch="UniformToFill" />
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="已经到底啦! 没有找到想加速的游戏的话可以搜索添加哦~" />
</StackPanel>
</StackPanel>
</ScrollViewer>
</spp:ContentLoader>
<spp:GameDetail
Margin="0,0,10,0"
Content="{Binding Source={x:Static s:GameAcceleratorService.Current}, Path=CurrentAcceleratorGame}"
IsVisible="{Binding Source={x:Static s:GameAcceleratorService.Current}, Path=CurrentAcceleratorGame.IsAccelerated}" />
</Panel>
<!-- 平台加速 -->
<ScrollViewer
Padding="0,0,10,0"
@@ -464,7 +471,25 @@
HorizontalAlignment="Left"
DockPanel.Dock="Left"
IsChecked="{Binding ThreeStateEnable, Mode=TwoWay}">
<TextBlock VerticalAlignment="Center" Text="{Binding Name}" />
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock VerticalAlignment="Center" Text="{Binding Name}" />
<Border
Padding="5,0"
CornerRadius="5"
IsVisible="{Binding ProxyType, Converter={StaticResource EnumEqualValueConverter}, ConverterParameter={x:Static enum:ProxyType.ServerAccelerate}}"
ToolTip.Tip="Beta 测试加速项,不稳定且随时可能调整">
<Border.Background>
<LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
<GradientStop Offset="0.0" Color="#43cbff" />
<GradientStop Offset="1.0" Color="#9708cc" />
</LinearGradientBrush>
</Border.Background>
<TextBlock
VerticalAlignment="Center"
FontSize="10"
Text="Beta" />
</Border>
</StackPanel>
</CheckBox>
<TextBlock
HorizontalAlignment="Right"
@@ -544,6 +569,67 @@
</Border>
</Grid>
<!-- 游戏加速 -->
<Panel x:DataType="spp:GameAcceleratorPageViewModel">
<Panel.DataContext>
<spp:GameAcceleratorPageViewModel />
</Panel.DataContext>
<spp:ContentLoader
IsLoading="{Binding Source={x:Static s:GameAcceleratorService.Current}, Path=IsLoadingGames, Mode=OneWay}"
IsShowNoResultText="{Binding !!!Games.Count}"
IsVisible="{Binding Source={x:Static s:GameAcceleratorService.Current}, Path=!CurrentAcceleratorGame.IsAccelerated}"
NoResultMessage="{x:Static spp:Strings.GameAccelerator_GamesEmptyTip}}">
<ScrollViewer
Name="GameScrollViewer"
Padding="0,0,10,0"
HorizontalScrollBarVisibility="Disabled"
IsVisible="{Binding !!Games.Count}"
VerticalScrollBarVisibility="Auto">
<StackPanel>
<ItemsRepeater ItemsSource="{Binding Games}" VerticalCacheLength="30">
<ItemsRepeater.Layout>
<UniformGridLayout
ItemsJustification="Start"
ItemsStretch="Uniform"
MinColumnSpacing="10"
MinItemHeight="240"
MinItemWidth="200"
MinRowSpacing="10" />
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<DataTemplate DataType="spp:XunYouGameViewModel">
<spp:GameAppItem ButtonCommand="{Binding GameAcceleratorCommand, Source={x:Static s:GameAcceleratorService.Current}}" />
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
<StackPanel
Margin="0,30"
HorizontalAlignment="Center"
Spacing="10">
<spp:Image2
Width="100"
Height="100"
HorizontalAlignment="Center"
VerticalAlignment="Center"
RenderOptions.BitmapInterpolationMode="HighQuality"
Source="avares://BD.WTTS.Client.Avalonia/UI/Assets/Icons/empty.png"
Stretch="UniformToFill" />
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="已经到底啦! 没有找到想加速的游戏的话可以搜索添加哦~" />
</StackPanel>
</StackPanel>
</ScrollViewer>
</spp:ContentLoader>
<spp:GameDetail
Margin="0,0,10,0"
Content="{Binding Source={x:Static s:GameAcceleratorService.Current}, Path=CurrentAcceleratorGame}"
IsVisible="{Binding Source={x:Static s:GameAcceleratorService.Current}, Path=CurrentAcceleratorGame.IsAccelerated}" />
</Panel>
<!--<TabItem Header="加速日志">
</TabItem>-->
@@ -552,75 +638,126 @@
</TabItem>-->
</Carousel>
<AutoCompleteBox
Name="SearchGameBox"
<StackPanel
Grid.ColumnSpan="2"
Width="240"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Classes="Search"
FilterMode="ContainsOrdinal"
IsVisible="{Binding #GameAccTab.IsSelected}"
ItemsSource="{Binding Source={x:Static s:GameAcceleratorService.Current}, Path=AllGames}"
MaxDropDownHeight="300"
ValueMemberBinding="{Binding Name, x:DataType=spp:XunYouGame}"
Watermark="{x:Static spp:Strings.GameAccelerator_SearchGame}">
<AutoCompleteBox.ItemTemplate>
<DataTemplate DataType="spp:XunYouGame">
<WrapPanel>
<spp:Image2
Width="20"
Height="20"
Margin="0,0,5,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
DecodeWidth="20"
Source="{Binding IconUrl}">
<spp:Image2.Transitions>
<Transitions>
<DoubleTransition
Easing="0,0 0,1"
Property="Width"
Duration="00:00:00.25" />
<DoubleTransition
Easing="0,0 0,1"
Property="Height"
Duration="00:00:00.25" />
</Transitions>
</spp:Image2.Transitions>
</spp:Image2>
<TextBlock
VerticalAlignment="Center"
MaxLines="2"
Text="{Binding Name}"
TextTrimming="CharacterEllipsis"
TextWrapping="WrapWithOverflow" />
</WrapPanel>
</DataTemplate>
</AutoCompleteBox.ItemTemplate>
</AutoCompleteBox>
Orientation="Horizontal"
Spacing="5">
<Border
Padding="5,1"
VerticalAlignment="Center"
CornerRadius="2"
IsVisible="{Binding Source={x:Static s:GameAcceleratorService.Current}, Path=VipEndTimeString, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}">
<Border.Background>
<LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
<GradientStop Offset="0.0" Color="#453a94" />
<GradientStop Offset="1.0" Color="#f43b47" />
</LinearGradientBrush>
</Border.Background>
<TextBlock
VerticalAlignment="Center"
FontSize="12"
Foreground="White"
Text="{Binding Source={x:Static s:GameAcceleratorService.Current}, Path=VipEndTimeString}" />
</Border>
<Button
Command="{Binding OpenBrowserCommand, Source={x:Static spp:App.Instance}}"
CommandParameter="https://steampp.net/customer/service"
Cursor="Hand"
Theme="{StaticResource TransparentButton}"
ToolTip.Tip="联系客服">
<ui:FontIcon FontSize="22" Glyph="&#xE95B;" />
</Button>
<AutoCompleteBox
Name="SearchGameBox"
Width="240"
VerticalAlignment="Center"
Classes="Search"
FilterMode="ContainsOrdinal"
ItemsSource="{Binding Source={x:Static s:GameAcceleratorService.Current}, Path=AllGames}"
MaxDropDownHeight="300"
ValueMemberBinding="{Binding Name, x:DataType=spp:XunYouGame}"
Watermark="{x:Static spp:Strings.GameAccelerator_SearchGame}">
<AutoCompleteBox.ItemTemplate>
<DataTemplate DataType="spp:XunYouGame">
<WrapPanel>
<spp:Image2
Width="20"
Height="20"
Margin="0,0,5,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
DecodeWidth="20"
Source="{Binding IconUrl}">
<spp:Image2.Transitions>
<Transitions>
<DoubleTransition
Easing="0,0 0,1"
Property="Width"
Duration="00:00:00.25" />
<DoubleTransition
Easing="0,0 0,1"
Property="Height"
Duration="00:00:00.25" />
</Transitions>
</spp:Image2.Transitions>
</spp:Image2>
<TextBlock
VerticalAlignment="Center"
MaxLines="2"
Text="{Binding Name}"
TextTrimming="CharacterEllipsis"
TextWrapping="WrapWithOverflow" />
</WrapPanel>
</DataTemplate>
</AutoCompleteBox.ItemTemplate>
</AutoCompleteBox>
</StackPanel>
<!--<StackPanel
<StackPanel
Grid.ColumnSpan="2"
HorizontalAlignment="Right"
VerticalAlignment="Center"
IsVisible="{Binding Source={x:Static s:ProxyService.Current}, Path=ProxyStatus, Mode=OneWay}"
Orientation="Horizontal"
Spacing="8">
<StackPanel.IsVisible>
<MultiBinding Converter="{x:Static BoolConverters.And}">
<CompiledBinding
Mode="OneWay"
Path="ProxyStatus"
Source="{x:Static s:ProxyService.Current}" />
<Binding Path="!#GameAccTab.IsSelected" />
</MultiBinding>
</StackPanel.IsVisible>
<StackPanel.Styles>
<Style Selector="TextBlock">
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</StackPanel.Styles>
<TextBlock>
<Run Text="{x:Static spp:Strings.CommunityFix_ProxyMode}" />
<Run Text="{Binding Source={x:Static ms:ProxySettings.ProxyMode}, Path=Value, Mode=OneWay, Converter={StaticResource EnumLocalizationNameConverter}}" />
<Button Theme="{StaticResource TransparentButton}">
<ToolTip.Tip>
<TextBlock>
<Run FontSize="16" Text="Q:为什么加速后流量一直显示 0KB ?" />
<LineBreak />
<Run Text="A:流量统计图表是用于查看实时流量数据信息,您需要先访问对应的网站,这边才会有相应的流量波动数据,请检查是否已经选择了对应的网站加速项目,如果确定有正常勾选加速项目并且访问网站依然无流量,则可能是加速的监听服务没有启用成功,尝试更换加速模式。" />
<LineBreak />
<LineBreak />
<Run FontSize="16" Text="Q:加速后对应网站打不开显示SSL错误或者Steam浏览器显示-100错误?" />
<LineBreak />
<Run Text="A:可以尝试执行以下操作进行修复,关闭加速,点击加速设置-移除证书再安装证书,重开加速。或者加速设置-代理设置-尝试更换doh地址或者关闭doh使用dns等方案。" />
</TextBlock>
</ToolTip.Tip>
<ui:FontIcon FontSize="22" Glyph="&#xE82F;" />
</Button>
<TextBlock Text="{x:Static spp:Strings.CommunityFix_ProxyMode}" />
<TextBlock Text="{Binding Source={x:Static ms:ProxySettings.ProxyMode}, Path=Value, Mode=OneWay, Converter={StaticResource EnumLocalizationNameConverter}}" />
<Run Text=" " />
<Run Text="{x:Static spp:Strings.CommunityFix_EnableScriptService}" />
<Run Text="{Binding Source={x:Static s:ProxyService.Current}, Path=IsEnableScript, Converter={StaticResource StringFormatConverter}}" />
</TextBlock>
</StackPanel>-->
<TextBlock Text="{x:Static spp:Strings.CommunityFix_EnableScriptService}" />
<TextBlock Text="{Binding Source={x:Static s:ProxyService.Current}, Path=IsEnableScript, Converter={StaticResource StringFormatConverter}}" />
</StackPanel>
<spp:AdControl
Grid.Row="1"
@@ -1,6 +1,7 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
using static System.Net.Mime.MediaTypeNames;
namespace BD.WTTS.UI.Views.Pages;
@@ -12,6 +13,8 @@ public partial class AcceleratorPage2 : PageBase<AcceleratorPageViewModel>
{
readonly Dictionary<string, string[]> dictPinYinArray = new();
List<int> acceleratorTabsSelectedIndexs = new();
/// <summary>
/// Initializes a new instance of the <see cref="AcceleratorPage2"/> class.
/// </summary>
@@ -21,7 +24,27 @@ public partial class AcceleratorPage2 : PageBase<AcceleratorPageViewModel>
var mode = ProxySettings.ProxyMode.Value;
InitializeComponent();
this.SetViewModel<AcceleratorPageViewModel>();
this.SetViewModel<AcceleratorPageViewModel>(true);
for (int i = 0; i < AcceleratorTabs.Items.Count; i++)
{
var item = AcceleratorTabs.Items[i];
if (item is Visual visual && visual.IsVisible)
{
acceleratorTabsSelectedIndexs.Add(i);
}
}
var itemCount = AcceleratorTabs.ItemCount;
var acceleratorTabsSelectedIndex = ProxySettings.AcceleratorTabsSelectedIndex.Value;
if (acceleratorTabsSelectedIndex >= 0 && acceleratorTabsSelectedIndex < itemCount)
{
if (acceleratorTabsSelectedIndexs.Contains(acceleratorTabsSelectedIndex))
{
AcceleratorTabs.SelectedIndex = acceleratorTabsSelectedIndex;
}
}
AcceleratorTabs.SelectionChanged += AcceleratorTabs_SelectionChanged;
//重置回保存的值
ProxySettings.ProxyMode.Value = mode;
@@ -31,7 +54,7 @@ public partial class AcceleratorPage2 : PageBase<AcceleratorPageViewModel>
ProxyService.Current.WhenValueChanged(x => x.ProxyStatus, false)
.Subscribe(x =>
{
AcceleratorTabs.SelectedIndex = x ? 2 : 1;
AcceleratorTabs.SelectedIndex = x ? 1 : 0;
}));
if (XunYouSDK.IsSupported)
@@ -48,15 +71,31 @@ public partial class AcceleratorPage2 : PageBase<AcceleratorPageViewModel>
else
{
GameAccTab.IsVisible = false;
AcceleratorTabs.SelectedIndex = 1;
AcceleratorTabs.SelectedIndex = 0;
}
});
SearchGameBox.DropDownClosed += SearchGameBox_DropDownClosed;
SearchGameBox.TextSelector = (_, _) => null;
SearchGameBox.TextSelector = (_, _) => null!;
SearchGameBox.TextFilter = GameContains;
}
void AcceleratorTabs_SelectionChanged(object? sender, SelectionChangedEventArgs e)
{
var value = AcceleratorTabs.SelectedIndex;
if (acceleratorTabsSelectedIndexs.Contains(value))
{
ProxySettings.AcceleratorTabsSelectedIndex.Value = value;
}
}
protected override void OnLoaded(RoutedEventArgs e)
{
base.OnLoaded(e);
if (AcceleratorTabs.SelectedIndex == default && ProxyService.Current.ProxyStatus)
AcceleratorTabs.SelectedIndex = 1;
}
private void SearchGameBox_DropDownClosed(object? sender, EventArgs e)
{
if (SearchGameBox.SelectedItem is XunYouGame xunYouGame && xunYouGame is not null)
@@ -98,17 +137,17 @@ public partial class AcceleratorPage2 : PageBase<AcceleratorPageViewModel>
}
/// <inheritdoc/>
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnDetachedFromVisualTree(e);
//protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
//{
// base.OnDetachedFromVisualTree(e);
//try
//{
// ISettingsLoadService.Current.ForceSave<GameAcceleratorSettingsModel>();
//}
//catch (Exception ex)
//{
// Log.Error(nameof(AcceleratorPage), ex, "ForceSave fail.");
//}
}
// //try
// //{
// // ISettingsLoadService.Current.ForceSave<GameAcceleratorSettingsModel>();
// //}
// //catch (Exception ex)
// //{
// // Log.Error(nameof(AcceleratorPage), ex, "ForceSave fail.");
// //}
//}
}
@@ -30,7 +30,19 @@
</On>
</OnFormFactor>
</TabStrip.ItemsPanel>
<TabStripItem Content="{Binding Path=Res.CommunityFix, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
<TabStripItem>
<WrapPanel>
<Border
Margin="-5,0,3,0"
VerticalAlignment="Center"
CornerRadius="2">
<ui:ImageIcon
Width="24"
Height="24"
Source="avares://BD.WTTS.Client.Plugins.Accelerator/UI/Assets/accelerator.ico" />
</Border>
<TextBlock VerticalAlignment="Center" Text="{Binding Path=Res.CommunityFix, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
</WrapPanel>
<TabStripItem.Tag>
<x:Type TypeName="spp:AcceleratorPage2" />
</TabStripItem.Tag>
@@ -40,7 +52,19 @@
<x:Type TypeName="spp:AcceleratorPage" />
</TabStripItem.Tag>
</TabStripItem>-->
<TabStripItem Content="{Binding Path=Res.ScriptConfig, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
<TabStripItem>
<WrapPanel>
<Border
Margin="-5,0,3,0"
VerticalAlignment="Center"
CornerRadius="2">
<ui:ImageIcon
Width="24"
Height="24"
Source="avares://BD.WTTS.Client.Plugins.Accelerator/UI/Assets/script.ico" />
</Border>
<TextBlock VerticalAlignment="Center" Text="{Binding Path=Res.ScriptConfig, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
</WrapPanel>
<TabStripItem.Tag>
<x:Type TypeName="spp:ScriptPage" />
</TabStripItem.Tag>
@@ -54,13 +54,6 @@
</ui:SettingsExpanderItem.Footer>
</ui:SettingsExpanderItem>
<ui:SettingsExpanderItem>
<TextBlock Text="{Binding Path=Res.CommunityFix_ProxyOnlyOnScript, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<ui:SettingsExpanderItem.Footer>
<ToggleSwitch Classes="LeftContent" IsChecked="{Binding Source={x:Static ms:ProxySettings.OnlyEnableProxyScript}, Path=Value, Mode=TwoWay}" />
</ui:SettingsExpanderItem.Footer>
</ui:SettingsExpanderItem>
<ui:SettingsExpanderItem>
<TextBlock Text="{Binding Path=Res.CommunityFix_EnableHttpProxyToHttps, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<ui:SettingsExpanderItem.Footer>
@@ -95,6 +88,13 @@
<Label Content="自定义根证书" ></Label>
<Button Content="选择证书"/>
</DockPanel>-->
<ui:SettingsExpanderItem Description="*该选项勾选后会导致程序的加速完全不生效,请确认是仅需要脚本功能后再启用">
<TextBlock Text="{Binding Path=Res.CommunityFix_ProxyOnlyOnScript, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<ui:SettingsExpanderItem.Footer>
<ToggleSwitch Classes="LeftContent" IsChecked="{Binding Source={x:Static ms:ProxySettings.OnlyEnableProxyScript}, Path=Value, Mode=TwoWay}" />
</ui:SettingsExpanderItem.Footer>
</ui:SettingsExpanderItem>
</ui:SettingsExpander>
</StackPanel>
</UserControl>
@@ -141,7 +141,6 @@
<DataTemplate DataType="spp:ScriptDTO">
<spp:AppItem
Title="{Binding Name}"
MaxHeight="200"
Description="{Binding Describe}"
ImageMargin="30"
ImageStretch="None">
@@ -159,31 +158,31 @@
Margin="0,0,3,0"
Orientation="Horizontal"
Spacing="5">
<Button
<Button
Command="{Binding $parent[spp:PageBase].((spp:ScriptPageViewModel)DataContext).DownloadScriptItemCommand}"
CommandParameter="{Binding}"
IsVisible="{Binding IsUpdate}"
Theme="{DynamicResource TransparentButton}">
<ToolTip.Tip>
<MultiBinding StringFormat="{}{0} v{1}">
<CompiledBinding
<ToolTip.Tip>
<MultiBinding StringFormat="{}{0} v{1}">
<CompiledBinding
Mode="OneWay"
Path="Res.Script_Update"
Source="{x:Static s:ResourceService.Current}" />
<CompiledBinding Mode="OneWay" Path="NewVersion" />
</MultiBinding>
</ToolTip.Tip>
<StackPanel Orientation="Horizontal" Spacing="3">
<Viewbox Width="16" Height="16">
<ui:SymbolIcon Symbol="Download" />
</Viewbox>
<TextBlock VerticalAlignment="Center" Text="{Binding NewVersion}" />
<Ellipse
<CompiledBinding Mode="OneWay" Path="NewVersion" />
</MultiBinding>
</ToolTip.Tip>
<StackPanel Orientation="Horizontal" Spacing="3">
<Viewbox Width="16" Height="16">
<ui:SymbolIcon Symbol="Download" />
</Viewbox>
<TextBlock VerticalAlignment="Center" Text="{Binding NewVersion}" />
<Ellipse
Width="6"
Height="6"
Fill="#dd5a5a" />
</StackPanel>
</Button>
</StackPanel>
</Button>
<Button
Command="{Binding $parent[spp:PageBase].((spp:ScriptPageViewModel)DataContext).EditScriptItemCommand}"
CommandParameter="{Binding}"
@@ -0,0 +1,18 @@
namespace Mobius.Enums;
/// <summary>
/// 调用加速器默认启动当前加速的游戏返回值
/// <para>23.接口 xunyou_start_game</para>
/// </summary>
public enum XunYouStartGameCode
{
/// <summary>
/// 发送失败
/// </summary>
失败 = -1,
/// <summary>
/// 发送命令到客户端成功
/// </summary>
成功 = 0,
}
@@ -23,4 +23,6 @@ public enum XunYouState
停止加速中 = 403,
加速已断开 = 404,
加速失败 = 405,
启动游戏失败 = 406,
启动游戏成功 = 407,
}
@@ -1,6 +1,6 @@
namespace Mobius;
partial class XunYouSDK // 1.接口 xunyou_install
partial class XunYouSDK // 21.接口 xunyou_install_ex
{
/// <summary>
/// 迅游下载进度回调函数委托

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