mirror of
https://github.com/BeyondDimension/SteamTools.git
synced 2026-10-20 16:21:46 +08:00
Compare commits
93 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d382d70487 | |||
| c438656378 | |||
| 035b1a6421 | |||
| f3db1a23ed | |||
| 59096c898c | |||
| 4d76decf73 | |||
| c2d95a1833 | |||
| fd6f5ff3ea | |||
| 5bd381f553 | |||
| 55bad031df | |||
| 866ad1a821 | |||
| 9fbe6408ab | |||
| c8ea806360 | |||
| a8b0f9877c | |||
| d82f94f95d | |||
| a40fb84783 | |||
| c9cbf696e4 | |||
| cc86913b72 | |||
| ba02250f61 | |||
| 451de6ca55 | |||
| 691fb360bb | |||
| 686e3987f8 | |||
| 79871c3bcb | |||
| c1b19b4929 | |||
| c564ea10eb | |||
| d5006da378 | |||
| 878e9dbd32 | |||
| bd7f9e76b8 | |||
| fc285cf583 | |||
| 3ab0ae46c0 | |||
| 4550ff1621 | |||
| 1663bd4277 | |||
| 679afdef1b | |||
| d38588d45c | |||
| 42b11ce241 | |||
| c01512bcf6 | |||
| dd89595629 | |||
| 94b5539823 | |||
| 317baff79c | |||
| f702c3ae62 | |||
| 177216a51e | |||
| 46b1c01107 | |||
| 798355e342 | |||
| ee741d3138 | |||
| e31b668beb | |||
| c00955205c | |||
| 5345926c8b | |||
| 0987f58fee | |||
| 715737bce2 | |||
| 44245aa2b7 | |||
| 97e6b92ef6 | |||
| 445f130272 | |||
| 39fcc4d9a8 | |||
| b4a755a647 | |||
| 083189c264 | |||
| 676c628b6f | |||
| 43ca455e70 | |||
| 95e834a188 | |||
| e9d822bb0c | |||
| f395383db8 | |||
| f805911f4e | |||
| b3d203fbda | |||
| bb022f45fd | |||
| e4a97463f4 | |||
| 11adabb749 | |||
| 8a7ad67363 | |||
| 7af0888b0a | |||
| 42fc93a524 | |||
| 5c832f489b | |||
| 5e7ed26bc6 | |||
| 085ad3d944 | |||
| 334503445c | |||
| cf17ca8dd6 | |||
| 0b88de7195 | |||
| 3342e35440 | |||
| 56baba4a53 | |||
| 8b1a946fe2 | |||
| 9e08c0b7c4 | |||
| 3a38333dfc | |||
| 16d1bba515 | |||
| 00cf9da911 | |||
| 088256faf9 | |||
| ca244edc51 | |||
| c91608da09 | |||
| 2945e9fa3e | |||
| 1f0a40cd3b | |||
| b1fbe64ab2 | |||
| 9a13665e68 | |||
| 5c0f71f4a7 | |||
| 3e045e5db0 | |||
| c4f99906ab | |||
| 94e50f663b | |||
| 49e08101c6 |
@@ -1,13 +0,0 @@
|
||||
### 该问题是怎么引起的?
|
||||
|
||||
|
||||
|
||||
### 重现步骤
|
||||
|
||||
|
||||
|
||||
### 报错信息
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
### 相关的Issue
|
||||
|
||||
|
||||
### 原因(目的、解决的问题等)
|
||||
|
||||
|
||||
### 描述(做了什么,变更了什么)
|
||||
|
||||
|
||||
### 测试用例(新增、改动、可能影响的功能)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ib/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,12 @@
|
||||
<Project>
|
||||
<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>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+95
-30
@@ -1,40 +1,105 @@
|
||||
# Steam++工具箱 v1.0
|
||||
<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才能使用。
|
||||

