Compare commits

..
86 Commits
Author SHA1 Message Date
rmbgame 0509d2b843 ready 1.1.4 2021-02-23 02:34:20 +08:00
rmbgame 8aa450f25f ready 1.1.4 2021-02-23 02:33:41 +08:00
rmbgame 81aaa50508 修改更新日志从网络请求数据而不是写在程序内 2021-02-23 02:14:16 +08:00
rmbgame 927b652c42 添加steam更新的代理服务,解决部分用户steam更新无法连接网络的问题 2021-02-22 19:37:56 +08:00
rmbgame 4de1ac13f0 添加windows系统代理方式 2021-02-22 17:25:49 +08:00
Aigio Liu 46de667c17 添加Win7疑难解答程序
优化发布配置
优化电话服务
2021-02-22 17:00:10 +08:00
rmbgame 9d14dce321 Merge branch 'develop' of https://github.com/rmbadmin/SteamTools into develop 2021-02-22 03:02:15 +08:00
rmbgame ea33fa3444 优化反代速度
修复steam图片反代启动时创意工坊图片显示不了的问题
修复uplay更新反代启动时更新失败的问题
2021-02-22 03:00:13 +08:00
Aigio Liu 9b980427f6 fix 2021-02-22 01:02:42 +08:00
Aigio Liu 451d707626 Merge branch 'develop' of https://github.com/rmbadmin/SteamTools into develop 2021-02-22 01:02:24 +08:00
Aigio Liu f483a5dcba 优化 MSBuild 在 Release 时 不生成PDB
新增平台架构(win/mac/linux)
优化 发布配置
2021-02-22 01:02:19 +08:00
rmbgame 31c4111495 修复成就图标加载失败 2021-02-22 00:39:53 +08:00
rmbgame f0a14e332d ready 1.1.3 2021-02-21 21:39:02 +08:00
rmbgame d382d70487 修改部分提示文本,修复证书生成安装失败 2021-02-21 21:37:47 +08:00
rmbgame c438656378 修改证书生成方式避免324错误和100错误 2021-02-21 16:50:44 +08:00
Aigio Liu 035b1a6421 更新 Readme 2021-02-20 23:10:54 +08:00
Aigio Liu f3db1a23ed 优化MSBuild配置 2021-02-20 20:27:32 +08:00
Aigio Liu 59096c898c Merge branch 'develop' of https://github.com/rmbadmin/SteamTools into develop 2021-02-20 17:02:25 +08:00
Aigio Liu 4d76decf73 V1.2 新构架 2021-02-20 16:45:44 +08:00
Aigio Liu c2d95a1833 V1.2 新构架 2021-02-20 16:45:05 +08:00
rmbgame fd6f5ff3ea 更新nuge包 2021-02-20 10:51:16 +08:00
rmbgame 5bd381f553 修复faq文本错误 2021-02-20 10:39:25 +08:00
rmbgame 55bad031df 修复在某些情况下出现算法不同证书验证错误问题 2021-02-20 00:47:40 +08:00
rmbgame 866ad1a821 库存游戏列表添加clienticon图标显示
无边框窗口化功能添加操作窗口历史记录
2021-01-30 20:34:58 +08:00
rmbgame 948016c84f ready 1.1.2 2021-01-29 19:10:07 +08:00
rmbgame 9fbe6408ab 修复某些情况下开机自启失效问题
修复配置文件加载时提示根元素错误
配置文件备份机制完善
2021-01-29 19:08:11 +08:00
rmbgame c8ea806360 关于里加入FAQ 2021-01-28 23:11:18 +08:00
rmbgame a8b0f9877c 新增账号切换登录新账号功能
账号切换可以实时刷新新登录的账号了
2021-01-28 20:08:43 +08:00
rmbgame d82f94f95d 修改谷歌验证码代理方式为全局跳转www.recaptcha.net 2021-01-27 19:06:00 +08:00
rmbgame a40fb84783 记录更详细错误日志 2021-01-27 14:34:34 +08:00
rmbgame c9cbf696e4 新增Steam图片上传的代理选项 2021-01-25 17:22:43 +08:00
rmbgame 98da730c18 push 1.1.1 2021-01-23 00:02:52 +08:00
rmbgame cc86913b72 修复某些情况下配置读取错误 2021-01-23 00:02:17 +08:00
rmbgame ba02250f61 update readme 2021-01-22 23:32:03 +08:00
rmbgame 451de6ca55 令牌交易确认功能上线
新增消息通知设置项
新增检测是否蒸汽平台启动
2021-01-22 22:25:08 +08:00
rmbgame 691fb360bb 修改了所有代理服务的域名解析方式
修复twitch聊天频道连接失效
修复gihub头像资源加载失败
新增pixiv图片的代理选项来修复pixiv图片失效
2021-01-22 16:24:37 +08:00
rmbgame 686e3987f8 修复discord更新下载和图片失效
新增github gist代理服务支持
2021-01-20 17:06:13 +08:00
rmbgame 79871c3bcb 自动更新增加一个简单的文件效验
保存备份机制修改
2021-01-19 15:21:52 +08:00
rmbgame c1b19b4929 ui库代码更新 2021-01-18 20:47:25 +08:00
rmbgame c564ea10eb 令牌交易确认的进度推进
许多细节改进
2021-01-18 20:33:16 +08:00
rmbgame d5006da378 新增steam史低查询脚本
修复仅在steam内置浏览器生效功能有时候没有用的问题
2021-01-14 05:00:03 +08:00
rmbgame ab6bfd45b7 ready 1.0.6 2021-01-12 16:25:19 +08:00
rmbgame 878e9dbd32 修改用户信息api为steam官方api 2021-01-12 16:22:10 +08:00
rmbgame bd7f9e76b8 增加80端口反代,以便自动跳转http访问到https请求上 2021-01-12 16:10:39 +08:00
rmbgame fc285cf583 修改生成的cer证书编码格式为utf8 2021-01-12 11:16:23 +08:00
rmbgame 3ab0ae46c0 新增启用日志设置项
修复twitch反代聊天连接错误和直播视频无法观看
使httpclient更稳定
2021-01-11 11:18:42 +08:00
rmbgame 4550ff1621 放宽令牌同步时网络请求超时时间 2021-01-08 21:50:18 +08:00
rmbgame 1663bd4277 fix text error 2021-01-08 10:56:53 +08:00
rmbgame 8abfc81ba2 ready 1.0.5 2021-01-08 09:57:34 +08:00
rmbgame 679afdef1b ready 1.0.5 2021-01-08 09:55:03 +08:00
rmbgame d38588d45c 修复了因为steamdb.ml api挂掉导致的程序启动崩溃 2021-01-08 09:44:07 +08:00
rmbgame 42b11ce241 帐户切换功能增加离线模式选项
更改了许多文本问题
2021-01-07 09:37:56 +08:00
rmbgame c01512bcf6 帐户切换功能增加离线模式选项
更改了许多文本问题
2021-01-07 09:37:48 +08:00
rmbgame dd89595629 update readme 2021-01-06 06:55:40 +08:00
rmbgame 94b5539823 last 2021-01-06 06:36:21 +08:00
rmbgame 317baff79c fix submodules path 2021-01-06 06:28:51 +08:00
rmbgame f702c3ae62 子模块路径修复
修复一些.NET 5的BUG
2021-01-06 06:25:34 +08:00
rmbgame 177216a51e fix 2021-01-06 06:25:21 +08:00
rmbgame 46b1c01107 submodule sync 2021-01-06 04:59:08 +08:00
rmbgame 798355e342 更新目录结构
新增反代脚本只对Steam内置浏览器生效的选项
2021-01-06 04:30:56 +08:00
rmbgame ee741d3138 新增令牌数据刷新功能 2021-01-05 02:07:11 +08:00
rmbgame e31b668beb 更新引用 2021-01-04 14:26:50 +08:00
rmbgame c00955205c .NET 5 2021-01-04 14:26:05 +08:00
rmbgame 5345926c8b 引用项目改为子模块方式
更新引用项目升级到.NET5
2021-01-04 14:26:01 +08:00
rmbgame 0987f58fee 增加了启动时自动运行Steam的设置项
社区加速功能的证书会同时生成一份cer证书文件在程序根目录(方便导入火狐等浏览器)
2021-01-04 06:55:53 +08:00
rmbgame 715737bce2 优化反代过程逻辑
修复一些文本错误
2020-12-30 20:43:55 +08:00
rmbgame d4d6c2fb51 update readme 2020-12-29 03:26:07 +08:00
rmbgame 44245aa2b7 md 2020-12-29 03:02:42 +08:00
rmbgame 97e6b92ef6 update readme 2020-12-29 03:02:18 +08:00
rmbgame 445f130272 移除无用代码,更新readme 2020-12-29 02:43:15 +08:00
rmbgame 8da01ac3dd ready 1.0.4 2020-12-28 20:35:45 +08:00
rmbgame 39fcc4d9a8 update text 2020-12-28 20:34:57 +08:00
rmbgame b4a755a647 edit text 2020-12-28 20:34:55 +08:00
rmbgame 083189c264 更友好的自动更新 2020-12-28 20:00:57 +08:00
rmbgame 676c628b6f 更友好的更新提示 2020-12-28 20:00:50 +08:00
rmbgame 43ca455e70 尝试不需要帐号密码实现确认交易的可能性 2020-12-28 20:00:38 +08:00
rmbgame 95e834a188 新增令牌导出备份功能
新增令牌数据保存在程序目录设置项
2020-12-28 20:00:24 +08:00
rmbgame e9d822bb0c *修改了配置文件的加载保存路径和格式(如果更新到此版本会丢失之前的配置)
新增令牌导出功能
2020-12-28 01:15:46 +08:00
rmbgame 2ab26f7848 ready 1.0.3 2020-12-26 22:20:50 +08:00
rmbgame d646eacda1 ready 1.0.2 2020-12-21 21:54:23 +08:00
rmbgame fb029f729b ready 1.0.0 2020-12-21 21:47:08 +08:00
rmbgame 5ef6663269 delete ref lib 2020-12-21 21:36:17 +08:00
rmbgame 5c86b53000 ready 1.0.0 2020-12-17 12:10:47 +08:00
rmbgame efb6adbd9b delete ref lib 2020-12-16 10:38:03 +08:00
rmbgame 209202b5cf sync develop 2020-12-16 10:36:52 +08:00
rmbgame c0a081e226 delete ref lib 2020-12-16 10:34:52 +08:00
978 changed files with 55175 additions and 5291 deletions
-13
View File
@@ -1,13 +0,0 @@
### 该问题是怎么引起的?
### 重现步骤
### 报错信息
-15
View File
@@ -1,15 +0,0 @@
### 相关的Issue
### 原因(目的、解决的问题等)
### 描述(做了什么,变更了什么)
### 测试用例(新增、改动、可能影响的功能)
+6
View File
@@ -0,0 +1,6 @@
[submodule "references/Titanium-Web-Proxy"]
path = references/Titanium-Web-Proxy
url = https://github.com/rmbadmin/Titanium-Web-Proxy.git
[submodule "references/MetroRadiance"]
path = references/MetroRadiance
url = https://github.com/rmbadmin/MetroRadiance.git
-155
View File
@@ -1,155 +0,0 @@
[
{
"Index": 1,
"Name": "*瑞",
"Amount": 5,
"OrderNumber": "",
"PayType": 1,
"Remark": "请大佬喝瓶饮料",
"PayTime": "2020-12-17 19:41:57"
},
{
"Index": 2,
"Name": "**耀",
"Amount": 5,
"OrderNumber": "",
"PayType": 1,
"Remark": "小小支持一波!",
"PayTime": "2020-12-17 20:46:01"
},
{
"Index": 3,
"Name": "**皓",
"Amount": 1,
"OrderNumber": "",
"PayType": 1,
"Remark": "2077掏空了我,等挂卡出来。在。。em",
"PayTime": "2020-12-17 22:41:27"
},
{
"Index": 4,
"Name": "**宇",
"Amount": 1,
"OrderNumber": "",
"PayType": 1,
"Remark": "",
"PayTime": "2020-12-18 08:39:42"
},
{
"Index": 5,
"Name": "*钊",
"Amount": 20,
"OrderNumber": "",
"PayType": 1,
"Remark": "其乐坛友bzll6538一点心意",
"PayTime": "2020-12-19 17:10:44"
},
{
"Index": 6,
"Name": "R*n",
"Amount": 20,
"OrderNumber": "",
"PayType": 2,
"Remark": "绿豆",
"PayTime": "2020-12-17 14:32:00"
},
{
"Index": 7,
"Name": "*炜",
"Amount": 100,
"OrderNumber": "",
"PayType": 1,
"Remark": "其乐坛友Davyheaven",
"PayTime": "2020-12-20 12:02:17"
},
{
"Index": 8,
"Name": "**智",
"Amount": 20,
"OrderNumber": "",
"PayType": 1,
"Remark": "派大星",
"PayTime": "2020-12-20 12:21:04"
},
{
"Index": 9,
"Name": "*森",
"Amount": 66,
"OrderNumber": "",
"PayType": 1,
"Remark": "区区心意,不成敬意(三个六给不起)",
"PayTime": "2020-12-21 23:03:26"
},
{
"Index": 10,
"Name": "*珂",
"Amount": 50,
"OrderNumber": "",
"PayType": 1,
"Remark": "其乐YK93,支持大佬",
"PayTime": "2020-12-21 23:18:09"
},
{
"Index": 11,
"Name": "**丰",
"Amount": 1,
"OrderNumber": "",
"PayType": 1,
"Remark": "",
"PayTime": "2020-12-22 12:33:46"
},
{
"Index": 12,
"Name": "Ruby",
"Amount": 77,
"OrderNumber": "",
"PayType": 2,
"Remark": "资瓷一下",
"PayTime": "2020-12-24 19:40:25"
},
{
"Index": 13,
"Name": "**桐",
"Amount": 1,
"OrderNumber": "",
"PayType": 1,
"Remark": "",
"PayTime": "2020-12-26 09:32:57"
},
{
"Index": 14,
"Name": "**珂",
"Amount": 5,
"OrderNumber": "",
"PayType": 1,
"Remark": "其乐坛友wjkhj123,小小支持一波",
"PayTime": "2020-12-26 13:28:07"
},
{
"Index": 15,
"Name": "z.w",
"Amount": 10,
"OrderNumber": "",
"PayType": 2,
"Remark": "滋瓷一下",
"PayTime": "2020-12-26 15:34:50"
},
{
"Index": 16,
"Name": "**林",
"Amount": 6,
"OrderNumber": "",
"PayType": 2,
"Remark": "一丶心意,大佬加油!",
"PayTime": "2020-12-26 18:25:06"
},
{
"Index": 17,
"Name": "**立",
"Amount": 1,
"OrderNumber": "",
"PayType": 2,
"Remark": "",
"PayTime": "2020-12-26 18:56:57"
}
]
+16
View File
@@ -0,0 +1,16 @@
<Project>
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols>
</PropertyGroup>
<PropertyGroup>
<LangVersion>9.0</LangVersion>
<Nullable>enable</Nullable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<PropertyGroup Condition="Exists('..\Unicorn.pfx')">
<SignAssembly>true</SignAssembly>
<DelaySign>false</DelaySign>
<AssemblyOriginatorKeyFile>..\Unicorn.pfx</AssemblyOriginatorKeyFile>
</PropertyGroup>
</Project>
+80 -62
View File
@@ -1,78 +1,78 @@
# Steam++ SteamTools
<h1 align="center">Steam++ Tools 🧰</h1>
<div align="center">
「Steam++」是一个包含多种Steam工具功能的工具箱。
「Steam++」is a toolkit that contains a variety of Steam tools, most of which require you to download and install Steam in order to use them.
此工具的大部分功能都是需要您下载安装Steam才能使用。
![Release Download](https://img.shields.io/github/downloads/rmbadmin/SteamTools/latest/total?style=flat-square)
[![Release Version](https://img.shields.io/github/v/release/rmbadmin/SteamTools?style=flat-square)](https://github.com/rmbadmin/SteamTools/releases/latest)
[![GitHub license](https://img.shields.io/github/license/rmbadmin/SteamTools?style=flat-square)](LICENSE)
[![GitHub Star](https://img.shields.io/github/stars/rmbadmin/SteamTools?style=flat-square)](https://github.com/rmbadmin/SteamTools/stargazers)
[![GitHub Fork](https://img.shields.io/github/forks/rmbadmin/SteamTools?style=flat-square)](https://github.com/rmbadmin/SteamTools/network/members)
![GitHub repo size](https://img.shields.io/github/repo-size/rmbadmin/SteamTools?style=flat-square&color=3cb371)
------
</div>
## 核心功能
English | [简体中文](./README.md)
### 1. 反代Steam的社区网页使其能正常访问
## ✨ Functions
1. Local reverse proxy for Steam's community webpage to enable normal access in **the Chinese Mainland, Mainland of China**
2. Quickly switch the Steam account that the current PC has remembered to log into
- This feature is to read the local user login records stored under the Steam path to directly display the operation, you can switch between multiple accounts without re-entering passwords and tokens.
3. Achievement stat modifications for Steam games
- Function reference SteamAchievementManager for secondary development, modified the game list loading and operation ease of use.
4. Steam Local Two-Step Authenticator
- The function reference [WinAuth](https://github.com/winauth/winauth) is developed to enable you to view your token without launching the mobile version of Steam App, similar function software are [WinAuth](https://github.com/winauth/winauth), [SteamDesktopAuthenticator](https://github.com/Jessecar96/SteamDesktopAuthenticator).
5. Some game tools
- Currently there is a forced game borderless windowing, CSGO fix VAC shield.
功能类似羽翼城大佬的Steam302,使用[Titanium-Web-Proxy](https://github.com/justcoding121/Titanium-Web-Proxy)开源项目进行本地反代,相比302工具具有更快的启动速度,以及支持简单的脚本注入。
<!--Prerequisites Microsoft Visual C++ 2015-2019 Redistributable [64 bit](https://aka.ms/vs/16/release/vc_redist.x64.exe) / [32 bit](https://aka.ms/vs/16/release/vc_redist.x86.exe)-->
## 🖥 Operating Environment
- Windows 10 1607+
- Windows 8.1 / Windows Server 2012 R2
- Windows 7 SP1 [ESU](https://docs.microsoft.com/troubleshoot/windows-client/windows-7-eos-faq/windows-7-extended-security-updates-faq)
- Prerequisites
- KB3063858 [64 bit](https://www.microsoft.com/download/details.aspx?id=47442) / [32 bit](https://www.microsoft.com/download/details.aspx?id=47409)
- ~~macOS 10.13 High Sierra Or Higher~~
<!--
- ~~Alpine Linux 3.11+~~
- ~~CentOS 7+~~
- ~~Debian 9+~~
- ~~Fedora 32+~~
- ~~Linux Mint 18+~~
- ~~openSUSE 15+~~
- ~~Red Hat Enterprise Linux 7+~~
- ~~SUSE Enterprise Linux (SLES) 12 SP2+~~
- ~~Ubuntu 20.10, 20.04, 18.04, 16.04~~
- ~~Android 5.0+~~
- ~~iOS 10.0+~~
-->
---
### 2. 快速切换当前PC已经记住登陆的Steam账号
## 🌎 Roadmap
Read what we [milestones](https://github.com/SteamTools-Team/SteamTools/milestones), and feel free to ask questions.
该功能是读取Steam路径下存储的本地用户登录记录直接展示操作,可以多账号切换无需重新输入密码和令牌。
## ⌨️ Development Environment
[Visual Studio 2019 Version 16.8 Or Higher](https://visualstudio.microsoft.com/vs/) Or [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/) Or [JetBrains Rider](https://www.jetbrains.com/rider/) Or [Visual Studio Code](https://code.visualstudio.com/)
- Workload
- Web and Cloud
- ASP.NET and Web Development
- Desktop and Mobile Applications
- .NET Desktop Development
- Mobile Development using .Net
- Other Toolsets
- .NET Core Cross Platform Development
- Single Component
- GitHub Extension for Visual Studio
- [Visual Studio Marketplace](https://marketplace.visualstudio.com/)
- [Avalonia for Visual Studio](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio)
- [NUnit VS Templates](https://marketplace.visualstudio.com/items?itemName=NUnitDevelopers.NUnitTemplatesforVisualStudio)
---
### 3. Steam游戏的成就统计管理功能
功能参考[SteamAchievementManager](https://github.com/gibbed/SteamAchievementManager)进行二次开发,修改了游戏列表的加载和操作易用性。
---
### 4. Steam本地两步身份验证器
功能参考[WinAuth](https://github.com/winauth/winauth)开发,可以使您不用启动移动版Steam App也能查看您的令牌,功能类似的软件有[WinAuth](https://github.com/winauth/winauth)、[SteamDesktopAuthenticator](https://github.com/Jessecar96/SteamDesktopAuthenticator)。
---
### 5. 一些游戏工具
目前已有强制游戏无边框窗口化,CSGO修复VAC屏蔽。
这一块是随缘做一些我经常用或者闲着没事捣鼓的功能。
---
## 预计后续添加的功能
### Steam自动挂卡
尝试用社区反代功能结合成就解锁功能来重新实现,目的是实现在软件内登录Steam即可直接获取徽章卡片信息并开始挂卡。
### Steam皮肤设计器
挖坑画大饼,可视化编辑Steam皮肤,而且如果软件能上架Steam的话打算支持创意工坊分享设计的Steam皮肤,短期内肯定做不完。
### 插件形式加载运行ASF
以插件形式支持ASF在工具内运行并增强ASF在Windows Desktop环境下的使用。
### Steam自定义封面管理
增强Steam自定义封面的管理以及从[SteamGridDB](https://www.steamgriddb.com/)快速匹配下载应用封面。
### 更多其它游戏平台功能
### 更多非作弊游戏功能
---
## 运行环境
> 程序使用C# WPF在 .NET Framework4.7.2环境下开发,如果无法运行请下载安装[.NET Framework 4.7.2](https://dotnet.microsoft.com/download/dotnet-framework/net472)。
---
## License
> [GPL-3.0 License](LICENSE.txt)
> 根据GPLv3许可发布的开源/免费软件。
---
## 感谢以下开源项目
## 📄 Thanks to the following Open Source Projects
* [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json)
* [MetroRadiance](https://github.com/Grabacr07/MetroRadiance)
* [MetroTrilithon](https://github.com/Grabacr07/MetroTrilithon)
* [Livet](https://github.com/runceel/Livet)
* [StatefulModel](https://github.com/Grabacr07/MetroTrilithonhttps://github.com/ugaya40/StatefulModel)
* [StatefulModel](https://github.com/ugaya40/StatefulModel)
* [Hardcodet.NotifyIcon](https://github.com/HavenDV/Hardcodet.NotifyIcon.Wpf.NetCore)
* [System.Reactive](https://github.com/dotnet/reactive)
* [Titanium-Web-Proxy](https://github.com/justcoding121/Titanium-Web-Proxy)
@@ -82,4 +82,22 @@
* [SteamAchievementManager](https://github.com/gibbed/SteamAchievementManager)
* [ArchiSteamFarm](https://github.com/JustArchiNET/ArchiSteamFarm)
* [WinAuth](https://github.com/winauth/winauth)
* [SteamDesktopAuthenticator](https://github.com/Jessecar96/SteamDesktopAuthenticator)
* [SteamDesktopAuthenticator](https://github.com/Jessecar96/SteamDesktopAuthenticator)
* [Gameloop.Vdf](https://github.com/shravan2x/Gameloop.Vdf)
* [Costura.Fody](https://github.com/Fody/Costura)
* [MessagePack-CSharp](https://github.com/neuecc/MessagePack-CSharp)
* [Nito.Comparers](https://github.com/StephenCleary/Comparers)
* [Crc32.NET](https://github.com/force-net/Crc32.NET)
* [gfoidl.Base64](https://github.com/gfoidl/Base64)
* [sqlite-net-pcl](https://github.com/praeclarum/sqlite-net)
* [Polly](https://github.com/App-vNext/Polly)
* [NLog](https://github.com/nlog/NLog)
* [NUnit](https://github.com/nunit/nunit)
* [ReactiveUI](https://github.com/reactiveui/reactiveui)
* [MessageBox.Avalonia](https://github.com/AvaloniaUtils/MessageBox.Avalonia)
* [AvaloniaUI](https://github.com/AvaloniaUI/Avalonia)
* [EntityFrameworkCore](https://github.com/dotnet/efcore)
* [ASP.NET Core](https://github.com/dotnet/aspnetcore)
* [Xamarin.Essentials](https://github.com/xamarin/essentials)
* [.NET Extensions](https://github.com/dotnet/extensions)
* [.NET Runtime](https://github.com/dotnet/runtime)
+87 -63
View File
@@ -1,80 +1,88 @@
# Steam++工具箱
<h1 align="center">Steam++ 工具箱 🧰</h1>
「Steam++」是一个包含多种Steam工具功能的工具箱。
<div align="center">
此工具的大部分功能都是需要您下载安装Steam才能使用。
「Steam++」是一个包含多种Steam工具功能的工具箱,此工具的大部分功能都是需要您下载安装Steam才能使用。
------
![Release Download](https://img.shields.io/github/downloads/rmbadmin/SteamTools/latest/total?style=flat-square)
[![Release Version](https://img.shields.io/github/v/release/rmbadmin/SteamTools?style=flat-square)](https://github.com/rmbadmin/SteamTools/releases/latest)
[![GitHub license](https://img.shields.io/github/license/rmbadmin/SteamTools?style=flat-square)](LICENSE)
[![GitHub Star](https://img.shields.io/github/stars/rmbadmin/SteamTools?style=flat-square)](https://github.com/rmbadmin/SteamTools/stargazers)
[![GitHub Fork](https://img.shields.io/github/forks/rmbadmin/SteamTools?style=flat-square)](https://github.com/rmbadmin/SteamTools/network/members)
![GitHub repo size](https://img.shields.io/github/repo-size/rmbadmin/SteamTools?style=flat-square&color=3cb371)
## 核心功能
</div>
### 1. 反代Steam的社区网页使其能正常访问
<div align="center"><img src="./resources/screenshots.jpg" /></div>
功能类似羽翼城大佬的Steam302,使用[Titanium-Web-Proxy](https://github.com/justcoding121/Titanium-Web-Proxy)开源项目进行本地反代,相比302工具具有更快的启动速度,以及支持简单的脚本注入。
[English](./README.en.md) | 简体中文
---
### 2. 快速切换当前PC已经记住登陆的Steam账号
## ✨ 功能
1. 反代 Steam 的社区网页使其能正常访问
- 功能类似羽翼城大佬的 [steamcommunity_302](https://www.dogfight360.com/blog/686/)
- 使用 [Titanium-Web-Proxy](https://github.com/justcoding121/Titanium-Web-Proxy) 开源项目进行本地反代,使国内用户可以正常访问steam社区页
- 相比 **302工具** 具有更快的启动速度,以及支持简单的脚本注入(还顺便支持了Pixiv、Discord、Twitch等网站的反代支持)
2. 快速切换当前设备已记住登陆的 Steam 账号
- 该功能是读取 Steam 路径下存储的本地用户登录记录直接展示操作,可以多账号切换无需重新输入密码和令牌
3. Steam游戏的成就统计管理功能
- 功能参考 [SteamAchievementManager](https://github.com/gibbed/SteamAchievementManager) 进行二次开发,修改了游戏列表的加载和操作易用性
4. Steam本地两步身份验证器
- 功能参考 [WinAuth](https://github.com/winauth/winauth) 开发,可以使您不用启动移动版 Steam App 也能查看您的令牌
- 本地令牌交易市场报价确认
- 功能类似的软件例如:
- [WinAuth](https://github.com/winauth/winauth)
- [SteamDesktopAuthenticator](https://github.com/Jessecar96/SteamDesktopAuthenticator)
5. 其他游戏工具
- 目前已有强制游戏无边框窗口化,CSGO 修复 VAC 屏蔽
该功能是读取Steam路径下存储的本地用户登录记录直接展示操作,可以多账号切换无需重新输入密码和令牌。
<!--发布配置SelfContained=true时会自动打包VC++相关程序集-->
<!--先决条件 Microsoft Visual C++ 2015-2019 Redistributable [64 位](https://aka.ms/vs/16/release/vc_redist.x64.exe) / [32 位](https://aka.ms/vs/16/release/vc_redist.x86.exe)-->
## 🖥 系统要求
- Windows 10 1607+
- Windows 8.1 / Windows Server 2012 R2
- Windows 7 SP1 [ESU](https://docs.microsoft.com/zh-cn/troubleshoot/windows-client/windows-7-eos-faq/windows-7-extended-security-updates-faq)
- 先决条件
- KB3063858 [64 位](https://www.microsoft.com/zh-cn/download/details.aspx?id=47442) / [32 位](https://www.microsoft.com/zh-cn/download/details.aspx?id=47409)
- ~~macOS 10.13 High Sierra 或更高版本~~
<!--
- ~~Alpine Linux 3.11+~~
- ~~CentOS 7+~~
- ~~Debian 9+~~
- ~~Fedora 32+~~
- ~~Linux Mint 18+~~
- ~~openSUSE 15+~~
- ~~Red Hat Enterprise Linux 7+~~
- ~~SUSE Enterprise Linux (SLES) 12 SP2+~~
- ~~Ubuntu 20.10, 20.04, 18.04, 16.04~~
- ~~Android 5.0+~~
- ~~iOS 10.0+~~
-->
---
### 3. Steam游戏的成就统计管理功能
功能参考[SteamAchievementManager](https://github.com/gibbed/SteamAchievementManager)进行二次开发,修改了游戏列表的加载和操作易用性。
## 🌎 路线图
查看这个 [milestones](https://github.com/SteamTools-Team/SteamTools/milestones) 来了解我们下一步的开发计划,并随时提出问题。
---
## ⌨️ 开发环境
[Visual Studio 2019 版本 16.8 或更高版本](https://visualstudio.microsoft.com/zh-hans/vs/) 或 [Visual Studio for Mac](https://visualstudio.microsoft.com/zh-hans/vs/mac/) 或 [JetBrains Rider](https://www.jetbrains.com/rider/) 或 [Visual Studio Code](https://code.visualstudio.com/)
- 工作负载
- Web 和云
- ASP.NET 和 Web 开发
- 桌面应用和移动应用
- .NET 桌面开发
- 使用 .NET 的移动开发
- 其他工具集
- .NET Core 跨平台开发
- 单个组件
- GitHub Extension for Visual Studio
- [Visual Studio Marketplace](https://marketplace.visualstudio.com/)
- [Avalonia for Visual Studio](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio)
- [NUnit VS Templates](https://marketplace.visualstudio.com/items?itemName=NUnitDevelopers.NUnitTemplatesforVisualStudio)
### 4. Steam本地两步身份验证器
功能参考[WinAuth](https://github.com/winauth/winauth)开发,可以使您不用启动移动版Steam App也能查看您的令牌,功能类似的软件有[WinAuth](https://github.com/winauth/winauth)、[SteamDesktopAuthenticator](https://github.com/Jessecar96/SteamDesktopAuthenticator)。
---
### 5. 一些游戏工具
目前已有强制游戏无边框窗口化,CSGO修复VAC屏蔽。
这一块是随缘做一些我经常用或者闲着没事捣鼓的功能。
---
## 预计后续添加的功能
### Steam自动挂卡
尝试用社区反代功能结合成就解锁功能来重新实现,目的是实现在软件内无需登录Steam帐户即可直接获取徽章卡片信息并开始挂卡。
### Steam皮肤设计器
挖坑画大饼,可视化编辑Steam皮肤,而且如果软件能上架Steam的话打算支持创意工坊分享设计的Steam皮肤,短期内肯定做不完。
### 插件形式加载运行ASF
以插件形式支持ASF在工具内运行并增强ASF在Windows Desktop环境下的使用。
### Steam自定义封面管理
增强Steam自定义封面的管理以及从[SteamGridDB](https://www.steamgriddb.com/)快速匹配下载应用封面。
### 更多其它游戏平台功能
### 更多非作弊游戏功能
---
## 运行环境
> 程序使用C# WPF在 .NET Framework4.7.2环境下开发,如果无法运行请下载安装[.NET Framework 4.7.2](https://dotnet.microsoft.com/download/dotnet-framework/net472)。
> 缺失的程序集为我自己修改后的项目
* [Titanium-Web-Proxy](https://github.com/rmbadmin/Titanium-Web-Proxy)
* [MetroRadiance](https://github.com/rmbadmin/MetroRadiance)
---
## License
> [GPL-3.0 License](LICENSE.txt)
> 根据GPLv3许可发布的开源/免费软件。
---
## 感谢以下开源项目
## 📄 感谢以下开源项目
* [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json)
* [MetroRadiance](https://github.com/Grabacr07/MetroRadiance)
* [MetroTrilithon](https://github.com/Grabacr07/MetroTrilithon)
* [Livet](https://github.com/runceel/Livet)
* [StatefulModel](https://github.com/Grabacr07/MetroTrilithonhttps://github.com/ugaya40/StatefulModel)
* [StatefulModel](https://github.com/ugaya40/StatefulModel)
* [Hardcodet.NotifyIcon](https://github.com/HavenDV/Hardcodet.NotifyIcon.Wpf.NetCore)
* [System.Reactive](https://github.com/dotnet/reactive)
* [Titanium-Web-Proxy](https://github.com/justcoding121/Titanium-Web-Proxy)
@@ -86,4 +94,20 @@
* [WinAuth](https://github.com/winauth/winauth)
* [SteamDesktopAuthenticator](https://github.com/Jessecar96/SteamDesktopAuthenticator)
* [Gameloop.Vdf](https://github.com/shravan2x/Gameloop.Vdf)
* [Costura.Fody](https://github.com/Fody/Costura)
* [Costura.Fody](https://github.com/Fody/Costura)
* [MessagePack-CSharp](https://github.com/neuecc/MessagePack-CSharp)
* [Nito.Comparers](https://github.com/StephenCleary/Comparers)
* [Crc32.NET](https://github.com/force-net/Crc32.NET)
* [gfoidl.Base64](https://github.com/gfoidl/Base64)
* [sqlite-net-pcl](https://github.com/praeclarum/sqlite-net)
* [Polly](https://github.com/App-vNext/Polly)
* [NLog](https://github.com/nlog/NLog)
* [NUnit](https://github.com/nunit/nunit)
* [ReactiveUI](https://github.com/reactiveui/reactiveui)
* [MessageBox.Avalonia](https://github.com/AvaloniaUtils/MessageBox.Avalonia)
* [AvaloniaUI](https://github.com/AvaloniaUI/Avalonia)
* [EntityFrameworkCore](https://github.com/dotnet/efcore)
* [ASP.NET Core](https://github.com/dotnet/aspnetcore)
* [Xamarin.Essentials](https://github.com/xamarin/essentials)
* [.NET Extensions](https://github.com/dotnet/extensions)
* [.NET Runtime](https://github.com/dotnet/runtime)
@@ -1,880 +0,0 @@
/*
* Copyright (C) 2015 Colin Mackie.
* This software is distributed under the terms of the GNU General Public License.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Cache;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.XPath;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Macs;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Paddings;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Generators;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
#if NUNIT
using NUnit.Framework;
#endif
#if NETCF
using OpenNETCF.Security.Cryptography;
#endif
namespace WinAuth
{
/// <summary>
/// Class that implements Steam's SteamGuadrd version of the RFC6238 Authenticator
/// </summary>
public class SteamAuthenticator : Authenticator
{
/// <summary>
/// Number of characters in code
/// </summary>
private const int CODE_DIGITS = 5;
/// <summary>
/// Number of minutes to ignore syncing if network error
/// </summary>
private const int SYNC_ERROR_MINUTES = 60;
/// <summary>
/// Number of attempts to activate
/// </summary>
private const int ENROLL_ACTIVATE_RETRIES = 30;
/// <summary>
/// Incorrect activation code
/// </summary>
private const int INVALID_ACTIVATION_CODE = 89;
/// <summary>
/// Time for http request when calling Sync in ms
/// </summary>
private const int SYNC_TIMEOUT = 5000;
/// <summary>
/// Steam issuer for KeyUri
/// </summary>
private const string STEAM_ISSUER = "Steam";
/// <summary>
/// URLs for all mobile services
/// </summary>
private static string COMMUNITY_BASE = "https://steamcommunity.com";
private static string WEBAPI_BASE = "https://api.steampowered.com";
private static string SYNC_URL = "https://api.steampowered.com:443/ITwoFactorService/QueryTime/v0001";
/// <summary>
/// Character set for authenticator code
/// </summary>
private static char[] STEAMCHARS = new char[] {
'2', '3', '4', '5', '6', '7', '8', '9', 'B', 'C',
'D', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q',
'R', 'T', 'V', 'W', 'X', 'Y'};
/// <summary>
/// Enrolling state
/// </summary>
public class EnrollState
{
public string Username { get; set; }
public string Password { get; set; }
public string CaptchaId { get; set; }
public string CaptchaUrl { get; set; }
public string CaptchaText { get; set; }
public string EmailDomain { get; set; }
public string EmailAuthText { get; set; }
public string ActivationCode { get; set; }
public CookieContainer Cookies { get; set; }
public string SteamId { get; set; }
public string OAuthToken { get; set; }
public bool RequiresLogin { get; set; }
public bool RequiresCaptcha { get; set; }
public bool Requires2FA { get; set; }
public bool RequiresEmailAuth { get; set; }
public bool RequiresActivation { get; set; }
public string RevocationCode { get; set; }
public string SecretKey { get; set; }
public bool Success { get; set; }
public string Error { get; set; }
}
#region Authenticator data
/// <summary>
/// Time of last Sync error
/// </summary>
private static DateTime _lastSyncError = DateTime.MinValue;
/// <summary>
/// Returned serial number of authenticator
/// </summary>
public string Serial { get; set; }
/// <summary>
/// Random device ID we created and registered
/// </summary>
public string DeviceId { get; set; }
/// <summary>
/// JSON steam data
/// </summary>
public string SteamData { get; set; }
/// <summary>
/// JSON session data
/// </summary>
public string SessionData { get; set; }
/// <summary>
///
/// </summary>
public string PollData { get; set; }
/// <summary>
/// Current Steam client instance
/// </summary>
public SteamClient Client { get; protected set; }
#endregion
/// <summary>
/// Expanding offsets to retry when creating first code
/// </summary>
private int[] ENROLL_OFFSETS = new int[] { 0, -30, 30, -60, 60, -90, 90, -120, 120};
/// <summary>
/// Create a new Authenticator object
/// </summary>
public SteamAuthenticator()
: base(CODE_DIGITS)
{
Issuer = STEAM_ISSUER;
}
/// <summary>
/// Get/set the combined secret data value
/// </summary>
public override string SecretData
{
get
{
if (this.Client != null && this.Client.Session != null)
{
this.SessionData = this.Client.Session.ToString();
}
//if (Logger != null)
//{
// Logger.Debug("Get Steam data: {0}, Session:{1}", (SteamData ?? string.Empty).Replace("\n"," ").Replace("\r",""), (SessionData ?? string.Empty).Replace("\n", " ").Replace("\r", ""));
//}
// this is the key | serial | deviceid
return base.SecretData
+ "|" + Authenticator.ByteArrayToString(Encoding.UTF8.GetBytes(Serial))
+ "|" + Authenticator.ByteArrayToString(Encoding.UTF8.GetBytes(DeviceId))
+ "|" + Authenticator.ByteArrayToString(Encoding.UTF8.GetBytes(SteamData))
+ "|" + (string.IsNullOrEmpty(SessionData) == false ? Authenticator.ByteArrayToString(Encoding.UTF8.GetBytes(SessionData)) : string.Empty);
}
set
{
// extract key + serial + deviceid
if (string.IsNullOrEmpty(value) == false)
{
string[] parts = value.Split('|');
base.SecretData = value;
Serial = (parts.Length > 1 ? Encoding.UTF8.GetString(Authenticator.StringToByteArray(parts[1])) : null);
DeviceId = (parts.Length > 2 ? Encoding.UTF8.GetString(Authenticator.StringToByteArray(parts[2])) : null);
SteamData = (parts.Length > 3 ? Encoding.UTF8.GetString(Authenticator.StringToByteArray(parts[3])) : string.Empty);
if (string.IsNullOrEmpty(SteamData) == false && SteamData[0] != '{')
{
// convert old recovation code into SteamData json
SteamData = "{\"revocation_code\":\"" + SteamData + "\"}";
}
string session = (parts.Length > 4 ? Encoding.UTF8.GetString(Authenticator.StringToByteArray(parts[4])) : null);
//if (Logger != null)
//{
// Logger.Debug("Set Steam data: {0}, Session:{1}", (SteamData ?? string.Empty).Replace("\n", " ").Replace("\r", ""), (SessionData ?? string.Empty).Replace("\n", " ").Replace("\r", ""));
//}
if (string.IsNullOrEmpty(session) == false)
{
SessionData = session;
}
}
else
{
SecretKey = null;
Serial = null;
DeviceId = null;
SteamData = null;
SessionData = null;
}
}
}
/// <summary>
/// Get (or create) the current Steam client for this Authenticator
/// </summary>
/// <returns>current or new SteamClient</returns>
public SteamClient GetClient()
{
lock (this)
{
if (this.Client == null)
{
this.Client = new SteamClient(this, this.SessionData);
}
return this.Client;
}
}
/// <summary>
/// Perform a request to the Steam WebAPI service
/// </summary>
/// <param name="url">API url</param>
/// <param name="method">GET or POST</param>
/// <param name="data">Name-data pairs</param>
/// <param name="cookies">current cookie container</param>
/// <returns>response body</returns>
private string Request(string url, string method, NameValueCollection data = null, CookieContainer cookies = null, NameValueCollection headers = null, int timeout = 0)
{
// create form-encoded data for query or body
string query = (data == null ? string.Empty : string.Join("&", Array.ConvertAll(data.AllKeys, key => String.Format("{0}={1}", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(data[key])))));
if (string.Compare(method, "GET", true) == 0)
{
url += (url.IndexOf("?") == -1 ? "?" : "&") + query;
}
// call the server
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = method;
request.Accept = "text/javascript, text/html, application/xml, text/xml, */*";
request.ServicePoint.Expect100Continue = false;
request.UserAgent = "Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; Google Nexus 4 - 4.1.1 - API 16 - 768x1280 Build/JRO03S) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30";
request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
request.Referer = COMMUNITY_BASE; // + "/mobilelogin?oauth_client_id=DE45CD61&oauth_scope=read_profile%20write_profile%20read_client%20write_client";
if (headers != null)
{
request.Headers.Add(headers);
}
if (cookies != null)
{
request.CookieContainer = cookies;
}
if (timeout != 0)
{
request.Timeout = timeout;
}
if (string.Compare(method, "POST", true) == 0)
{
request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
request.ContentLength = query.Length;
StreamWriter requestStream = new StreamWriter(request.GetRequestStream());
requestStream.Write(query);
requestStream.Close();
}
try {
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
LogRequest(method, url, cookies, data, response.StatusCode.ToString() + " " + response.StatusDescription);
// OK?
if (response.StatusCode != HttpStatusCode.OK)
{
throw new InvalidRequestException(string.Format("{0}: {1}", (int)response.StatusCode, response.StatusDescription));
}
// load the response
using (StreamReader responseStream = new StreamReader(response.GetResponseStream()))
{
string responseData = responseStream.ReadToEnd();
LogRequest(method, url, cookies, data, responseData);
return responseData;
}
}
}
catch (Exception ex)
{
LogException(method, url, cookies, data, ex);
if (ex is WebException && ((WebException)ex).Response != null && ((HttpWebResponse)((WebException)ex).Response).StatusCode == HttpStatusCode.Forbidden)
{
throw new UnauthorisedRequestException(ex);
}
throw new InvalidRequestException(ex.Message, ex);
}
}
/// <summary>
/// Enroll the authenticator with the server
/// </summary>
public bool Enroll(EnrollState state)
{
// clear error
state.Error = null;
try
{
var data = new NameValueCollection();
var cookies = state.Cookies = state.Cookies ?? new CookieContainer();
string response;
if (string.IsNullOrEmpty(state.OAuthToken) == true)
{
// get session
if (cookies.Count == 0)
{
cookies.Add(new Uri(COMMUNITY_BASE + "/"), new Cookie("mobileClientVersion", "3067969+%282.1.3%29"));
cookies.Add(new Uri(COMMUNITY_BASE + "/"), new Cookie("mobileClient", "android"));
cookies.Add(new Uri(COMMUNITY_BASE + "/"), new Cookie("steamid", ""));
cookies.Add(new Uri(COMMUNITY_BASE + "/"), new Cookie("steamLogin", ""));
cookies.Add(new Uri(COMMUNITY_BASE + "/"), new Cookie("Steam_Language", "english"));
cookies.Add(new Uri(COMMUNITY_BASE + "/"), new Cookie("dob", ""));
NameValueCollection headers = new NameValueCollection();
headers.Add("X-Requested-With", "com.valvesoftware.android.steam.community");
response = Request("https://steamcommunity.com/mobilelogin?oauth_client_id=DE45CD61&oauth_scope=read_profile%20write_profile%20read_client%20write_client", "GET", null, cookies, headers);
}
// Steam strips any non-ascii chars from username and password
state.Username = Regex.Replace(state.Username, @"[^\u0000-\u007F]", string.Empty);
state.Password = Regex.Replace(state.Password, @"[^\u0000-\u007F]", string.Empty);
// get the user's RSA key
data.Add("username", state.Username);
response = Request(COMMUNITY_BASE + "/mobilelogin/getrsakey", "POST", data, cookies);
var rsaresponse = JObject.Parse(response);
if (rsaresponse.SelectToken("success").Value<bool>() != true)
{
throw new InvalidEnrollResponseException("Cannot get steam information for user: " + state.Username);
}
// encrypt password with RSA key
RNGCryptoServiceProvider random = new RNGCryptoServiceProvider();
byte[] encryptedPassword;
using (var rsa = new RSACryptoServiceProvider())
{
var passwordBytes = Encoding.ASCII.GetBytes(state.Password);
var p = rsa.ExportParameters(false);
p.Exponent = Authenticator.StringToByteArray(rsaresponse.SelectToken("publickey_exp").Value<string>());
p.Modulus = Authenticator.StringToByteArray(rsaresponse.SelectToken("publickey_mod").Value<string>());
rsa.ImportParameters(p);
encryptedPassword = rsa.Encrypt(passwordBytes, false);
}
// login request
data = new NameValueCollection();
data.Add("password", Convert.ToBase64String(encryptedPassword));
data.Add("username", state.Username);
data.Add("twofactorcode", "");
data.Add("emailauth", (state.EmailAuthText != null ? state.EmailAuthText : string.Empty));
data.Add("loginfriendlyname", "#login_emailauth_friendlyname_mobile");
data.Add("captchagid", (state.CaptchaId != null ? state.CaptchaId : "-1"));
data.Add("captcha_text", (state.CaptchaText != null ? state.CaptchaText : "enter above characters"));
data.Add("emailsteamid", (state.EmailAuthText != null ? state.SteamId ?? string.Empty : string.Empty));
data.Add("rsatimestamp", rsaresponse.SelectToken("timestamp").Value<string>());
data.Add("remember_login", "false");
data.Add("oauth_client_id", "DE45CD61");
data.Add("oauth_scope", "read_profile write_profile read_client write_client");
data.Add("donotache", new DateTime().ToUniversalTime().Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds.ToString());
response = Request(COMMUNITY_BASE + "/mobilelogin/dologin/", "POST", data, cookies);
Dictionary<string, object> loginresponse = JsonConvert.DeserializeObject<Dictionary<string, object>>(response);
if (loginresponse.ContainsKey("emailsteamid") == true)
{
state.SteamId = loginresponse["emailsteamid"] as string;
}
// require captcha
if (loginresponse.ContainsKey("captcha_needed") == true && (bool)loginresponse["captcha_needed"] == true)
{
state.RequiresCaptcha = true;
state.CaptchaId = (string)loginresponse["captcha_gid"];
state.CaptchaUrl = COMMUNITY_BASE + "/public/captcha.php?gid=" + state.CaptchaId;
}
else
{
state.RequiresCaptcha = false;
state.CaptchaId = null;
state.CaptchaUrl = null;
state.CaptchaText = null;
}
// require email auth
if (loginresponse.ContainsKey("emailauth_needed") == true && (bool)loginresponse["emailauth_needed"] == true)
{
if (loginresponse.ContainsKey("emaildomain") == true)
{
var emaildomain = (string)loginresponse["emaildomain"];
if (string.IsNullOrEmpty(emaildomain) == false)
{
state.EmailDomain = emaildomain;
}
}
state.RequiresEmailAuth = true;
}
else
{
state.EmailDomain = null;
state.RequiresEmailAuth = false;
}
// require email auth
if (loginresponse.ContainsKey("requires_twofactor") == true && (bool)loginresponse["requires_twofactor"] == true)
{
state.Requires2FA = true;
}
else
{
state.Requires2FA = false;
}
// if we didn't login, return the result
if (loginresponse.ContainsKey("login_complete") == false || (bool)loginresponse["login_complete"] == false || loginresponse.ContainsKey("oauth") == false)
{
if (loginresponse.ContainsKey("oauth") == false)
{
state.Error = "Invalid response from Steam (No OAuth token)";
}
if (loginresponse.ContainsKey("message") == true)
{
state.Error = (string)loginresponse["message"];
}
return false;
}
// get the OAuth token - is stringified json
string oauth = (string)loginresponse["oauth"];
var oauthjson = JObject.Parse(oauth);
state.OAuthToken = oauthjson.SelectToken("oauth_token").Value<string>();
if (oauthjson.SelectToken("steamid") != null)
{
state.SteamId = oauthjson.SelectToken("steamid").Value<string>();
}
}
// login to webapi
data.Clear();
data.Add("access_token", state.OAuthToken);
response = Request(WEBAPI_BASE + "/ISteamWebUserPresenceOAuth/Logon/v0001", "POST", data);
var sessionid = cookies.GetCookies(new Uri(COMMUNITY_BASE + "/"))["sessionid"].Value;
if (state.RequiresActivation == false)
{
data.Clear();
data.Add("op", "has_phone");
data.Add("arg", "null");
data.Add("sessionid", sessionid);
response = Request(COMMUNITY_BASE + "/steamguard/phoneajax", "POST", data, cookies);
var jsonresponse = JObject.Parse(response);
bool hasPhone = jsonresponse.SelectToken("has_phone").Value<Boolean>();
if (hasPhone == false)
{
state.OAuthToken = null; // force new login
state.RequiresLogin = true;
state.Cookies = null;
state.Error = "Your Steam account must have a SMS-capable phone number attached. Go into Account Details of the Steam client or Steam website and click Add a Phone Number.";
return false;
}
//response = Request(COMMUNITY_BASE + "/steamguard/phone_checksms?bForTwoFactor=1&bRevoke2fOnCancel=", "GET", null, cookies);
// add a new authenticator
data.Clear();
string deviceId = BuildRandomId();
data.Add("access_token", state.OAuthToken);
data.Add("steamid", state.SteamId);
data.Add("authenticator_type", "1");
data.Add("device_identifier", deviceId);
data.Add("sms_phone_id", "1");
response = Request(WEBAPI_BASE + "/ITwoFactorService/AddAuthenticator/v0001", "POST", data);
var tfaresponse = JObject.Parse(response);
if (response.IndexOf("status") == -1 && tfaresponse.SelectToken("response.status").Value<int>() == 84)
{
// invalid response
state.OAuthToken = null; // force new login
state.RequiresLogin = true;
state.Cookies = null;
state.Error = "Unable to send SMS. Check your phone is registered on your Steam account.";
return false;
}
if (response.IndexOf("shared_secret") == -1)
{
// invalid response
state.OAuthToken = null; // force new login
state.RequiresLogin = true;
state.Cookies = null;
state.Error = "Invalid response from Steam: " + response;
return false;
}
// save data into this authenticator
var secret = tfaresponse.SelectToken("response.shared_secret").Value<string>();
this.SecretKey = Convert.FromBase64String(secret);
this.Serial = tfaresponse.SelectToken("response.serial_number").Value<string>();
this.DeviceId = deviceId;
state.RevocationCode = tfaresponse.SelectToken("response.revocation_code").Value<string>();
// add the steamid into the data
var steamdata = JObject.Parse(tfaresponse.SelectToken("response").ToString());
if (steamdata.SelectToken("steamid") == null)
{
steamdata.Add("steamid", state.SteamId);
}
if (steamdata.SelectToken("steamguard_scheme") == null)
{
steamdata.Add("steamguard_scheme", "2");
}
this.SteamData = steamdata.ToString(Newtonsoft.Json.Formatting.None);
// calculate server drift
long servertime = tfaresponse.SelectToken("response.server_time").Value<long>() * 1000;
ServerTimeDiff = servertime - CurrentTime;
LastServerTime = DateTime.Now.Ticks;
state.RequiresActivation = true;
return false;
}
// finalize adding the authenticator
data.Clear();
data.Add("access_token", state.OAuthToken);
data.Add("steamid", state.SteamId);
data.Add("activation_code", state.ActivationCode);
// try and authorise
var retries = 0;
while (state.RequiresActivation == true && retries < ENROLL_ACTIVATE_RETRIES)
{
data.Add("authenticator_code", this.CalculateCode(false));
data.Add("authenticator_time", this.ServerTime.ToString());
response = Request(WEBAPI_BASE + "/ITwoFactorService/FinalizeAddAuthenticator/v0001", "POST", data);
var finalizeresponse = JObject.Parse(response);
if (response.IndexOf("status") != -1 && finalizeresponse.SelectToken("response.status").Value<int>() == INVALID_ACTIVATION_CODE)
{
state.Error = "Invalid activation code";
return false;
}
// reset our time
if (response.IndexOf("server_time") != -1)
{
long servertime = finalizeresponse.SelectToken("response.server_time").Value<long>() * 1000;
ServerTimeDiff = servertime - CurrentTime;
LastServerTime = DateTime.Now.Ticks;
}
// check success
if (finalizeresponse.SelectToken("response.success").Value<bool>() == true)
{
if (response.IndexOf("want_more") != -1 && finalizeresponse.SelectToken("response.want_more").Value<bool>() == true)
{
ServerTimeDiff += ((long)this.Period * 1000L);
retries++;
continue;
}
state.RequiresActivation = false;
break;
}
ServerTimeDiff += ((long)this.Period * 1000L);
retries++;
}
if (state.RequiresActivation == true)
{
state.Error = "There was a problem activating. There might be an issue with the Steam servers. Please try again later.";
return false;
}
// mark and successful and return key
state.Success = true;
state.SecretKey = Authenticator.ByteArrayToString(this.SecretKey);
// send confirmation email
data.Clear();
data.Add("access_token", state.OAuthToken);
data.Add("steamid", state.SteamId);
data.Add("email_type", "2");
response = Request(WEBAPI_BASE + "/ITwoFactorService/SendEmail/v0001", "POST", data);
return true;
}
catch (UnauthorisedRequestException ex)
{
throw new InvalidEnrollResponseException("You are not allowed to add an authenticator. Have you enabled 'community-generated content' in Family View?", ex);
}
catch (InvalidRequestException ex)
{
throw new InvalidEnrollResponseException("Error enrolling new authenticator", ex);
}
}
/// <summary>
/// Synchronise this authenticator's time with Steam.
/// </summary>
public override void Sync()
{
// check if data is protected
if (this.SecretKey == null && this.EncryptedData != null)
{
throw new EncryptedSecretDataException();
}
// don't retry for 5 minutes
if (_lastSyncError >= DateTime.Now.AddMinutes(0 - SYNC_ERROR_MINUTES))
{
return;
}
try
{
var response = Request(SYNC_URL, "POST", null, null, null, SYNC_TIMEOUT);
var json = JObject.Parse(response);
// get servertime in ms
long servertime = json.SelectToken("response.server_time").Value<long>() * 1000;
// get the difference between the server time and our current time
ServerTimeDiff = servertime - CurrentTime;
LastServerTime = DateTime.Now.Ticks;
// clear any sync error
_lastSyncError = DateTime.MinValue;
}
catch (Exception ex)
{
// don't retry for a while after error
_lastSyncError = DateTime.Now;
throw ex;
// set to zero to force reset
//ServerTimeDiff = 0;
}
}
/// <summary>
/// Calculate the current code for the authenticator.
/// </summary>
/// <param name="resyncTime">flag to resync time</param>
/// <returns>authenticator code</returns>
protected override string CalculateCode(bool resyncTime = false, long interval = -1)
{
// sync time if required
if (resyncTime == true || ServerTimeDiff == 0)
{
if (interval > 0)
{
ServerTimeDiff = (interval * ((long)this.Period * 1000L)) - CurrentTime;
}
else
{
Sync();
}
}
HMac hmac = new HMac(new Sha1Digest());
hmac.Init(new KeyParameter(SecretKey));
byte[] codeIntervalArray = BitConverter.GetBytes(CodeInterval);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(codeIntervalArray);
}
hmac.BlockUpdate(codeIntervalArray, 0, codeIntervalArray.Length);
byte[] mac = new byte[hmac.GetMacSize()];
hmac.DoFinal(mac, 0);
// the last 4 bits of the mac say where the code starts (e.g. if last 4 bit are 1100, we start at byte 12)
int start = mac[19] & 0x0f;
// extract those 4 bytes
byte[] bytes = new byte[4];
Array.Copy(mac, start, bytes, 0, 4);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(bytes);
}
uint fullcode = BitConverter.ToUInt32(bytes, 0) & 0x7fffffff;
// build the alphanumeric code
StringBuilder code = new StringBuilder();
for (var i=0; i<CODE_DIGITS; i++)
{
code.Append(STEAMCHARS[fullcode % STEAMCHARS.Length]);
fullcode /= (uint)STEAMCHARS.Length;
}
return code.ToString();
}
/// <summary>
/// Create a random Device ID string for Enrolling
/// </summary>
/// <returns>Random string</returns>
private static string BuildRandomId()
{
return "android:" + Guid.NewGuid().ToString();
}
/// <summary>
/// Log an exception from a Request
/// </summary>
/// <param name="method">Get or POST</param>
/// <param name="url">Request URL</param>
/// <param name="cookies">cookie container</param>
/// <param name="request">Request data</param>
/// <param name="ex">Thrown exception</param>
private static void LogException(string method, string url, CookieContainer cookies, NameValueCollection request, Exception ex)
{
StringBuilder data = new StringBuilder();
if (cookies != null)
{
foreach (Cookie cookie in cookies.GetCookies(new Uri(url)))
{
if (data.Length == 0)
{
data.Append("Cookies:");
}
else
{
data.Append("&");
}
data.Append(cookie.Name + "=" + cookie.Value);
}
data.Append(" ");
}
if (request != null)
{
foreach (var key in request.AllKeys)
{
if (data.Length == 0)
{
data.Append("Req:");
}
else
{
data.Append("&");
}
data.Append(key + "=" + request[key]);
}
data.Append(" ");
}
}
/// <summary>
/// Log a normal response
/// </summary>
/// <param name="method">Get or POST</param>
/// <param name="url">Request URL</param>
/// <param name="cookies">cookie container</param>
/// <param name="request">Request data</param>
/// <param name="response">response body</param>
private static void LogRequest(string method, string url, CookieContainer cookies, NameValueCollection request, string response)
{
StringBuilder data = new StringBuilder();
if (cookies != null)
{
foreach (Cookie cookie in cookies.GetCookies(new Uri(url)))
{
if (data.Length == 0)
{
data.Append("Cookies:");
}
else
{
data.Append("&");
}
data.Append(cookie.Name + "=" + cookie.Value);
}
data.Append(" ");
}
if (request != null)
{
foreach (var key in request.AllKeys)
{
if (data.Length == 0)
{
data.Append("Req:");
}
else
{
data.Append("&");
}
data.Append(key + "=" + request[key]);
}
data.Append(" ");
}
}
/// <summary>
/// Our custom exception for the internal Http Request
/// </summary>
class InvalidRequestException : ApplicationException
{
public InvalidRequestException(string msg = null, Exception ex = null) : base(msg, ex) { }
}
/// <summary>
/// 403 forbidden responses
/// </summary>
class UnauthorisedRequestException : InvalidRequestException
{
public UnauthorisedRequestException(Exception ex = null) : base("Unauthorised", ex) { }
}
}
}
File diff suppressed because it is too large Load Diff
-33
View File
@@ -1,33 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using SteamTools.Model;
using Newtonsoft.Json;
namespace SteamTools.Helper
{
public static class ConfigHelper
{
private const string ConfigFileName = "SteamToolData.dat";
private static readonly string ConfigPath =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), ConfigFileName);
public static SteamToolConfig SteamToolConfig { get; set; }
public static void SaveConfig()
{
var jsonData = JsonConvert.SerializeObject(SteamToolConfig);
File.WriteAllText(ConfigPath, jsonData, Encoding.UTF8);
}
public static SteamToolConfig ReadConfig()
{
SteamToolConfig = JsonConvert.DeserializeObject<SteamToolConfig>(File.ReadAllText(ConfigPath, Encoding.UTF8));
return SteamToolConfig;
}
}
}
@@ -1,75 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Win32;
namespace SteamTools.Helper
{
public static class RegistryKeyHelper
{
/// <summary>
/// 创建注册表项
/// </summary>
/// <param name="registryKey"></param>
/// <param name="path"></param>
/// <returns></returns>
public static RegistryKey CreateRegistryKey(RegistryKey registryKey, string path)
{
return registryKey.CreateSubKey(path);
}
/// <summary>
/// 删除注册表项
/// </summary>
/// <param name="registryKey"></param>
/// <param name="path"></param>
/// <returns></returns>
public static void DeleteRegistryKey(RegistryKey registryKey, string path)
{
registryKey.DeleteSubKey(path, true); //该方法无返回值,直接调用即可
registryKey.Close();
}
/// <summary>
/// 读取注册表值
/// </summary>
/// <param name="registryKey"></param>
/// <param name="path"></param>
/// <param name="key"></param>
/// <returns></returns>
public static string ReadRegistryKey(RegistryKey registryKey, string path, string key)
{
var myreg = registryKey.OpenSubKey(path);
if (myreg != null)
{
var info = myreg.GetValue(key).ToString();
myreg.Close();
return info;
}
return string.Empty;
}
/// <summary>
/// 新增或修改注册表值
/// </summary>
/// <param name="registryKey"></param>
/// <param name="path"></param>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="registryValueKind"></param>
/// <returns></returns>
public static void AddOrUpdateRegistryKey(RegistryKey registryKey, string path, string key, string value, RegistryValueKind registryValueKind)
{
RegistryKey myreg = registryKey.OpenSubKey(path, true); //该项必须已存在
if (myreg != null)
{
myreg.SetValue(key, value, registryValueKind);
myreg.Close();
}
}
}
}
-107
View File
@@ -1,107 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Gameloop.Vdf.Linq;
using Microsoft.Win32;
using SteamTool.Common.Helper;
using SteamTools.Model;
namespace SteamTools.Helper
{
public class SteamHelper
{
public static readonly SteamHelper Instance = new SteamHelper();
public string SteamPath { get; set; }
public string SteamExePath { get; set; }
private const string SteamRegistryPath = @"SOFTWARE\Valve\Steam";
public SteamHelper()
{
var steamExePath = RegistryKeyHelper.ReadRegistryKey(Registry.CurrentUser, SteamRegistryPath, "SteamExe");
var steamPath = RegistryKeyHelper.ReadRegistryKey(Registry.CurrentUser, SteamRegistryPath, "SteamPath");
if (File.Exists(steamExePath))
{
SteamExePath = steamExePath;
}
if (Directory.Exists(steamPath))
{
SteamPath = steamPath;
}
}
public void KillSteamProcess()
{
Process[] processes = Process.GetProcesses();
foreach (Process process in processes)
{
if (process.ProcessName == "Steam" || process.ProcessName == "SteamService" || process.ProcessName == "steamwebhelper")
{
process.Kill();
}
}
}
public void StartSteam(string param = "")
{
if (!string.IsNullOrEmpty(SteamExePath))
{
Process.Start(SteamExePath, param);
}
}
/// <summary>
/// 获取最后一次自动登陆steam用户名称
/// </summary>
/// <returns></returns>
public string GetLastLoginUserName()
{
return RegistryKeyHelper.ReadRegistryKey(Registry.CurrentUser, SteamRegistryPath, "AutoLoginUser");
}
/// <summary>
/// 获取所有记住登陆steam用户信息
/// </summary>
/// <returns></returns>
public List<SteamUser> GetAllUser()
{
var users = new List<SteamUser>();
if (SteamPath != null)
{
var v = VdfHelper.GetVdfModelByPath(SteamPath + "/config/loginusers.vdf");
foreach (var item in v.Value)
{
var i = item.Value;
var user = new SteamUser
{
AccountName = i.AccountName.ToString(),
PersonaName = i.PersonaName.ToString(),
RememberPassword = Convert.ToBoolean(Convert.ToInt64(i.RememberPassword.ToString())),
MostRecent = Convert.ToBoolean(Convert.ToInt64(i.MostRecent.ToString())),
Timestamp = Convert.ToInt64(i.Timestamp.ToString())
};
user.LastLoginTime= new DateTime(1970, 1, 1, 8, 0, 0).AddSeconds(user.Timestamp);
users.Add(user);
}
}
return users;
}
/// <summary>
/// 设置下次登陆steam用户
/// </summary>
public void SetCurrentUser(string username)
{
RegistryKeyHelper.AddOrUpdateRegistryKey(Registry.CurrentUser, SteamRegistryPath, "AutoLoginUser", username, RegistryValueKind.String);
}
}
}
-35
View File
@@ -1,35 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Gameloop.Vdf;
using Gameloop.Vdf.Linq;
namespace SteamTool.Common.Helper
{
public static class VdfHelper
{
/// <summary>
/// 获取VDF类型内容
/// </summary>
/// <param name="path">vdf文件内容</param>
/// <returns></returns>
public static dynamic GetVdfModel(string text)
{
return VdfConvert.Deserialize(text);
}
/// <summary>
/// 根据路径获取VDF类型内容
/// </summary>
/// <param name="path">vdf文件路径</param>
/// <returns></returns>
public static dynamic GetVdfModelByPath(string path)
{
string text = File.ReadAllText(path,Encoding.UTF8);
return GetVdfModel(text); ;
}
}
}
-21
View File
@@ -1,21 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SteamTools.Model
{
public class SteamToolConfig
{
/// <summary>
/// 启动参数
/// </summary>
public string SteamRunParam { get; set; }
/// <summary>
/// 保存用户
/// </summary>
public List<SteamUser> SteamUsers { get; set; }
}
}
-65
View File
@@ -1,65 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SteamTools.Model
{
public class SteamUser
{
public string SteamId3 { get; set; }
public int SteamId3_Int { get; }
public string SteamId32 { get; set; }
public int SteamId32_Int { get; }
public long SteamId64 { get; set; }
/// <summary>
/// 个人资料链接
/// </summary>
public string ProfileUrl { get; set; }
/// <summary>
/// 昵称
/// </summary>
public string PersonaName { get; set; }
/// <summary>
/// 用户名
/// </summary>
public string AccountName { get; set; }
/// <summary>
/// 是否记住密码
/// </summary>
public bool RememberPassword { get; set; }
/// <summary>
/// 密码
/// </summary>
public string PassWord { get; set; }
/// <summary>
/// 最后登录时间戳
/// </summary>
public long Timestamp { get; set; }
/// <summary>
/// 最后登录时间
/// </summary>
public DateTime LastLoginTime { get; set; }
/// <summary>
/// 最近登录
/// </summary>
public bool MostRecent { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
}
}
@@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("SteamTool.Common")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SteamTool.Common")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("75e148c7-5f32-4f01-9444-cedefa28748a")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -1,14 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SteamTool.Common.Service
{
public class SteamToolsService
{
}
}
-74
View File
@@ -1,74 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{75E148C7-5F32-4F01-9444-CEDEFA28748A}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SteamTool.Common</RootNamespace>
<AssemblyName>SteamTool.Common</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == '发布|AnyCPU'">
<OutputPath>bin\发布\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Gameloop.Vdf, Version=0.6.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Gameloop.Vdf.0.6.1\lib\net45\Gameloop.Vdf.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Helper\ConfigHelper.cs" />
<Compile Include="Helper\RegistryKeyHelper.cs" />
<Compile Include="Helper\SteamHelper.cs" />
<Compile Include="Helper\VdfHelper.cs" />
<Compile Include="Model\SteamToolConfig.cs" />
<Compile Include="Model\SteamUser.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Service\SteamToolsService.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
-5
View File
@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Gameloop.Vdf" version="0.6.1" targetFramework="net46" />
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net46" />
</packages>
-26
View File
@@ -1,26 +0,0 @@
using SteamTool.Model;
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace SteamTool.Proxy
{
public static class CertificateEx
{
public static string GetPublicPemCertificateString(this X509Certificate2 @this)
{
StringBuilder builder = new StringBuilder();
builder.AppendLine(Const.HOST_TAG);
builder.AppendLine("-----BEGIN CERTIFICATE-----");
builder.AppendLine(
Convert.ToBase64String(@this.RawData, Base64FormattingOptions.InsertLineBreaks));
builder.AppendLine("-----END CERTIFICATE-----");
builder.AppendLine(Const.HOST_TAG);
return builder.ToString();
}
}
}
+105 -240
View File
@@ -7,382 +7,189 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UI", "UI", "{45E5B6B2-0A6D-
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{350F425C-AF5A-4ED2-BDDC-B905A4E63A14}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTool.Proxy", "SteamTool.Proxy\SteamTool.Proxy.csproj", "{A70C148D-042C-48DA-9963-0B777FC60215}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTool.Proxy", "source\SteamTool.Proxy\SteamTool.Proxy.csproj", "{A70C148D-042C-48DA-9963-0B777FC60215}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Composition", "Composition", "{F62E508E-B374-4149-B9AC-0A8090AA6CD1}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Reference", "Reference", "{F62E508E-B374-4149-B9AC-0A8090AA6CD1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTool.Steam.Service", "SteamTool.Steam.Service\SteamTool.Steam.Service.csproj", "{2A155A7B-3DFD-4F16-929D-9693D2411B83}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTool.Steam.Service", "source\SteamTool.Steam.Service\SteamTool.Steam.Service.csproj", "{2A155A7B-3DFD-4F16-929D-9693D2411B83}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTool.Core", "SteamTool.Core\SteamTool.Core.csproj", "{23E26040-19A5-4623-8863-B9ED539403B0}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTool.Core", "source\SteamTool.Core\SteamTool.Core.csproj", "{23E26040-19A5-4623-8863-B9ED539403B0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTools", "SteamTools\SteamTools.csproj", "{0663899A-2EC5-4929-868C-9D9620FEA4FE}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTools", "source\SteamTools\SteamTools.csproj", "{0663899A-2EC5-4929-868C-9D9620FEA4FE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTool.Steam4NET.Test", "SteamTool.Steam4NET.Test\SteamTool.Steam4NET.Test.csproj", "{790D22D4-94B0-4575-8E2D-C451EC520407}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTool.Steam4NET.Test", "source\SteamTool.Steam4NET.Test\SteamTool.Steam4NET.Test.csproj", "{790D22D4-94B0-4575-8E2D-C451EC520407}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTool.Steam4NET", "SteamTool.Steam4NET\SteamTool.Steam4NET.csproj", "{D4157059-D31A-4A21-AF4C-2D458F768041}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTool.Steam4NET", "source\SteamTool.Steam4NET\SteamTool.Steam4NET.csproj", "{D4157059-D31A-4A21-AF4C-2D458F768041}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{D245A82C-66B2-4CD5-881C-3ED4332FC91D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTool.Steamworks.Test", "SteamTool.Steamworks.Test\SteamTool.Steamworks.Test.csproj", "{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTool.Steamworks.Test", "source\SteamTool.Steamworks.Test\SteamTool.Steamworks.Test.csproj", "{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lib", "lib", "{868B3B33-14B3-49AF-AE01-28D85FD98C1F}"
ProjectSection(SolutionItems) = preProject
Lib\MetroRadiance.Chrome.dll = Lib\MetroRadiance.Chrome.dll
Lib\MetroRadiance.Core.dll = Lib\MetroRadiance.Core.dll
Lib\MetroRadiance.dll = Lib\MetroRadiance.dll
C:\Users\Dark\Desktop\Titanium-Web-Proxy-master\Titanium-Web-Proxy-master\src\Titanium.Web.Proxy\obj\Debug\netstandard2.0\Titanium.Web.Proxy.dll = C:\Users\Dark\Desktop\Titanium-Web-Proxy-master\Titanium-Web-Proxy-master\src\Titanium.Web.Proxy\obj\Debug\netstandard2.0\Titanium.Web.Proxy.dll
EndProjectSection
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTool.Proxy.Test", "source\SteamTool.Proxy.Test\SteamTool.Proxy.Test.csproj", "{4C441E34-FA65-4425-8242-4EB767BA9B95}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTool.Proxy.Test", "SteamTool.Proxy.Test\SteamTool.Proxy.Test.csproj", "{4C441E34-FA65-4425-8242-4EB767BA9B95}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTool.Model", "source\SteamTool.Model\SteamTool.Model.csproj", "{BDBACE3A-0138-4930-95F6-82562EA03F7A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTool.Model", "SteamTool.Model\SteamTool.Model.csproj", "{BDBACE3A-0138-4930-95F6-82562EA03F7A}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTool.SteamAPI", "source\SteamTool.SteamAPI\SteamTool.SteamAPI.csproj", "{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTool.SteamAPI", "SteamTool.SteamAPI\SteamTool.SteamAPI.csproj", "{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTool.Authenticator", "source\SteamTool.Authenticator\SteamTool.Authenticator.csproj", "{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamTool.Authenticator", "SteamTool.Authenticator\SteamTool.Authenticator.csproj", "{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}"
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "SteamTools.UWP", "source\SteamTools.UWP\SteamTools.UWP.wapproj", "{2E755C75-E472-44E0-8AC4-F40209A60172}"
EndProject
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "SteamTools.UWP", "SteamTools.UWP\SteamTools.UWP.wapproj", "{2E755C75-E472-44E0-8AC4-F40209A60172}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Titanium.Web.Proxy", "references\Titanium-Web-Proxy\src\Titanium.Web.Proxy\Titanium.Web.Proxy.csproj", "{BBB75CAC-2BA3-473D-935D-0E59406F5E61}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MetroRadiance", "MetroRadiance", "{2B74A2B2-148D-4518-BF74-3408095E920B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MetroTrilithon.Desktop", "references\MetroRadiance\source\MetroTrilithon.Desktop\MetroTrilithon.Desktop.csproj", "{4E2EB2E0-E5FE-4FEB-A3E5-5F2F05CD1A67}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MetroRadiance.Core", "references\MetroRadiance\source\MetroRadiance.Core\MetroRadiance.Core.csproj", "{AF006EF5-D4BC-49C6-8E0E-DC2B882BE767}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MetroRadiance.Chrome", "references\MetroRadiance\source\MetroRadiance.Chrome\MetroRadiance.Chrome.csproj", "{DE0B3A58-C301-4671-8B32-4F195C9457A7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MetroRadiance", "references\MetroRadiance\source\MetroRadiance\MetroRadiance.csproj", "{2E226B1E-80F6-448D-B02B-0A029C5BC09E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MetroTrilithon", "references\MetroRadiance\source\MetroTrilithon\MetroTrilithon.csproj", "{2EE1744F-2D3C-4032-9A9E-C57FA3B512B3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|ARM = Debug|ARM
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|ARM = Release|ARM
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release|x86 = Release|x86
发布|Any CPU = 发布|Any CPU
发布|ARM = 发布|ARM
发布|ARM64 = 发布|ARM64
发布|x64 = 发布|x64
发布|x86 = 发布|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A70C148D-042C-48DA-9963-0B777FC60215}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.Debug|ARM.ActiveCfg = Debug|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.Debug|ARM.Build.0 = Debug|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.Debug|ARM64.Build.0 = Debug|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.Debug|x64.ActiveCfg = Debug|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.Debug|x64.Build.0 = Debug|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.Debug|x86.ActiveCfg = Debug|x86
{A70C148D-042C-48DA-9963-0B777FC60215}.Debug|x86.Build.0 = Debug|x86
{A70C148D-042C-48DA-9963-0B777FC60215}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.Release|Any CPU.Build.0 = Release|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.Release|ARM.ActiveCfg = Release|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.Release|ARM.Build.0 = Release|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.Release|ARM64.ActiveCfg = Release|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.Release|ARM64.Build.0 = Release|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.Release|x64.ActiveCfg = Release|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.Release|x64.Build.0 = Release|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.Release|x86.ActiveCfg = Release|x86
{A70C148D-042C-48DA-9963-0B777FC60215}.Release|x86.Build.0 = Release|x86
{A70C148D-042C-48DA-9963-0B777FC60215}.发布|Any CPU.ActiveCfg = 发布|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.发布|Any CPU.Build.0 = 发布|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.发布|ARM.ActiveCfg = 发布|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.发布|ARM.Build.0 = 发布|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.发布|ARM64.ActiveCfg = 发布|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.发布|ARM64.Build.0 = 发布|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.发布|x64.ActiveCfg = 发布|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.发布|x64.Build.0 = 发布|Any CPU
{A70C148D-042C-48DA-9963-0B777FC60215}.发布|x86.ActiveCfg = 发布|x86
{A70C148D-042C-48DA-9963-0B777FC60215}.发布|x86.Build.0 = 发布|x86
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.Debug|ARM.ActiveCfg = Debug|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.Debug|ARM.Build.0 = Debug|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.Debug|ARM64.Build.0 = Debug|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.Debug|x64.ActiveCfg = Debug|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.Debug|x64.Build.0 = Debug|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.Debug|x86.ActiveCfg = Debug|x86
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.Debug|x86.Build.0 = Debug|x86
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.Release|Any CPU.Build.0 = Release|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.Release|ARM.ActiveCfg = Release|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.Release|ARM.Build.0 = Release|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.Release|ARM64.ActiveCfg = Release|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.Release|ARM64.Build.0 = Release|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.Release|x64.ActiveCfg = Release|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.Release|x64.Build.0 = Release|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.Release|x86.ActiveCfg = Release|x86
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.Release|x86.Build.0 = Release|x86
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.发布|Any CPU.ActiveCfg = 发布|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.发布|Any CPU.Build.0 = 发布|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.发布|ARM.ActiveCfg = 发布|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.发布|ARM.Build.0 = 发布|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.发布|ARM64.ActiveCfg = 发布|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.发布|ARM64.Build.0 = 发布|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.发布|x64.ActiveCfg = 发布|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.发布|x64.Build.0 = 发布|Any CPU
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.发布|x86.ActiveCfg = 发布|x86
{2A155A7B-3DFD-4F16-929D-9693D2411B83}.发布|x86.Build.0 = 发布|x86
{23E26040-19A5-4623-8863-B9ED539403B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.Debug|ARM.ActiveCfg = Debug|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.Debug|ARM.Build.0 = Debug|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.Debug|ARM64.Build.0 = Debug|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.Debug|x64.ActiveCfg = Debug|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.Debug|x64.Build.0 = Debug|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.Debug|x86.ActiveCfg = Debug|x86
{23E26040-19A5-4623-8863-B9ED539403B0}.Debug|x86.Build.0 = Debug|x86
{23E26040-19A5-4623-8863-B9ED539403B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.Release|Any CPU.Build.0 = Release|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.Release|ARM.ActiveCfg = Release|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.Release|ARM.Build.0 = Release|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.Release|ARM64.ActiveCfg = Release|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.Release|ARM64.Build.0 = Release|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.Release|x64.ActiveCfg = Release|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.Release|x64.Build.0 = Release|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.Release|x86.ActiveCfg = Release|x86
{23E26040-19A5-4623-8863-B9ED539403B0}.Release|x86.Build.0 = Release|x86
{23E26040-19A5-4623-8863-B9ED539403B0}.发布|Any CPU.ActiveCfg = Release|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.发布|Any CPU.Build.0 = Release|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.发布|ARM.ActiveCfg = Release|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.发布|ARM.Build.0 = Release|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.发布|ARM64.ActiveCfg = Release|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.发布|ARM64.Build.0 = Release|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.发布|x64.ActiveCfg = Release|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.发布|x64.Build.0 = Release|Any CPU
{23E26040-19A5-4623-8863-B9ED539403B0}.发布|x86.ActiveCfg = Debug|x86
{23E26040-19A5-4623-8863-B9ED539403B0}.发布|x86.Build.0 = Debug|x86
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.Debug|ARM.ActiveCfg = Debug|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.Debug|ARM.Build.0 = Debug|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.Debug|ARM64.Build.0 = Debug|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.Debug|x64.ActiveCfg = Debug|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.Debug|x64.Build.0 = Debug|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.Debug|x86.ActiveCfg = Debug|x86
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.Debug|x86.Build.0 = Debug|x86
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.Release|Any CPU.Build.0 = Release|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.Release|ARM.ActiveCfg = Release|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.Release|ARM.Build.0 = Release|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.Release|ARM64.ActiveCfg = Release|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.Release|ARM64.Build.0 = Release|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.Release|x64.ActiveCfg = Release|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.Release|x64.Build.0 = Release|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.Release|x86.ActiveCfg = Release|x86
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.Release|x86.Build.0 = Release|x86
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.发布|Any CPU.ActiveCfg = Release|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.发布|Any CPU.Build.0 = Release|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.发布|ARM.ActiveCfg = Release|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.发布|ARM.Build.0 = Release|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.发布|ARM64.ActiveCfg = Release|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.发布|ARM64.Build.0 = Release|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.发布|x64.ActiveCfg = Release|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.发布|x64.Build.0 = Release|Any CPU
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.发布|x86.ActiveCfg = Debug|x86
{0663899A-2EC5-4929-868C-9D9620FEA4FE}.发布|x86.Build.0 = Debug|x86
{790D22D4-94B0-4575-8E2D-C451EC520407}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{790D22D4-94B0-4575-8E2D-C451EC520407}.Debug|Any CPU.Build.0 = Debug|Any CPU
{790D22D4-94B0-4575-8E2D-C451EC520407}.Debug|ARM.ActiveCfg = Debug|Any CPU
{790D22D4-94B0-4575-8E2D-C451EC520407}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{790D22D4-94B0-4575-8E2D-C451EC520407}.Debug|x64.ActiveCfg = Debug|Any CPU
{790D22D4-94B0-4575-8E2D-C451EC520407}.Debug|x86.ActiveCfg = Debug|x86
{790D22D4-94B0-4575-8E2D-C451EC520407}.Debug|x86.Build.0 = Debug|x86
{790D22D4-94B0-4575-8E2D-C451EC520407}.Release|Any CPU.ActiveCfg = Release|Any CPU
{790D22D4-94B0-4575-8E2D-C451EC520407}.Release|Any CPU.Build.0 = Release|Any CPU
{790D22D4-94B0-4575-8E2D-C451EC520407}.Release|ARM.ActiveCfg = Release|Any CPU
{790D22D4-94B0-4575-8E2D-C451EC520407}.Release|ARM64.ActiveCfg = Release|Any CPU
{790D22D4-94B0-4575-8E2D-C451EC520407}.Release|x64.ActiveCfg = Release|Any CPU
{790D22D4-94B0-4575-8E2D-C451EC520407}.Release|x86.ActiveCfg = Release|x86
{790D22D4-94B0-4575-8E2D-C451EC520407}.Release|x86.Build.0 = Release|x86
{790D22D4-94B0-4575-8E2D-C451EC520407}.发布|Any CPU.ActiveCfg = Release|Any CPU
{790D22D4-94B0-4575-8E2D-C451EC520407}.发布|Any CPU.Build.0 = Release|Any CPU
{790D22D4-94B0-4575-8E2D-C451EC520407}.发布|ARM.ActiveCfg = Release|Any CPU
{790D22D4-94B0-4575-8E2D-C451EC520407}.发布|ARM64.ActiveCfg = Release|Any CPU
{790D22D4-94B0-4575-8E2D-C451EC520407}.发布|x64.ActiveCfg = Release|Any CPU
{790D22D4-94B0-4575-8E2D-C451EC520407}.发布|x86.ActiveCfg = Debug|x86
{790D22D4-94B0-4575-8E2D-C451EC520407}.发布|x86.Build.0 = Debug|x86
{D4157059-D31A-4A21-AF4C-2D458F768041}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.Debug|ARM.ActiveCfg = Debug|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.Debug|ARM.Build.0 = Debug|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.Debug|ARM64.Build.0 = Debug|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.Debug|x64.ActiveCfg = Debug|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.Debug|x64.Build.0 = Debug|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.Debug|x86.ActiveCfg = Debug|x86
{D4157059-D31A-4A21-AF4C-2D458F768041}.Debug|x86.Build.0 = Debug|x86
{D4157059-D31A-4A21-AF4C-2D458F768041}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.Release|Any CPU.Build.0 = Release|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.Release|ARM.ActiveCfg = Release|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.Release|ARM.Build.0 = Release|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.Release|ARM64.ActiveCfg = Release|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.Release|ARM64.Build.0 = Release|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.Release|x64.ActiveCfg = Release|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.Release|x64.Build.0 = Release|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.Release|x86.ActiveCfg = Release|x86
{D4157059-D31A-4A21-AF4C-2D458F768041}.Release|x86.Build.0 = Release|x86
{D4157059-D31A-4A21-AF4C-2D458F768041}.发布|Any CPU.ActiveCfg = Release|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.发布|Any CPU.Build.0 = Release|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.发布|ARM.ActiveCfg = Release|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.发布|ARM.Build.0 = Release|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.发布|ARM64.ActiveCfg = Release|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.发布|ARM64.Build.0 = Release|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.发布|x64.ActiveCfg = Release|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.发布|x64.Build.0 = Release|Any CPU
{D4157059-D31A-4A21-AF4C-2D458F768041}.发布|x86.ActiveCfg = Debug|x86
{D4157059-D31A-4A21-AF4C-2D458F768041}.发布|x86.Build.0 = Debug|x86
{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}.Debug|ARM.ActiveCfg = Debug|Any CPU
{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}.Debug|x64.ActiveCfg = Debug|Any CPU
{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}.Debug|x86.ActiveCfg = Debug|x86
{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}.Debug|x86.Build.0 = Debug|x86
{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}.Release|Any CPU.Build.0 = Release|Any CPU
{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}.Release|ARM.ActiveCfg = Release|Any CPU
{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}.Release|ARM64.ActiveCfg = Release|Any CPU
{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}.Release|x64.ActiveCfg = Release|Any CPU
{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}.Release|x86.ActiveCfg = Release|x86
{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}.Release|x86.Build.0 = Release|x86
{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}.发布|Any CPU.ActiveCfg = Release|Any CPU
{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}.发布|Any CPU.Build.0 = Release|Any CPU
{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}.发布|ARM.ActiveCfg = Release|Any CPU
{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}.发布|ARM64.ActiveCfg = Release|Any CPU
{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}.发布|x64.ActiveCfg = Release|Any CPU
{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}.发布|x86.ActiveCfg = Debug|x86
{C03E4CF5-D68F-4CAC-B002-3A6799ED9E15}.发布|x86.Build.0 = Debug|x86
{4C441E34-FA65-4425-8242-4EB767BA9B95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.Debug|ARM.ActiveCfg = Debug|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.Debug|ARM.Build.0 = Debug|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.Debug|ARM64.Build.0 = Debug|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.Debug|x64.ActiveCfg = Debug|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.Debug|x64.Build.0 = Debug|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.Debug|x86.ActiveCfg = Debug|x86
{4C441E34-FA65-4425-8242-4EB767BA9B95}.Debug|x86.Build.0 = Debug|x86
{4C441E34-FA65-4425-8242-4EB767BA9B95}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.Release|Any CPU.Build.0 = Release|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.Release|ARM.ActiveCfg = Release|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.Release|ARM.Build.0 = Release|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.Release|ARM64.ActiveCfg = Release|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.Release|ARM64.Build.0 = Release|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.Release|x64.ActiveCfg = Release|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.Release|x64.Build.0 = Release|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.Release|x86.ActiveCfg = Release|x86
{4C441E34-FA65-4425-8242-4EB767BA9B95}.Release|x86.Build.0 = Release|x86
{4C441E34-FA65-4425-8242-4EB767BA9B95}.发布|Any CPU.ActiveCfg = Release|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.发布|Any CPU.Build.0 = Release|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.发布|ARM.ActiveCfg = Release|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.发布|ARM.Build.0 = Release|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.发布|ARM64.ActiveCfg = Release|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.发布|ARM64.Build.0 = Release|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.发布|x64.ActiveCfg = Release|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.发布|x64.Build.0 = Release|Any CPU
{4C441E34-FA65-4425-8242-4EB767BA9B95}.发布|x86.ActiveCfg = Debug|x86
{4C441E34-FA65-4425-8242-4EB767BA9B95}.发布|x86.Build.0 = Debug|x86
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.Debug|ARM.ActiveCfg = Debug|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.Debug|ARM.Build.0 = Debug|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.Debug|ARM64.Build.0 = Debug|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.Debug|x64.ActiveCfg = Debug|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.Debug|x64.Build.0 = Debug|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.Debug|x86.ActiveCfg = Debug|x86
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.Debug|x86.Build.0 = Debug|x86
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.Release|Any CPU.Build.0 = Release|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.Release|ARM.ActiveCfg = Release|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.Release|ARM.Build.0 = Release|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.Release|ARM64.ActiveCfg = Release|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.Release|ARM64.Build.0 = Release|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.Release|x64.ActiveCfg = Release|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.Release|x64.Build.0 = Release|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.Release|x86.ActiveCfg = Release|x86
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.Release|x86.Build.0 = Release|x86
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.发布|Any CPU.ActiveCfg = Release|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.发布|Any CPU.Build.0 = Release|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.发布|ARM.ActiveCfg = Release|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.发布|ARM.Build.0 = Release|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.发布|ARM64.ActiveCfg = Release|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.发布|ARM64.Build.0 = Release|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.发布|x64.ActiveCfg = Release|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.发布|x64.Build.0 = Release|Any CPU
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.发布|x86.ActiveCfg = Debug|x86
{BDBACE3A-0138-4930-95F6-82562EA03F7A}.发布|x86.Build.0 = Debug|x86
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.Debug|ARM.ActiveCfg = Debug|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.Debug|ARM.Build.0 = Debug|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.Debug|ARM64.Build.0 = Debug|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.Debug|x64.ActiveCfg = Debug|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.Debug|x64.Build.0 = Debug|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.Debug|x86.ActiveCfg = Debug|x86
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.Debug|x86.Build.0 = Debug|x86
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.Release|Any CPU.Build.0 = Release|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.Release|ARM.ActiveCfg = Release|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.Release|ARM.Build.0 = Release|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.Release|ARM64.ActiveCfg = Release|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.Release|ARM64.Build.0 = Release|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.Release|x64.ActiveCfg = Release|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.Release|x64.Build.0 = Release|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.Release|x86.ActiveCfg = Release|x86
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.Release|x86.Build.0 = Release|x86
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.发布|Any CPU.ActiveCfg = Debug|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.发布|Any CPU.Build.0 = Debug|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.发布|ARM.ActiveCfg = Release|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.发布|ARM.Build.0 = Release|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.发布|ARM64.ActiveCfg = Release|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.发布|ARM64.Build.0 = Release|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.发布|x64.ActiveCfg = Release|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.发布|x64.Build.0 = Release|Any CPU
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.发布|x86.ActiveCfg = Debug|x86
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F}.发布|x86.Build.0 = Debug|x86
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.Debug|Any CPU.Build.0 = Debug|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.Debug|ARM.ActiveCfg = Debug|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.Debug|ARM.Build.0 = Debug|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.Debug|ARM64.Build.0 = Debug|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.Debug|x64.ActiveCfg = Debug|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.Debug|x64.Build.0 = Debug|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.Debug|x86.ActiveCfg = Debug|x86
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.Debug|x86.Build.0 = Debug|x86
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.Release|Any CPU.ActiveCfg = Release|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.Release|Any CPU.Build.0 = Release|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.Release|ARM.ActiveCfg = Release|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.Release|ARM.Build.0 = Release|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.Release|ARM64.ActiveCfg = Release|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.Release|ARM64.Build.0 = Release|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.Release|x64.ActiveCfg = Release|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.Release|x64.Build.0 = Release|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.Release|x86.ActiveCfg = Release|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.Release|x86.Build.0 = Release|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.发布|Any CPU.ActiveCfg = Debug|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.发布|Any CPU.Build.0 = Debug|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.发布|ARM.ActiveCfg = Release|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.发布|ARM.Build.0 = Release|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.发布|ARM64.ActiveCfg = Release|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.发布|ARM64.Build.0 = Release|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.发布|x64.ActiveCfg = Release|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.发布|x64.Build.0 = Release|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.发布|x86.ActiveCfg = Debug|Any CPU
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666}.发布|x86.Build.0 = Debug|Any CPU
{2E755C75-E472-44E0-8AC4-F40209A60172}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2E755C75-E472-44E0-8AC4-F40209A60172}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2E755C75-E472-44E0-8AC4-F40209A60172}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{2E755C75-E472-44E0-8AC4-F40209A60172}.Debug|ARM.ActiveCfg = Debug|ARM
{2E755C75-E472-44E0-8AC4-F40209A60172}.Debug|ARM.Build.0 = Debug|ARM
{2E755C75-E472-44E0-8AC4-F40209A60172}.Debug|ARM.Deploy.0 = Debug|ARM
{2E755C75-E472-44E0-8AC4-F40209A60172}.Debug|ARM64.ActiveCfg = Debug|ARM64
{2E755C75-E472-44E0-8AC4-F40209A60172}.Debug|ARM64.Build.0 = Debug|ARM64
{2E755C75-E472-44E0-8AC4-F40209A60172}.Debug|ARM64.Deploy.0 = Debug|ARM64
{2E755C75-E472-44E0-8AC4-F40209A60172}.Debug|x64.ActiveCfg = Debug|x64
{2E755C75-E472-44E0-8AC4-F40209A60172}.Debug|x64.Build.0 = Debug|x64
{2E755C75-E472-44E0-8AC4-F40209A60172}.Debug|x64.Deploy.0 = Debug|x64
@@ -392,33 +199,84 @@ Global
{2E755C75-E472-44E0-8AC4-F40209A60172}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2E755C75-E472-44E0-8AC4-F40209A60172}.Release|Any CPU.Build.0 = Release|Any CPU
{2E755C75-E472-44E0-8AC4-F40209A60172}.Release|Any CPU.Deploy.0 = Release|Any CPU
{2E755C75-E472-44E0-8AC4-F40209A60172}.Release|ARM.ActiveCfg = Release|ARM
{2E755C75-E472-44E0-8AC4-F40209A60172}.Release|ARM.Build.0 = Release|ARM
{2E755C75-E472-44E0-8AC4-F40209A60172}.Release|ARM.Deploy.0 = Release|ARM
{2E755C75-E472-44E0-8AC4-F40209A60172}.Release|ARM64.ActiveCfg = Release|ARM64
{2E755C75-E472-44E0-8AC4-F40209A60172}.Release|ARM64.Build.0 = Release|ARM64
{2E755C75-E472-44E0-8AC4-F40209A60172}.Release|ARM64.Deploy.0 = Release|ARM64
{2E755C75-E472-44E0-8AC4-F40209A60172}.Release|x64.ActiveCfg = Release|x64
{2E755C75-E472-44E0-8AC4-F40209A60172}.Release|x64.Build.0 = Release|x64
{2E755C75-E472-44E0-8AC4-F40209A60172}.Release|x64.Deploy.0 = Release|x64
{2E755C75-E472-44E0-8AC4-F40209A60172}.Release|x86.ActiveCfg = Release|x86
{2E755C75-E472-44E0-8AC4-F40209A60172}.Release|x86.Build.0 = Release|x86
{2E755C75-E472-44E0-8AC4-F40209A60172}.Release|x86.Deploy.0 = Release|x86
{2E755C75-E472-44E0-8AC4-F40209A60172}.发布|Any CPU.ActiveCfg = Release|Any CPU
{2E755C75-E472-44E0-8AC4-F40209A60172}.发布|Any CPU.Build.0 = Release|Any CPU
{2E755C75-E472-44E0-8AC4-F40209A60172}.发布|Any CPU.Deploy.0 = Release|Any CPU
{2E755C75-E472-44E0-8AC4-F40209A60172}.发布|ARM.ActiveCfg = Debug|ARM
{2E755C75-E472-44E0-8AC4-F40209A60172}.发布|ARM.Build.0 = Debug|ARM
{2E755C75-E472-44E0-8AC4-F40209A60172}.发布|ARM.Deploy.0 = Debug|ARM
{2E755C75-E472-44E0-8AC4-F40209A60172}.发布|ARM64.ActiveCfg = Debug|ARM64
{2E755C75-E472-44E0-8AC4-F40209A60172}.发布|ARM64.Build.0 = Debug|ARM64
{2E755C75-E472-44E0-8AC4-F40209A60172}.发布|ARM64.Deploy.0 = Debug|ARM64
{2E755C75-E472-44E0-8AC4-F40209A60172}.发布|x64.ActiveCfg = Debug|x64
{2E755C75-E472-44E0-8AC4-F40209A60172}.发布|x64.Build.0 = Debug|x64
{2E755C75-E472-44E0-8AC4-F40209A60172}.发布|x64.Deploy.0 = Debug|x64
{2E755C75-E472-44E0-8AC4-F40209A60172}.发布|x86.ActiveCfg = Debug|x86
{2E755C75-E472-44E0-8AC4-F40209A60172}.发布|x86.Build.0 = Debug|x86
{2E755C75-E472-44E0-8AC4-F40209A60172}.发布|x86.Deploy.0 = Debug|x86
{BBB75CAC-2BA3-473D-935D-0E59406F5E61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BBB75CAC-2BA3-473D-935D-0E59406F5E61}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BBB75CAC-2BA3-473D-935D-0E59406F5E61}.Debug|x64.ActiveCfg = Debug|Any CPU
{BBB75CAC-2BA3-473D-935D-0E59406F5E61}.Debug|x64.Build.0 = Debug|Any CPU
{BBB75CAC-2BA3-473D-935D-0E59406F5E61}.Debug|x86.ActiveCfg = Debug|Any CPU
{BBB75CAC-2BA3-473D-935D-0E59406F5E61}.Debug|x86.Build.0 = Debug|Any CPU
{BBB75CAC-2BA3-473D-935D-0E59406F5E61}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BBB75CAC-2BA3-473D-935D-0E59406F5E61}.Release|Any CPU.Build.0 = Release|Any CPU
{BBB75CAC-2BA3-473D-935D-0E59406F5E61}.Release|x64.ActiveCfg = Release|Any CPU
{BBB75CAC-2BA3-473D-935D-0E59406F5E61}.Release|x64.Build.0 = Release|Any CPU
{BBB75CAC-2BA3-473D-935D-0E59406F5E61}.Release|x86.ActiveCfg = Release|Any CPU
{BBB75CAC-2BA3-473D-935D-0E59406F5E61}.Release|x86.Build.0 = Release|Any CPU
{4E2EB2E0-E5FE-4FEB-A3E5-5F2F05CD1A67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4E2EB2E0-E5FE-4FEB-A3E5-5F2F05CD1A67}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4E2EB2E0-E5FE-4FEB-A3E5-5F2F05CD1A67}.Debug|x64.ActiveCfg = Debug|Any CPU
{4E2EB2E0-E5FE-4FEB-A3E5-5F2F05CD1A67}.Debug|x64.Build.0 = Debug|Any CPU
{4E2EB2E0-E5FE-4FEB-A3E5-5F2F05CD1A67}.Debug|x86.ActiveCfg = Debug|Any CPU
{4E2EB2E0-E5FE-4FEB-A3E5-5F2F05CD1A67}.Debug|x86.Build.0 = Debug|Any CPU
{4E2EB2E0-E5FE-4FEB-A3E5-5F2F05CD1A67}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4E2EB2E0-E5FE-4FEB-A3E5-5F2F05CD1A67}.Release|Any CPU.Build.0 = Release|Any CPU
{4E2EB2E0-E5FE-4FEB-A3E5-5F2F05CD1A67}.Release|x64.ActiveCfg = Release|Any CPU
{4E2EB2E0-E5FE-4FEB-A3E5-5F2F05CD1A67}.Release|x64.Build.0 = Release|Any CPU
{4E2EB2E0-E5FE-4FEB-A3E5-5F2F05CD1A67}.Release|x86.ActiveCfg = Release|Any CPU
{4E2EB2E0-E5FE-4FEB-A3E5-5F2F05CD1A67}.Release|x86.Build.0 = Release|Any CPU
{AF006EF5-D4BC-49C6-8E0E-DC2B882BE767}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AF006EF5-D4BC-49C6-8E0E-DC2B882BE767}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AF006EF5-D4BC-49C6-8E0E-DC2B882BE767}.Debug|x64.ActiveCfg = Debug|Any CPU
{AF006EF5-D4BC-49C6-8E0E-DC2B882BE767}.Debug|x64.Build.0 = Debug|Any CPU
{AF006EF5-D4BC-49C6-8E0E-DC2B882BE767}.Debug|x86.ActiveCfg = Debug|Any CPU
{AF006EF5-D4BC-49C6-8E0E-DC2B882BE767}.Debug|x86.Build.0 = Debug|Any CPU
{AF006EF5-D4BC-49C6-8E0E-DC2B882BE767}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF006EF5-D4BC-49C6-8E0E-DC2B882BE767}.Release|Any CPU.Build.0 = Release|Any CPU
{AF006EF5-D4BC-49C6-8E0E-DC2B882BE767}.Release|x64.ActiveCfg = Release|Any CPU
{AF006EF5-D4BC-49C6-8E0E-DC2B882BE767}.Release|x64.Build.0 = Release|Any CPU
{AF006EF5-D4BC-49C6-8E0E-DC2B882BE767}.Release|x86.ActiveCfg = Release|Any CPU
{AF006EF5-D4BC-49C6-8E0E-DC2B882BE767}.Release|x86.Build.0 = Release|Any CPU
{DE0B3A58-C301-4671-8B32-4F195C9457A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DE0B3A58-C301-4671-8B32-4F195C9457A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DE0B3A58-C301-4671-8B32-4F195C9457A7}.Debug|x64.ActiveCfg = Debug|Any CPU
{DE0B3A58-C301-4671-8B32-4F195C9457A7}.Debug|x64.Build.0 = Debug|Any CPU
{DE0B3A58-C301-4671-8B32-4F195C9457A7}.Debug|x86.ActiveCfg = Debug|Any CPU
{DE0B3A58-C301-4671-8B32-4F195C9457A7}.Debug|x86.Build.0 = Debug|Any CPU
{DE0B3A58-C301-4671-8B32-4F195C9457A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DE0B3A58-C301-4671-8B32-4F195C9457A7}.Release|Any CPU.Build.0 = Release|Any CPU
{DE0B3A58-C301-4671-8B32-4F195C9457A7}.Release|x64.ActiveCfg = Release|Any CPU
{DE0B3A58-C301-4671-8B32-4F195C9457A7}.Release|x64.Build.0 = Release|Any CPU
{DE0B3A58-C301-4671-8B32-4F195C9457A7}.Release|x86.ActiveCfg = Release|Any CPU
{DE0B3A58-C301-4671-8B32-4F195C9457A7}.Release|x86.Build.0 = Release|Any CPU
{2E226B1E-80F6-448D-B02B-0A029C5BC09E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2E226B1E-80F6-448D-B02B-0A029C5BC09E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2E226B1E-80F6-448D-B02B-0A029C5BC09E}.Debug|x64.ActiveCfg = Debug|Any CPU
{2E226B1E-80F6-448D-B02B-0A029C5BC09E}.Debug|x64.Build.0 = Debug|Any CPU
{2E226B1E-80F6-448D-B02B-0A029C5BC09E}.Debug|x86.ActiveCfg = Debug|Any CPU
{2E226B1E-80F6-448D-B02B-0A029C5BC09E}.Debug|x86.Build.0 = Debug|Any CPU
{2E226B1E-80F6-448D-B02B-0A029C5BC09E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2E226B1E-80F6-448D-B02B-0A029C5BC09E}.Release|Any CPU.Build.0 = Release|Any CPU
{2E226B1E-80F6-448D-B02B-0A029C5BC09E}.Release|x64.ActiveCfg = Release|Any CPU
{2E226B1E-80F6-448D-B02B-0A029C5BC09E}.Release|x64.Build.0 = Release|Any CPU
{2E226B1E-80F6-448D-B02B-0A029C5BC09E}.Release|x86.ActiveCfg = Release|Any CPU
{2E226B1E-80F6-448D-B02B-0A029C5BC09E}.Release|x86.Build.0 = Release|Any CPU
{2EE1744F-2D3C-4032-9A9E-C57FA3B512B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2EE1744F-2D3C-4032-9A9E-C57FA3B512B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2EE1744F-2D3C-4032-9A9E-C57FA3B512B3}.Debug|x64.ActiveCfg = Debug|Any CPU
{2EE1744F-2D3C-4032-9A9E-C57FA3B512B3}.Debug|x64.Build.0 = Debug|Any CPU
{2EE1744F-2D3C-4032-9A9E-C57FA3B512B3}.Debug|x86.ActiveCfg = Debug|Any CPU
{2EE1744F-2D3C-4032-9A9E-C57FA3B512B3}.Debug|x86.Build.0 = Debug|Any CPU
{2EE1744F-2D3C-4032-9A9E-C57FA3B512B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2EE1744F-2D3C-4032-9A9E-C57FA3B512B3}.Release|Any CPU.Build.0 = Release|Any CPU
{2EE1744F-2D3C-4032-9A9E-C57FA3B512B3}.Release|x64.ActiveCfg = Release|Any CPU
{2EE1744F-2D3C-4032-9A9E-C57FA3B512B3}.Release|x64.Build.0 = Release|Any CPU
{2EE1744F-2D3C-4032-9A9E-C57FA3B512B3}.Release|x86.ActiveCfg = Release|Any CPU
{2EE1744F-2D3C-4032-9A9E-C57FA3B512B3}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -436,6 +294,13 @@ Global
{4E66F4F4-7771-4FFA-A907-3F99A95C6A7F} = {F62E508E-B374-4149-B9AC-0A8090AA6CD1}
{86F6CF23-35C4-45AD-BC0D-6BD50C03F666} = {F62E508E-B374-4149-B9AC-0A8090AA6CD1}
{2E755C75-E472-44E0-8AC4-F40209A60172} = {45E5B6B2-0A6D-4D57-804B-7B8313145B62}
{BBB75CAC-2BA3-473D-935D-0E59406F5E61} = {F62E508E-B374-4149-B9AC-0A8090AA6CD1}
{2B74A2B2-148D-4518-BF74-3408095E920B} = {F62E508E-B374-4149-B9AC-0A8090AA6CD1}
{4E2EB2E0-E5FE-4FEB-A3E5-5F2F05CD1A67} = {2B74A2B2-148D-4518-BF74-3408095E920B}
{AF006EF5-D4BC-49C6-8E0E-DC2B882BE767} = {2B74A2B2-148D-4518-BF74-3408095E920B}
{DE0B3A58-C301-4671-8B32-4F195C9457A7} = {2B74A2B2-148D-4518-BF74-3408095E920B}
{2E226B1E-80F6-448D-B02B-0A029C5BC09E} = {2B74A2B2-148D-4518-BF74-3408095E920B}
{2EE1744F-2D3C-4032-9A9E-C57FA3B512B3} = {2B74A2B2-148D-4518-BF74-3408095E920B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5214732D-5A99-44C5-9F02-56348CC457EF}
@@ -1,24 +0,0 @@
using MetroTrilithon.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace SteamTools.Models.Settings
{
public static class AuthSettings
{
/// <summary>
/// ÁîÅÆÊý¾Ý(ѹËõ´æ´¢£©
/// </summary>
public static SerializableProperty<string> Authenticators { get; }
= new SerializableProperty<string>(GetKey(), Providers.Local) { AutoSave = true };
private static string GetKey([CallerMemberName] string propertyName = "")
{
return nameof(GeneralSettings) + "." + propertyName;
}
}
}
-35
View File
@@ -1,35 +0,0 @@
using SteamTool.Core.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SteamTools
{
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main(string[] args)
{
try
{
if (args.ContainsArg("-log"))
{
Logger.EnableTextLog = true;
}
App app = new App();
app.InitializeComponent();
app.Run();
}
catch (Exception ex)
{
Logger.Error(ex);
}
}
}
}
@@ -1,8 +0,0 @@
{
"profiles": {
"SteamTools": {
"commandName": "Project",
"commandLineArgs": "-log"
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 510 B

-120
View File
@@ -1,120 +0,0 @@
using SteamTool.Core;
using SteamTool.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using SteamTool.Model.ToolModel;
using SteamTools.Models;
using SteamTool.Core.Common;
using System.Net;
using System.IO;
using Livet;
using SteamTools.Properties;
namespace SteamTools.Services
{
public class AutoUpdateService : NotificationObject
{
#region static members
public static AutoUpdateService Current { get; } = new AutoUpdateService();
#endregion
private readonly HttpServices httpServices = SteamToolCore.Instance.Get<HttpServices>();
#region 更新进度变更通知
private double _ProgressValue;
public double ProgressValue
{
get => this._ProgressValue;
set
{
if (this._ProgressValue != value)
{
this._ProgressValue = value;
this.RaisePropertyChanged();
}
}
}
#endregion
#region 是否有更新
private bool _IsExistUpdate;
public bool IsExistUpdate
{
get => this._IsExistUpdate;
set
{
if (this._IsExistUpdate != value)
{
this._IsExistUpdate = value;
this.RaisePropertyChanged();
}
}
}
#endregion
public async void CheckUpdate()
{
try
{
StatusService.Current.Notify("正在从Github检查更新...");
var result = await httpServices.Get(Const.GITHUB_LATEST_RELEASEAPI_URL);
var model = JsonConvert.DeserializeObject<GithubReleaseModel>(result);
if (!(ProductInfo.Version < model.version))
{
IsExistUpdate = false;
StatusService.Current.Notify("当前已是最新版本");
return;
}
IsExistUpdate = true;
DownloadUpdate(model);
}
catch (Exception ex)
{
Logger.Error("更新出错:", ex);
WindowService.Current.ShowDialogWindow($"更新出错:{ex.Message}");
}
}
public async void DownloadUpdate(GithubReleaseModel model)
{
if (WindowService.Current.ShowDialogWindow($"检测到新版本更新内容:{model.body}\r\n是否立即更新?", $"{ProductInfo.Title} | 更新提示") == true)
{
//var name = model.assets.FirstOrDefault()?.name;
var name = Path.Combine(AppContext.BaseDirectory, @$"{ProductInfo.Title} {model.version}.zip");
if (File.Exists(name))
{
StatusService.Current.Notify("更新文件已经存在,不需要下载");
return;
}
var fileReq = WebRequest.Create(model.assets.FirstOrDefault()?.browser_download_url);
await fileReq?.GetResponseAsync().ContinueWith(s =>
{
long totalBytes = s.Result.ContentLength;
using Stream responseStream = s.Result.GetResponseStream();
using FileStream fileStream = new FileStream(name, FileMode.Create, FileAccess.Write);
long totalDownloadBytes = 0;
byte[] bs = new byte[4096];
int size = responseStream.Read(bs, 0, bs.Length);
while (size > 0)
{
totalDownloadBytes += size;
fileStream.Write(bs, 0, size);
ProgressValue = ((double)totalDownloadBytes / (double)totalBytes);
StatusService.Current.Set($"下载更新{ProgressValue:P}");
size = responseStream.Read(bs, 0, bs.Length);
}
fileStream.Flush();
fileStream.Close();
StatusService.Current.Set(Resources.Ready);
StatusService.Current.Notify($"{ProductInfo.Title} {model.version}版本已经下载到程序根目录下,暂时请手动替换更新");
});
}
}
}
}
-164
View File
@@ -1,164 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Livet;
using SteamTool.Core.Common;
using SteamTool.Model;
using SteamTool.Steam.Service;
using SteamTool.Steam.Service.Local;
using SteamTool.Steam.Service.Web;
using SteamTools.Properties;
using SteamTools.ViewModels;
namespace SteamTools.Services
{
public class SteamConnectService : NotificationObject
{
#region static members
public static SteamConnectService Current { get; } = new SteamConnectService();
#endregion
//public readonly SteamDLLService DLLService = SteamService.Instance.Get<SteamDLLService>();
public readonly SteamworksApiService ApiService = SteamService.Instance.Get<SteamworksApiService>();
public readonly SteamworksWebApiService SteamworksWebApiService = SteamService.Instance.Get<SteamworksWebApiService>();
public readonly SteamDbApiService steamDbApiService = SteamService.Instance.Get<SteamDbApiService>();
#region Steam游戏列表
private IReadOnlyCollection<SteamApp> _SteamApps;
public IReadOnlyCollection<SteamApp> SteamApps
{
get => _SteamApps;
set
{
if (_SteamApps != value)
{
_SteamApps = value;
this.RaisePropertyChanged();
}
}
}
#endregion
#region 运行中的游戏列表
private IList<SteamApp> _RuningSteamApps = new List<SteamApp>();
public IList<SteamApp> RuningSteamApps
{
get => _RuningSteamApps;
set
{
if (_RuningSteamApps != value)
{
_RuningSteamApps = value;
this.RaisePropertyChanged();
}
}
}
#endregion
#region 当前steam登录用户
private SteamUser _CurrentSteamUser;
public SteamUser CurrentSteamUser
{
get => _CurrentSteamUser;
set
{
if (_CurrentSteamUser != value)
{
_CurrentSteamUser = value;
this.RaisePropertyChanged();
}
}
}
#endregion
#region 连接steamclient是否成功
private bool _IsConnectToSteam;
public bool IsConnectToSteam
{
get => _IsConnectToSteam;
set
{
if (_IsConnectToSteam != value)
{
_IsConnectToSteam = value;
this.RaisePropertyChanged();
}
}
}
#endregion
public void Initialize()
{
var t = new Task(async () =>
{
Thread.CurrentThread.IsBackground = true;
while (true)
{
if (Process.GetProcessesByName("steam").Length > 0)
{
if (!IsConnectToSteam)
{
if (ApiService.Initialize())
{
var id = ApiService.GetSteamId64();
if (id == 76561197960265728)
{
//该64位id的steamID3等于0,是steam未获取到当前登录用户的默认返回值,所以直接重新获取,
//希望这位用户不会用steam++,嗯...
ApiService.SteamClient.Dispose();
continue;
}
IsConnectToSteam = true;
CurrentSteamUser = await steamDbApiService.GetUserInfo(id);
CurrentSteamUser.IPCountry = ApiService.GetIPCountry();
var mainViewModel = (WindowService.Current.MainWindow as MainWindowViewModel);
await mainViewModel.SteamAppPage.Initialize();
#if DEBUG
await mainViewModel.SystemTabItems[mainViewModel.SystemTabItems.Count - 1].Initialize();
#endif
SteamConnectService.Current.DisposeSteamClient();
}
}
}
else
{
IsConnectToSteam = false;
//StatusService.Current.Notify(Resources.Steam_Not_Runing);
}
await Task.Delay(1500);
}
}, TaskCreationOptions.LongRunning);
t.ContinueWith(s => { Logger.Error(s.Exception); WindowService.Current.ShowDialogWindow(s.Exception.Message); }, TaskContinuationOptions.OnlyOnFaulted);
t.Start();
}
public void Initialize(int appid)
{
if (Process.GetProcessesByName("steam").Length > 0)
{
IsConnectToSteam = ApiService.Initialize(appid);
}
}
public void Shutdown()
{
foreach (var app in SteamConnectService.Current.RuningSteamApps)
{
if (!app.Process.HasExited)
app.Process.Kill();
}
}
public void DisposeSteamClient()
{
ApiService.SteamClient.Dispose();
}
}
}
@@ -1,70 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Windows;
using SteamTools.Win32;
using MetroRadiance.Interop.Win32;
using System.Diagnostics;
using SteamTool.Core.Common;
using System.Runtime.InteropServices;
using SteamTools.Services;
using SteamTool.Steam.Service.Web;
using SteamTool.Core;
using SteamTool.Steam.Service;
using SteamTool.Model;
using Newtonsoft.Json;
using SteamTools.Models.Settings;
using System.IO;
namespace SteamTools.ViewModels
{
public class SettingsGeneralViewModel : Livet.ViewModel
{
private SteamworksWebApiService SteamworksWebApi => SteamService.Instance.Get<SteamworksWebApiService>();
private SteamToolService SteamTool => SteamToolCore.Instance.Get<SteamToolService>();
private bool IsRefreshGameListCache;
public void RefreshGameListCache()
{
if (SteamConnectService.Current.IsConnectToSteam)
{
if (IsRefreshGameListCache)
{
StatusService.Current.Notify("正在下载Steam游戏数据中...");
return;
}
StatusService.Current.Notify("刷新Steam游戏数据");
IsRefreshGameListCache = true;
Task.Run(async () =>
{
var result = await SteamworksWebApi.GetAllSteamAppsString();
if (GeneralSettings.IsSteamAppListLocalCache)
SteamTool.UpdateAppListJson(result, Path.Combine(AppContext.BaseDirectory, Const.APP_LIST_FILE));
var apps = JsonConvert.DeserializeObject<SteamApps>(result).AppList.Apps;
apps = apps.DistinctBy(d => d.AppId).ToList();
//SteamConnectService.Current.SteamApps = apps;
SteamConnectService.Current.SteamApps = SteamConnectService.Current.ApiService.OwnsApps(apps);
}).ContinueWith(s => { Logger.Error(s.Exception); WindowService.Current.ShowDialogWindow(s.Exception.Message); }, TaskContinuationOptions.OnlyOnFaulted).ContinueWith(s =>
{
StatusService.Current.Notify("刷新Steam游戏数据完成");
IsRefreshGameListCache = false;
s.Dispose();
});
}
else
{
StatusService.Current.Notify("未检测到Steam运行");
}
}
public void CheckUpdate_Click()
{
AutoUpdateService.Current.CheckUpdate();
}
}
}
@@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SteamTools.ViewModels
{
public class SteamIdlePageViewModel : TabItemViewModel
{
public override string Name
{
get { return Properties.Resources.IdleCard; }
protected set { throw new NotImplementedException(); }
}
}
}
@@ -1,36 +0,0 @@
using Microsoft.Win32;
using SteamTools.Models;
using SteamTools.Models.Settings;
using SteamTools.Properties;
using SteamTools.Services;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using SteamTool.Core.Common;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using WinAuth;
namespace SteamTools.ViewModels
{
public class AuthTradeWindowViewModel : MainWindowViewModelBase
{
private SteamAuthenticator _Authenticator;
public AuthTradeWindowViewModel()
{
this.Title = ProductInfo.Title + " | " + Resources.Auth_TradeTitle;
}
public AuthTradeWindowViewModel(WinAuthAuthenticator auth)
{
_Authenticator = auth.AuthenticatorData as SteamAuthenticator;
this.Title = ProductInfo.Title + " | " + Resources.Auth_TradeTitle;
}
}
}
@@ -1,142 +0,0 @@
<UserControl x:Class="SteamTools.Views.Content.AboutUpdateHistory"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:SteamTools.Views.Content"
xmlns:viewModel="clr-namespace:SteamTools.ViewModels"
xmlns:services="clr-namespace:SteamTools.Services"
xmlns:metro="http://schemes.grabacr.net/winfx/2014/controls"
xmlns:metro2="http://schemes.grabacr.net/winfx/2015/personal/controls"
xmlns:model="clr-namespace:SteamTool.Model;assembly=SteamTool.Model"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:livet="http://schemas.livet-mvvm.net/2011/wpf"
mc:Ignorable="d"
d:DesignHeight="400"
d:DesignWidth="600"
Background="{DynamicResource ThemeBrushKey}">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="..\Common.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<DockPanel Margin="8">
<TextBlock DockPanel.Dock="Top" Text="{Binding Resources.AboutUpdateHistory, Source={x:Static services:ResourceService.Current}, Mode=OneWay}"
Style="{DynamicResource SettingsHeaderTextStyleKey}" />
<Border Grid.Column="1">
<FlowDocumentScrollViewer Padding="0,-18,0,0"
HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Auto">
<FlowDocument FontSize="12"
Foreground="{DynamicResource ForegroundBrushKey}"
FontFamily="Meiryo UI"
TextAlignment="Left"
MaxPageWidth="900">
<Paragraph Language="zh-cn">
<Run Text="Steam++ v1.0.3" FontSize="16"/>
<Run Text="&#160;"/>
<Run Text="2020-12-26" FontSize="10" />
<LineBreak />
<Run Text="更新内容"></Run>
<LineBreak />
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="新增pixiv本地反代服务支持" />
<LineBreak/>
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="新增在欢迎页steam昵称后显示steam的登陆区域" />
<LineBreak/>
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="添加steam图片修复的本地反代支持" />
<LineBreak/>
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="修复最小化恢复时UI边框错位的BUG"></Run>
<LineBreak/>
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="修复令牌编辑和导入时出现的非空报错"></Run>
<LineBreak/>
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="帐户切换功能的最近登陆时间从北京时间改为当前系统时区时间"></Run>
<LineBreak/>
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="修复一个因为DNS解析错误会导致程序内存溢出闪退的BUG"></Run>
<LineBreak/>
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="SDA令牌导入不再支持导入加密文件,如果要导入加密的maFile请先在SDA移除加密"></Run>
<LineBreak/>
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="修改初始化的方式和steam api的连接逻辑来避免steam游戏掉帧的BUG"></Run>
<LineBreak/>
<LineBreak />
<Run Text="已知的未修复问题"></Run>
<LineBreak />
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="部分用户无法加载游戏列表,无法复现,原因暂时不明。(也可能是加载太慢,过半小时才能加载出来)" />
</Paragraph>
<Paragraph Language="zh-cn">
<Run Text="Steam++ v1.0.2" FontSize="16"/>
<Run Text="&#160;"/>
<Run Text="2020-12-21" FontSize="10" />
<LineBreak />
<Run Text="更新内容"></Run>
<LineBreak />
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="更新了由Benares制作的图标" />
<LineBreak/>
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="新增帐户切换删除功能" />
<LineBreak/>
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="添加github图片资源文件代理服务与discord代理服务支持" />
<LineBreak/>
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="因为有问题暂时去掉了GOG Galaxy代理选项"></Run>
<LineBreak/>
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="修复一个会导致程序启动没有反应的bug"></Run>
<LineBreak/>
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="修复托盘菜单steam昵称过长ui错位bug"></Run>
<LineBreak/>
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="新增steam启动参数设置"></Run>
<LineBreak/>
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="新增启动时程序最小化到托盘菜单设置"></Run>
<LineBreak/>
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="新增捐助列表的展示"></Run>
<LineBreak/>
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="新增工具自动更新功能"></Run>
<LineBreak />
<LineBreak />
<Run Text="已知的未修复问题"></Run>
<LineBreak />
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="(严重)经反馈,程序运行时可能会影响部分steam游戏掉帧,GPU占用率变低,这个BUG目前在作者的机器上无法复现所以暂时没有修复,如果你遇到这个问题可以手动关闭steam++解决。" />
<LineBreak />
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="程序在高DPI缩放分辨率下可能会UI布局错位,目前暂时拖动程序可恢复。" />
<LineBreak />
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="部分用户无法加载游戏列表,无法复现,原因暂时不明。" />
</Paragraph>
<Paragraph Language="zh-cn">
<Run Text="Steam++ v1.0.0" FontSize="16"/>
<Run Text="&#160;"/>
<Run Text="2020-12-14" FontSize="10" />
<LineBreak />
<Run Text="发布第一个版本" />
<LineBreak/>
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="主要功能:社区反代,帐户切换,成就解锁,本地令牌。"></Run>
<LineBreak/>
<Run Text="&#160;&#160;&#160;&#160;"/>
<Run Text="次要功能:强制无边框窗口化以及CSGO VAC屏蔽修复。"></Run>
</Paragraph>
</FlowDocument>
</FlowDocumentScrollViewer>
</Border>
</DockPanel>
</UserControl>
@@ -1,144 +0,0 @@
<UserControl x:Class="SteamTools.Views.Content.GameCommon"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:SteamTools.Views.Content"
xmlns:viewModel="clr-namespace:SteamTools.ViewModels"
xmlns:services="clr-namespace:SteamTools.Services"
xmlns:metro="http://schemes.grabacr.net/winfx/2014/controls"
xmlns:metro2="http://schemes.grabacr.net/winfx/2015/personal/controls"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:livet="http://schemas.livet-mvvm.net/2011/wpf"
mc:Ignorable="d"
d:DesignHeight="400"
d:DesignWidth="600"
d:DataContext="{d:DesignInstance viewModel:GameRelatedPageViewModel}"
Background="{DynamicResource ThemeBrushKey}">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="..\Common.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<StackPanel>
<TextBlock Text="{Binding Resources.BorderlessWindow, Source={x:Static services:ResourceService.Current}, Mode=OneWay}"
Style="{DynamicResource SettingsHeaderTextStyleKey}" />
<StackPanel Orientation="Vertical" Visibility="{Binding Path=SelectWindow,Mode=OneWay,Converter={StaticResource NullToVisibilityConverter}}"
Margin="20,0,10,00">
<TextBlock Margin="0,0,10,0" TextWrapping="WrapWithOverflow">
<Run Text="标题 :"></Run>
<Run Text="{Binding SelectWindow.Title,Mode=OneWay}"></Run>
<LineBreak></LineBreak>
<LineBreak></LineBreak>
<Run Text="类名 :"></Run>
<Run Text="{Binding SelectWindow.ClassName,Mode=OneWay}"></Run>
<LineBreak></LineBreak>
<LineBreak></LineBreak>
<Run Text="进程 :"></Run>
<Run Text="{Binding SelectWindow.Name,Mode=OneWay}"></Run>
<LineBreak></LineBreak>
<LineBreak></LineBreak>
<Run Text="程序路径 :"></Run>
<!--<Run Text="{Binding SelectWindow.Path,Mode=OneWay}"></Run>-->
<!--<LineBreak></LineBreak>-->
</TextBlock>
<TextBlock Margin="0,0,10,0" TextWrapping="WrapWithOverflow" Text="{Binding SelectWindow.Path,Mode=OneWay}"></TextBlock>
</StackPanel>
<StackPanel Orientation="Horizontal"
Margin="20,10,0,00">
<Image Width="64" HorizontalAlignment="Left" Source="/Resources/Asstes/movecross.png">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<livet:LivetCallMethodAction
MethodName="Cross_MouseDown"
MethodTarget="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Image>
<TextBlock Margin="10,0" Text="拖拽十字到游戏窗口,即可获取游戏信息执行对应操作。"></TextBlock>
</StackPanel>
<StackPanel Orientation="Horizontal"
Margin="20,20,0,0">
<Button Height="30" Content="结束进程">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<livet:LivetCallMethodAction
MethodName="WindowKill_Click"
MethodTarget="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Height="30" Content="无边框窗口化">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<livet:LivetCallMethodAction
MethodName="BorderlessWindow_Click"
MethodTarget="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Height="30" Content="最大化">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<livet:LivetCallMethodAction
MethodName="MaximizeWindow_Click"
MethodTarget="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Height="30" Content="还原最大化">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<livet:LivetCallMethodAction
MethodName="NormalWindow_Click"
MethodTarget="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Height="30" Content="隐藏">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<livet:LivetCallMethodAction
MethodName="HideWindow_Click"
MethodTarget="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Height="30" Content="显示">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<livet:LivetCallMethodAction
MethodName="ShowWindow_Click"
MethodTarget="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Height="30" Content="置于壁纸层">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<livet:LivetCallMethodAction
MethodName="ToWallerpaperWindow_Click"
MethodTarget="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Height="30" Content="刷新壁纸">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<livet:LivetCallMethodAction
MethodName="ResetWallerpaperWindow_Click"
MethodTarget="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</StackPanel>
<TextBlock Style="{StaticResource DetailTextStyleKey}" Margin="20,6,0,0">
<Run Text="*置于壁纸层的游戏可能会无法操控,这个问题可以解决但是目前开发精力不在这,目前这个功能就这样了。游戏结束后桌面会依然留下冻结的画面,这时可以点击刷新壁纸来恢复默认壁纸。"/>
<Run Text="并且将窗口放置于桌面壁纸层功能与Wallpaper Engine和其它动态桌面软件不兼容,使用时注意关掉Wallpaper Engine等软件。"/>
</TextBlock>
<Rectangle Style="{DynamicResource SeparatorStyleKey}" />
</StackPanel>
</UserControl>
-79
View File
@@ -1,79 +0,0 @@
<UserControl x:Class="SteamTools.Views.Controls.StatusBar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:SteamTools.Views.Controls"
xmlns:metro="http://schemes.grabacr.net/winfx/2014/controls"
xmlns:services="clr-namespace:SteamTools.Services"
xmlns:vm="clr-namespace:SteamTools.ViewModels"
mc:Ignorable="d"
d:DesignHeight="25" d:DesignWidth="780"
d:DataContext="{d:DesignInstance vm:StatusBarViewModel}">
<Grid Grid.Row="2" Background="{DynamicResource AccentBrushKey}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="23" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
FontSize="13"
Style="{DynamicResource DefaultTextStyleKey}"
Foreground="{DynamicResource AccentForegroundBrushKey}"
TextWrapping="NoWrap"
Margin="8,0" >
<Run
Text="{Binding Source={x:Static services:StatusService.Current}, Path=Message}"/>
</TextBlock>
<ContentControl Grid.Column="1"
Content="{Binding}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type vm:WelcomePageViewModel}" />
<DataTemplate DataType="{x:Type vm:CommunityProxyPageViewModel}" />
<DataTemplate DataType="{x:Type vm:SteamAccountPageViewModel}" />
<DataTemplate DataType="{x:Type vm:SteamAppPageViewModel}" >
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground"
Value="{DynamicResource AccentForegroundBrushKey}" />
<Setter Property="FontFamily"
Value="{DynamicResource DefaultFontFamilyKey}" />
<Setter Property="FontSize"
Value="{DynamicResource DefaultFontSizeKey}" />
<Setter Property="VerticalAlignment"
Value="Center" />
</Style>
</StackPanel.Resources>
<TextBlock VerticalAlignment="Center" Text="{Binding Source={x:Static services:ResourceService.Current}, Path=Resources.Steam_Not_Runing_Tips}"
Visibility="{Binding Source={x:Static services:SteamConnectService.Current}, Path=IsConnectToSteam,Mode=OneWay,Converter={StaticResource ReverseBooleanToVisibilityConverter}}">
</TextBlock>
<TextBlock Text="{Binding Source={x:Static services:ResourceService.Current}, Path=Resources.Game_Total, StringFormat='{}{0}: '}" />
<TextBlock Text="{Binding Games.Count,Mode=OneWay}"
MinWidth="45" />
<TextBlock Text="{Binding Source={x:Static services:ResourceService.Current}, Path=Resources.Game_Install, StringFormat='{}{0}: '}" />
<TextBlock Text="{Binding InstalledCount,Mode=OneWay}"
MinWidth="65" />
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:SettingsPageViewModel}" />
<DataTemplate DataType="{x:Type vm:OtherPlatformPageViewModel}" />
<DataTemplate DataType="{x:Type vm:LocalAuthPageViewModel}" />
<DataTemplate DataType="{x:Type vm:GameRelatedPageViewModel}" />
<DataTemplate DataType="{x:Type vm:ArchiSteamFarmPlusPageViewModel}" />
<DataTemplate DataType="{x:Type vm:AboutPageViewModel}" />
<DataTemplate DataType="{x:Type vm:DebugPageViewModel}" />
<DataTemplate DataType="{x:Type vm:AchievementWindowViewModel}" />
<DataTemplate DataType="{x:Type vm:SteamIdlePageViewModel}" />
</ContentControl.Resources>
</ContentControl>
<!--<metro:CaptionButton Grid.Column="2" VerticalAlignment="Center"
ToolTip="{Binding Path=Badge,StringFormat=Resources.NotificationString,Source={x:Static services:ResourceService.Current}, Mode=OneWay}"
Style="{DynamicResource StatusButtonStyleKey}" >
<svgc:SvgViewbox IsHitTestVisible="False" Source="pack://application:,,,/Resources/Asstes/bell.svg" Width="11" />
</metro:CaptionButton>-->
<metro:ResizeGrip Grid.Column="3" />
</Grid>
</UserControl>
-208
View File
@@ -1,208 +0,0 @@
<UserControl x:Class="SteamTools.Views.Controls.TaskBarPopup"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:metro2="http://schemes.grabacr.net/winfx/2015/personal/controls"
xmlns:vm="clr-namespace:SteamTools.ViewModels"
xmlns:services="clr-namespace:SteamTools.Services"
xmlns:metro="http://schemes.grabacr.net/winfx/2014/controls"
xmlns:models="clr-namespace:SteamTools.Models"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:livet="http://schemas.livet-mvvm.net/2011/wpf"
mc:Ignorable="d"
Height="350" Width="180"
FontSize="14"
UseLayoutRounding="True"
TextOptions.TextFormattingMode="Display"
TextOptions.TextRenderingMode="Auto"
SnapsToDevicePixels="True"
Foreground="{DynamicResource ForegroundBrushKey}"
d:DataContext="{d:DesignInstance vm:TaskBarViewModel}">
<Border>
<Grid>
<Rectangle Stroke="{DynamicResource AccentBrushKey}"
StrokeThickness="3">
<Rectangle.Effect>
<BlurEffect Radius="8" />
</Rectangle.Effect>
</Rectangle>
<Border Background="{DynamicResource ThemeBrushKey}"
BorderBrush="{DynamicResource AccentBrushKey}"
BorderThickness=".99">
<Grid Margin="8,0">
<Grid.RowDefinitions>
<RowDefinition Height="70"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<DockPanel Grid.Row="0" Margin="0,8,0,0" Visibility="{Binding ElementName=user,Path=IsVisible,Converter={StaticResource ReverseBooleanToVisibilityConverter}}">
<Image Source="pack://application:,,,/Resources/Asstes/app.ico" Width="64" Height="64" Cursor="Hand">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<livet:LivetCallMethodAction MethodName="ShowUrl"
MethodTarget="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Image>
<StackPanel VerticalAlignment="Center">
<TextBlock Text="{Binding Source={x:Static services:ResourceService.Current}, Path=Resources.WinTitle,Mode=OneWay}"
Foreground="{DynamicResource HighlightForegroundBrushKey}" Style="{StaticResource HeaderTextStyleKey}" FontSize="16"/>
<TextBlock Text="{Binding Source={x:Static models:ProductInfo.VersionString}, StringFormat=版本 {0}, Mode=OneWay}"
Foreground="{DynamicResource HighlightForegroundBrushKey}" Style="{StaticResource DetailTextStyleKey}"/>
</StackPanel>
</DockPanel>
<DockPanel x:Name="user" Grid.Row="0" Margin="0,8,0,0" Visibility="{Binding CurrentSteamUser,Source={x:Static services:SteamConnectService.Current},Mode=OneWay,Converter={StaticResource NullToVisibilityConverter}}">
<Image Source="{Binding CurrentSteamUser.AvatarMedium,Source={x:Static services:SteamConnectService.Current},Mode=OneWay}" Width="64" Height="64" Cursor="Hand">
<Image.Clip>
<!--设置图像如何显示-->
<EllipseGeometry RadiusX="32" RadiusY="32" Center="32,32"/>
</Image.Clip>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<livet:LivetCallMethodAction MethodName="ShowUrl"
MethodTarget="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Image>
<StackPanel VerticalAlignment="Center" Margin="8,0,0,0">
<TextBlock Text="{Binding CurrentSteamUser.SteamID,Source={x:Static services:SteamConnectService.Current},Mode=OneWay}" VerticalAlignment="Center" TextTrimming="CharacterEllipsis"
Foreground="{DynamicResource HighlightForegroundBrushKey}"
Style="{StaticResource HeaderTextStyleKey}" FontSize="16"></TextBlock>
<TextBlock
Foreground="{DynamicResource HighlightForegroundBrushKey}"
Style="{StaticResource DetailTextStyleKey}">
<Run Text="{Binding Source={x:Static models:ProductInfo.Title}, Mode=OneWay}"></Run>
<LineBreak/>
<Run Text="{Binding Source={x:Static models:ProductInfo.VersionString}, StringFormat=版本 {0}, Mode=OneWay}"></Run>
</TextBlock>
</StackPanel>
</DockPanel>
<StackPanel Grid.Row="1">
<Rectangle Height=".99"
Fill="{DynamicResource InactiveForegroundBrushKey}"
Margin="0,8" />
<DockPanel>
<TextBlock VerticalAlignment="Center" Foreground="{DynamicResource HighlightForegroundBrushKey}" FontFamily="{StaticResource DefaultFontFamilyKey}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding ProxyStatus,Source={x:Static services:ProxyService.Current},Mode=OneWay}" Value="False">
<Setter Property="Text" Value="{Binding Resources.StartService,Source={x:Static services:ResourceService.Current}, Mode=OneWay}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ProxyStatus,Source={x:Static services:ProxyService.Current},Mode=OneWay}" Value="True">
<Setter Property="Text" Value="{Binding Resources.StopService,Source={x:Static services:ResourceService.Current}, Mode=OneWay}"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<CheckBox x:Name="service" Style="{DynamicResource SliderCheckBox}" Margin="5" HorizontalAlignment="Right"
IsChecked="{Binding ProxyStatus,Source={x:Static services:ProxyService.Current},Mode=TwoWay}">
</CheckBox>
</DockPanel>
<!--<metro:LinkButton Text="{Binding Source={x:Static services:ResourceService.Current}, Path=Resources.Exit}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<livet:LivetCallMethodAction MethodName="ExitApplication"
MethodTarget="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</metro:LinkButton>-->
<Rectangle Height=".99"
Fill="{DynamicResource InactiveForegroundBrushKey}"
Margin="0,8" />
</StackPanel>
<StackPanel Grid.Row="2" VerticalAlignment="Bottom">
<ListBox Style="{StaticResource MetroListBox}" FontSize="12" FontFamily="{StaticResource CaptionFontFamilyKey}" BorderThickness="0" Margin="-8,0">
<ListBoxItem>
<Border Padding="8">
<StackPanel>
<TextBlock Text="{Binding Source={x:Static services:ResourceService.Current}, Path=Resources.CommunityFix}" VerticalAlignment="Center"></TextBlock>
</StackPanel>
</Border>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<livet:LivetCallMethodAction MethodName="NavigateTabItem"
MethodTarget="{Binding}" MethodParameter="1"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBoxItem>
<ListBoxItem>
<Border Padding="8">
<StackPanel>
<TextBlock Text="{Binding Source={x:Static services:ResourceService.Current}, Path=Resources.UserFastChange}" VerticalAlignment="Center"></TextBlock>
</StackPanel>
</Border>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<livet:LivetCallMethodAction MethodName="NavigateTabItem"
MethodTarget="{Binding}" MethodParameter="2"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBoxItem>
<ListBoxItem>
<Border Padding="8">
<StackPanel>
<TextBlock Text="{Binding Source={x:Static services:ResourceService.Current}, Path=Resources.GameList}" VerticalAlignment="Center"></TextBlock>
</StackPanel>
</Border>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<livet:LivetCallMethodAction MethodName="NavigateTabItem"
MethodTarget="{Binding}" MethodParameter="3"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBoxItem>
<ListBoxItem>
<Border Padding="8">
<StackPanel>
<TextBlock Text="{Binding Source={x:Static services:ResourceService.Current}, Path=Resources.SteamAuth}" VerticalAlignment="Center"></TextBlock>
</StackPanel>
</Border>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<livet:LivetCallMethodAction MethodName="NavigateTabItem"
MethodTarget="{Binding}" MethodParameter="4"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBoxItem>
<ListBoxItem IsEnabled="False" Margin="0,5">
<Rectangle Height=".99"
Fill="{DynamicResource InactiveForegroundBrushKey}"
Margin="8,0" />
</ListBoxItem>
<ListBoxItem>
<Border Padding="8">
<StackPanel>
<TextBlock Text="{Binding Source={x:Static services:ResourceService.Current}, Path=Resources.Settings}" VerticalAlignment="Center"></TextBlock>
</StackPanel>
</Border>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<livet:LivetCallMethodAction MethodName="NavigateTabItem"
MethodTarget="{Binding}" MethodParameter="-1"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBoxItem>
<ListBoxItem>
<Border Padding="8">
<StackPanel>
<TextBlock Text="{Binding Source={x:Static services:ResourceService.Current}, Path=Resources.Exit}" VerticalAlignment="Center"></TextBlock>
</StackPanel>
</Border>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<livet:LivetCallMethodAction MethodName="ExitApplication"
MethodTarget="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBoxItem>
</ListBox>
</StackPanel>
</Grid>
</Border>
</Grid>
</Border>
</UserControl>
@@ -1,97 +0,0 @@
<metro:MetroWindow x:Class="SteamTools.AuthTradeWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:livet="http://schemas.livet-mvvm.net/2011/wpf"
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:metro="http://schemes.grabacr.net/winfx/2014/controls"
xmlns:metro2="clr-namespace:MetroTrilithon.UI.Controls;assembly=MetroTrilithon.Desktop"
xmlns:viewModel="clr-namespace:SteamTools.ViewModels"
xmlns:prop="clr-namespace:SteamTools.Properties"
xmlns:services="clr-namespace:SteamTools.Services"
xmlns:input="clr-namespace:System.Windows.Input;assembly=PresentationCore"
xmlns:controls="clr-namespace:SteamTools.Views.Controls"
xmlns:models="clr-namespace:SteamTools.Models"
mc:Ignorable="d"
Width="600"
Height="400"
IsRestoringWindowPlacement="True"
WindowStartupLocation="CenterScreen"
Title="{Binding Title}"
Background="{DynamicResource ThemeBrushKey}"
Foreground="{DynamicResource ActiveForegroundBrushKey}"
FontFamily="{StaticResource DefaultFontFamilyKey}"
FontSize="16"
ResizeMode="NoResize"
UseLayoutRounding="True"
TextOptions.TextFormattingMode="Display"
SnapsToDevicePixels="True"
d:DataContext="{d:DesignInstance viewModel:ShowAuthWindowViewModel}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="ContentRendered">
<livet:LivetCallMethodAction MethodTarget="{Binding}"
MethodName="Initialize" />
</i:EventTrigger>
<i:EventTrigger EventName="Closed">
<livet:DataContextDisposeAction />
</i:EventTrigger>
<livet:InteractionMessageTrigger Messenger="{Binding Messenger, Mode=OneWay}"
MessageKey="Window.Activate">
<livet:WindowInteractionMessageAction InvokeActionOnlyWhenWindowIsActive="False" />
</livet:InteractionMessageTrigger>
<livet:InteractionMessageTrigger Messenger="{Binding Messenger}"
MessageKey="Window.Transition">
<livet:TransitionInteractionMessageAction InvokeActionOnlyWhenWindowIsActive="False"
IsOwned="False" />
</livet:InteractionMessageTrigger>
<livet:InteractionMessageTrigger Messenger="{Binding Messenger}"
MessageKey="Window.Transition.Child">
<livet:TransitionInteractionMessageAction InvokeActionOnlyWhenWindowIsActive="False"
IsOwned="True" />
</livet:InteractionMessageTrigger>
</i:Interaction.Triggers>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!--Title-->
<Border Grid.Row="0"
metro:MetroWindow.IsCaptionBar="True" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<metro:CaptionIcon Grid.Column="0" Padding="6,3">
<Image Source="pack://application:,,,/Resources/Asstes/app.ico" Width="32" Height="32"></Image>
</metro:CaptionIcon>
<TextBlock Grid.Column="1"
Grid.Row="0"
Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=Title}"
TextTrimming="CharacterEllipsis"
Foreground="{DynamicResource ForegroundBrushKey}"
FontSize="16"
VerticalAlignment="Center" />
<metro:SystemButtons Grid.Column="2"
Grid.Row="0"
VerticalAlignment="Top" />
</Grid>
</Border>
<!--Body-->
<Grid Grid.Row="1">
<Grid Margin="0,8,0,0">
</Grid>
</Grid>
</Grid>
</metro:MetroWindow>
-15
View File
@@ -1,15 +0,0 @@
// ==UserScript==
// @name GM
// @namespace
// @version 0.1
// @description 基础脚本框架
// @author 软妹币玩家
// @match *
// @enable true
// @grant GM_xmlhttpRequest
// ==/UserScript==
var unsafeWindow = this;
function GM_xmlhttpRequest(details)
{
}
+193
View File
@@ -0,0 +1,193 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31005.135
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Application.Repositories.sqlite-net-pcl", "System.Application.Repositories.sqlite-net-pcl\System.Application.Repositories.sqlite-net-pcl.csproj", "{512B0511-41AB-444D-BAD8-E19B7D3B52CB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Common.ClientLib", "System.Common.ClientLib\System.Common.ClientLib.csproj", "{8B9F2E93-B31B-4BA7-920D-732695A473E6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Common.CoreLib", "System.Common.CoreLib\System.Common.CoreLib.csproj", "{E7468FDD-75F7-4B08-BA47-B715BBCFCC11}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Common.ClientLib.Droid", "System.Common.ClientLib.Droid\System.Common.ClientLib.Droid.csproj", "{7C8D906E-426B-49AB-9072-178555370F62}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Common.ClientLib.iOS", "System.Common.ClientLib.iOS\System.Common.ClientLib.iOS.csproj", "{F8F6973C-5831-43D1-89C2-1AD543CE7408}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "0_Common", "0_Common", "{2D44BDCF-B70C-4C02-BDC8-4F1DD5066A75}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "0_Shared", "0_Shared", "{D40853F1-B3C5-418A-B1D3-E0FB70B2F394}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2_Client", "2_Client", "{9AF522B5-8923-41E6-8A0A-FAE8E8F83439}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4_Repositories.Implementation", "4_Repositories.Implementation", "{DA8EFCA8-5396-48C7-8DC0-CB28A09488D9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1_SteamTools", "1_SteamTools", "{B43459A1-709B-4623-9677-AAC2FEE4FBA3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Application.SteamTools.Services.CloudService.Models", "System.Application.SteamTools.Services.CloudService.Models\System.Application.SteamTools.Services.CloudService.Models.csproj", "{6CD71E14-5036-4A16-8084-4AD108D34FF7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Application.SteamTools.Services.CloudService", "System.Application.SteamTools.Services.CloudService\System.Application.SteamTools.Services.CloudService.csproj", "{65DE552F-5E62-4E4F-ADCB-F19AD3DB3F78}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1_ServerApiClient", "1_ServerApiClient", "{F7AFD002-B231-4A5E-B320-56EFC3210E2C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "0_Launch", "0_Launch", "{1460800B-D9ED-4147-B1E7-ABF502BEF59A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3_Test", "3_Test", "{EBC9DD0C-F7D0-4A00-B263-E69CF4E194F1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Common.UnitTest", "System.Common.UnitTest\System.Common.UnitTest.csproj", "{B9D4C8C7-BF96-417B-A7F8-9A67AE75A38B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Common.UnitTest.Droid", "System.Common.UnitTest.Droid\System.Common.UnitTest.Droid.csproj", "{0073A08E-6336-4C09-99F9-2E808889D715}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Common.UnitTest.Droid.App", "System.Common.UnitTest.Droid.App\System.Common.UnitTest.Droid.App.csproj", "{AD7B78B0-AE51-4FB7-9B11-4E22A2B538CA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Application.SteamTools", "System.Application.SteamTools\System.Application.SteamTools.csproj", "{66B7BFD6-6D4D-421B-BA5B-915348E53708}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Application.SteamTools.Client", "System.Application.SteamTools.Client\System.Application.SteamTools.Client.csproj", "{0A624994-B0A9-4F1F-B7D0-97FE2929936B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Application.SteamTools.Client.Desktop", "System.Application.SteamTools.Client.Desktop\System.Application.SteamTools.Client.Desktop.csproj", "{D1F15D97-802E-4AA3-A4A5-B890ABE32897}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Application.SteamTools.Client.Desktop.Avalonia.App", "System.Application.SteamTools.Client.Desktop.Avalonia.App\System.Application.SteamTools.Client.Desktop.Avalonia.App.csproj", "{2FFA5BCE-B3C3-46EA-8830-838C938BF814}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B4B548C1-9AFE-4EBB-96E4-990B57C0A953}"
ProjectSection(SolutionItems) = preProject
.gitignore = .gitignore
Directory.Build.props = Directory.Build.props
global.json = global.json
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Application.SteamTools.Client.Desktop.Avalonia", "System.Application.SteamTools.Client.Desktop.Avalonia\System.Application.SteamTools.Client.Desktop.Avalonia.csproj", "{4F09B6D1-3F83-45A0-AEC8-0F243E7CD263}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Application.SteamTools.Client.Desktop.Platform", "System.Application.SteamTools.Client.Desktop.Platform\System.Application.SteamTools.Client.Desktop.Platform.csproj", "{DD2973AE-D1FC-4307-AFE2-EE2945183D3D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Application.SteamTools.Client.Desktop.Platform.Linux", "System.Application.SteamTools.Client.Desktop.Platform.Linux\System.Application.SteamTools.Client.Desktop.Platform.Linux.csproj", "{D4CF08F5-8EAB-48FB-AAA3-1A221F7B2A82}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Application.SteamTools.Client.Desktop.Platform.Mac", "System.Application.SteamTools.Client.Desktop.Platform.Mac\System.Application.SteamTools.Client.Desktop.Platform.Mac.csproj", "{948C1EA8-12DB-4F8A-A190-8615DFBD9FE4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Application.SteamTools.Client.Desktop.Platform.Windows", "System.Application.SteamTools.Client.Desktop.Platform.Windows\System.Application.SteamTools.Client.Desktop.Platform.Windows.csproj", "{141532E1-540E-4E50-8723-96936C191281}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Win7Troubleshoot", "Win7Troubleshoot\Win7Troubleshoot.csproj", "{60530AF8-4790-4A85-BCE2-C5673E9C601B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{512B0511-41AB-444D-BAD8-E19B7D3B52CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{512B0511-41AB-444D-BAD8-E19B7D3B52CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{512B0511-41AB-444D-BAD8-E19B7D3B52CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{512B0511-41AB-444D-BAD8-E19B7D3B52CB}.Release|Any CPU.Build.0 = Release|Any CPU
{8B9F2E93-B31B-4BA7-920D-732695A473E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8B9F2E93-B31B-4BA7-920D-732695A473E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8B9F2E93-B31B-4BA7-920D-732695A473E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8B9F2E93-B31B-4BA7-920D-732695A473E6}.Release|Any CPU.Build.0 = Release|Any CPU
{E7468FDD-75F7-4B08-BA47-B715BBCFCC11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E7468FDD-75F7-4B08-BA47-B715BBCFCC11}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E7468FDD-75F7-4B08-BA47-B715BBCFCC11}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E7468FDD-75F7-4B08-BA47-B715BBCFCC11}.Release|Any CPU.Build.0 = Release|Any CPU
{7C8D906E-426B-49AB-9072-178555370F62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C8D906E-426B-49AB-9072-178555370F62}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C8D906E-426B-49AB-9072-178555370F62}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C8D906E-426B-49AB-9072-178555370F62}.Release|Any CPU.Build.0 = Release|Any CPU
{F8F6973C-5831-43D1-89C2-1AD543CE7408}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F8F6973C-5831-43D1-89C2-1AD543CE7408}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F8F6973C-5831-43D1-89C2-1AD543CE7408}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F8F6973C-5831-43D1-89C2-1AD543CE7408}.Release|Any CPU.Build.0 = Release|Any CPU
{6CD71E14-5036-4A16-8084-4AD108D34FF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6CD71E14-5036-4A16-8084-4AD108D34FF7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6CD71E14-5036-4A16-8084-4AD108D34FF7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6CD71E14-5036-4A16-8084-4AD108D34FF7}.Release|Any CPU.Build.0 = Release|Any CPU
{65DE552F-5E62-4E4F-ADCB-F19AD3DB3F78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{65DE552F-5E62-4E4F-ADCB-F19AD3DB3F78}.Debug|Any CPU.Build.0 = Debug|Any CPU
{65DE552F-5E62-4E4F-ADCB-F19AD3DB3F78}.Release|Any CPU.ActiveCfg = Release|Any CPU
{65DE552F-5E62-4E4F-ADCB-F19AD3DB3F78}.Release|Any CPU.Build.0 = Release|Any CPU
{B9D4C8C7-BF96-417B-A7F8-9A67AE75A38B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B9D4C8C7-BF96-417B-A7F8-9A67AE75A38B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B9D4C8C7-BF96-417B-A7F8-9A67AE75A38B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B9D4C8C7-BF96-417B-A7F8-9A67AE75A38B}.Release|Any CPU.Build.0 = Release|Any CPU
{0073A08E-6336-4C09-99F9-2E808889D715}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0073A08E-6336-4C09-99F9-2E808889D715}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0073A08E-6336-4C09-99F9-2E808889D715}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0073A08E-6336-4C09-99F9-2E808889D715}.Release|Any CPU.Build.0 = Release|Any CPU
{AD7B78B0-AE51-4FB7-9B11-4E22A2B538CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AD7B78B0-AE51-4FB7-9B11-4E22A2B538CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AD7B78B0-AE51-4FB7-9B11-4E22A2B538CA}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{AD7B78B0-AE51-4FB7-9B11-4E22A2B538CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AD7B78B0-AE51-4FB7-9B11-4E22A2B538CA}.Release|Any CPU.Build.0 = Release|Any CPU
{AD7B78B0-AE51-4FB7-9B11-4E22A2B538CA}.Release|Any CPU.Deploy.0 = Release|Any CPU
{66B7BFD6-6D4D-421B-BA5B-915348E53708}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66B7BFD6-6D4D-421B-BA5B-915348E53708}.Debug|Any CPU.Build.0 = Debug|Any CPU
{66B7BFD6-6D4D-421B-BA5B-915348E53708}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66B7BFD6-6D4D-421B-BA5B-915348E53708}.Release|Any CPU.Build.0 = Release|Any CPU
{0A624994-B0A9-4F1F-B7D0-97FE2929936B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0A624994-B0A9-4F1F-B7D0-97FE2929936B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0A624994-B0A9-4F1F-B7D0-97FE2929936B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0A624994-B0A9-4F1F-B7D0-97FE2929936B}.Release|Any CPU.Build.0 = Release|Any CPU
{D1F15D97-802E-4AA3-A4A5-B890ABE32897}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D1F15D97-802E-4AA3-A4A5-B890ABE32897}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D1F15D97-802E-4AA3-A4A5-B890ABE32897}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D1F15D97-802E-4AA3-A4A5-B890ABE32897}.Release|Any CPU.Build.0 = Release|Any CPU
{2FFA5BCE-B3C3-46EA-8830-838C938BF814}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2FFA5BCE-B3C3-46EA-8830-838C938BF814}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2FFA5BCE-B3C3-46EA-8830-838C938BF814}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2FFA5BCE-B3C3-46EA-8830-838C938BF814}.Release|Any CPU.Build.0 = Release|Any CPU
{4F09B6D1-3F83-45A0-AEC8-0F243E7CD263}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4F09B6D1-3F83-45A0-AEC8-0F243E7CD263}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4F09B6D1-3F83-45A0-AEC8-0F243E7CD263}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4F09B6D1-3F83-45A0-AEC8-0F243E7CD263}.Release|Any CPU.Build.0 = Release|Any CPU
{DD2973AE-D1FC-4307-AFE2-EE2945183D3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DD2973AE-D1FC-4307-AFE2-EE2945183D3D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DD2973AE-D1FC-4307-AFE2-EE2945183D3D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DD2973AE-D1FC-4307-AFE2-EE2945183D3D}.Release|Any CPU.Build.0 = Release|Any CPU
{D4CF08F5-8EAB-48FB-AAA3-1A221F7B2A82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D4CF08F5-8EAB-48FB-AAA3-1A221F7B2A82}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D4CF08F5-8EAB-48FB-AAA3-1A221F7B2A82}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4CF08F5-8EAB-48FB-AAA3-1A221F7B2A82}.Release|Any CPU.Build.0 = Release|Any CPU
{948C1EA8-12DB-4F8A-A190-8615DFBD9FE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{948C1EA8-12DB-4F8A-A190-8615DFBD9FE4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{948C1EA8-12DB-4F8A-A190-8615DFBD9FE4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{948C1EA8-12DB-4F8A-A190-8615DFBD9FE4}.Release|Any CPU.Build.0 = Release|Any CPU
{141532E1-540E-4E50-8723-96936C191281}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{141532E1-540E-4E50-8723-96936C191281}.Debug|Any CPU.Build.0 = Debug|Any CPU
{141532E1-540E-4E50-8723-96936C191281}.Release|Any CPU.ActiveCfg = Release|Any CPU
{141532E1-540E-4E50-8723-96936C191281}.Release|Any CPU.Build.0 = Release|Any CPU
{60530AF8-4790-4A85-BCE2-C5673E9C601B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{60530AF8-4790-4A85-BCE2-C5673E9C601B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{60530AF8-4790-4A85-BCE2-C5673E9C601B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{60530AF8-4790-4A85-BCE2-C5673E9C601B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{512B0511-41AB-444D-BAD8-E19B7D3B52CB} = {DA8EFCA8-5396-48C7-8DC0-CB28A09488D9}
{8B9F2E93-B31B-4BA7-920D-732695A473E6} = {9AF522B5-8923-41E6-8A0A-FAE8E8F83439}
{E7468FDD-75F7-4B08-BA47-B715BBCFCC11} = {D40853F1-B3C5-418A-B1D3-E0FB70B2F394}
{7C8D906E-426B-49AB-9072-178555370F62} = {9AF522B5-8923-41E6-8A0A-FAE8E8F83439}
{F8F6973C-5831-43D1-89C2-1AD543CE7408} = {9AF522B5-8923-41E6-8A0A-FAE8E8F83439}
{D40853F1-B3C5-418A-B1D3-E0FB70B2F394} = {2D44BDCF-B70C-4C02-BDC8-4F1DD5066A75}
{9AF522B5-8923-41E6-8A0A-FAE8E8F83439} = {2D44BDCF-B70C-4C02-BDC8-4F1DD5066A75}
{DA8EFCA8-5396-48C7-8DC0-CB28A09488D9} = {2D44BDCF-B70C-4C02-BDC8-4F1DD5066A75}
{6CD71E14-5036-4A16-8084-4AD108D34FF7} = {F7AFD002-B231-4A5E-B320-56EFC3210E2C}
{65DE552F-5E62-4E4F-ADCB-F19AD3DB3F78} = {F7AFD002-B231-4A5E-B320-56EFC3210E2C}
{F7AFD002-B231-4A5E-B320-56EFC3210E2C} = {B43459A1-709B-4623-9677-AAC2FEE4FBA3}
{1460800B-D9ED-4147-B1E7-ABF502BEF59A} = {B43459A1-709B-4623-9677-AAC2FEE4FBA3}
{EBC9DD0C-F7D0-4A00-B263-E69CF4E194F1} = {2D44BDCF-B70C-4C02-BDC8-4F1DD5066A75}
{B9D4C8C7-BF96-417B-A7F8-9A67AE75A38B} = {EBC9DD0C-F7D0-4A00-B263-E69CF4E194F1}
{0073A08E-6336-4C09-99F9-2E808889D715} = {EBC9DD0C-F7D0-4A00-B263-E69CF4E194F1}
{AD7B78B0-AE51-4FB7-9B11-4E22A2B538CA} = {EBC9DD0C-F7D0-4A00-B263-E69CF4E194F1}
{66B7BFD6-6D4D-421B-BA5B-915348E53708} = {B43459A1-709B-4623-9677-AAC2FEE4FBA3}
{0A624994-B0A9-4F1F-B7D0-97FE2929936B} = {B43459A1-709B-4623-9677-AAC2FEE4FBA3}
{D1F15D97-802E-4AA3-A4A5-B890ABE32897} = {B43459A1-709B-4623-9677-AAC2FEE4FBA3}
{2FFA5BCE-B3C3-46EA-8830-838C938BF814} = {1460800B-D9ED-4147-B1E7-ABF502BEF59A}
{4F09B6D1-3F83-45A0-AEC8-0F243E7CD263} = {B43459A1-709B-4623-9677-AAC2FEE4FBA3}
{DD2973AE-D1FC-4307-AFE2-EE2945183D3D} = {B43459A1-709B-4623-9677-AAC2FEE4FBA3}
{D4CF08F5-8EAB-48FB-AAA3-1A221F7B2A82} = {B43459A1-709B-4623-9677-AAC2FEE4FBA3}
{948C1EA8-12DB-4F8A-A190-8615DFBD9FE4} = {B43459A1-709B-4623-9677-AAC2FEE4FBA3}
{141532E1-540E-4E50-8723-96936C191281} = {B43459A1-709B-4623-9677-AAC2FEE4FBA3}
{60530AF8-4790-4A85-BCE2-C5673E9C601B} = {1460800B-D9ED-4147-B1E7-ABF502BEF59A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3833E7C5-69BC-4CB3-92CE-A8854AA35D8A}
EndGlobalSection
EndGlobal
@@ -0,0 +1,187 @@
using Polly;
using SQLite;
using System.Application.Entities;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
namespace System.Application.Repositories
{
/// <summary>
/// 由 sqlite-net-pcl 实现的仓储层
/// </summary>
public abstract class Repository : IRepository
{
#region https://codetraveler.io/2019/11/26/efficiently-initializing-sqlite-database/
static string? mDataBaseDirectory;
/// <summary>
/// 获取或设定数据库目录,默认值为 <see cref="IOPath.AppDataDirectory"/>
/// </summary>
public static string DataBaseDirectory
{
get
{
if (string.IsNullOrWhiteSpace(mDataBaseDirectory)) mDataBaseDirectory = IOPath.AppDataDirectory;
return mDataBaseDirectory;
}
set
{
mDataBaseDirectory = value;
}
}
static SQLiteAsyncConnection GetConnection()
{
var dbPath = DataBaseDirectory;
IOPath.DirCreateByNotExists(dbPath);
dbPath = Path.Combine(dbPath, "application.dbf");
return new SQLiteAsyncConnection(dbPath, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create | SQLiteOpenFlags.SharedCache);
}
static readonly Lazy<SQLiteAsyncConnection> dbConnection = new Lazy<SQLiteAsyncConnection>(GetConnection);
static SQLiteAsyncConnection DbConnection => dbConnection.Value;
protected static async ValueTask<SQLiteAsyncConnection> GetDbConnection<T>()
{
if (!DbConnection.TableMappings.Any(x => x.MappedType == typeof(T)))
{
// On sqlite-net v1.6.0+, enabling write-ahead logging allows for faster database execution
await DbConnection.EnableWriteAheadLoggingAsync().ConfigureAwait(false);
await DbConnection.CreateTablesAsync(CreateFlags.None, typeof(T)).ConfigureAwait(false);
}
return DbConnection;
}
protected static Task<T> AttemptAndRetry<T>(Func<Task<T>> action, int numRetries = 10)
{
return Policy.Handle<SQLiteException>().WaitAndRetryAsync(numRetries, pollyRetryAttempt).ExecuteAsync(action);
static TimeSpan pollyRetryAttempt(int attemptNumber) => TimeSpan.FromMilliseconds(Math.Pow(2, attemptNumber));
}
#endregion
}
/// <inheritdoc cref="Repository"/>
public abstract class Repository<TEntity> : Repository, IRepository<TEntity> where TEntity : class, new()
{
protected static ValueTask<SQLiteAsyncConnection> GetDbConnection() => GetDbConnection<TEntity>();
#region 增(Insert Funs) 立即执行并返回受影响的行数
public virtual async Task<int> InsertAsync(TEntity entity)
{
var dbConnection = await GetDbConnection().ConfigureAwait(false);
return await AttemptAndRetry(() => dbConnection.InsertAsync(entity)).ConfigureAwait(false);
}
public virtual async Task<int> InsertRangeAsync(IEnumerable<TEntity> entities)
{
var dbConnection = await GetDbConnection().ConfigureAwait(false);
return await AttemptAndRetry(() => dbConnection.InsertAllAsync(entities)).ConfigureAwait(false);
}
#endregion
#region 删(Delete Funs) 立即执行并返回受影响的行数
public virtual async Task<int> DeleteAsync(TEntity entity)
{
var dbConnection = await GetDbConnection().ConfigureAwait(false);
return await AttemptAndRetry(() => dbConnection.DeleteAsync(entity)).ConfigureAwait(false);
}
#endregion
#region 改(Update Funs) 立即执行并返回受影响的行数
public virtual async Task<int> UpdateAsync(TEntity entity)
{
var dbConnection = await GetDbConnection().ConfigureAwait(false);
return await AttemptAndRetry(() => dbConnection.UpdateAsync(entity)).ConfigureAwait(false);
}
public virtual async Task<int> UpdateRangeAsync(IEnumerable<TEntity> entities)
{
var dbConnection = await GetDbConnection().ConfigureAwait(false);
return await AttemptAndRetry(() => dbConnection.UpdateAllAsync(entities)).ConfigureAwait(false);
}
#endregion
#region 查(通用查询)
public virtual async Task<TEntity?> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate)
{
var dbConnection = await GetDbConnection().ConfigureAwait(false);
return await AttemptAndRetry(() => dbConnection.FindAsync(predicate)).ConfigureAwait(false);
}
#endregion
}
/// <inheritdoc cref="IRepository"/>
public abstract class Repository<TEntity, TPrimaryKey> : Repository<TEntity>, IRepository<TEntity, TPrimaryKey>
where TEntity : class, IEntity<TPrimaryKey>, new()
where TPrimaryKey : IEquatable<TPrimaryKey>
{
object IGetPrimaryKey<TEntity>.GetPrimaryKey(TEntity entity) => GetPrimaryKey(entity);
protected TPrimaryKey GetPrimaryKey(TEntity entity)
{
IGetPrimaryKey<TEntity, TPrimaryKey> getPrimaryKey = this;
return getPrimaryKey.GetPrimaryKey(entity);
}
#region 删(Delete Funs) 立即执行并返回受影响的行数
public override Task<int> DeleteAsync(TEntity entity)
{
var primaryKey = GetPrimaryKey(entity);
return DeleteAsync(primaryKey);
}
public virtual async Task<int> DeleteAsync(TPrimaryKey primaryKey)
{
var dbConnection = await GetDbConnection().ConfigureAwait(false);
return await AttemptAndRetry(() => dbConnection.DeleteAsync<TEntity>(primaryKey)).ConfigureAwait(false);
}
#endregion
#region 查(通用查询)
public virtual async ValueTask<TEntity?> FindAsync(TPrimaryKey primaryKey)
{
if (IRepository<TEntity, TPrimaryKey>.IsDefault(primaryKey)) return default;
var dbConnection = await GetDbConnection().ConfigureAwait(false);
return await AttemptAndRetry(() => dbConnection.FindAsync<TEntity>(primaryKey)).ConfigureAwait(false);
}
public virtual async ValueTask<bool> ExistAsync(TPrimaryKey primaryKey)
{
if (IRepository<TEntity, TPrimaryKey>.IsDefault(primaryKey)) return false;
var dbConnection = await GetDbConnection().ConfigureAwait(false);
var count = await AttemptAndRetry(CountAsync).ConfigureAwait(false);
return count > 0;
Task<int> CountAsync() => dbConnection.Table<TEntity>().CountAsync(IRepository<TEntity, TPrimaryKey>.LambdaEqualId(primaryKey));
}
#endregion
#region 增或改(InsertOrUpdate Funs) 立即执行并返回受影响的行数
public virtual async Task<(int rowCount, DbRowExecResult result)> InsertOrUpdateAsync(TEntity entity)
{
var dbConnection = await GetDbConnection().ConfigureAwait(false);
var rowCount = await AttemptAndRetry(() => dbConnection.InsertOrReplaceAsync(entity)).ConfigureAwait(false);
return (rowCount, DbRowExecResult.InsertOrUpdate);
}
#endregion
}
}
@@ -0,0 +1,64 @@
using SQLite;
using System.Application.Models;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
namespace System
{
public static class AsyncTableQueryExtensions
{
#region WhereOr
/// <inheritdoc cref="QueryableExtensions.WhereOr{T}(IReadOnlyList{Expression{Func{T, bool}}})"/>
public static AsyncTableQuery<T> WhereOr<T>(this AsyncTableQuery<T> source, IReadOnlyList<Expression<Func<T, bool>>> predicates) where T : new()
{
var predicate = ExpressionHelper.WhereOr(predicates);
return source.Where(predicate);
}
/// <inheritdoc cref="QueryableExtensions.WhereOr{T}(IReadOnlyList{Expression{Func{T, bool}}})"/>
public static AsyncTableQuery<T> WhereOr<T>(this AsyncTableQuery<T> source, IEnumerable<Expression<Func<T, bool>>> predicates) where T : new()
=> source.WhereOr(predicates.ToArray());
/// <inheritdoc cref="QueryableExtensions.WhereOr{T}(IReadOnlyList{Expression{Func{T, bool}}})"/>
public static AsyncTableQuery<T> WhereOr<T>(this AsyncTableQuery<T> source, params Expression<Func<T, bool>>[] predicates) where T : new()
{
IReadOnlyList<Expression<Func<T, bool>>> _predicates = predicates;
return source.WhereOr(_predicates);
}
#endregion
#region Paging
/// <summary>
/// 分页查询,调用此方法前必须进行排序
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="source"></param>
/// <param name="current"></param>
/// <param name="pageSize"></param>
/// <returns></returns>
public static async Task<PagedModel<TEntity>> PagingAsync<TEntity>(
this AsyncTableQuery<TEntity> source,
int current = IPagedModel.DefaultCurrent,
int pageSize = IPagedModel.DefaultPageSize) where TEntity : new()
{
var skipCount = (pageSize - 1) * pageSize;
var total = await source.CountAsync();
var dataSource = await source.Skip(skipCount).Take(pageSize).ToListAsync();
var pagedModel = new PagedModel<TEntity>
{
Current = current,
PageSize = pageSize,
Total = total,
DataSource = dataSource,
};
return pagedModel;
}
#endregion
}
}
@@ -0,0 +1,100 @@
using System.Application.Columns;
using System.Runtime.CompilerServices;
namespace System
{
/// <summary>
/// SQL语句字符串常量,使用字符串拼接时应注意防止 SQL注入攻击
/// <para>EFCore 可采用 <see cref="FormattableString"/> 参数化传入参数</para>
/// </summary>
public static partial class SQLStrings
{
/// <summary>
/// "select * from "
/// <para>查询所有列</para>
/// </summary>
public const string SelectALLFrom = "select * from ";
/// <summary>
/// "select count(Id) from "
/// <para>查询总数,仅Id列</para>
/// </summary>
public const string SelectCountFrom = "select count(Id) from ";
/// <summary>
/// "select count({0}) from "
/// <para>查询总数,仅某一列</para>
/// <para>注意:参数仅使用列名固定值,不可传递变量,防止SQL注入攻击</para>
/// </summary>
public const string SelectCountFrom_0 = "select count({0}) from ";
/// <summary>
/// " order by CreationTime desc"
/// <para>根据 创建时间 倒序</para>
/// </summary>
public const string OrderByCreationTimeDescending = " order by CreationTime desc";
/// <summary>
/// " order by ReceiveTime, CreationTime desc"
/// <para>根据 接收时间, 创建时间 倒序</para>
/// </summary>
public const string OrderByReceiveTimeThenByCreationTimeDescending = " order by ReceiveTime, CreationTime desc";
/// <summary>
/// " order by {0} desc"
/// <para>根据 某一列 倒序</para>
/// <para>注意:参数仅使用列名固定值,不可传递变量,防止SQL注入攻击</para>
/// </summary>
public const string OrderBy_Descending_0 = " order by {0} desc";
/// <summary>
/// "delete from "
/// </summary>
public const string DeleteFrom = "delete from ";
/// <summary>
/// " where Id = {0}"
/// <para>注意:参数仅使用列名固定值,不可传递变量,防止SQL注入攻击</para>
/// </summary>
public const string WhereIdEqual_0 = " where Id = {0}";
/// <summary>
/// "delete from {tableName} where Id = {0}"
/// </summary>
/// <param name="tableName"></param>
/// <param name="id"></param>
/// <returns></returns>
public static FormattableString DeleteFromTableNameWhereIdEqual(string tableName, object id)
{
var sql = DeleteFrom + tableName + WhereIdEqual_0;
return FormattableStringFactory.Create(sql, id);
}
/// <summary>
/// "update from {tableName} set IsSoftDeleted = 1 where Id = {0}"
/// </summary>
/// <param name="tableName"></param>
/// <param name="id"></param>
/// <returns></returns>
public static FormattableString SoftDeleteFromTableNameWhereIdEqual(string tableName, object id)
{
var sql = UpdateFrom + tableName + " set " + nameof(ISoftDeleted.SoftDeleted) + " = 1" + WhereIdEqual_0;
return FormattableStringFactory.Create(sql, id);
}
/// <summary>
/// "update from "
/// </summary>
public const string UpdateFrom = "update from ";
/// <summary>
/// " where Id in ("
/// </summary>
public const string WhereInIds_ = " where Id in (";
/// <summary>
/// 右括号
/// </summary>
public const char RightBracket = ')';
}
}
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<RootNamespace>System</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\System.Common.CoreLib\Properties\AssemblyInfo.cs">
<Link>Properties\AssemblyInfo.cs</Link>
</Compile>
<Compile Include="..\System.Common.CoreLib\Properties\InternalsVisibleTo.cs">
<Link>Properties\InternalsVisibleTo.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\System.Common.CoreLib\System.Common.CoreLib.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="sqlite-net-pcl" Version="1.7.335" />
<PackageReference Include="Polly" Version="7.2.1" />
</ItemGroup>
</Project>
@@ -0,0 +1,17 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="clr-namespace:System.Application.UI"
x:Class="System.Application.UI.App">
<Application.DataTemplates>
<ui:ViewLocator/>
</Application.DataTemplates>
<Application.Styles>
<FluentTheme Mode="Dark" />
<StyleInclude Source="/Styles/Styles.xaml" />
<StyleInclude Source="/Styles/SideBar.xaml" />
<!--<StyleInclude Source="avares://AvaloniaEdit/AvaloniaEdit.xaml"/>-->
<Style Selector="Window">
<Setter Property="Icon" Value="/Assets/Icon.ico"/>
</Style>
</Application.Styles>
</Application>
@@ -0,0 +1,36 @@
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using System.Application.UI.ViewModels;
using System.Application.UI.Views;
using AvaloniaApplication = Avalonia.Application;
namespace System.Application.UI
{
public class App : AvaloniaApplication
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
// ÔÚUIÔ¤ÀÀÖУ¬ApplicationLifetime Ϊ null
ViewModelBase.IsInDesignMode = ApplicationLifetime == null;
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = new MainWindow
{
DataContext = DataContext = DI.Get<MainWindowViewModel>(),
};
desktop.ShutdownMode = ShutdownMode.OnMainWindowClose;
}
base.OnFrameworkInitializationCompleted();
}
public static async void SetClipboardText(string s) => await Current.Clipboard.SetTextAsync(s);
}
}

Before

Width:  |  Height:  |  Size: 364 KiB

After

Width:  |  Height:  |  Size: 364 KiB

@@ -0,0 +1,46 @@
using Avalonia.Controls.Primitives;
using Avalonia.Platform;
using Avalonia.Styling;
using System;
// ReSharper disable once CheckNamespace
namespace Avalonia.Controls
{
public class FluentWindow : Window, IStyleable
{
Type IStyleable.StyleKey => typeof(Window);
public FluentWindow()
{
ExtendClientAreaToDecorationsHint = true;
ExtendClientAreaTitleBarHeightHint = -1;
TransparencyLevelHint = WindowTransparencyLevel.AcrylicBlur;
this.GetObservable(WindowStateProperty)
.Subscribe(x =>
{
PseudoClasses.Set(":maximized", x == WindowState.Maximized);
PseudoClasses.Set(":fullscreen", x == WindowState.FullScreen);
});
this.GetObservable(IsExtendedIntoWindowDecorationsProperty)
.Subscribe(x =>
{
if (!x)
{
SystemDecorations = SystemDecorations.Full;
TransparencyLevelHint = WindowTransparencyLevel.Blur;
}
});
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
ExtendClientAreaChromeHints =
ExtendClientAreaChromeHints.PreferSystemChrome |
ExtendClientAreaChromeHints.OSXThickTitleBar;
}
}
}
@@ -0,0 +1,36 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:System.Application.UI.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="System.Application.UI.Pages.SettingsPage">
<Design.DataContext>
<vm:MainWindowViewModel/>
</Design.DataContext>
<StackPanel HorizontalAlignment="Stretch" Margin="{StaticResource PageMargin}" Background="Transparent" Spacing="20">
<Grid RowDefinitions="Auto, Auto, Auto, Auto, Auto, Auto">
<StackPanel Orientation="Vertical"
HorizontalAlignment="Stretch"
Spacing="16">
<TextBlock FontSize="18" Text="{Binding Path=SettingsPage.Settings_General}"/>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Path=SettingsPage.Language}" Margin="0 0 0 20"/>
<ComboBox HorizontalAlignment="Stretch"
SelectedIndex="{Binding Path=SettingsPage.CurrentLanguageIndex}"
Items="{Binding Path=SettingsPage.Languages}" />
</StackPanel>
<Border Background="{DynamicResource SystemControlHighlightBaseLowBrush}" BorderThickness="1" Margin="15"/>
</StackPanel>
<StackPanel Orientation="Vertical"
HorizontalAlignment="Stretch"
Spacing="16"
Grid.Row="1">
<TextBlock FontSize="18" Text="{Binding Path=SettingsPage.Settings_Auth}"/>
<StackPanel Orientation="Vertical">
</StackPanel>
<Border Background="{DynamicResource SystemControlHighlightBaseLowBrush}" BorderThickness="1" Margin="15"/>
</StackPanel>
</Grid>
</StackPanel>
</UserControl>
@@ -0,0 +1,19 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using System.Application.UI.ViewModels;
namespace System.Application.UI.Pages
{
public class SettingsPage : UserControl
{
public SettingsPage()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}
@@ -0,0 +1,44 @@
using Avalonia;
using Avalonia.ReactiveUI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System.Application.UI.ViewModels;
namespace System.Application.UI
{
static class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
static void Main(string[] args)
{
ModelValidatorProvider.Init();
DI.Init(ConfigureServices);
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
}
// Avalonia configuration, don't remove; also used by visual designer.
static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.With(new SkiaOptions { MaxGpuResourceSizeBytes = 8096000 })
.With(new Win32PlatformOptions { AllowEglInitialization = true })
.LogToTrace()
.UseReactiveUI();
static void ConfigureServices(IServiceCollection services)
{
services.AddLogging(l => l.AddProvider(NullLoggerProvider.Instance));
services.AddDesktopPlatformService();
services.TryAddModelValidator();
services.AddLocalizationService();
services.AddMainThreadPlatformService();
services.AddViewModelCollectionService();
services.AddViewModel<MainWindowViewModel>();
services.AddViewModel<SettingsPageViewModel>();
}
}
}
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<DefineConstants>PUBLISH;$(DefineConstants)</DefineConstants>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>bin\Release\Publish\linux-x64</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>true</PublishSingleFile>
<PublishTrimmed>True</PublishTrimmed>
<TrimMode>link</TrimMode>
<SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
<DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols>
</PropertyGroup>
</Project>
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<DefineConstants>PUBLISH;$(DefineConstants)</DefineConstants>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>bin\Release\Publish\osx-x64</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>true</PublishSingleFile>
<PublishTrimmed>True</PublishTrimmed>
<TrimMode>link</TrimMode>
<SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
<DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols>
</PropertyGroup>
</Project>
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<DefineConstants>PUBLISH;$(DefineConstants)</DefineConstants>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>bin\Release\Publish\win-x64</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>true</PublishSingleFile>
<PublishReadyToRun>true</PublishReadyToRun>
<!--可以通过将应用程序集编译为 ReadyToRun (R2R) 格式来改进 .NET Core 应用程序的启动时间和延迟。 R2R 是一种预先 (AOT) 编译形式 https://docs.microsoft.com/zh-cn/dotnet/core/deploying/ready-to-run-->
<PublishTrimmed>True</PublishTrimmed>
<TrimMode>link</TrimMode>
<TrimmerRemoveSymbols>true</TrimmerRemoveSymbols>
<!--剪裁框架库功能 https://docs.microsoft.com/zh-cn/dotnet/core/deploying/trimming-options#trimming-framework-library-features-->
<DebuggerSupport>false</DebuggerSupport>
<EnableUnsafeBinaryFormatterSerialization>false</EnableUnsafeBinaryFormatterSerialization>
<EnableUnsafeUTF7Encoding>false</EnableUnsafeUTF7Encoding>
<SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
<EventSourceSupport>false</EventSourceSupport>
<HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>
<UseSystemResourceKeys>true</UseSystemResourceKeys>
<DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols>
</PropertyGroup>
</Project>
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!-- UAC 清单选项
如果想要更改 Windows 用户帐户控制级别,请使用
以下节点之一替换 requestedExecutionLevel 节点。n
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
<requestedExecutionLevel level="highestAvailable" uiAccess="false"/>
指定 requestedExecutionLevel 元素将禁用文件和注册表虚拟化。
如果你的应用程序需要此虚拟化来实现向后兼容性,则删除此
元素。
-->
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- 设计此应用程序与其一起工作且已针对此应用程序进行测试的
Windows 版本的列表。取消评论适当的元素,
Windows 将自动选择最兼容的环境。 -->
<!-- Windows Vista -->
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
<!--Windows 7-->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!--Windows 8-->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!--Windows 8.1-->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!--Windows 10-->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
<!-- 指示该应用程序可以感知 DPI 且 Windows 在 DPI 较高时将不会对其进行
自动缩放。Windows Presentation Foundation (WPF)应用程序自动感知 DPI,无需
选择加入。选择加入此设置的 Windows 窗体应用程序(目标设定为 .NET Framework 4.6 )还应
在其 app.config 中将 "EnableWindowsFormsHighDpiAutoResizing" 设置设置为 "true"。-->
<!--
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
</windowsSettings>
</application>
-->
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
</windowsSettings>
</application>
<!-- 启用 Windows 公共控件和对话框的主题(Windows XP 和更高版本) -->
<!--
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"/>
</dependentAssembly>
</dependency>
-->
</assembly>
@@ -0,0 +1,74 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<Border Padding="20">
<TabControl Classes="sidebar">
<TabItem Header="Item1"/>
<TabItem Header="Item2"/>
</TabControl>
</Border>
</Design.PreviewWith>
<Style Selector="TabControl.sidebar">
<Setter Property="TabStripPlacement" Value="Left"/>
<Setter Property="Padding" Value="0 0 0 0"/>
<Setter Property="Background" Value="{x:Null}"/>
<Setter Property="Template">
<ControlTemplate>
<Border
Margin="{TemplateBinding Margin}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<DockPanel>
<ScrollViewer Width="240" Margin="0 30 0 0"
Name="PART_ScrollViewer"
HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}"
Background="{TemplateBinding Background}"
DockPanel.Dock="Left">
<ItemsPresenter
Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}">
</ItemsPresenter>
</ScrollViewer>
<ContentControl Content="{TemplateBinding Tag}" HorizontalContentAlignment="Right" DockPanel.Dock="Bottom"/>
<ScrollViewer Background="{x:Null}"
HorizontalScrollBarVisibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SelectedItem.(ScrollViewer.HorizontalScrollBarVisibility)}"
VerticalScrollBarVisibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SelectedItem.(ScrollViewer.VerticalScrollBarVisibility)}">
<ContentPresenter
Name="PART_SelectedContentHost"
Margin="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding SelectedContent}"
ContentTemplate="{TemplateBinding SelectedContentTemplate}">
</ContentPresenter>
</ScrollViewer>
</DockPanel>
</Border>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="TabControl.sidebar > TabItem">
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="16"/>
<Setter Property="Width" Value="240" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="(ScrollViewer.HorizontalScrollBarVisibility)" Value="Auto"/>
<Setter Property="(ScrollViewer.VerticalScrollBarVisibility)" Value="Auto"/>
</Style>
<Style Selector="TabControl.sidebar > TabItem:selected /template/ Border#PART_SelectedPipe">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="TabControl.sidebar > TabItem:selected">
<Setter Property="Background" Value="#1fffffff"/>
</Style>
<Style Selector="TabControl.sidebar > TabItem:pointerover /template/ Border#PART_LayoutRoot">
<Setter Property="Background" Value="#3fffffff"/>
</Style>
</Styles>
@@ -0,0 +1,18 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<Border Padding="20">
<StackPanel Spacing="5">
<TextBlock Text="Code Font Family" FontFamily="{StaticResource CodeFontFamily}" />
</StackPanel>
</Border>
</Design.PreviewWith>
<Styles.Resources>
<Thickness x:Key="PageMargin">40 0 40 0</Thickness>
<!--<FontFamily x:Key="CodeFontFamily">avares://Steam++/Assets/Fonts#Source Code Pro</FontFamily>-->
</Styles.Resources>
<Style Selector="TextBlock.code">
<!--<Setter Property="FontFamily" Value="{StaticResource CodeFontFamily}" />-->
</Style>
</Styles>
@@ -0,0 +1,77 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<SignAssembly>false</SignAssembly>
<!--(SignAssembly)对此程序集进行签名会导致编译失败(CompileAvaloniaXamlTask)-->
<RootNamespace>System.Application.UI</RootNamespace>
<AssemblyName>Steam++</AssemblyName>
<ApplicationIcon>Assets\Icon.ico</ApplicationIcon>
<ApplicationManifest>Properties\app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\System.Common.CoreLib\Properties\AssemblyInfo.cs">
<Link>Properties\AssemblyInfo.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\System.Application.SteamTools.Client.Desktop.Avalonia\System.Application.SteamTools.Client.Desktop.Avalonia.csproj" />
<ProjectReference Include="..\System.Application.SteamTools.Client.Desktop.Platform\System.Application.SteamTools.Client.Desktop.Platform.csproj" />
<ProjectReference Include="..\System.Application.SteamTools.Client.Desktop\System.Application.SteamTools.Client.Desktop.csproj" />
<ProjectReference Include="..\System.Common.CoreLib\System.Common.CoreLib.csproj" />
</ItemGroup>
<ItemGroup Condition=" $(RuntimeIdentifier.Contains(`win`)) Or ('$(OS)' == 'Windows_NT' And !$(DefineConstants.Contains(`PUBLISH`))) ">
<ProjectReference Include="..\System.Application.SteamTools.Client.Desktop.Platform.Windows\System.Application.SteamTools.Client.Desktop.Platform.Windows.csproj" />
</ItemGroup>
<ItemGroup Condition=" $(RuntimeIdentifier.Contains(`osx`)) Or ('$(OS)' == 'OSX' And !$(DefineConstants.Contains(`PUBLISH`))) ">
<ProjectReference Include="..\System.Application.SteamTools.Client.Desktop.Platform.Mac\System.Application.SteamTools.Client.Desktop.Platform.Mac.csproj" />
</ItemGroup>
<ItemGroup Condition=" $(RuntimeIdentifier.Contains(`linux`)) Or ('$(OS)' == 'Unix' And !$(DefineConstants.Contains(`PUBLISH`))) ">
<ProjectReference Include="..\System.Application.SteamTools.Client.Desktop.Platform.Linux\System.Application.SteamTools.Client.Desktop.Platform.Linux.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MessageBox.Avalonia" Version="1.0.5">
<Aliases>MessageBox_Avalonia</Aliases>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Compile Update="**\*.xaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<AvaloniaResource Include="**\*.xaml">
<SubType>Designer</SubType>
</AvaloniaResource>
<AvaloniaResource Include="Assets\**" />
</ItemGroup>
<ItemGroup>
<AvaloniaResource Remove="Styles\SideBar.axaml" />
</ItemGroup>
<ItemGroup>
<AvaloniaXaml Remove="Styles\SideBar.axaml" />
</ItemGroup>
<ItemGroup>
<None Include="..\Resources\AppIcon\VisualElements_150.png">
<Link>Assets\VisualElements_150.png</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="..\Resources\AppIcon\VisualElements_70.png">
<Link>Assets\VisualElements_70.png</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="..\Resources\AppIcon\visualelementsmanifest.xml">
<Link>steam++.visualelementsmanifest.xml</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
@@ -0,0 +1,33 @@
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using System.Application.UI.ViewModels;
namespace System.Application.UI
{
public class ViewLocator : IDataTemplate
{
#pragma warning disable CA1822 // 将成员标记为 static
public bool SupportsRecycling => false;
#pragma warning restore CA1822 // 将成员标记为 static
public IControl Build(object data)
{
var name = data.GetType().FullName?.Replace("ViewModel", "View");
var type = name == null ? null : Type.GetType(name);
if (type != null)
{
var view = (Control?)Activator.CreateInstance(type);
if (view != null)
{
return view;
}
}
return new TextBlock { Text = "Not Found: " + name };
}
public bool Match(object data)
{
return data is ViewModelBase;
}
}
}
@@ -0,0 +1,100 @@
using ReactiveUI;
using System.Properties;
namespace System.Application.UI.ViewModels
{
public class MainWindowViewModel : WindowViewModel
{
bool mTopmost;
public bool Topmost
{
get => mTopmost;
set => this.RaiseAndSetIfChanged(ref mTopmost, value);
}
public MainWindowViewModel() : base()
{
Title = ThisAssembly.AssemblyTrademark;
SettingsPage = GetViewModel<SettingsPageViewModel>();
}
#region ResStrings
string mWelcome = string.Empty;
[ResString]
public string Welcome
{
get => mWelcome;
set => this.RaiseAndSetIfChanged(ref mWelcome, value);
}
string mCommunityFix = string.Empty;
[ResString]
public string CommunityFix
{
get => mCommunityFix;
set => this.RaiseAndSetIfChanged(ref mCommunityFix, value);
}
string mUserFastChange = string.Empty;
[ResString]
public string UserFastChange
{
get => mUserFastChange;
set => this.RaiseAndSetIfChanged(ref mUserFastChange, value);
}
string mSteamApps = string.Empty;
[ResString]
public string SteamApps
{
get => mSteamApps;
set => this.RaiseAndSetIfChanged(ref mSteamApps, value);
}
string mSteamAuth = string.Empty;
[ResString]
public string SteamAuth
{
get => mSteamAuth;
set => this.RaiseAndSetIfChanged(ref mSteamAuth, value);
}
string mGameRelated = string.Empty;
[ResString]
public string GameRelated
{
get => mGameRelated;
set => this.RaiseAndSetIfChanged(ref mGameRelated, value);
}
string mSettings = string.Empty;
[ResString]
public string Settings
{
get => mSettings;
set => this.RaiseAndSetIfChanged(ref mSettings, value);
}
string mAbout = string.Empty;
[ResString]
public string About
{
get => mAbout;
set => this.RaiseAndSetIfChanged(ref mAbout, value);
}
#endregion
public SettingsPageViewModel SettingsPage { get; }
}
}
@@ -0,0 +1,76 @@
using Avalonia.Controls;
using ReactiveUI;
using System.Application.Services;
using System.Collections.Generic;
using System.Linq;
namespace System.Application.UI.ViewModels
{
public class SettingsPageViewModel : ViewModelBase, ILocalizationViewModel
{
#region ResStrings
string mSettings_General = string.Empty;
[ResString]
public string Settings_General
{
get => mSettings_General;
set => this.RaiseAndSetIfChanged(ref mSettings_General, value);
}
string mSettings_Auth = string.Empty;
[ResString]
public string Settings_Auth
{
get => mSettings_Auth;
set => this.RaiseAndSetIfChanged(ref mSettings_Auth, value);
}
string mLanguage = string.Empty;
[ResString]
public string Language
{
get => mLanguage;
set => this.RaiseAndSetIfChanged(ref mLanguage, value);
}
#endregion
public SettingsPageViewModel()
{
Languages = ILocalizationService.Languages.Select(Convert).ToList();
}
int mCurrentLanguageIndex;
public int CurrentLanguageIndex
{
get => mCurrentLanguageIndex;
set
{
this.RaiseAndSetIfChanged(ref mCurrentLanguageIndex, value);
if (!IsInDesignMode)
{
var localizationService = DI.Get<ILocalizationService>();
var cultureName = Languages[value].Tag?.ToString();
if (string.IsNullOrWhiteSpace(cultureName))
{
cultureName = localizationService.DefaultCurrentUICulture?.Name;
}
if (!string.IsNullOrWhiteSpace(cultureName))
{
localizationService.ChangeLanguage(cultureName);
}
}
}
}
public List<ComboBoxItem> Languages { get; }
static ComboBoxItem Convert(KeyValuePair<string, string> pair)
=> new ComboBoxItem { Tag = pair.Key, Content = pair.Value };
}
}
@@ -0,0 +1,54 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:System.Application.UI.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="1350" d:DesignHeight="700"
xmlns:pages="clr-namespace:System.Application.UI.Pages"
x:Class="System.Application.UI.Views.MainView"
FontSize="14"
Foreground="{StaticResource SystemBaseHighColor}">
<Design.DataContext>
<vm:MainWindowViewModel/>
</Design.DataContext>
<Panel>
<DockPanel HorizontalAlignment="Stretch">
<ExperimentalAcrylicBorder DockPanel.Dock="Left" Width="240">
<ExperimentalAcrylicBorder.Material>
<ExperimentalAcrylicMaterial TintColor="Black" MaterialOpacity="0.85" TintOpacity="1"/>
</ExperimentalAcrylicBorder.Material>
<!--<AutoCompleteBox HorizontalAlignment="Stretch" Margin="20 40 20 0" Watermark="Search" Items="{Binding SearchItems}" />-->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Height="110" VerticalAlignment="Top">
<Image Source="/Assets/Icon.ico" Height="64" Width="64" VerticalAlignment="Center" Margin="-8,0,0,0"/>
<Label Content="Steam++" VerticalContentAlignment="Center" FontSize="20" Margin="8,0,0,0"/>
</StackPanel>
</ExperimentalAcrylicBorder>
<ExperimentalAcrylicBorder IsHitTestVisible="False">
<ExperimentalAcrylicBorder.Material>
<ExperimentalAcrylicMaterial TintColor="#222222" MaterialOpacity="0.85" TintOpacity="1"/>
</ExperimentalAcrylicBorder.Material>
<TextBlock Text="{Binding #TabControl.SelectedItem.Header}" Margin="40 20" FontSize="32" FontWeight="Light"/>
</ExperimentalAcrylicBorder>
</DockPanel>
<TabControl x:Name="TabControl" Classes="sidebar" Margin="0 40 0 20">
<TabItem Header="{Binding Path=Welcome}">
</TabItem>
<TabItem Header="{Binding Path=CommunityFix}">
</TabItem>
<TabItem Header="{Binding Path=UserFastChange}">
</TabItem>
<TabItem Header="{Binding Path=SteamAuth}">
</TabItem>
<TabItem Header="{Binding Path=SteamAuth}">
</TabItem>
<TabItem Header="{Binding Path=GameRelated}">
</TabItem>
<TabItem Header="{Binding Path=Settings}">
<pages:SettingsPage />
</TabItem>
<TabItem Header="{Binding Path=About}">
</TabItem>
</TabControl>
</Panel>
</UserControl>
@@ -0,0 +1,18 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace System.Application.UI.Views
{
public class MainView : UserControl
{
public MainView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}
@@ -0,0 +1,30 @@
<FluentWindow xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:System.Application.UI.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignWidth="1350" Width="1400" MinWidth="800"
d:DesignHeight="700" Height="800" MinHeight="600"
xmlns:pages="clr-namespace:System.Application.UI.Pages"
xmlns:local="clr-namespace:System.Application.UI.Views"
x:Class="System.Application.UI.Views.MainWindow"
x:Name="MainWindow"
WindowStartupLocation="CenterScreen"
Background="{x:Null}"
Title="{Binding Title}"
Topmost="{Binding Topmost}">
<FluentWindow.Styles>
<Style Selector="TitleBar:fullscreen">
<Setter Property="Background" Value="#7f000000" />
</Style>
</FluentWindow.Styles>
<Design.DataContext>
<vm:MainWindowViewModel/>
</Design.DataContext>
<Panel Margin="{Binding #MainWindow.OffScreenMargin}">
<local:MainView />
</Panel>
</FluentWindow>
@@ -0,0 +1,23 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using System.Application.UI.ViewModels;
namespace System.Application.UI.Views
{
public class MainWindow : FluentWindow
{
public MainWindow()
{
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}
@@ -0,0 +1,11 @@
using Avalonia.Threading;
namespace System.Application.Services.Implementation
{
internal sealed class MainThreadPlatformServiceImpl : IMainThreadPlatformService
{
public bool PlatformIsMainThread => Dispatcher.UIThread.CheckAccess();
public void PlatformBeginInvokeOnMainThread(Action action) => Dispatcher.UIThread.Post(action);
}
}
@@ -0,0 +1,97 @@
using Avalonia.Input;
using System.Collections.Generic;
namespace System.Application.UI
{
/// <summary>
/// 拖拽功能工具类
/// https://github.com/AvaloniaUI/Avalonia/blob/0.10.0-preview6/samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs
/// </summary>
public static class DragDropUtil
{
public static void InitDragDrop(this IOnDragDropListener listener,
InputElement element)
{
element.PointerPressed += async (_, e)
=> await DragDrop.DoDragDrop(e, new DataObject(), DragDropEffects.Copy);
element.AddHandler(DragDrop.DropEvent, Drop);
element.AddHandler(DragDrop.DragOverEvent, DragOver);
void DragOver(object? s, DragEventArgs? e)
{
if (e?.Data == null) return;
listener.DragOver(s is InputElement el ? el : element, e);
}
void Drop(object? s, DragEventArgs? e)
{
if (e?.Data == null) return;
listener.Drop(s is InputElement el ? el : element, e);
}
}
public static void InitDragDrop(this IOnDragDropListener listener,
IEnumerable<InputElement> elements)
{
foreach (var element in elements)
{
listener.InitDragDrop(element);
}
}
public static void InitDragDrop(this IOnDragDropListener listener,
params InputElement[] elements)
{
IEnumerable<InputElement> elements_ = elements;
listener.InitDragDrop(elements_);
}
public interface IOnDragDropListener
{
void DragOver(InputElement sender, DragEventArgs e)
{
// Only allow Copy or Link as Drop Operations.
e.DragEffects &= (DragDropEffects.Copy | DragDropEffects.Link);
// Only allow if the dragged data contains text or filenames.
if (!e.Data.Contains(DataFormats.Text)
&& !e.Data.Contains(DataFormats.FileNames))
e.DragEffects = DragDropEffects.None;
}
void Drop(InputElement sender, DragEventArgs e)
{
if (e.Data.Contains(DataFormats.Text))
{
var text = e.Data.GetText();
if (text != null)
{
DropText(sender, text);
}
}
else if (e.Data.Contains(DataFormats.FileNames))
{
var fileNames = e.Data.GetFileNames();
if (fileNames != null)
{
DropFileNames(sender, fileNames);
}
}
}
/// <summary>
/// 拖拽文本
/// </summary>
/// <param name="sender"></param>
/// <param name="text"></param>
void DropText(InputElement sender, string text);
/// <summary>
/// 拖拽路径,路径可能是文件也可能是文件夹
/// </summary>
/// <param name="sender"></param>
/// <param name="fileNames"></param>
void DropFileNames(InputElement sender, IEnumerable<string> fileNames);
}
}
}
@@ -0,0 +1,15 @@
using System.Application.Services;
using System.Application.Services.Implementation;
// ReSharper disable once CheckNamespace
namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddMainThreadPlatformService(this IServiceCollection services)
{
services.AddSingleton<IMainThreadPlatformService, MainThreadPlatformServiceImpl>();
return services;
}
}
}
@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<RootNamespace>System</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\System.Common.CoreLib\Properties\AssemblyInfo.cs">
<Link>Properties\AssemblyInfo.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\System.Application.SteamTools.Client.Desktop\System.Application.SteamTools.Client.Desktop.csproj" />
<ProjectReference Include="..\System.Common.CoreLib\System.Common.CoreLib.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.0" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.0" />
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.0" />
<PackageReference Include="MessageBox.Avalonia" Version="1.0.5">
<Aliases>MessageBox_Avalonia</Aliases>
</PackageReference>
</ItemGroup>
<ItemGroup Condition="'$(Configuration)'=='Debug'">
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.0" />
</ItemGroup>
</Project>
@@ -0,0 +1,113 @@
extern alias MessageBox_Avalonia;
using Avalonia.Controls;
using MessageBox_Avalonia::MessageBox.Avalonia;
using MessageBox_Avalonia::MessageBox.Avalonia.BaseWindows.Base;
using MessageBox_Avalonia::MessageBox.Avalonia.DTO;
using MessageBox_Avalonia::MessageBox.Avalonia.Enums;
using System.Reflection;
using System.Threading.Tasks;
// ReSharper disable once CheckNamespace
namespace System.Windows
{
/// <summary>
/// 显示消息框。
/// </summary>
public static class MessageBox
{
static ButtonEnum GetButtonEnum(this MessageBoxButton button) => button switch
{
MessageBoxButton.OK => ButtonEnum.Ok,
MessageBoxButton.OKCancel => ButtonEnum.OkCancel,
MessageBoxButton.YesNo => ButtonEnum.YesNo,
MessageBoxButton.YesNoCancel => ButtonEnum.YesNoCancel,
#pragma warning disable CS0618 // 类型或成员已过时
MessageBoxButton.OkAbort => ButtonEnum.OkAbort,
MessageBoxButton.YesNoAbort => ButtonEnum.YesNoAbort,
#pragma warning restore CS0618 // 类型或成员已过时
_ => throw new ArgumentOutOfRangeException(nameof(button), $"value: {button}"),
};
static Icon GetIcon(this MessageBoxImage icon) => icon switch
{
MessageBoxImage.Asterisk => Icon.Info,
MessageBoxImage.Error => Icon.Error,
MessageBoxImage.Exclamation => Icon.Warning,
MessageBoxImage.None => Icon.None,
#pragma warning disable CS0618 // 类型或成员已过时
MessageBoxImage.Question => Icon.Info,
MessageBoxImage.Battery => Icon.Battery,
MessageBoxImage.Database => Icon.Database,
MessageBoxImage.Folder => Icon.Folder,
MessageBoxImage.Forbidden => Icon.Forbidden,
MessageBoxImage.Plus => Icon.Plus,
MessageBoxImage.Setting => Icon.Setting,
MessageBoxImage.SpeakerLess => Icon.SpeakerLess,
MessageBoxImage.SpeakerMore => Icon.SpeakerMore,
MessageBoxImage.Stop2 => Icon.Stop,
MessageBoxImage.Stopwatch => Icon.Stopwatch,
MessageBoxImage.Wifi => Icon.Wifi,
#pragma warning restore CS0618 // 类型或成员已过时
_ => throw new ArgumentOutOfRangeException(nameof(icon), $"value: {icon}"),
};
static MessageBoxResult GetResult(this ButtonResult result) => result switch
{
ButtonResult.Ok => MessageBoxResult.OK,
ButtonResult.Yes => MessageBoxResult.Yes,
ButtonResult.No => MessageBoxResult.No,
#pragma warning disable CS0618 // 类型或成员已过时
ButtonResult.Abort => MessageBoxResult.Abort,
#pragma warning restore CS0618 // 类型或成员已过时
ButtonResult.Cancel => MessageBoxResult.Cancel,
ButtonResult.None => MessageBoxResult.None,
_ => throw new ArgumentOutOfRangeException(nameof(result), $"value: {result}"),
};
/// <summary>
/// 显示一个消息框,该消息框包含消息、标题栏标题、按钮和图标,并且返回结果。
/// </summary>
/// <param name="messageBoxText">一个 <see cref="string"/>,用于指定要显示的文本。</param>
/// <param name="caption">一个 <see cref="string"/>,用于指定要显示的标题栏标题。</param>
/// <param name="button">一个 <see cref="MessageBoxButton"/> 值,用于指定要显示哪个按钮或哪些按钮。</param>
/// <param name="icon">一个 <see cref="MessageBoxImage"/> 值,用于指定要显示的图标。</param>
/// <returns>一个 <see cref="MessageBoxResult"/> 值,用于指定用户单击了哪个消息框按钮。</returns>
public static async Task<MessageBoxResult> ShowAsync(
string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon)
{
var parms = new MessageBoxStandardParams
{
ButtonDefinitions = button.GetButtonEnum(),
ContentTitle = caption,
ContentMessage = messageBoxText,
Icon = icon.GetIcon(),
Style = Style.None,
WindowStartupLocation = WindowStartupLocation.CenterScreen,
};
var msBoxStandardWindow = MessageBoxManager.GetMessageBoxStandardWindow(parms);
var window = GetWindow(msBoxStandardWindow);
if (window != null)
{
window.Topmost = true;
window.SetResizeMode(ResizeMode.NoResize);
window.SetDefaultFontFamily();
}
var result = await msBoxStandardWindow.Show();
return GetResult(result);
}
static Window? GetWindow(IMsBoxWindow<ButtonResult> window)
{
var _window = window.GetType().GetField("_window", BindingFlags.NonPublic | BindingFlags.Instance);
if (_window != null && _window.FieldType.IsSubclassOf(typeof(Window)))
{
if (_window.GetValue(window) is Window w)
{
return w;
}
}
return null;
}
}
}
@@ -0,0 +1,19 @@
// ReSharper disable once CheckNamespace
namespace System.Windows
{
/// <summary>
/// 指定显示在消息框上的按钮。 用作 <see cref="MessageBox"/>.Show... 方法的参数。
/// </summary>
public enum MessageBoxButton
{
OK = 0,
OKCancel = 1,
YesNo = 4,
YesNoCancel = 3,
[Obsolete("non-standard api")]
OkAbort = 1000,
[Obsolete("non-standard api")]
YesNoAbort = 1001,
}
}
@@ -0,0 +1,45 @@
// ReSharper disable once CheckNamespace
namespace System.Windows
{
/// <summary>
/// 指定消息框所显示的图标。
/// </summary>
public enum MessageBoxImage
{
#pragma warning disable CA1069 // 不应复制枚举值
Asterisk = 64,
Error = 16,
Exclamation = 48,
Hand = 16,
Information = 64,
None = 0,
[Obsolete("The question mark message icon is no longer recommended because it does not clearly represent a specific type of message and because the phrasing of a message as a question could apply to any message type. In addition, users can confuse the question mark symbol with a help information symbol. Therefore, do not use this question mark symbol in your message boxes. The system continues to support its inclusion only for backward compatibility.")]
Question = 32,
Stop = 16,
Warning = 48,
[Obsolete("non-standard api")]
Battery = 1000,
[Obsolete("non-standard api")]
Database,
[Obsolete("non-standard api")]
Folder,
[Obsolete("non-standard api")]
Forbidden,
[Obsolete("non-standard api")]
Plus,
[Obsolete("non-standard api")]
Setting,
[Obsolete("non-standard api")]
SpeakerLess,
[Obsolete("non-standard api")]
SpeakerMore,
[Obsolete("non-standard api")]
Stop2,
[Obsolete("non-standard api")]
Stopwatch,
[Obsolete("non-standard api")]
Wifi,
#pragma warning restore CA1069 // 不应复制枚举值
}
}
@@ -0,0 +1,18 @@
// ReSharper disable once CheckNamespace
namespace System.Windows
{
/// <summary>
/// 指定用户单击的消息框按钮。 由 <see cref="MessageBox"/>.Show... 方法返回。
/// </summary>
public enum MessageBoxResult
{
Cancel = 2,
No = 7,
None = 0,
OK = 1,
Yes = 6,
[Obsolete("non-standard api")]
Abort = 1000,
}
}
@@ -0,0 +1,32 @@
using System.Application.Services;
// ReSharper disable once CheckNamespace
namespace System.Windows
{
/// <summary>
/// 指定是否可以调整窗口大小,并在可调整大小的情况下指定如何调整窗口大小。由 SetResizeMode 使用。
/// </summary>
public enum ResizeMode
{
/// <summary>
/// 用户无法调整窗口的大小。 不显示 "最大化" 和 "最小化" 框。
/// </summary>
NoResize = IDesktopPlatformService.ResizeMode_NoResize,
/// <summary>
/// 用户只能最小化窗口并从任务栏还原。 同时显示 "最小化" 和 "最大化" 框,但只启用 "最小化" 框。
/// </summary>
CanMinimize = IDesktopPlatformService.ResizeMode_CanMinimize,
/// <summary>
/// 用户可以通过使用 "最小化" 和 "最大化" 框以及围绕窗口的可拖动轮廓来完全调整窗口的大小。 显示和启用 "最小化" 和 "最大化" 框。 (默认) 。
/// </summary>
CanResize = IDesktopPlatformService.ResizeMode_CanResize,
/// <summary>
/// 此选项具有与相同的功能 <see cref="CanResize"/> ,但会将 "调整手柄" 添加到窗口的右下角。
/// </summary>
[Obsolete("not implemented")]
CanResizeWithGrip = IDesktopPlatformService.ResizeMode_CanResizeWithGrip,
}
}
@@ -0,0 +1,75 @@
using System.Application.Services;
using System.IO;
using FontFamily = Avalonia.Media.FontFamily;
using Window = Avalonia.Controls.Window;
// ReSharper disable once CheckNamespace
namespace System.Windows
{
/// <summary>
/// 通过扩展兼容WPF部分API的内容
/// </summary>
public static partial class WpfCompatExtensions
{
static readonly Lazy<bool> lazy_has_msyh = new Lazy<bool>(() =>
{
if (DI.Platform == Platform.Windows)
{
var fontsPath = Environment.GetFolderPath(Environment.SpecialFolder.Fonts);
var msyhFilePath = Path.Combine(fontsPath, "msyh.ttc");
return File.Exists(msyhFilePath);
}
else
{
return false;
}
});
public static bool HAS_FONT_MSYH => lazy_has_msyh.Value;
public static void SetDefaultFontFamily(this Window window)
{
if (DI.Platform == Platform.Windows)
{
if (HAS_FONT_MSYH) // (版权、许可)不能在非WinOS上使用 微软雅黑字体,不可将字体嵌入程序
{
string name;
var major = Environment.OSVersion.Version.Major;
if (major > 6 || (major == 6 && Environment.OSVersion.Version.Minor >= 2))
{
name = "Microsoft YaHei UI";
}
else
{
name = "Microsoft YaHei";
}
window.FontFamily = new FontFamily(name);
}
}
}
/// <summary>
/// 设置调整大小模式。
/// </summary>
/// <param name="window"></param>
/// <param name="value"></param>
public static void SetResizeMode(this Window window, ResizeMode value)
{
var p = DI.Get<IDesktopPlatformService>();
switch (value)
{
case ResizeMode.NoResize:
case ResizeMode.CanMinimize:
window.CanResize = false;
break;
case ResizeMode.CanResize:
#pragma warning disable CS0618 // 类型或成员已过时
case ResizeMode.CanResizeWithGrip:
#pragma warning restore CS0618 // 类型或成员已过时
window.CanResize = true;
break;
}
p.SetResizeMode(window.PlatformImpl.Handle.Handle, (int)value);
}
}
}
@@ -0,0 +1,10 @@
namespace System.Application.Services.Implementation
{
internal sealed class LinuxDesktopPlatformServiceImpl : IDesktopPlatformService
{
public void SetResizeMode(IntPtr hWnd, int value)
{
}
}
}
@@ -0,0 +1,23 @@
using System;
using System.Application.Services;
using System.Application.Services.Implementation;
// ReSharper disable once CheckNamespace
namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddDesktopPlatformService(this IServiceCollection services)
{
if (DI.Platform == Platform.Linux)
{
services.AddSingleton<IDesktopPlatformService, LinuxDesktopPlatformServiceImpl>();
}
else
{
throw new PlatformNotSupportedException();
}
return services;
}
}
}
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<RootNamespace>System.Application.Services</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\System.Common.CoreLib\Properties\AssemblyInfo.cs">
<Link>Properties\AssemblyInfo.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\System.Application.SteamTools.Client.Desktop.Platform\System.Application.SteamTools.Client.Desktop.Platform.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,9 @@
namespace System.Application.Services.Implementation
{
internal sealed class MacDesktopPlatformServiceImpl : IDesktopPlatformService
{
public void SetResizeMode(IntPtr hWnd, int value)
{
}
}
}
@@ -0,0 +1,23 @@
using System;
using System.Application.Services;
using System.Application.Services.Implementation;
// ReSharper disable once CheckNamespace
namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddDesktopPlatformService(this IServiceCollection services)
{
if (DI.Platform == Platform.Apple)
{
services.AddSingleton<IDesktopPlatformService, MacDesktopPlatformServiceImpl>();
}
else
{
throw new PlatformNotSupportedException();
}
return services;
}
}
}
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<RootNamespace>System.Application.Services</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\System.Common.CoreLib\Properties\AssemblyInfo.cs">
<Link>Properties\AssemblyInfo.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\System.Application.SteamTools.Client.Desktop.Platform\System.Application.SteamTools.Client.Desktop.Platform.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,90 @@
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
namespace System.Application.Services.Implementation
{
[SupportedOSPlatform("Windows")]
internal sealed class WindowsDesktopPlatformServiceImpl : IDesktopPlatformService
{
#region 窗口右上角的三个按钮(最小化,最大化,关闭)
// https://stackoverflow.com/questions/339620/how-do-i-remove-minimize-and-maximize-from-a-resizable-window-in-wpf
// https://blog.magnusmontin.net/2014/11/30/disabling-or-hiding-the-minimize-maximize-or-close-button-of-a-wpf-window/
public const int MF_BYCOMMAND = 0x00000000;
public const int SC_CLOSE = 0xF060;
public const int SC_MINIMIZE = 0xF020;
public const int SC_MAXIMIZE = 0xF030;
[DllImport("user32.dll")]
public static extern int DeleteMenu(IntPtr hMenu, int nPosition, int wFlags);
[DllImport("user32.dll")]
public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
public const int GWL_STYLE = -16,
WS_MAXIMIZEBOX = 0x10000,
WS_MINIMIZEBOX = 0x20000;
[DllImport("user32.dll")]
public extern static int GetWindowLong(IntPtr hwnd, int index);
[DllImport("user32.dll")]
public extern static int SetWindowLong(IntPtr hwnd, int index, int value);
public const int WS_SYSMENU = 0x80000;
public static void EnableMinimizeButton(IntPtr hWnd)
{
_ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) | WS_MINIMIZEBOX);
}
public static void EnableMaximizeButton(IntPtr hWnd)
{
_ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) | WS_MAXIMIZEBOX);
}
public static void ShowMinimizeAndMaximizeButtons(IntPtr hWnd)
{
_ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) | WS_MAXIMIZEBOX | WS_MINIMIZEBOX);
}
public static void ShowAllButtons(IntPtr hWnd)
{
_ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) | WS_SYSMENU);
}
public static void HideMinimizeAndMaximizeButtons(IntPtr hWnd)
{
_ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX);
}
public static void DisableMinimizeButton(IntPtr hWnd)
{
_ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) & ~WS_MINIMIZEBOX);
}
public static void DisableMaximizeButton(IntPtr hWnd)
{
_ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) & ~WS_MAXIMIZEBOX);
}
public void SetResizeMode(IntPtr hWnd, int value)
{
switch (value)
{
case IDesktopPlatformService.ResizeMode_NoResize:
_ = DeleteMenu(GetSystemMenu(hWnd, false), SC_MAXIMIZE, MF_BYCOMMAND);
_ = DeleteMenu(GetSystemMenu(hWnd, false), SC_MINIMIZE, MF_BYCOMMAND);
HideMinimizeAndMaximizeButtons(hWnd);
break;
case IDesktopPlatformService.ResizeMode_CanMinimize:
_ = DeleteMenu(GetSystemMenu(hWnd, false), SC_MAXIMIZE, MF_BYCOMMAND);
DisableMaximizeButton(hWnd);
break;
}
}
#endregion
}
}
@@ -0,0 +1,23 @@
using System;
using System.Application.Services;
using System.Application.Services.Implementation;
// ReSharper disable once CheckNamespace
namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddDesktopPlatformService(this IServiceCollection services)
{
if (DI.Platform == Platform.Windows)
{
services.AddSingleton<IDesktopPlatformService, WindowsDesktopPlatformServiceImpl>();
}
else
{
throw new PlatformNotSupportedException();
}
return services;
}
}
}
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<RootNamespace>System.Application.Services</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\System.Common.CoreLib\Properties\AssemblyInfo.cs">
<Link>Properties\AssemblyInfo.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\System.Application.SteamTools.Client.Desktop.Platform\System.Application.SteamTools.Client.Desktop.Platform.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,14 @@
using ResizeMode = System.Int32;
namespace System.Application.Services
{
public interface IDesktopPlatformService
{
void SetResizeMode(IntPtr hWnd, ResizeMode value);
public const ResizeMode ResizeMode_NoResize = 0;
public const ResizeMode ResizeMode_CanMinimize = 1;
public const ResizeMode ResizeMode_CanResize = 2;
public const ResizeMode ResizeMode_CanResizeWithGrip = 3;
}
}
@@ -0,0 +1,9 @@
namespace System.Application.Services.Implementation
{
public class DesktopPlatformServiceImpl : IDesktopPlatformService
{
public void SetResizeMode(IntPtr hWnd, int value)
{
}
}
}
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<RootNamespace>System.Application.Services</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\System.Common.CoreLib\Properties\AssemblyInfo.cs">
<Link>Properties\AssemblyInfo.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\System.Application.SteamTools.Client\System.Application.SteamTools.Client.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,133 @@
using System.Threading.Tasks;
using static System.Application.Services.IMainThreadPlatformService;
namespace System.Application
{
/// <summary>
/// 适用于桌面端的主线程帮助类,参考 Xamarin.Essentials.MainThread
/// <para><see cref="https://github.com/xamarin/Essentials/blob/main/Xamarin.Essentials/MainThread/MainThread.shared.cs"/></para>
/// </summary>
public static class MainThreadDesktop
{
public static bool IsMainThread => Instance.PlatformIsMainThread;
public static void BeginInvokeOnMainThread(Action action)
{
if (IsMainThread)
{
action();
}
else
{
Instance.PlatformBeginInvokeOnMainThread(action);
}
}
public static Task InvokeOnMainThreadAsync(Action action)
{
if (IsMainThread)
{
action();
#if NETSTANDARD1_0
return Task.FromResult(true);
#else
return Task.CompletedTask;
#endif
}
var tcs = new TaskCompletionSource<bool>();
BeginInvokeOnMainThread(() =>
{
try
{
action();
tcs.TrySetResult(true);
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
});
return tcs.Task;
}
public static Task<T> InvokeOnMainThreadAsync<T>(Func<T> func)
{
if (IsMainThread)
{
return Task.FromResult(func());
}
var tcs = new TaskCompletionSource<T>();
BeginInvokeOnMainThread(() =>
{
try
{
var result = func();
tcs.TrySetResult(result);
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
});
return tcs.Task;
}
public static Task InvokeOnMainThreadAsync(Func<Task> funcTask)
{
if (IsMainThread)
{
return funcTask();
}
var tcs = new TaskCompletionSource<object?>();
BeginInvokeOnMainThread(
async () =>
{
try
{
await funcTask().ConfigureAwait(false);
tcs.SetResult(null);
}
catch (Exception e)
{
tcs.SetException(e);
}
});
return tcs.Task;
}
public static Task<T> InvokeOnMainThreadAsync<T>(Func<Task<T>> funcTask)
{
if (IsMainThread)
{
return funcTask();
}
var tcs = new TaskCompletionSource<T>();
BeginInvokeOnMainThread(
async () =>
{
try
{
var ret = await funcTask().ConfigureAwait(false);
tcs.SetResult(ret);
}
catch (Exception e)
{
tcs.SetException(e);
}
});
return tcs.Task;
}
}
}
@@ -0,0 +1,45 @@
using System.Application.Services;
using System.Application.Services.Implementation;
using System.Application.UI.ViewModels;
// ReSharper disable once CheckNamespace
namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionExtensions
{
/// <summary>
/// 添加本地化、多语言服务
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddLocalizationService(this IServiceCollection services)
{
services.AddSingleton<ILocalizationService, LocalizationServiceImpl>();
return services;
}
/// <summary>
/// 添加视图模型组服务
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddViewModelCollectionService(this IServiceCollection services)
{
services.AddSingleton(new ViewModelCollectionServiceImpl(services));
services.AddSingleton<IViewModelCollectionService>(s => s.GetRequiredService<ViewModelCollectionServiceImpl>());
return services;
}
/// <summary>
/// 添加视图模型
/// </summary>
/// <typeparam name="TViewModel"></typeparam>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddViewModel<TViewModel>(this IServiceCollection services) where TViewModel : ViewModelBase
{
services.AddSingleton<TViewModel>();
return services;
}
}
}
@@ -0,0 +1,39 @@
using System.Application.UI.ViewModels;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
namespace System.Application.Services
{
/// <summary>
/// 本地化、多语言服务
/// </summary>
public interface ILocalizationService
{
CultureInfo DefaultCurrentUICulture { get; }
/// <summary>
/// 更改语言
/// </summary>
/// <param name="cultureName"></param>
void ChangeLanguage(string cultureName);
/// <summary>
/// 绑定资源字符串的视图模型组
/// </summary>
ILocalizationViewModel[] ViewModels { get; }
public static IList<KeyValuePair<string, string>> Languages;
static ILocalizationService()
{
Languages = new Dictionary<string, string>()
{
{ "", "Auto" },
{ "en", "English" },
{ "zh-Hans", "Chinese(Simplified)" },
{ "zh-Hant", "Chinese(Traditional)" },
}.ToList();
}
}
}
@@ -0,0 +1,14 @@
namespace System.Application.Services
{
/// <summary>
/// 由平台实现的主线程帮助类
/// </summary>
public interface IMainThreadPlatformService
{
bool PlatformIsMainThread { get; }
void PlatformBeginInvokeOnMainThread(Action action);
public static IMainThreadPlatformService Instance => DI.Get<IMainThreadPlatformService>();
}
}
@@ -0,0 +1,23 @@
using System.Application.UI.ViewModels;
using System.Collections.Generic;
namespace System.Application.Services
{
/// <summary>
/// 视图模型组服务
/// </summary>
public interface IViewModelCollectionService
{
/// <summary>
/// 获取所有的视图模型
/// </summary>
IEnumerable<ViewModelBase> ViewModels { get; }
/// <summary>
/// 根据类型过滤获取视图模型
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
IEnumerable<T> GetViewModels<T>();
}
}
@@ -0,0 +1,64 @@
using System.Application.UI.ViewModels;
using System.Globalization;
using System.Linq;
namespace System.Application.Services.Implementation
{
internal sealed class LocalizationServiceImpl : ILocalizationService
{
readonly IViewModelCollectionService vmss;
public LocalizationServiceImpl(IViewModelCollectionService vmss)
{
this.vmss = vmss;
DefaultCurrentUICulture = CultureInfo.CurrentUICulture;
}
public CultureInfo DefaultCurrentUICulture { get; }
ILocalizationViewModel[]? viewModels;
public ILocalizationViewModel[] ViewModels
{
get
{
if (viewModels == null)
{
viewModels = vmss.GetViewModels<ILocalizationViewModel>().ToArray();
}
return viewModels;
}
}
static bool IsMatch(CultureInfo cultureInfo, string cultureName)
{
if (string.IsNullOrWhiteSpace(cultureInfo.Name))
{
return false;
}
if (cultureInfo.Name == cultureName)
{
return true;
}
else
{
return IsMatch(cultureInfo.Parent, cultureName);
}
}
public void ChangeLanguage(string cultureName)
{
if (IsMatch(CultureInfo.CurrentUICulture, cultureName)) return;
if (!ViewModels.Any()) return;
void ChangeLanguage()
{
CultureInfo.CurrentUICulture = new CultureInfo(cultureName);
foreach (var viewModel in ViewModels)
{
viewModel.OnChangeLanguage();
}
}
MainThreadDesktop.BeginInvokeOnMainThread(ChangeLanguage);
}
}
}
@@ -0,0 +1,32 @@
using Microsoft.Extensions.DependencyInjection;
using System.Application.UI.ViewModels;
using System.Collections.Generic;
using System.Linq;
namespace System.Application.Services.Implementation
{
internal sealed class ViewModelCollectionServiceImpl : IViewModelCollectionService
{
readonly IEnumerable<ServiceDescriptor> services;
public ViewModelCollectionServiceImpl(IEnumerable<ServiceDescriptor> services)
{
this.services = services;
}
public IEnumerable<ViewModelBase> ViewModels => GetViewModels<ViewModelBase>();
public IEnumerable<T> GetViewModels<T>()
{
var tType = typeof(T);
var vType = typeof(ViewModelBase);
var tIsvType = tType == vType;
return from s in services
where s.ServiceType == s.ImplementationType &&
s.Lifetime == ServiceLifetime.Singleton &&
tType.IsAssignableFrom(s.ImplementationType) &&
(tIsvType || vType.IsAssignableFrom(s.ImplementationType))
select (T)DI.Get(s.ServiceType);
}
}
}
@@ -0,0 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<RootNamespace>System.Application</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\System.Common.CoreLib\Properties\AssemblyInfo.cs">
<Link>Properties\AssemblyInfo.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<PackageReference Include="ReactiveUI" Version="13.1.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\System.Application.SteamTools.Client.Desktop.Platform\System.Application.SteamTools.Client.Desktop.Platform.csproj" />
<ProjectReference Include="..\System.Application.SteamTools.Client\System.Application.SteamTools.Client.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="UI\Resx\AppResources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>AppResources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="UI\Resx\AppResources.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>
@@ -0,0 +1,162 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace System.Application.UI.Resx {
using System;
/// <summary>
/// 一个强类型的资源类,用于查找本地化的字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class AppResources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal AppResources() {
}
/// <summary>
/// 返回此类使用的缓存的 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("System.Application.UI.Resx.AppResources", typeof(AppResources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// 查找类似 关于 的本地化字符串。
/// </summary>
public static string About {
get {
return ResourceManager.GetString("About", resourceCulture);
}
}
/// <summary>
/// 查找类似 社区加速 的本地化字符串。
/// </summary>
public static string CommunityFix {
get {
return ResourceManager.GetString("CommunityFix", resourceCulture);
}
}
/// <summary>
/// 查找类似 库存游戏 的本地化字符串。
/// </summary>
public static string GameList {
get {
return ResourceManager.GetString("GameList", resourceCulture);
}
}
/// <summary>
/// 查找类似 游戏功能 的本地化字符串。
/// </summary>
public static string GameRelated {
get {
return ResourceManager.GetString("GameRelated", resourceCulture);
}
}
/// <summary>
/// 查找类似 语言 的本地化字符串。
/// </summary>
public static string Language {
get {
return ResourceManager.GetString("Language", resourceCulture);
}
}
/// <summary>
/// 查找类似 设置 的本地化字符串。
/// </summary>
public static string Settings {
get {
return ResourceManager.GetString("Settings", resourceCulture);
}
}
/// <summary>
/// 查找类似 令牌设置 的本地化字符串。
/// </summary>
public static string Settings_Auth {
get {
return ResourceManager.GetString("Settings_Auth", resourceCulture);
}
}
/// <summary>
/// 查找类似 基本设置 的本地化字符串。
/// </summary>
public static string Settings_General {
get {
return ResourceManager.GetString("Settings_General", resourceCulture);
}
}
/// <summary>
/// 查找类似 本地令牌 的本地化字符串。
/// </summary>
public static string SteamAuth {
get {
return ResourceManager.GetString("SteamAuth", resourceCulture);
}
}
/// <summary>
/// 查找类似 账号切换 的本地化字符串。
/// </summary>
public static string UserFastChange {
get {
return ResourceManager.GetString("UserFastChange", resourceCulture);
}
}
/// <summary>
/// 查找类似 起始页 的本地化字符串。
/// </summary>
public static string Welcome {
get {
return ResourceManager.GetString("Welcome", resourceCulture);
}
}
}
}
@@ -0,0 +1,153 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="About" xml:space="preserve">
<value>About</value>
</data>
<data name="CommunityFix" xml:space="preserve">
<value>Fix Steam 302 Error</value>
</data>
<data name="GameList" xml:space="preserve">
<value>My Games</value>
</data>
<data name="GameRelated" xml:space="preserve">
<value>Game Related</value>
</data>
<data name="Language" xml:space="preserve">
<value>Language</value>
</data>
<data name="Settings" xml:space="preserve">
<value>Settings</value>
</data>
<data name="Settings_Auth" xml:space="preserve">
<value>Auth Settings</value>
</data>
<data name="Settings_General" xml:space="preserve">
<value>General Settings</value>
</data>
<data name="SteamAuth" xml:space="preserve">
<value>Steam Auth</value>
</data>
<data name="UserFastChange" xml:space="preserve">
<value>Account Change</value>
</data>
<data name="Welcome" xml:space="preserve">
<value>Start Page</value>
</data>
</root>
@@ -0,0 +1,153 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="About" xml:space="preserve">
<value>关于</value>
</data>
<data name="CommunityFix" xml:space="preserve">
<value>社区加速</value>
</data>
<data name="GameList" xml:space="preserve">
<value>库存游戏</value>
</data>
<data name="GameRelated" xml:space="preserve">
<value>游戏功能</value>
</data>
<data name="Language" xml:space="preserve">
<value>语言</value>
</data>
<data name="Settings" xml:space="preserve">
<value>设置</value>
</data>
<data name="Settings_Auth" xml:space="preserve">
<value>令牌设置</value>
</data>
<data name="Settings_General" xml:space="preserve">
<value>基本设置</value>
</data>
<data name="SteamAuth" xml:space="preserve">
<value>本地令牌</value>
</data>
<data name="UserFastChange" xml:space="preserve">
<value>账号切换</value>
</data>
<data name="Welcome" xml:space="preserve">
<value>起始页</value>
</data>
</root>
@@ -0,0 +1,153 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="About" xml:space="preserve">
<value>關於</value>
</data>
<data name="CommunityFix" xml:space="preserve">
<value>社區加速</value>
</data>
<data name="GameList" xml:space="preserve">
<value>遊戲列表</value>
</data>
<data name="GameRelated" xml:space="preserve">
<value>遊戲功能</value>
</data>
<data name="Language" xml:space="preserve">
<value>語言</value>
</data>
<data name="Settings" xml:space="preserve">
<value>設定</value>
</data>
<data name="Settings_Auth" xml:space="preserve">
<value>令牌設定</value>
</data>
<data name="Settings_General" xml:space="preserve">
<value>基本設定</value>
</data>
<data name="SteamAuth" xml:space="preserve">
<value>本地令牌</value>
</data>
<data name="UserFastChange" xml:space="preserve">
<value>帳號切換</value>
</data>
<data name="Welcome" xml:space="preserve">
<value>起始頁</value>
</data>
</root>
@@ -0,0 +1,27 @@
using System.Application.UI.Resx;
using System.Linq;
using System.Reflection;
namespace System.Application.UI.ViewModels
{
/// <summary>
/// 本地化、多语言视图模型
/// </summary>
public interface ILocalizationViewModel
{
public void OnChangeLanguage()
{
var properties = GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
var query = from p in properties
let attr = p.GetCustomAttribute<ResStringAttribute>()
where p.PropertyType == typeof(string) && attr != null
select (p, attr.ResId);
foreach (var (p, ResId) in query)
{
var resId = ResId ?? p.Name;
var value = AppResources.ResourceManager.GetString(resId);
p.SetValue(this, value);
}
}
}
}
@@ -0,0 +1,13 @@
namespace System.Application.UI.ViewModels
{
[AttributeUsage(AttributeTargets.Property)]
public sealed class ResStringAttribute : Attribute
{
public string? ResId { get; }
public ResStringAttribute(string? resId = null)
{
ResId = resId;
}
}
}
@@ -0,0 +1,24 @@
using ReactiveUI;
namespace System.Application.UI.ViewModels
{
public class ViewModelBase : ReactiveObject, ILocalizationViewModel
{
public ViewModelBase()
{
ILocalizationViewModel localization = this;
localization.OnChangeLanguage();
}
/// <summary>
/// 是否在设计器的上下文中运行
/// </summary>
public static bool IsInDesignMode { get; set; }
protected static TViewModel GetViewModel<TViewModel>() where TViewModel : ViewModelBase, new()
{
if (IsInDesignMode) return new TViewModel();
return DI.Get<TViewModel>();
}
}
}
@@ -0,0 +1,15 @@
using ReactiveUI;
namespace System.Application.UI.ViewModels
{
public class WindowViewModel : ViewModelBase
{
string title = string.Empty;
public string Title
{
get => title;
set => this.RaiseAndSetIfChanged(ref title, value);
}
}
}

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