@@ -0,0 +1,30 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
namespace Shadowsocks.Net.Settings | |||||
{ | |||||
public class ForwardProxySettings | |||||
{ | |||||
public bool NoProxy { get; set; } | |||||
public bool UseSocks5Proxy { get; set; } | |||||
public bool UseHttpProxy { get; set; } | |||||
public string Address { get; set; } | |||||
public int Port { get; set; } | |||||
public string Username { get; set; } | |||||
public string Password { get; set; } | |||||
public ForwardProxySettings() | |||||
{ | |||||
NoProxy = true; | |||||
UseSocks5Proxy = false; | |||||
UseHttpProxy = false; | |||||
Address = ""; | |||||
Port = 1088; | |||||
Username = ""; | |||||
Password = ""; | |||||
} | |||||
} | |||||
} |
@@ -12,6 +12,8 @@ namespace Shadowsocks.Net.Settings | |||||
public string HttpListeningAddress { get; set; } | public string HttpListeningAddress { get; set; } | ||||
public int Socks5ListeningPort { get; set; } | public int Socks5ListeningPort { get; set; } | ||||
public int HttpListeningPort { get; set; } | public int HttpListeningPort { get; set; } | ||||
public ForwardProxySettings ForwardProxy { get; set; } | |||||
public NetSettings() | public NetSettings() | ||||
{ | { | ||||
@@ -21,6 +23,8 @@ namespace Shadowsocks.Net.Settings | |||||
HttpListeningAddress = "::1"; | HttpListeningAddress = "::1"; | ||||
Socks5ListeningPort = 1080; | Socks5ListeningPort = 1080; | ||||
HttpListeningPort = 1080; | HttpListeningPort = 1080; | ||||
ForwardProxy = new ForwardProxySettings(); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -0,0 +1,76 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"> | |||||
<assemblyIdentity version="5.0.0.0" name="Shadowsocks.WPF"/> | |||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> | |||||
<security> | |||||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> | |||||
<!-- UAC Manifest Options | |||||
If you want to change the Windows User Account Control level replace the | |||||
requestedExecutionLevel node with one of the following. | |||||
<requestedExecutionLevel level="asInvoker" uiAccess="false" /> | |||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> | |||||
<requestedExecutionLevel level="highestAvailable" uiAccess="false" /> | |||||
Specifying requestedExecutionLevel element will disable file and registry virtualization. | |||||
Remove this element if your application requires this virtualization for backwards | |||||
compatibility. | |||||
--> | |||||
<requestedExecutionLevel level="asInvoker" uiAccess="false" /> | |||||
</requestedPrivileges> | |||||
</security> | |||||
</trustInfo> | |||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> | |||||
<application> | |||||
<!-- A list of the Windows versions that this application has been tested on | |||||
and is designed to work with. Uncomment the appropriate elements | |||||
and Windows will automatically select the most compatible environment. --> | |||||
<!-- 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> | |||||
<!-- Indicates that the application is DPI-aware and will not be automatically scaled by Windows at higher | |||||
DPIs. Windows Presentation Foundation (WPF) applications are automatically DPI-aware and do not need | |||||
to opt in. Windows Forms applications targeting .NET Framework 4.6 that opt into this setting, should | |||||
also set the 'EnableWindowsFormsHighDpiAutoResizing' setting to 'true' in their app.config. --> | |||||
<application xmlns="urn:schemas-microsoft-com:asm.v3"> | |||||
<windowsSettings> | |||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor, System</dpiAwareness> | |||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware> | |||||
</windowsSettings> | |||||
</application> | |||||
<!-- Enable themes for Windows common controls and dialogs (Windows XP and later) --> | |||||
<!-- | |||||
<dependency> | |||||
<dependentAssembly> | |||||
<assemblyIdentity | |||||
type="win32" | |||||
name="Microsoft.Windows.Common-Controls" | |||||
version="6.0.0.0" | |||||
processorArchitecture="*" | |||||
publicKeyToken="6595b64144ccf1df" | |||||
language="*" | |||||
/> | |||||
</dependentAssembly> | |||||
</dependency> | |||||
--> | |||||
</assembly> |
@@ -1,43 +0,0 @@ | |||||
using System; | |||||
namespace Shadowsocks.WPF.Models | |||||
{ | |||||
[Serializable] | |||||
public class ForwardProxyConfig | |||||
{ | |||||
public const int PROXY_SOCKS5 = 0; | |||||
public const int PROXY_HTTP = 1; | |||||
public const int MaxProxyTimeoutSec = 10; | |||||
private const int DefaultProxyTimeoutSec = 3; | |||||
public bool useProxy; | |||||
public int proxyType; | |||||
public string proxyServer; | |||||
public int proxyPort; | |||||
public int proxyTimeout; | |||||
public bool useAuth; | |||||
public string authUser; | |||||
public string authPwd; | |||||
public ForwardProxyConfig() | |||||
{ | |||||
useProxy = false; | |||||
proxyType = PROXY_SOCKS5; | |||||
proxyServer = ""; | |||||
proxyPort = 0; | |||||
proxyTimeout = DefaultProxyTimeoutSec; | |||||
useAuth = false; | |||||
authUser = ""; | |||||
authPwd = ""; | |||||
} | |||||
public void CheckConfig() | |||||
{ | |||||
if (proxyType < PROXY_SOCKS5 || proxyType > PROXY_HTTP) | |||||
{ | |||||
proxyType = PROXY_SOCKS5; | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -1,33 +0,0 @@ | |||||
using System; | |||||
namespace Shadowsocks.WPF.Models | |||||
{ | |||||
/* | |||||
* Format: | |||||
* <modifiers-combination>+<key> | |||||
* | |||||
*/ | |||||
[Serializable] | |||||
public class HotkeyConfig | |||||
{ | |||||
public string SwitchSystemProxy; | |||||
public string SwitchSystemProxyMode; | |||||
public string SwitchAllowLan; | |||||
public string ShowLogs; | |||||
public string ServerMoveUp; | |||||
public string ServerMoveDown; | |||||
public bool RegHotkeysAtStartup; | |||||
public HotkeyConfig() | |||||
{ | |||||
SwitchSystemProxy = ""; | |||||
SwitchSystemProxyMode = ""; | |||||
SwitchAllowLan = ""; | |||||
ShowLogs = ""; | |||||
ServerMoveUp = ""; | |||||
ServerMoveDown = ""; | |||||
RegHotkeysAtStartup = false; | |||||
} | |||||
} | |||||
} |
@@ -36,8 +36,8 @@ namespace Shadowsocks.WPF.Models | |||||
const string LOGGER_FILE_NAME_ATTRIBUTE = "fileName"; | const string LOGGER_FILE_NAME_ATTRIBUTE = "fileName"; | ||||
XmlDocument doc = new XmlDocument(); | XmlDocument doc = new XmlDocument(); | ||||
XmlElement logFileNameElement; | |||||
XmlElement logLevelElement; | |||||
XmlElement? logFileNameElement; | |||||
XmlElement? logLevelElement; | |||||
/// <summary> | /// <summary> | ||||
/// Load the NLog config xml file content | /// Load the NLog config xml file content | ||||
@@ -46,8 +46,8 @@ namespace Shadowsocks.WPF.Models | |||||
{ | { | ||||
NLogConfig config = new NLogConfig(); | NLogConfig config = new NLogConfig(); | ||||
config.doc.Load(NLOG_CONFIG_FILE_NAME); | config.doc.Load(NLOG_CONFIG_FILE_NAME); | ||||
config.logLevelElement = (XmlElement)SelectSingleNode(config.doc, "//nlog:logger[@name='*']"); | |||||
config.logFileNameElement = (XmlElement)SelectSingleNode(config.doc, "//nlog:target[@name='file']"); | |||||
config.logLevelElement = (XmlElement?)SelectSingleNode(config.doc, "//nlog:logger[@name='*']"); | |||||
config.logFileNameElement = (XmlElement?)SelectSingleNode(config.doc, "//nlog:target[@name='file']"); | |||||
return config; | return config; | ||||
} | } | ||||
@@ -105,7 +105,7 @@ namespace Shadowsocks.WPF.Models | |||||
/// <param name="doc"></param> | /// <param name="doc"></param> | ||||
/// <param name="xpath"></param> | /// <param name="xpath"></param> | ||||
/// <returns></returns> | /// <returns></returns> | ||||
private static XmlNode SelectSingleNode(XmlDocument doc, string xpath) | |||||
private static XmlNode? SelectSingleNode(XmlDocument doc, string xpath) | |||||
{ | { | ||||
XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable); | XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable); | ||||
manager.AddNamespace("nlog", "http://www.nlog-project.org/schemas/NLog.xsd"); | manager.AddNamespace("nlog", "http://www.nlog-project.org/schemas/NLog.xsd"); | ||||
@@ -121,7 +121,7 @@ namespace Shadowsocks.WPF.Models | |||||
if (!File.Exists(NLOG_CONFIG_FILE_NAME)) | if (!File.Exists(NLOG_CONFIG_FILE_NAME)) | ||||
{ | { | ||||
File.WriteAllText(NLOG_CONFIG_FILE_NAME, Properties.Resources.NLog_config); | |||||
File.WriteAllText(NLOG_CONFIG_FILE_NAME, Properties.Resources.NLog); | |||||
LogManager.LoadConfiguration(NLOG_CONFIG_FILE_NAME); | LogManager.LoadConfiguration(NLOG_CONFIG_FILE_NAME); | ||||
} | } | ||||
} | } | ||||
@@ -133,12 +133,15 @@ namespace Shadowsocks.WPF.Services | |||||
var filename = asset.GetProperty("name").GetString(); | var filename = asset.GetProperty("name").GetString(); | ||||
var browser_download_url = asset.GetProperty("browser_download_url").GetString(); | var browser_download_url = asset.GetProperty("browser_download_url").GetString(); | ||||
var response = await httpClient.GetAsync(browser_download_url); | var response = await httpClient.GetAsync(browser_download_url); | ||||
using (var downloadedFileStream = File.Create(Utils.Utilities.GetTempPath(filename))) | |||||
await response.Content.CopyToAsync(downloadedFileStream); | |||||
logger.Info($"Downloaded {filename}."); | |||||
// store .zip filename | |||||
if (filename.EndsWith(".zip")) | |||||
NewReleaseZipFilename = filename; | |||||
if (filename is string) | |||||
{ | |||||
using (var downloadedFileStream = File.Create(Utils.Utilities.GetTempPath(filename))) | |||||
await response.Content.CopyToAsync(downloadedFileStream); | |||||
logger.Info($"Downloaded {filename}."); | |||||
// store .zip filename | |||||
if (filename.EndsWith(".zip")) | |||||
NewReleaseZipFilename = filename; | |||||
} | |||||
} | } | ||||
logger.Info("Finished downloading."); | logger.Info("Finished downloading."); | ||||
// notify user | // notify user | ||||
@@ -1,17 +1,21 @@ | |||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> | |||||
<Project Sdk="Microsoft.NET.Sdk"> | |||||
<PropertyGroup> | <PropertyGroup> | ||||
<OutputType>Exe</OutputType> | <OutputType>Exe</OutputType> | ||||
<TargetFramework>net5.0-windows</TargetFramework> | <TargetFramework>net5.0-windows</TargetFramework> | ||||
<UseWPF>true</UseWPF> | <UseWPF>true</UseWPF> | ||||
<Authors>clowwindy & community 2020</Authors> | |||||
<PackageId>Shadowsocks.WPF</PackageId> | |||||
<Product>Shadowsocks WPF GUI</Product> | |||||
<AssemblyVersion>5.0.0.0</AssemblyVersion> | |||||
<Version>1.0.0</Version> | |||||
<ApplicationManifest>App.manifest</ApplicationManifest> | |||||
<Product>Shadowsocks for Windows WPF GUI</Product> | |||||
<Authors>Clowwindy & The Community</Authors> | |||||
<Version>5.0.0</Version> | |||||
<ApplicationIcon>Assets\shadowsocks.ico</ApplicationIcon> | <ApplicationIcon>Assets\shadowsocks.ico</ApplicationIcon> | ||||
<NoWin32Manifest>true</NoWin32Manifest> | |||||
<Nullable>enable</Nullable> | <Nullable>enable</Nullable> | ||||
<Copyright>© 2020 Clowwindy & The Community</Copyright> | |||||
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile> | |||||
<PackageProjectUrl>https://github.com/shadowsocks/shadowsocks-windows</PackageProjectUrl> | |||||
<RepositoryUrl>https://github.com/shadowsocks/shadowsocks-windows</RepositoryUrl> | |||||
<RepositoryType>Public</RepositoryType> | |||||
<Description>If you want to keep a secret, you must also hide it from yourself.</Description> | |||||
</PropertyGroup> | </PropertyGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
@@ -40,6 +44,10 @@ | |||||
<None Remove="Resources\ss32Out.png" /> | <None Remove="Resources\ss32Out.png" /> | ||||
<None Remove="Resources\ss32Outline.png" /> | <None Remove="Resources\ss32Outline.png" /> | ||||
<None Remove="Resources\ssw128.png" /> | <None Remove="Resources\ssw128.png" /> | ||||
<None Include="..\LICENSE.txt"> | |||||
<Pack>True</Pack> | |||||
<PackagePath></PackagePath> | |||||
</None> | |||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
@@ -115,8 +123,4 @@ | |||||
<Resource Include="Resources\ssw128.png" /> | <Resource Include="Resources\ssw128.png" /> | ||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | |||||
<Folder Include="Properties\PublishProfiles\" /> | |||||
</ItemGroup> | |||||
</Project> | </Project> |
@@ -1,15 +1,20 @@ | |||||
using Shadowsocks.Net.SystemProxy; | using Shadowsocks.Net.SystemProxy; | ||||
using Shadowsocks.PAC; | |||||
using Shadowsocks.WPF.Models; | |||||
using Shadowsocks.WPF.Services.SystemProxy; | using Shadowsocks.WPF.Services.SystemProxy; | ||||
using Splat; | |||||
using System.Windows; | using System.Windows; | ||||
namespace Shadowsocks.WPF.Utils | namespace Shadowsocks.WPF.Utils | ||||
{ | { | ||||
public static class SystemProxy | public static class SystemProxy | ||||
{ | { | ||||
public static void Update(Configuration config, bool forceDisable, PACServer pacSrv, bool noRetry = false) | |||||
public static void Update(bool forceDisable, bool enabled, bool global) | |||||
{ | { | ||||
bool global = config.global; | |||||
bool enabled = config.enabled; | |||||
var settings = Locator.Current.GetService<Settings>(); | |||||
var appSettings = settings.App; | |||||
var netSettings = settings.Net; | |||||
var pacSettings = settings.PAC; | |||||
if (forceDisable || !WinINet.operational) | if (forceDisable || !WinINet.operational) | ||||
{ | { | ||||
@@ -22,20 +27,12 @@ namespace Shadowsocks.WPF.Utils | |||||
{ | { | ||||
if (global) | if (global) | ||||
{ | { | ||||
WinINet.ProxyGlobal("localhost:" + config.localPort.ToString(), "<local>"); | |||||
WinINet.ProxyGlobal($"localhost:{netSettings.HttpListeningPort}", "<local>"); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
string pacUrl; | |||||
if (config.useOnlinePac && !string.IsNullOrEmpty(config.pacUrl)) | |||||
{ | |||||
pacUrl = config.pacUrl; | |||||
} | |||||
else | |||||
{ | |||||
pacUrl = pacSrv.PacUrl; | |||||
} | |||||
var pacUrl = string.IsNullOrEmpty(pacSettings.CustomPACUrl) | |||||
? Locator.Current.GetService<PACServer>().PacUrl : pacSettings.CustomPACUrl; | |||||
WinINet.ProxyPAC(pacUrl); | WinINet.ProxyPAC(pacUrl); | ||||
} | } | ||||
} | } | ||||
@@ -46,8 +43,8 @@ namespace Shadowsocks.WPF.Utils | |||||
} | } | ||||
catch (ProxyException ex) | catch (ProxyException ex) | ||||
{ | { | ||||
logger.LogUsefulException(ex); | |||||
if (ex.Type != ProxyExceptionType.Unspecific && !noRetry) | |||||
LogHost.Default.Error(ex, "An error occurred while updating system proxy."); | |||||
/*if (ex.Type != ProxyExceptionType.Unspecific && !noRetry) | |||||
{ | { | ||||
var ret = MessageBox.Show(I18N.GetString("Error occured when process proxy setting, do you want reset current setting and retry?"), I18N.GetString("Shadowsocks"), MessageBoxButtons.YesNo, MessageBoxIcon.Warning); | var ret = MessageBox.Show(I18N.GetString("Error occured when process proxy setting, do you want reset current setting and retry?"), I18N.GetString("Shadowsocks"), MessageBoxButtons.YesNo, MessageBoxIcon.Warning); | ||||
if (ret == DialogResult.Yes) | if (ret == DialogResult.Yes) | ||||
@@ -59,7 +56,7 @@ namespace Shadowsocks.WPF.Utils | |||||
else | else | ||||
{ | { | ||||
MessageBox.Show(I18N.GetString("Unrecoverable proxy setting error occured, see log for detail"), I18N.GetString("Shadowsocks"), MessageBoxButtons.OK, MessageBoxIcon.Error); | MessageBox.Show(I18N.GetString("Unrecoverable proxy setting error occured, see log for detail"), I18N.GetString("Shadowsocks"), MessageBoxButtons.OK, MessageBoxIcon.Error); | ||||
} | |||||
}*/ | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -2,7 +2,9 @@ using ReactiveUI; | |||||
using ReactiveUI.Fody.Helpers; | using ReactiveUI.Fody.Helpers; | ||||
using ReactiveUI.Validation.Extensions; | using ReactiveUI.Validation.Extensions; | ||||
using ReactiveUI.Validation.Helpers; | using ReactiveUI.Validation.Helpers; | ||||
using Shadowsocks.Net.Settings; | |||||
using Shadowsocks.WPF.Models; | using Shadowsocks.WPF.Models; | ||||
using Splat; | |||||
using System.Linq; | using System.Linq; | ||||
using System.Reactive; | using System.Reactive; | ||||
using System.Reactive.Linq; | using System.Reactive.Linq; | ||||
@@ -13,19 +15,18 @@ namespace Shadowsocks.WPF.ViewModels | |||||
{ | { | ||||
public ForwardProxyViewModel() | public ForwardProxyViewModel() | ||||
{ | { | ||||
if (!_config.proxy.useProxy) | |||||
NoProxy = true; | |||||
else if (_config.proxy.proxyType == 0) | |||||
UseSocks5Proxy = true; | |||||
else | |||||
UseHttpProxy = true; | |||||
_forwardProxySettings = Locator.Current.GetService<Settings>().Net.ForwardProxy; | |||||
Address = _config.proxy.proxyServer; | |||||
Port = _config.proxy.proxyPort; | |||||
Timeout = _config.proxy.proxyTimeout; | |||||
NoProxy = _forwardProxySettings.NoProxy; | |||||
UseSocks5Proxy = _forwardProxySettings.UseSocks5Proxy; | |||||
UseHttpProxy = _forwardProxySettings.UseHttpProxy; | |||||
Username = _config.proxy.authUser; | |||||
Password = _config.proxy.authPwd; | |||||
Address = _forwardProxySettings.Address; | |||||
Port = _forwardProxySettings.Port; | |||||
Timeout = 5; | |||||
Username = _forwardProxySettings.Username; | |||||
Password = _forwardProxySettings.Password; | |||||
this.WhenAnyValue(x => x.NoProxy, x => !x) | this.WhenAnyValue(x => x.NoProxy, x => !x) | ||||
.ToPropertyEx(this, x => x.CanModifyDetails); | .ToPropertyEx(this, x => x.CanModifyDetails); | ||||
@@ -52,12 +53,13 @@ namespace Shadowsocks.WPF.ViewModels | |||||
Save = ReactiveCommand.Create(() => | Save = ReactiveCommand.Create(() => | ||||
{ | { | ||||
_controller.SaveProxy(GetForwardProxyConfig()); | |||||
_menuViewController.CloseForwardProxyWindow(); | |||||
// TODO: save settings | |||||
}, canSave); | }, canSave); | ||||
Cancel = ReactiveCommand.Create(_menuViewController.CloseForwardProxyWindow); | |||||
//Cancel = ReactiveCommand.Create(_menuViewController.CloseForwardProxyWindow); | |||||
} | } | ||||
private ForwardProxySettings _forwardProxySettings; | |||||
public ValidationHelper AddressRule { get; } | public ValidationHelper AddressRule { get; } | ||||
public ValidationHelper PortRule { get; } | public ValidationHelper PortRule { get; } | ||||
public ValidationHelper TimeoutRule { get; } | public ValidationHelper TimeoutRule { get; } | ||||
@@ -93,29 +95,16 @@ namespace Shadowsocks.WPF.ViewModels | |||||
[Reactive] | [Reactive] | ||||
public string Password { get; set; } | public string Password { get; set; } | ||||
private ForwardProxyConfig GetForwardProxyConfig() | |||||
{ | |||||
var forwardProxyConfig = new ForwardProxyConfig() | |||||
private ForwardProxySettings GetForwardProxySettings() | |||||
=> new ForwardProxySettings() | |||||
{ | { | ||||
proxyServer = Address, | |||||
proxyPort = Port, | |||||
proxyTimeout = Timeout, | |||||
authUser = Username, | |||||
authPwd = Password | |||||
NoProxy = NoProxy, | |||||
UseSocks5Proxy = UseSocks5Proxy, | |||||
UseHttpProxy = UseHttpProxy, | |||||
Address = Address, | |||||
Port = Port, | |||||
Username = Username, | |||||
Password = Password, | |||||
}; | }; | ||||
if (NoProxy) | |||||
forwardProxyConfig.useProxy = false; | |||||
else if (UseSocks5Proxy) | |||||
{ | |||||
forwardProxyConfig.useProxy = true; | |||||
forwardProxyConfig.proxyType = 0; | |||||
} | |||||
else | |||||
{ | |||||
forwardProxyConfig.useProxy = true; | |||||
forwardProxyConfig.proxyType = 1; | |||||
} | |||||
return forwardProxyConfig; | |||||
} | |||||
} | } | ||||
} | } |
@@ -18,7 +18,7 @@ namespace Shadowsocks.WPF.ViewModels | |||||
{ | { | ||||
public OnlineConfigViewModel() | public OnlineConfigViewModel() | ||||
{ | { | ||||
Sources = new ObservableCollection<string>(_config.onlineConfigSource); | |||||
Sources = new ObservableCollection<string>(); | |||||
SelectedSource = ""; | SelectedSource = ""; | ||||
Address = ""; | Address = ""; | ||||
@@ -39,8 +39,8 @@ namespace Shadowsocks.WPF.ViewModels | |||||
address => Uri.IsWellFormedUriString(address, UriKind.Absolute) && | address => Uri.IsWellFormedUriString(address, UriKind.Absolute) && | ||||
(address.StartsWith("https://") || address.StartsWith("http://"))); | (address.StartsWith("https://") || address.StartsWith("http://"))); | ||||
Update = ReactiveCommand.CreateFromTask(() => _controller.UpdateOnlineConfig(SelectedSource), canUpdateCopyRemove); | |||||
UpdateAll = ReactiveCommand.CreateFromTask(_controller.UpdateAllOnlineConfig, canUpdateAll); | |||||
//Update = ReactiveCommand.CreateFromTask(() => _controller.UpdateOnlineConfig(SelectedSource), canUpdateCopyRemove); | |||||
//UpdateAll = ReactiveCommand.CreateFromTask(_controller.UpdateAllOnlineConfig, canUpdateAll); | |||||
CopyLink = ReactiveCommand.Create(() => Clipboard.SetText(SelectedSource), canUpdateCopyRemove); | CopyLink = ReactiveCommand.Create(() => Clipboard.SetText(SelectedSource), canUpdateCopyRemove); | ||||
Remove = ReactiveCommand.Create(() => | Remove = ReactiveCommand.Create(() => | ||||
{ | { | ||||
@@ -50,13 +50,13 @@ namespace Shadowsocks.WPF.ViewModels | |||||
{ | { | ||||
result = Sources.Remove(urlToRemove); | result = Sources.Remove(urlToRemove); | ||||
} while (result); | } while (result); | ||||
_controller.RemoveOnlineConfig(urlToRemove); | |||||
//_controller.RemoveOnlineConfig(urlToRemove); | |||||
}, canUpdateCopyRemove); | }, canUpdateCopyRemove); | ||||
Add = ReactiveCommand.Create(() => | Add = ReactiveCommand.Create(() => | ||||
{ | { | ||||
Sources.Add(Address); | Sources.Add(Address); | ||||
SelectedSource = Address; | SelectedSource = Address; | ||||
_controller.SaveOnlineConfigSource(Sources.ToList()); | |||||
//_controller.SaveOnlineConfigSource(Sources.ToList()); | |||||
Address = ""; | Address = ""; | ||||
}, canAdd); | }, canAdd); | ||||