|
||||
[](https://github.com/rmbadmin/SteamTools/releases/latest)
|
||||
[](LICENSE)
|
||||
[](https://github.com/rmbadmin/SteamTools/stargazers)
|
||||
[](https://github.com/rmbadmin/SteamTools/network/members)
|
||||

|
||||
|
||||
------
|
||||
</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,相比之下有:
|
||||
## 🖥 Operating Environment
|
||||
- Windows 10 1607+
|
||||
- Windows 8.1 / Windows Server 2012 R2
|
||||
- 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)
|
||||
- Windows 7 SP1 [ESU](https://docs.microsoft.com/troubleshoot/windows-client/windows-7-eos-faq/windows-7-extended-security-updates-faq)
|
||||
- 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)
|
||||
- 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 8.0+~~
|
||||
-->
|
||||
|
||||
- [X] 更快的启动速度
|
||||
- [X] 支持脚本注入
|
||||
## 🌎 Roadmap
|
||||
Read what we [milestones](https://github.com/SteamTools-Team/SteamTools/milestones), and feel free to ask questions.
|
||||
|
||||
---
|
||||
### 2. 快速切换当前PC已经记住登陆的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)
|
||||
|
||||
该功能是读取Steam路径下存储的本地用户登录记录直接展示操作,可以多账号切换无需重新输入密码和令牌。
|
||||
|
||||
---
|
||||
### 3. Steam游戏的成就统计管理功能
|
||||
功能类似[SteamAchievementManager](https://github.com/gibbed/SteamAchievementManager),实现也参考了SAM,并且略作修改了,游戏列表的读取,解锁成就的逻辑。
|
||||
|
||||
---
|
||||
|
||||
### 4. Steam本地两步身份验证器
|
||||
可以使您不用启动移动版Steam App也能查看您的令牌,功能类似的软件有[WinAuth](https://github.com/winauth/winauth)、[SteamDesktopAuthenticator](https://github.com/Jessecar96/SteamDesktopAuthenticator)。
|
||||
|
||||
---
|
||||
|
||||
### 5. 一些游戏工具
|
||||
目前已有强制游戏无边框窗口化,CSGO修复VAC屏蔽。
|
||||
这一块是随缘做一些我经常用或者闲着没事捣鼓的功能。
|
||||
|
||||
---
|
||||
## 📄 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/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)
|
||||
* [Ninject](https://github.com/ninject/Ninject)
|
||||
* [log4net](https://github.com/apache/logging-log4net)
|
||||
* [SteamDB-API](https://github.com/SteamDB-API/api)
|
||||
* [SteamAchievementManager](https://github.com/gibbed/SteamAchievementManager)
|
||||
* [ArchiSteamFarm](https://github.com/JustArchiNET/ArchiSteamFarm)
|
||||
* [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)
|
||||
* [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,40 +1,112 @@
|
||||
# Steam++工具箱 v1.0
|
||||
<h1 align="center">Steam++ 工具箱 🧰</h1>
|
||||
|
||||
------
|
||||
<div align="center">
|
||||
|
||||
「Steam++」是一个包含多种Steam工具功能的工具箱。
|
||||
「Steam++」是一个包含多种Steam工具功能的工具箱,此工具的大部分功能都是需要您下载安装Steam才能使用。
|
||||
|
||||
此工具的大部分功能都是需要您下载安装Steam才能使用。
|
||||

|
||||
[](https://github.com/rmbadmin/SteamTools/releases/latest)
|
||||
[](LICENSE)
|
||||
[](https://github.com/rmbadmin/SteamTools/stargazers)
|
||||
[](https://github.com/rmbadmin/SteamTools/network/members)
|
||||

|
||||
|
||||
------
|
||||
</div>
|
||||
|
||||
## 主要功能
|
||||
[English](./README.en.md) | 简体中文
|
||||
|
||||
### 1. 反代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 屏蔽
|
||||
|
||||
功能类似羽翼城大佬的Steam302,相比之下有:
|
||||
## 🖥 系统要求
|
||||
- Windows 10 1607+
|
||||
- Windows 8.1 / Windows Server 2012 R2
|
||||
- 先决条件
|
||||
- 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 7 SP1 [ESU](https://docs.microsoft.com/zh-cn/troubleshoot/windows-client/windows-7-eos-faq/windows-7-extended-security-updates-faq)
|
||||
- 先决条件
|
||||
- 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)
|
||||
- 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 8.0+~~
|
||||
-->
|
||||
|
||||
- [X] 更快的启动速度
|
||||
- [X] 支持脚本注入
|
||||
## 🌎 路线图
|
||||
查看这个 [milestones](https://github.com/SteamTools-Team/SteamTools/milestones) 来了解我们下一步的开发计划,并随时提出问题。
|
||||
|
||||
---
|
||||
### 2. 快速切换当前PC已经记住登陆的Steam账号
|
||||
## ⌨️ 开发环境
|
||||
[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)
|
||||
|
||||
该功能是读取Steam路径下存储的本地用户登录记录直接展示操作,可以多账号切换无需重新输入密码和令牌。
|
||||
|
||||
---
|
||||
### 3. Steam游戏的成就统计管理功能
|
||||
功能类似[SteamAchievementManager](https://github.com/gibbed/SteamAchievementManager),实现也参考了SAM,并且略作修改了,游戏列表的读取,解锁成就的逻辑。
|
||||
|
||||
---
|
||||
|
||||
### 4. Steam本地两步身份验证器
|
||||
可以使您不用启动移动版Steam App也能查看您的令牌,功能类似的软件有[WinAuth](https://github.com/winauth/winauth)、[SteamDesktopAuthenticator](https://github.com/Jessecar96/SteamDesktopAuthenticator)。
|
||||
|
||||
---
|
||||
|
||||
### 5. 一些游戏工具
|
||||
目前已有强制游戏无边框窗口化,CSGO修复VAC屏蔽。
|
||||
这一块是随缘做一些我经常用或者闲着没事捣鼓的功能。
|
||||
|
||||
---
|
||||
## 📄 感谢以下开源项目
|
||||
* [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/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)
|
||||
* [Ninject](https://github.com/ninject/Ninject)
|
||||
* [log4net](https://github.com/apache/logging-log4net)
|
||||
* [SteamDB-API](https://github.com/SteamDB-API/api)
|
||||
* [SteamAchievementManager](https://github.com/gibbed/SteamAchievementManager)
|
||||
* [ArchiSteamFarm](https://github.com/JustArchiNET/ArchiSteamFarm)
|
||||
* [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)
|
||||
* [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,249 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using WinAuth;
|
||||
|
||||
namespace SteamTool.Auth
|
||||
{
|
||||
public static class AuthService
|
||||
{
|
||||
/// <summary>
|
||||
/// Import a file containing authenticators in the KeyUriFormat. The file might be plain text, encrypted zip or encrypted pgp.
|
||||
/// </summary>
|
||||
/// <param name="parent">parent Form</param>
|
||||
/// <param name="file">file name to import</param>
|
||||
/// <returns>list of imported authenticators</returns>
|
||||
public static List<WinAuthAuthenticator> ImportAuthenticators(string file)
|
||||
{
|
||||
List<WinAuthAuthenticator> authenticators = new List<WinAuthAuthenticator>();
|
||||
|
||||
StringBuilder lines = new StringBuilder();
|
||||
bool retry;
|
||||
do
|
||||
{
|
||||
retry = false;
|
||||
lines.Length = 0;
|
||||
// read a plain text file
|
||||
lines.Append(File.ReadAllText(file));
|
||||
} while (retry);
|
||||
|
||||
int linenumber = 0;
|
||||
try
|
||||
{
|
||||
using (var sr = new StringReader(lines.ToString()))
|
||||
{
|
||||
string line;
|
||||
while ((line = sr.ReadLine()) != null)
|
||||
{
|
||||
linenumber++;
|
||||
|
||||
// ignore blank lines or comments
|
||||
line = line.Trim();
|
||||
if (line.Length == 0 || line.IndexOf("#") == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// bug if there is a hash before ?
|
||||
var hash = line.IndexOf("#");
|
||||
var qm = line.IndexOf("?");
|
||||
if (hash != -1 && hash < qm)
|
||||
{
|
||||
line = line.Substring(0, hash) + "%23" + line.Substring(hash + 1);
|
||||
}
|
||||
|
||||
// parse and validate URI
|
||||
var uri = new Uri(line);
|
||||
|
||||
// we only support "otpauth"
|
||||
if (uri.Scheme != "otpauth")
|
||||
{
|
||||
throw new ApplicationException("Import only supports otpauth://");
|
||||
}
|
||||
// we only support totp (not hotp)
|
||||
if (uri.Host != "totp" && uri.Host != "hotp")
|
||||
{
|
||||
throw new ApplicationException("Import only supports otpauth://totp/ or otpauth://hotp/");
|
||||
}
|
||||
|
||||
// get the label and optional issuer
|
||||
string issuer = string.Empty;
|
||||
string label = (string.IsNullOrEmpty(uri.LocalPath) == false ? uri.LocalPath.Substring(1) : string.Empty); // skip past initial /
|
||||
int p = label.IndexOf(":");
|
||||
if (p != -1)
|
||||
{
|
||||
issuer = label.Substring(0, p);
|
||||
label = label.Substring(p + 1);
|
||||
}
|
||||
// + aren't decoded
|
||||
label = label.Replace("+", " ");
|
||||
|
||||
var query = HttpUtility.ParseQueryString(uri.Query);
|
||||
string secret = query["secret"];
|
||||
if (string.IsNullOrEmpty(secret) == true)
|
||||
{
|
||||
throw new ApplicationException("Authenticator does not contain secret");
|
||||
}
|
||||
|
||||
string counter = query["counter"];
|
||||
if (uri.Host == "hotp" && string.IsNullOrEmpty(counter) == true)
|
||||
{
|
||||
throw new ApplicationException("HOTP authenticator should have a counter");
|
||||
}
|
||||
|
||||
WinAuthAuthenticator importedAuthenticator = new WinAuthAuthenticator
|
||||
{
|
||||
AutoRefresh = false
|
||||
};
|
||||
//
|
||||
Authenticator auth;
|
||||
if (string.Compare(issuer, "BattleNet", true) == 0)
|
||||
{
|
||||
string serial = query["serial"];
|
||||
if (string.IsNullOrEmpty(serial) == true)
|
||||
{
|
||||
throw new ApplicationException("Battle.net Authenticator does not have a serial");
|
||||
}
|
||||
serial = serial.ToUpper();
|
||||
if (Regex.IsMatch(serial, @"^[A-Z]{2}-?[\d]{4}-?[\d]{4}-?[\d]{4}$") == false)
|
||||
{
|
||||
throw new ApplicationException("Invalid serial for Battle.net Authenticator");
|
||||
}
|
||||
auth = new BattleNetAuthenticator();
|
||||
//char[] decoded = Base32.getInstance().Decode(secret).Select(c => Convert.ToChar(c)).ToArray(); // this is hex string values
|
||||
//string hex = new string(decoded);
|
||||
//((BattleNetAuthenticator)auth).SecretKey = Authenticator.StringToByteArray(hex);
|
||||
|
||||
((BattleNetAuthenticator)auth).SecretKey = Base32.getInstance().Decode(secret);
|
||||
|
||||
((BattleNetAuthenticator)auth).Serial = serial;
|
||||
|
||||
issuer = string.Empty;
|
||||
}
|
||||
else if (string.Compare(issuer, "Steam", true) == 0)
|
||||
{
|
||||
auth = new SteamAuthenticator();
|
||||
((SteamAuthenticator)auth).SecretKey = Base32.getInstance().Decode(secret);
|
||||
((SteamAuthenticator)auth).Serial = string.Empty;
|
||||
((SteamAuthenticator)auth).DeviceId = query["deviceid"] ?? string.Empty;
|
||||
((SteamAuthenticator)auth).SteamData = query["data"] ?? string.Empty;
|
||||
issuer = string.Empty;
|
||||
}
|
||||
else if (uri.Host == "hotp")
|
||||
{
|
||||
auth = new HOTPAuthenticator();
|
||||
((HOTPAuthenticator)auth).SecretKey = Base32.getInstance().Decode(secret);
|
||||
((HOTPAuthenticator)auth).Counter = int.Parse(counter);
|
||||
|
||||
if (string.IsNullOrEmpty(issuer) == false)
|
||||
{
|
||||
auth.Issuer = issuer;
|
||||
}
|
||||
}
|
||||
else // if (string.Compare(issuer, "Google", true) == 0)
|
||||
{
|
||||
auth = new GoogleAuthenticator();
|
||||
((GoogleAuthenticator)auth).Enroll(secret);
|
||||
|
||||
if (string.Compare(issuer, "Google", true) == 0)
|
||||
{
|
||||
issuer = string.Empty;
|
||||
}
|
||||
else if (string.IsNullOrEmpty(issuer) == false)
|
||||
{
|
||||
auth.Issuer = issuer;
|
||||
}
|
||||
}
|
||||
|
||||
int period = 0;
|
||||
int.TryParse(query["period"], out period);
|
||||
if (period != 0)
|
||||
{
|
||||
auth.Period = period;
|
||||
}
|
||||
|
||||
int digits = 0;
|
||||
int.TryParse(query["digits"], out digits);
|
||||
if (digits != 0)
|
||||
{
|
||||
auth.CodeDigits = digits;
|
||||
}
|
||||
|
||||
Authenticator.HMACTypes hmactype;
|
||||
|
||||
if (Enum.TryParse<Authenticator.HMACTypes>(query["algorithm"], true, out hmactype) == true)
|
||||
{
|
||||
auth.HMACType = hmactype;
|
||||
}
|
||||
|
||||
//
|
||||
if (label.Length != 0)
|
||||
{
|
||||
importedAuthenticator.Name = (issuer.Length != 0 ? issuer + " (" + label + ")" : label);
|
||||
}
|
||||
else if (issuer.Length != 0)
|
||||
{
|
||||
importedAuthenticator.Name = issuer;
|
||||
}
|
||||
else
|
||||
{
|
||||
importedAuthenticator.Name = "Imported";
|
||||
}
|
||||
//
|
||||
importedAuthenticator.AuthenticatorData = auth;
|
||||
|
||||
// sync
|
||||
importedAuthenticator.Sync();
|
||||
|
||||
authenticators.Add(importedAuthenticator);
|
||||
}
|
||||
}
|
||||
|
||||
return authenticators;
|
||||
}
|
||||
catch (UriFormatException ex)
|
||||
{
|
||||
throw new ImportException(string.Format("Invalid authenticator at line {0}", linenumber), ex);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportException(string.Format("Error importing at line {0}:{1}", ex.Message), ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static string ExportAuthenticators(IList<WinAuthAuthenticator> authenticators, string password)
|
||||
{
|
||||
// create file in memory
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
using (var sw = new StreamWriter(ms))
|
||||
{
|
||||
List<WinAuthAuthenticator> unprotected = new List<WinAuthAuthenticator>();
|
||||
foreach (var auth in authenticators)
|
||||
{
|
||||
unprotected.Add(auth);
|
||||
string line = auth.ToUrl();
|
||||
sw.WriteLine(line);
|
||||
}
|
||||
|
||||
// reprotect
|
||||
foreach (var auth in unprotected)
|
||||
{
|
||||
auth.AuthenticatorData.Protect();
|
||||
}
|
||||
|
||||
// reset and write stream out to disk or as zip
|
||||
sw.Flush();
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
var result = Encoding.UTF8.GetString(ms.ToArray());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SteamTool.Auth
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception class wrapper for importing error
|
||||
/// </summary>
|
||||
public class ImportException : ApplicationException
|
||||
{
|
||||
public ImportException() : base() { }
|
||||
|
||||
public ImportException(string message) : base(message) { }
|
||||
|
||||
public ImportException(string message, Exception ex) : base(message, ex) { }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<Platforms>AnyCPU;x86</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SteamTool.Authenticator\SteamTool.Authenticator.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="PresentationCore">
|
||||
<HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\PresentationCore.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,22 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace SteamTool.Auth.Win32
|
||||
{
|
||||
public class WinAPI
|
||||
{
|
||||
public const string LibraryName = "user32.dll";
|
||||
|
||||
[DllImport(LibraryName, CharSet = CharSet.Auto)]
|
||||
internal static extern IntPtr GetOpenClipboardWindow();
|
||||
|
||||
[DllImport(LibraryName, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
internal static extern int GetWindowTextLength(IntPtr hWnd);
|
||||
|
||||
[DllImport(LibraryName, CharSet = CharSet.Auto, SetLastError = true)]
|
||||
internal static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,597 +0,0 @@
|
||||
using SteamTool.Auth.Win32;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using System.Windows;
|
||||
using System.Xml;
|
||||
using WinAuth;
|
||||
|
||||
namespace SteamTool.Auth
|
||||
{
|
||||
public interface IWinAuthAuthenticatorChangedListener
|
||||
{
|
||||
void OnWinAuthAuthenticatorChanged(WinAuthAuthenticator sender, WinAuthAuthenticatorChangedEventArgs e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper for real authenticator data used to save to file with other application information
|
||||
/// </summary>
|
||||
public class WinAuthAuthenticator : ICloneable
|
||||
{
|
||||
/// <summary>
|
||||
/// Event handler fired when property is changed
|
||||
/// </summary>
|
||||
public event WinAuthAuthenticatorChangedHandler OnWinAuthAuthenticatorChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Unique Id of authenticator saved in config
|
||||
/// </summary>
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Index for authenticator when in sorted list
|
||||
/// </summary>
|
||||
public int Index { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Actual authenticator data
|
||||
/// </summary>
|
||||
public Authenticator AuthenticatorData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When this authenticator was created
|
||||
/// </summary>
|
||||
public DateTime Created { get; set; }
|
||||
|
||||
private string _name;
|
||||
private bool _autoRefresh;
|
||||
private bool _allowCopy;
|
||||
private bool _copyOnCode;
|
||||
private bool _hideSerial;
|
||||
|
||||
/// <summary>
|
||||
/// Create the authenticator wrapper
|
||||
/// </summary>
|
||||
public WinAuthAuthenticator()
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
Created = DateTime.Now;
|
||||
_autoRefresh = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clone this authenticator
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public object Clone()
|
||||
{
|
||||
WinAuthAuthenticator clone = this.MemberwiseClone() as WinAuthAuthenticator;
|
||||
|
||||
clone.Id = Guid.NewGuid();
|
||||
clone.OnWinAuthAuthenticatorChanged = null;
|
||||
clone.AuthenticatorData = (this.AuthenticatorData != null ? this.AuthenticatorData.Clone() as Authenticator : null);
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mark this authenticator as having changed
|
||||
/// </summary>
|
||||
public void MarkChanged()
|
||||
{
|
||||
if (OnWinAuthAuthenticatorChanged != null)
|
||||
{
|
||||
OnWinAuthAuthenticatorChanged(this, new WinAuthAuthenticatorChangedEventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set the name of this authenticator
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
if (OnWinAuthAuthenticatorChanged != null)
|
||||
{
|
||||
OnWinAuthAuthenticatorChanged(this, new WinAuthAuthenticatorChangedEventArgs("Name"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set auto refresh flag
|
||||
/// </summary>
|
||||
public bool AutoRefresh
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.AuthenticatorData != null && this.AuthenticatorData is HOTPAuthenticator)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return _autoRefresh;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
// HTOP must always be false
|
||||
if (this.AuthenticatorData != null && this.AuthenticatorData is HOTPAuthenticator)
|
||||
{
|
||||
_autoRefresh = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_autoRefresh = value;
|
||||
}
|
||||
if (OnWinAuthAuthenticatorChanged != null)
|
||||
{
|
||||
OnWinAuthAuthenticatorChanged(this, new WinAuthAuthenticatorChangedEventArgs("AutoRefresh"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set allow copy flag
|
||||
/// </summary>
|
||||
public bool AllowCopy
|
||||
{
|
||||
get
|
||||
{
|
||||
return _allowCopy;
|
||||
}
|
||||
set
|
||||
{
|
||||
_allowCopy = value;
|
||||
if (OnWinAuthAuthenticatorChanged != null)
|
||||
{
|
||||
OnWinAuthAuthenticatorChanged(this, new WinAuthAuthenticatorChangedEventArgs("AllowCopy"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set auto copy flag
|
||||
/// </summary>
|
||||
public bool CopyOnCode
|
||||
{
|
||||
get
|
||||
{
|
||||
return _copyOnCode;
|
||||
}
|
||||
set
|
||||
{
|
||||
_copyOnCode = value;
|
||||
if (OnWinAuthAuthenticatorChanged != null)
|
||||
{
|
||||
OnWinAuthAuthenticatorChanged(this, new WinAuthAuthenticatorChangedEventArgs("CopyOnCode"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set hide serial flag
|
||||
/// </summary>
|
||||
public bool HideSerial
|
||||
{
|
||||
get
|
||||
{
|
||||
return _hideSerial;
|
||||
}
|
||||
set
|
||||
{
|
||||
_hideSerial = value;
|
||||
if (OnWinAuthAuthenticatorChanged != null)
|
||||
{
|
||||
OnWinAuthAuthenticatorChanged(this, new WinAuthAuthenticatorChangedEventArgs("HideSerial"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public string CurrentCode
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.AuthenticatorData == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string code = this.AuthenticatorData.CurrentCode;
|
||||
|
||||
if (this.AuthenticatorData is HOTPAuthenticator)
|
||||
{
|
||||
if (OnWinAuthAuthenticatorChanged != null)
|
||||
{
|
||||
OnWinAuthAuthenticatorChanged(this, new WinAuthAuthenticatorChangedEventArgs("HOTP", this.AuthenticatorData));
|
||||
}
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sync the current authenticator's time with its server
|
||||
/// </summary>
|
||||
public void Sync()
|
||||
{
|
||||
if (AuthenticatorData != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
AuthenticatorData.Sync();
|
||||
}
|
||||
catch (EncryptedSecretDataException)
|
||||
{
|
||||
// reset lastsync to force sync on next decryption
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the current code to the clipboard
|
||||
/// </summary>
|
||||
public void CopyCodeToClipboard(string code = null, bool showError = false)
|
||||
{
|
||||
if (code == null)
|
||||
{
|
||||
code = this.CurrentCode;
|
||||
}
|
||||
|
||||
bool clipRetry = false;
|
||||
do
|
||||
{
|
||||
bool failed = false;
|
||||
// check if the clipboard is locked
|
||||
IntPtr hWnd = WinAPI.GetOpenClipboardWindow();
|
||||
if (hWnd != IntPtr.Zero)
|
||||
{
|
||||
int len = WinAPI.GetWindowTextLength(hWnd);
|
||||
if (len == 0)
|
||||
{
|
||||
//WinAuthMain.LogException(new ApplicationException("Clipboard in use by another process"));
|
||||
}
|
||||
else
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(len + 1);
|
||||
WinAPI.GetWindowText(hWnd, sb, sb.Capacity);
|
||||
//WinAuthMain.LogException(new ApplicationException("Clipboard in use by '" + sb.ToString() + "'"));
|
||||
}
|
||||
|
||||
failed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Issue#170: can still get error copying even though it works, so just increase retries and ignore error
|
||||
try
|
||||
{
|
||||
Clipboard.Clear();
|
||||
|
||||
// add delay for clip error
|
||||
System.Threading.Thread.Sleep(100);
|
||||
Clipboard.SetDataObject(code, true);
|
||||
}
|
||||
catch (ExternalException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (failed == true && showError == true)
|
||||
{
|
||||
// only show an error the first time
|
||||
//clipRetry = (MessageBox.Show(form, strings.ClipboardInUse,
|
||||
// WinAuthMain.APPLICATION_NAME,
|
||||
// MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Yes);
|
||||
|
||||
}
|
||||
}
|
||||
while (clipRetry == true);
|
||||
}
|
||||
|
||||
public bool ReadXml(XmlReader reader, string password)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
Guid id;
|
||||
if (Guid.TryParse(reader.GetAttribute("id"), out id) == true)
|
||||
{
|
||||
Id = id;
|
||||
}
|
||||
|
||||
string authenticatorType = reader.GetAttribute("type");
|
||||
if (string.IsNullOrEmpty(authenticatorType) == false)
|
||||
{
|
||||
Type type = typeof(Authenticator).Assembly.GetType(authenticatorType, false, true);
|
||||
this.AuthenticatorData = Activator.CreateInstance(type) as Authenticator;
|
||||
}
|
||||
|
||||
//string encrypted = reader.GetAttribute("encrypted");
|
||||
//if (string.IsNullOrEmpty(encrypted) == false)
|
||||
//{
|
||||
// // read the encrypted text from the node
|
||||
// string data = reader.ReadElementContentAsString();
|
||||
// // decrypt
|
||||
// Authenticator.PasswordTypes passwordType;
|
||||
// data = Authenticator.DecryptSequence(data, encrypted, password, out passwordType);
|
||||
|
||||
// using (MemoryStream ms = new MemoryStream(Authenticator.StringToByteArray(data)))
|
||||
// {
|
||||
// reader = XmlReader.Create(ms);
|
||||
// ReadXml(reader, password);
|
||||
// }
|
||||
// this.PasswordType = passwordType;
|
||||
// this.Password = password;
|
||||
|
||||
// return;
|
||||
//}
|
||||
|
||||
reader.MoveToContent();
|
||||
|
||||
if (reader.IsEmptyElement)
|
||||
{
|
||||
reader.Read();
|
||||
return changed;
|
||||
}
|
||||
|
||||
reader.Read();
|
||||
while (reader.EOF == false)
|
||||
{
|
||||
if (reader.IsStartElement())
|
||||
{
|
||||
switch (reader.Name)
|
||||
{
|
||||
case "name":
|
||||
Name = reader.ReadElementContentAsString();
|
||||
break;
|
||||
|
||||
case "created":
|
||||
long t = reader.ReadElementContentAsLong();
|
||||
t += Convert.ToInt64(new TimeSpan(new DateTime(1970, 1, 1).Ticks).TotalMilliseconds);
|
||||
t *= TimeSpan.TicksPerMillisecond;
|
||||
Created = new DateTime(t).ToLocalTime();
|
||||
break;
|
||||
|
||||
case "autorefresh":
|
||||
_autoRefresh = reader.ReadElementContentAsBoolean();
|
||||
break;
|
||||
|
||||
case "allowcopy":
|
||||
_allowCopy = reader.ReadElementContentAsBoolean();
|
||||
break;
|
||||
|
||||
case "copyoncode":
|
||||
_copyOnCode = reader.ReadElementContentAsBoolean();
|
||||
break;
|
||||
|
||||
case "hideserial":
|
||||
_hideSerial = reader.ReadElementContentAsBoolean();
|
||||
break;
|
||||
|
||||
case "authenticatordata":
|
||||
try
|
||||
{
|
||||
// we don't pass the password as they are locked till clicked
|
||||
changed = this.AuthenticatorData.ReadXml(reader) || changed;
|
||||
}
|
||||
catch (EncryptedSecretDataException)
|
||||
{
|
||||
// no action needed
|
||||
}
|
||||
catch (BadPasswordException)
|
||||
{
|
||||
// no action needed
|
||||
}
|
||||
break;
|
||||
|
||||
// v2
|
||||
case "authenticator":
|
||||
this.AuthenticatorData = Authenticator.ReadXmlv2(reader, password);
|
||||
break;
|
||||
// v2
|
||||
case "servertimediff":
|
||||
this.AuthenticatorData.ServerTimeDiff = reader.ReadElementContentAsLong();
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
reader.Skip();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.Read();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the data as xml into an XmlWriter
|
||||
/// </summary>
|
||||
/// <param name="writer">XmlWriter to write config</param>
|
||||
public void WriteXmlString(XmlWriter writer)
|
||||
{
|
||||
writer.WriteStartElement(typeof(WinAuthAuthenticator).Name);
|
||||
writer.WriteAttributeString("id", this.Id.ToString());
|
||||
if (this.AuthenticatorData != null)
|
||||
{
|
||||
writer.WriteAttributeString("type", this.AuthenticatorData.GetType().FullName);
|
||||
}
|
||||
|
||||
//if (this.PasswordType != Authenticator.PasswordTypes.None)
|
||||
//{
|
||||
// string data;
|
||||
|
||||
// using (MemoryStream ms = new MemoryStream())
|
||||
// {
|
||||
// XmlWriterSettings settings = new XmlWriterSettings();
|
||||
// settings.Indent = true;
|
||||
// settings.Encoding = Encoding.UTF8;
|
||||
// using (XmlWriter encryptedwriter = XmlWriter.Create(ms, settings))
|
||||
// {
|
||||
// Authenticator.PasswordTypes savedpasswordType = PasswordType;
|
||||
// PasswordType = Authenticator.PasswordTypes.None;
|
||||
// WriteXmlString(encryptedwriter);
|
||||
// PasswordType = savedpasswordType;
|
||||
// }
|
||||
// //data = Encoding.UTF8.GetString(ms.ToArray());
|
||||
// data = Authenticator.ByteArrayToString(ms.ToArray());
|
||||
// }
|
||||
|
||||
// string encryptedTypes;
|
||||
// data = Authenticator.EncryptSequence(data, PasswordType, Password, out encryptedTypes);
|
||||
// writer.WriteAttributeString("encrypted", encryptedTypes);
|
||||
// writer.WriteString(data);
|
||||
// writer.WriteEndElement();
|
||||
|
||||
// return;
|
||||
//}
|
||||
|
||||
writer.WriteStartElement("name");
|
||||
writer.WriteValue(this.Name ?? string.Empty);
|
||||
writer.WriteEndElement();
|
||||
|
||||
writer.WriteStartElement("created");
|
||||
writer.WriteValue(Convert.ToInt64((this.Created.ToUniversalTime() - new DateTime(1970, 1, 1)).TotalMilliseconds));
|
||||
writer.WriteEndElement();
|
||||
|
||||
writer.WriteStartElement("autorefresh");
|
||||
writer.WriteValue(this.AutoRefresh);
|
||||
writer.WriteEndElement();
|
||||
//
|
||||
writer.WriteStartElement("allowcopy");
|
||||
writer.WriteValue(this.AllowCopy);
|
||||
writer.WriteEndElement();
|
||||
//
|
||||
writer.WriteStartElement("copyoncode");
|
||||
writer.WriteValue(this.CopyOnCode);
|
||||
writer.WriteEndElement();
|
||||
//
|
||||
writer.WriteStartElement("hideserial");
|
||||
writer.WriteValue(this.HideSerial);
|
||||
writer.WriteEndElement();
|
||||
//
|
||||
|
||||
// save the authenticator to the config file
|
||||
if (this.AuthenticatorData != null)
|
||||
{
|
||||
this.AuthenticatorData.WriteToWriter(writer);
|
||||
|
||||
// save script with password and generated salt
|
||||
//if (this.AutoLogin != null)
|
||||
//{
|
||||
// this.AutoLogin.WriteXmlString(writer, this.AuthenticatorData.PasswordType, this.AuthenticatorData.Password);
|
||||
//}
|
||||
}
|
||||
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a KeyUriFormat compatible URL
|
||||
/// See https://code.google.com/p/google-authenticator/wiki/KeyUriFormat
|
||||
/// </summary>
|
||||
/// <returns>string</returns>
|
||||
public virtual string ToUrl(bool compat = false)
|
||||
{
|
||||
string type = "totp";
|
||||
string extraparams = string.Empty;
|
||||
|
||||
Match match;
|
||||
string issuer = this.AuthenticatorData.Issuer;
|
||||
string label = this.Name;
|
||||
if (string.IsNullOrEmpty(issuer) == true && (match = Regex.Match(label, @"^([^\(]+)\s+\((.*?)\)(.*)")).Success == true)
|
||||
{
|
||||
issuer = match.Groups[1].Value;
|
||||
label = match.Groups[2].Value + match.Groups[3].Value;
|
||||
}
|
||||
if (string.IsNullOrEmpty(issuer) == false && (match = Regex.Match(label, @"^" + issuer + @"\s+\((.*?)\)(.*)")).Success == true)
|
||||
{
|
||||
label = match.Groups[1].Value + match.Groups[2].Value;
|
||||
}
|
||||
if (string.IsNullOrEmpty(issuer) == false)
|
||||
{
|
||||
extraparams += "&issuer=" + HttpUtility.UrlEncode(issuer);
|
||||
}
|
||||
|
||||
if (this.AuthenticatorData.HMACType != Authenticator.DEFAULT_HMAC_TYPE)
|
||||
{
|
||||
extraparams += "&algorithm=" + this.AuthenticatorData.HMACType.ToString();
|
||||
}
|
||||
|
||||
if (this.AuthenticatorData is BattleNetAuthenticator)
|
||||
{
|
||||
extraparams += "&serial=" + HttpUtility.UrlEncode(((BattleNetAuthenticator)this.AuthenticatorData).Serial.Replace("-", ""));
|
||||
}
|
||||
else if (this.AuthenticatorData is SteamAuthenticator)
|
||||
{
|
||||
if (compat == false)
|
||||
{
|
||||
extraparams += "&deviceid=" + HttpUtility.UrlEncode(((SteamAuthenticator)this.AuthenticatorData).DeviceId);
|
||||
extraparams += "&data=" + HttpUtility.UrlEncode(((SteamAuthenticator)this.AuthenticatorData).SteamData);
|
||||
}
|
||||
}
|
||||
else if (this.AuthenticatorData is HOTPAuthenticator)
|
||||
{
|
||||
type = "hotp";
|
||||
extraparams += "&counter=" + ((HOTPAuthenticator)this.AuthenticatorData).Counter;
|
||||
}
|
||||
|
||||
string secret = HttpUtility.UrlEncode(Base32.getInstance().Encode(this.AuthenticatorData.SecretKey));
|
||||
|
||||
if (this.AuthenticatorData.Period != Authenticator.DEFAULT_PERIOD)
|
||||
{
|
||||
extraparams += "&period=" + this.AuthenticatorData.Period;
|
||||
}
|
||||
|
||||
var url = string.Format("otpauth://" + type + "/{0}?secret={1}&digits={2}{3}",
|
||||
(string.IsNullOrEmpty(issuer) == false ? HttpUtility.UrlPathEncode(issuer) + ":" + HttpUtility.UrlPathEncode(label) : HttpUtility.UrlPathEncode(label)),
|
||||
secret,
|
||||
this.AuthenticatorData.CodeDigits,
|
||||
extraparams);
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delegate for ConfigChange event
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="args"></param>
|
||||
public delegate void WinAuthAuthenticatorChangedHandler(WinAuthAuthenticator source, WinAuthAuthenticatorChangedEventArgs args);
|
||||
|
||||
/// <summary>
|
||||
/// Change event arguments
|
||||
/// </summary>
|
||||
public class WinAuthAuthenticatorChangedEventArgs : EventArgs
|
||||
{
|
||||
public string Property { get; private set; }
|
||||
public Authenticator Authenticator { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public WinAuthAuthenticatorChangedEventArgs(string property = null, Authenticator authenticator = null)
|
||||
{
|
||||
Property = property;
|
||||
Authenticator = authenticator;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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); ;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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.HostTag);
|
||||
builder.AppendLine("-----BEGIN CERTIFICATE-----");
|
||||
builder.AppendLine(
|
||||
Convert.ToBase64String(@this.RawData, Base64FormattingOptions.InsertLineBreaks));
|
||||
builder.AppendLine("-----END CERTIFICATE-----");
|
||||
builder.AppendLine(Const.HostTag);
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +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.Core
|
||||
{
|
||||
public class VdfService
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 获取VDF类型内容
|
||||
/// </summary>
|
||||
/// <param name="path">vdf文件内容</param>
|
||||
/// <returns></returns>
|
||||
public dynamic GetVdfModel(string text)
|
||||
{
|
||||
return VdfConvert.Deserialize(text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据路径获取VDF类型内容
|
||||
/// </summary>
|
||||
/// <param name="path">vdf文件路径</param>
|
||||
/// <returns></returns>
|
||||
public dynamic GetVdfModelByPath(string path)
|
||||
{
|
||||
string text = File.ReadAllText(path,Encoding.UTF8);
|
||||
return GetVdfModel(text); ;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace SteamTool.Model
|
||||
{
|
||||
public class SteamUser
|
||||
{
|
||||
public string SteamId3 { get; set; }
|
||||
public long SteamId3_Int => ((SteamId64 >> (ushort)0) & 0xFFFFFFFF);
|
||||
|
||||
public string SteamId32 { get; set; }
|
||||
public long SteamId32_Int { get; set; }
|
||||
|
||||
public long SteamId64 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 个人资料链接
|
||||
/// </summary>
|
||||
public string ProfileUrl => string.Format("https://steamcommunity.com/profiles/{0}", SteamId64);
|
||||
|
||||
/// <summary>
|
||||
/// 在线状态
|
||||
/// </summary>
|
||||
public string OnlineState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 公开状态
|
||||
/// friendsonly
|
||||
/// public
|
||||
/// </summary>
|
||||
public string PrivacyState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 头像链接
|
||||
/// </summary>
|
||||
public string AvatarIcon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 头像链接
|
||||
/// </summary>
|
||||
public string AvatarMedium { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 头像链接
|
||||
/// </summary>
|
||||
public string AvatarFull { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 昵称
|
||||
/// </summary>
|
||||
public string SteamID { 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; }
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,14 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SteamTool.Composition.Interface
|
||||
{
|
||||
[PluginFeature]
|
||||
public interface ITool
|
||||
{
|
||||
string Name { get; }
|
||||
|
||||
object View { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SteamTool.Composition
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Interface)]
|
||||
public sealed class PluginFeatureAttribute : Attribute { }
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<Configurations>Debug;Release;发布</Configurations>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<Platforms>AnyCPU;x86</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
+105
-240
@@ -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", "SteamTools.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
using MetroTrilithon.Serialization;
|
||||
using SteamTool.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SteamTools.Models.Settings
|
||||
{
|
||||
public static class GeneralSettings
|
||||
{
|
||||
static GeneralSettings()
|
||||
{
|
||||
WindowsStartupAutoRun.ValueChanged += WindowsStartupAutoRun_ValueChanged;
|
||||
}
|
||||
|
||||
private static void WindowsStartupAutoRun_ValueChanged(object sender, ValueChangedEventArgs<bool> e)
|
||||
{
|
||||
var steamService = SteamToolCore.Instance.Get<SteamToolService>();
|
||||
steamService.SetWindowsStartupAutoRun(e.NewValue, ProductInfo.Title);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 多语言设置
|
||||
/// </summary>
|
||||
public static SerializableProperty<string> Culture { get; }
|
||||
= new SerializableProperty<string>(GetKey(), Providers.Roaming) { AutoSave = true };
|
||||
|
||||
/// <summary>
|
||||
/// 程序是否开机自启动
|
||||
/// </summary>
|
||||
public static SerializableProperty<bool> WindowsStartupAutoRun { get; }
|
||||
= new SerializableProperty<bool>(GetKey(), Providers.Roaming, false) { AutoSave = true };
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示起始页
|
||||
/// </summary>
|
||||
public static SerializableProperty<bool> IsShowStartPage { get; }
|
||||
= new SerializableProperty<bool>(GetKey(), Providers.Roaming, true) { AutoSave = true };
|
||||
|
||||
/// <summary>
|
||||
/// 游戏列表本地缓存
|
||||
/// </summary>
|
||||
public static SerializableProperty<bool> IsSteamAppListLocalCache { get; }
|
||||
= new SerializableProperty<bool>(GetKey(), Providers.Roaming, true) { AutoSave = true };
|
||||
|
||||
|
||||
private static string GetKey([CallerMemberName] string propertyName = "")
|
||||
{
|
||||
return nameof(GeneralSettings) + "." + propertyName;
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 243 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 510 B |
@@ -1,322 +0,0 @@
|
||||
using Livet;
|
||||
using SteamTool.Proxy;
|
||||
using SteamTool.Proxy.Properties;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
using SteamTool.Model;
|
||||
using SteamTools.Models;
|
||||
using SteamTools.Models.Settings;
|
||||
|
||||
namespace SteamTools.Services
|
||||
{
|
||||
public class ProxyService : NotificationObject
|
||||
{
|
||||
public static ProxyService Current { get; } = new ProxyService();
|
||||
|
||||
public HttpProxy Proxy { get; set; }
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
if (ProxySettings.SupportProxyServicesStatus.Value.Count > 0)
|
||||
{
|
||||
foreach (var item in ProxyDomains.Value)
|
||||
{
|
||||
if (ProxySettings.SupportProxyServicesStatus.Value.TryGetValue(item.Index, out bool value))
|
||||
{
|
||||
item.IsEnable = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
Proxy = new HttpProxy(ProxyDomains.Value, ProductInfo.Product);
|
||||
InitJsScript();
|
||||
}
|
||||
|
||||
private Lazy<IReadOnlyCollection<ProxyDomainModel>> _ProxyDomains = new Lazy<IReadOnlyCollection<ProxyDomainModel>>(() => new List<ProxyDomainModel>
|
||||
{
|
||||
new ProxyDomainModel{
|
||||
Index=0,
|
||||
Name=Resources.SteamCommunity,
|
||||
Domains = new List<string>{"steamcommunity.com" },
|
||||
ToDomain = "steamcommunity-a.akamaihd.net",
|
||||
Hosts = new List<string>{ "steamcommunity.com", "www.steamcommunity.com"},
|
||||
DomainTag = DomainTag.SteamCommunity,
|
||||
IsEnable= true,
|
||||
},
|
||||
new ProxyDomainModel{
|
||||
Index=1,
|
||||
Name=Resources.SteamStore,
|
||||
Domains = new List<string>{"steampowered.com" },
|
||||
ToDomain = "steamstore-a.akamaihd.net",
|
||||
Hosts = new List<string>{ "store.steampowered.com", "api.steampowered.com"},
|
||||
DomainTag = DomainTag.SteamStore,
|
||||
IsEnable= false,
|
||||
},
|
||||
//new ProxyDomainModel{
|
||||
// Index=2,
|
||||
// Name=Resources.SteamImage,
|
||||
// Domains = new List<string>{"steamcdn-a.akamaihd.net" },
|
||||
// ToDomain = "steamuserimages-a.akamaihd.net",
|
||||
// Hosts = new List<string>{ "steamcdn-a.akamaihd.net"},
|
||||
// DomainTag = DomainTag.SteamImage,
|
||||
// IsEnable= false,
|
||||
//},
|
||||
new ProxyDomainModel{
|
||||
Index=3,
|
||||
Name=Resources.SteamChat,
|
||||
Domains = new List<string>{"steam-chat.com" },
|
||||
ToDomain = "s.team",
|
||||
Hosts = new List<string>{ "steam-chat.com"},
|
||||
DomainTag = DomainTag.SteamChat,
|
||||
IsEnable= false,
|
||||
},
|
||||
//new ProxyDomainModel{
|
||||
//Index=4,
|
||||
// Name=Resources.Discord,
|
||||
// Domains = new List<string>{ "discordapp.com" },
|
||||
// ToDomain = "discord.com",
|
||||
// //ProxyIPAddres="104.16.10.231",
|
||||
// Hosts = new List<string>{
|
||||
// "discordapp.com",
|
||||
// "dl.discordapp.net",
|
||||
// "media.discordapp.net",
|
||||
// "images-ext-2.discordapp.net",
|
||||
// "images-ext-1.discordapp.net",
|
||||
// "support.discordapp.com",
|
||||
// "url9177.discordapp.com",
|
||||
// "canary-api.discordapp.com",
|
||||
// "cdn-ptb.discordapp.com",
|
||||
// "ptb.discordapp.com",
|
||||
// "status.discordapp.com",
|
||||
// "cdn-canary.discordapp.com",
|
||||
// "cdn.discordapp.com",
|
||||
// "streamkit.discordapp.com",
|
||||
// "i18n.discordapp.com" ,
|
||||
// "url9624.discordapp.com",
|
||||
// "url7195.discordapp.com",
|
||||
// "merch.discordapp.com",
|
||||
// "printer.discordapp.com",
|
||||
// "canary.discordapp.com",
|
||||
// "apps.discordapp.com",
|
||||
// "pax.discordapp.com",
|
||||
// },
|
||||
// DomainTag = DomainTag.Discord,
|
||||
// IsEnable= false,
|
||||
//},
|
||||
new ProxyDomainModel{
|
||||
Index=5,
|
||||
Name=Resources.Twitch,
|
||||
Domains = new List<string>{ "twitch.tv" },
|
||||
ToDomain="twitch.map.fastly.net",
|
||||
Hosts = new List<string>{
|
||||
"twitch.tv",
|
||||
"www.twitch.tv",
|
||||
"m.twitch.tv",
|
||||
"app.twitch.tv",
|
||||
"music.twitch.tv",
|
||||
"badges.twitch.tv",
|
||||
"blog.twitch.tv",
|
||||
"inspector.twitch.tv",
|
||||
"stream.twitch.tv",
|
||||
"dev.twitch.tv",
|
||||
"clips.twitch.tv",
|
||||
"spade.twitch.tv",
|
||||
"gql.twitch.tv",
|
||||
"vod-secure.twitch.tv",
|
||||
"vod-storyboards.twitch.tv",
|
||||
"trowel.twitch.tv",
|
||||
"countess.twitch.tv",
|
||||
"extension-files.twitch.tv",
|
||||
"vod-metro.twitch.tv",
|
||||
"pubster.twitch.tv",
|
||||
"help.twitch.tv",
|
||||
"passport.twitch.tv",
|
||||
"id.twitch.tv",
|
||||
"link.twitch.tv",
|
||||
"id-cdn.twitch.tv",
|
||||
"player.twitch.tv",
|
||||
"api.twitch.tv",
|
||||
"cvp.twitch.tv",
|
||||
"clips-media-assets2.twitch.tv",
|
||||
"client-event-reporter.twitch.tv",
|
||||
"gds-vhs-drops-campaign-images.twitch.tv",
|
||||
"us-west-2.uploads-regional.twitch.tv",
|
||||
"assets.help.twitch.tv",
|
||||
"discuss.dev.twitch.tv",
|
||||
"pubsub-edge.twitch.tv",
|
||||
"irc-ws.chat.twitch.tv",
|
||||
"irc-ws-r.chat.twitch.tv",
|
||||
//"platform.twitter.com",
|
||||
//"usher.ttvnw.net",
|
||||
},
|
||||
DomainTag = DomainTag.Twitch,
|
||||
IsEnable= false,
|
||||
},
|
||||
new ProxyDomainModel{
|
||||
Index=6,
|
||||
Name=Resources.OriginDownload,
|
||||
Domains = new List<string>{"origin-a.akamaihd.net" },
|
||||
ToDomain = "cctv4-lh.akamaihd.net",
|
||||
Hosts = new List<string>{ "origin-a.akamaihd.net"},
|
||||
DomainTag = DomainTag.OriginGameDownload,
|
||||
IsEnable= false,
|
||||
},
|
||||
//new ProxyDomainModel{
|
||||
// Name=Resources.UplayUpdate,
|
||||
// Domains = new List<string>{"static3.cdn.ubi.com" },
|
||||
// ToDomain = "static3.cdn.ubi.com",
|
||||
// Hosts = new List<string>{ "static3.cdn.ubi.com"},
|
||||
// DomainTag = DomainTag.UplayUpdate,
|
||||
// IsEnable= false,
|
||||
//},
|
||||
new ProxyDomainModel{
|
||||
Index=7,
|
||||
Name=Resources.GOG,
|
||||
Domains = new List<string>{ "gog.com" },
|
||||
ToDomain = "api.gog.com",
|
||||
Hosts = new List<string>{
|
||||
"www.gog.com",
|
||||
"images.gog.com",
|
||||
"images-1.gog.com",
|
||||
"images-2.gog.com",
|
||||
"images-3.gog.com",
|
||||
"images-4.gog.com",
|
||||
"webinstallers.gog.com",
|
||||
"menu.gog.com",
|
||||
"auth.gog.com",
|
||||
"login.gog.com",
|
||||
//"api.gog.com",
|
||||
"reviews.gog.com",
|
||||
"insights-collector.gog.com",
|
||||
"remote-config.gog.com",
|
||||
"external-accounts.gog.com",
|
||||
"chat.gog.com",
|
||||
"presence.gog.com",
|
||||
"external-users.gog.com",
|
||||
"gamesdb.gog.com",
|
||||
"gameplay.gog.com",
|
||||
"cfg.gog.com",
|
||||
"notifications.gog.com",
|
||||
"users.gog.com",
|
||||
},
|
||||
DomainTag = DomainTag.GOG,
|
||||
IsEnable= false,
|
||||
},
|
||||
new ProxyDomainModel{
|
||||
Index=8,
|
||||
Name=Resources.GoogleRecaptchaCode,
|
||||
Domains = new List<string>{"www.google.com" },
|
||||
ToDomain = "kh.google.com",
|
||||
Hosts = new List<string>{ "www.google.com"},
|
||||
DomainTag = DomainTag.GoogleCode,
|
||||
IsEnable= false,
|
||||
},
|
||||
});
|
||||
public Lazy<IReadOnlyCollection<ProxyDomainModel>> ProxyDomains
|
||||
{
|
||||
get => _ProxyDomains;
|
||||
set
|
||||
{
|
||||
if (_ProxyDomains != value)
|
||||
{
|
||||
_ProxyDomains = value;
|
||||
Proxy.ProxyDomains = value.Value;
|
||||
this.RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsEnableScript
|
||||
{
|
||||
get => ProxySettings.IsEnableScript.Value;
|
||||
set
|
||||
{
|
||||
if (ProxySettings.IsEnableScript.Value != value)
|
||||
{
|
||||
ProxySettings.IsEnableScript.Value = value;
|
||||
Proxy.IsEnableScript = value;
|
||||
this.RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region 代理状态变更通知
|
||||
public bool ProxyStatus
|
||||
{
|
||||
get { return Proxy.ProxyRunning; }
|
||||
set
|
||||
{
|
||||
if (value != Proxy.ProxyRunning)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
var isRun = Proxy.StartProxy(ProxySettings.IsProxyGOG.Value);
|
||||
if (isRun)
|
||||
{
|
||||
StatusService.Current.Notify(SteamTools.Properties.Resources.ProxyRun);
|
||||
}
|
||||
else
|
||||
{
|
||||
WindowService.Current.ShowDialogWindow("启动加速服务失败,请检查443端口是否被占用或者证书安装失败。");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Proxy.StopProxy();
|
||||
StatusService.Current.Notify(SteamTools.Properties.Resources.ProxyStop);
|
||||
}
|
||||
this.RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private List<ProxyScript> _ProxyScripts;
|
||||
public List<ProxyScript> ProxyScripts
|
||||
{
|
||||
get => _ProxyScripts;
|
||||
set
|
||||
{
|
||||
if (_ProxyScripts != value)
|
||||
{
|
||||
_ProxyScripts = value;
|
||||
Proxy.Scripts = value;
|
||||
this.RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载js脚本列表
|
||||
/// </summary>
|
||||
public void InitJsScript()
|
||||
{
|
||||
var scripts = new List<ProxyScript>();
|
||||
var dir = new DirectoryInfo(Const.SCRIPT_DIR);
|
||||
if (!dir.Exists)
|
||||
{
|
||||
dir.Create();
|
||||
return;
|
||||
}
|
||||
foreach (var file in dir.GetFiles())
|
||||
{
|
||||
if (file.Extension.Equals(".js", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (ProxyScript.TryParse(file.FullName, out var script))
|
||||
scripts.Add(script);
|
||||
else
|
||||
scripts.Add(new ProxyScript { FilePath = file.FullName, Name = Resources.Not_Support_JS });
|
||||
}
|
||||
}
|
||||
ProxyScripts = scripts;
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
Current.Proxy?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,151 +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()
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (Process.GetProcessesByName("steam").Length > 0)
|
||||
{
|
||||
if (!IsConnectToSteam)
|
||||
{
|
||||
IsConnectToSteam = ApiService.Initialize();
|
||||
if (IsConnectToSteam)
|
||||
{
|
||||
var id = ApiService.GetSteamId64();
|
||||
if (id == 76561197960265728)
|
||||
{
|
||||
//该64位id的steamID3等于0,是steam未获取到当前登录用户的默认返回值,所以直接重新获取
|
||||
IsConnectToSteam = false;
|
||||
continue;
|
||||
}
|
||||
CurrentSteamUser = await steamDbApiService.GetUserInfo(id);
|
||||
var mainViewModel = (WindowService.Current.MainWindow as MainWindowViewModel);
|
||||
mainViewModel.SteamAppPage.Initialize();
|
||||
#if DEBUG
|
||||
mainViewModel.SystemTabItems[mainViewModel.SystemTabItems.Count - 1].Initialize();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
IsConnectToSteam = false;
|
||||
//StatusService.Current.Notify(Resources.Steam_Not_Runing);
|
||||
}
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using SteamTools.Models;
|
||||
using Livet;
|
||||
using MetroRadiance.UI.Controls;
|
||||
using Livet.EventListeners;
|
||||
using SteamTools.Services;
|
||||
|
||||
namespace SteamTools.ViewModels
|
||||
{
|
||||
public abstract class TabItemViewModel : ItemViewModel, ITabItem
|
||||
{
|
||||
#region Name 変更通知
|
||||
|
||||
public abstract string Name { get; protected set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Badge 変更通知
|
||||
|
||||
private int? _Badge;
|
||||
|
||||
public virtual int? Badge
|
||||
{
|
||||
get { return this._Badge; }
|
||||
protected set
|
||||
{
|
||||
if (this._Badge != value)
|
||||
{
|
||||
this._Badge = value;
|
||||
this.RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Status 変更通知
|
||||
|
||||
private ViewModel _Status;
|
||||
|
||||
/// <summary>
|
||||
/// 获取状态栏中显示的状态
|
||||
/// </summary>
|
||||
public virtual ViewModel Status
|
||||
{
|
||||
get { return this._Status; }
|
||||
protected set
|
||||
{
|
||||
if (this._Status != value)
|
||||
{
|
||||
this._Status = value;
|
||||
this.RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
protected TabItemViewModel()
|
||||
{
|
||||
if (Models.Helper.IsInDesignMode) return;
|
||||
|
||||
this.CompositeDisposable.Add(new PropertyChangedEventListener(ResourceService.Current)
|
||||
{
|
||||
(sender, args) => this.RaisePropertyChanged(nameof(this.Name)),
|
||||
});
|
||||
}
|
||||
|
||||
internal virtual void Initialize()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,64 +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;
|
||||
|
||||
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, 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 =>
|
||||
{
|
||||
StatusService.Current.Notify("刷新Steam游戏数据完成");
|
||||
IsRefreshGameListCache = false;
|
||||
s.Dispose();
|
||||
});
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusService.Current.Notify("未检测到Steam运行");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
using MetroRadiance.Platform;
|
||||
using SteamTool.Steam.Service.Local;
|
||||
using SteamTools.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SteamTools.ViewModels
|
||||
{
|
||||
public class DebugPageViewModel : TabItemViewModel
|
||||
{
|
||||
public override string Name
|
||||
{
|
||||
get => Properties.Resources.Debug;
|
||||
protected set { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
private string _DebugText;
|
||||
public string DebugText
|
||||
{
|
||||
get => this._DebugText;
|
||||
set
|
||||
{
|
||||
if (this._DebugText != value)
|
||||
{
|
||||
this._DebugText = value;
|
||||
this.RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DebugPageViewModel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
internal override void Initialize()
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
DebugText += SteamConnectService.Current.IsConnectToSteam;
|
||||
DebugText += Environment.NewLine;
|
||||
DebugText += SteamConnectService.Current.ApiService.GetSteamId64();
|
||||
DebugText += Environment.NewLine;
|
||||
DebugText += SteamConnectService.Current.ApiService.SteamClient.SteamUtils.GetAppId();
|
||||
DebugText += Environment.NewLine;
|
||||
DebugText += SteamConnectService.Current.ApiService.SteamClient.SteamApps008.IsAppInstalled(730);
|
||||
DebugText += Environment.NewLine;
|
||||
DebugText += SteamConnectService.Current.ApiService.SteamClient.SteamApps008.IsSubscribedFromFamilySharing();
|
||||
DebugText += Environment.NewLine;
|
||||
DebugText += SteamConnectService.Current.ApiService.SteamClient.SteamApps008.GetAppInstallDir(730);
|
||||
DebugText += Environment.NewLine;
|
||||
}).ContinueWith(s => s.Dispose());
|
||||
}
|
||||
|
||||
public void Test_OnClick()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MetroRadiance.UI;
|
||||
using SteamTool.Model;
|
||||
using SteamTool.Core;
|
||||
using SteamTools.Models;
|
||||
using Microsoft.Xaml.Behaviors.Core;
|
||||
using System.Diagnostics;
|
||||
using SteamTool.Steam.Service.Web;
|
||||
using SteamTool.Steam.Service;
|
||||
using SteamTools.Services;
|
||||
|
||||
namespace SteamTools.ViewModels
|
||||
{
|
||||
public class SteamAccountPageViewModel : TabItemViewModel
|
||||
{
|
||||
private readonly SteamToolService steamService = SteamToolCore.Instance.Get<SteamToolService>();
|
||||
private readonly SteamDbApiService webApiService = SteamService.Instance.Get<SteamDbApiService>();
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { return Properties.Resources.UserFastChange; }
|
||||
protected set { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// steam记住的用户列表
|
||||
/// </summary>
|
||||
private List<SteamUser> _steamUsers;
|
||||
|
||||
public List<SteamUser> SteamUsers
|
||||
{
|
||||
get => this._steamUsers;
|
||||
set
|
||||
{
|
||||
if (this._steamUsers != value)
|
||||
{
|
||||
this._steamUsers = value;
|
||||
this.RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal override void Initialize()
|
||||
{
|
||||
StatusService.Current.Notify("加载本地Steam用户数据");
|
||||
Task.Run(async () =>
|
||||
{
|
||||
SteamUsers = steamService.GetAllUser();
|
||||
var users = SteamUsers.ToArray();
|
||||
for (var i = 0; i < SteamUsers.Count; i++)
|
||||
{
|
||||
var temp = users[i];
|
||||
users[i] = await webApiService.GetUserInfo(SteamUsers[i].SteamId64);
|
||||
users[i].AccountName = temp.AccountName;
|
||||
users[i].RememberPassword = temp.RememberPassword;
|
||||
users[i].MostRecent = temp.MostRecent;
|
||||
users[i].Timestamp = temp.Timestamp;
|
||||
users[i].LastLoginTime = temp.LastLoginTime;
|
||||
}
|
||||
if (SteamUsers.Count > 0)
|
||||
{
|
||||
SteamUsers = users.OrderByDescending(o => o.MostRecent).ThenByDescending(o => o.RememberPassword).ThenByDescending(o => o.LastLoginTime).ToList();
|
||||
StatusService.Current.Notify("加载本地Steam用户数据完成");
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusService.Current.Notify("没有检测到Steam用户数据");
|
||||
}
|
||||
}).ContinueWith(s => s.Dispose());
|
||||
}
|
||||
|
||||
|
||||
public void SteamId_OnClick(string parameter)
|
||||
{
|
||||
steamService.SetCurrentUser(parameter);
|
||||
steamService.KillSteamProcess();
|
||||
steamService.StartSteam();
|
||||
SteamConnectService.Current.IsConnectToSteam = false;
|
||||
}
|
||||
|
||||
public static void HeadImage_OnClick(string parameter)
|
||||
{
|
||||
Process.Start(parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,37 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using SteamTool.Model;
|
||||
using SteamTools.Models.Settings;
|
||||
using SteamTools.Services;
|
||||
|
||||
namespace SteamTools.ViewModels
|
||||
{
|
||||
public class WelcomePageViewModel: TabItemViewModel
|
||||
{
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { return Properties.Resources.Welcome; }
|
||||
protected set { throw new NotImplementedException(); }
|
||||
}
|
||||
public override bool IsShowTab
|
||||
{
|
||||
get { return GeneralSettings.IsShowStartPage.Value; }
|
||||
}
|
||||
|
||||
public MainWindowViewModel Content { get; }
|
||||
|
||||
public WelcomePageViewModel(MainWindowViewModel owner)
|
||||
{
|
||||
this.Content = owner;
|
||||
}
|
||||
|
||||
internal override void Initialize()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,55 +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"
|
||||
Padding="8"
|
||||
Background="{DynamicResource ThemeBrushKey}">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Common.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<DockPanel>
|
||||
<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.0" FontSize="16"/>
|
||||
<Run Text=" "/>
|
||||
<Run Text="2020-12-14" FontSize="10" />
|
||||
<LineBreak />
|
||||
<Run Text="    "/>
|
||||
<Run Text="发布第一个版本" />
|
||||
<LineBreak/>
|
||||
<Run Text="    "/>
|
||||
<Run Text="主要功能:社区反代,帐户切换,成就解锁,本地令牌。"></Run>
|
||||
<LineBreak/>
|
||||
<Run Text="    "/>
|
||||
<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>
|
||||
@@ -1,76 +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"
|
||||
Text="{Binding Source={x:Static services:StatusService.Current}, Path=Message}"
|
||||
FontSize="13"
|
||||
Style="{DynamicResource DefaultTextStyleKey}"
|
||||
Foreground="{DynamicResource AccentForegroundBrushKey}"
|
||||
TextWrapping="NoWrap"
|
||||
Margin="8,0" />
|
||||
<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>
|
||||
@@ -1,204 +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="345" Width="180"
|
||||
FontSize="14"
|
||||
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="Auto"></RowDefinition>
|
||||
<RowDefinition Height="*"></RowDefinition>
|
||||
<RowDefinition Height="Auto"></RowDefinition>
|
||||
</Grid.RowDefinitions>
|
||||
<WrapPanel 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>
|
||||
|
||||
</WrapPanel>
|
||||
<WrapPanel 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>
|
||||
</WrapPanel>
|
||||
<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,79 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
|
||||
|
||||
namespace SteamTools.Win32
|
||||
{
|
||||
internal class WinInet
|
||||
{
|
||||
// For PInvoke: Initiates the enumeration of the cache groups in the Internet cache
|
||||
[DllImport(@"wininet",
|
||||
SetLastError = true,
|
||||
CharSet = CharSet.Auto,
|
||||
EntryPoint = "FindFirstUrlCacheGroup",
|
||||
CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern IntPtr FindFirstUrlCacheGroup(
|
||||
int dwFlags,
|
||||
int dwFilter,
|
||||
IntPtr lpSearchCondition,
|
||||
int dwSearchCondition,
|
||||
ref long lpGroupId,
|
||||
IntPtr lpReserved);
|
||||
|
||||
// For PInvoke: Retrieves the next cache group in a cache group enumeration
|
||||
[DllImport(@"wininet",
|
||||
SetLastError = true,
|
||||
CharSet = CharSet.Auto,
|
||||
EntryPoint = "FindNextUrlCacheGroup",
|
||||
CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern bool FindNextUrlCacheGroup(
|
||||
IntPtr hFind,
|
||||
ref long lpGroupId,
|
||||
IntPtr lpReserved);
|
||||
|
||||
// For PInvoke: Releases the specified GROUPID and any associated state in the cache index file
|
||||
[DllImport(@"wininet",
|
||||
SetLastError = true,
|
||||
CharSet = CharSet.Auto,
|
||||
EntryPoint = "DeleteUrlCacheGroup",
|
||||
CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern bool DeleteUrlCacheGroup(
|
||||
long groupId,
|
||||
int dwFlags,
|
||||
IntPtr lpReserved);
|
||||
|
||||
// For PInvoke: Begins the enumeration of the Internet cache
|
||||
[DllImport(@"wininet",
|
||||
SetLastError = true,
|
||||
CharSet = CharSet.Auto,
|
||||
EntryPoint = "FindFirstUrlCacheEntryA",
|
||||
CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern IntPtr FindFirstUrlCacheEntry(
|
||||
[MarshalAs(UnmanagedType.LPTStr)] string lpszUrlSearchPattern,
|
||||
IntPtr lpFirstCacheEntryInfo,
|
||||
ref int lpdwFirstCacheEntryInfoBufferSize);
|
||||
|
||||
// For PInvoke: Retrieves the next entry in the Internet cache
|
||||
[DllImport(@"wininet",
|
||||
SetLastError = true,
|
||||
CharSet = CharSet.Auto,
|
||||
EntryPoint = "FindNextUrlCacheEntryA",
|
||||
CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern bool FindNextUrlCacheEntry(
|
||||
IntPtr hFind,
|
||||
IntPtr lpNextCacheEntryInfo,
|
||||
ref int lpdwNextCacheEntryInfoBufferSize);
|
||||
|
||||
// For PInvoke: Removes the file that is associated with the source name from the cache, if the file exists
|
||||
[DllImport(@"wininet",
|
||||
SetLastError = true,
|
||||
CharSet = CharSet.Auto,
|
||||
EntryPoint = "DeleteUrlCacheEntryA",
|
||||
CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern bool DeleteUrlCacheEntry(
|
||||
IntPtr lpszUrlName);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
|
||||
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.DesktopLib", "System.Common.DesktopLib\System.Common.DesktopLib.csproj", "{F37D23AA-4EA9-4E07-9B3D-F966ABED046F}"
|
||||
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
|
||||
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
|
||||
{F37D23AA-4EA9-4E07-9B3D-F966ABED046F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F37D23AA-4EA9-4E07-9B3D-F966ABED046F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F37D23AA-4EA9-4E07-9B3D-F966ABED046F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F37D23AA-4EA9-4E07-9B3D-F966ABED046F}.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
|
||||
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}
|
||||
{F37D23AA-4EA9-4E07-9B3D-F966ABED046F} = {9AF522B5-8923-41E6-8A0A-FAE8E8F83439}
|
||||
{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}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {3833E7C5-69BC-4CB3-92CE-A8854AA35D8A}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
+187
@@ -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 = ')';
|
||||
}
|
||||
}
|
||||
+25
@@ -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);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
<?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>
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Any CPU</Platform>
|
||||
<PublishDir>bin\Release\Publish</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>
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
<?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>
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Any CPU</Platform>
|
||||
<PublishDir>bin\Release\Publish</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>
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
<?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>
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Any CPU</Platform>
|
||||
<PublishDir>bin\Release\Publish</PublishDir>
|
||||
<PublishProtocol>FileSystem</PublishProtocol>
|
||||
<RuntimeIdentifier>win-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,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>
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
<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\System.Application.SteamTools.Client.Desktop.csproj" />
|
||||
<ProjectReference Include="..\System.Common.CoreLib\System.Common.CoreLib.csproj" />
|
||||
<ProjectReference Include="..\System.Common.DesktopLib\System.Common.DesktopLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.0" />
|
||||
<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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+100
@@ -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; }
|
||||
}
|
||||
}
|
||||
+76
@@ -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,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -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);
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
<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>
|
||||
<ProjectReference Include="..\System.Application.SteamTools.Client.Desktop\System.Application.SteamTools.Client.Desktop.csproj"/>
|
||||
<ProjectReference Include="..\System.Common.CoreLib\System.Common.CoreLib.csproj"/>
|
||||
<ProjectReference Include="..\System.Common.DesktopLib\System.Common.DesktopLib.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MessageBox.Avalonia" Version="1.0.5">
|
||||
<Aliases>MessageBox_Avalonia</Aliases>
|
||||
</PackageReference>
|
||||
</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>();
|
||||
}
|
||||
}
|
||||
+64
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</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\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>
|
||||
+162
@@ -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>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user