mirror of https://github.com/2dust/v2rayN
Add backup and restore
parent
d5f1cc99ac
commit
beddc71ed8
|
@ -106,7 +106,12 @@ namespace ServiceLib.Common
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ZipFile.CreateFromDirectory(sourceDirectoryName, destinationArchiveFileName);
|
if (File.Exists(destinationArchiveFileName))
|
||||||
|
{
|
||||||
|
File.Delete(destinationArchiveFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZipFile.CreateFromDirectory(sourceDirectoryName, destinationArchiveFileName, CompressionLevel.SmallestSize, true);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -115,5 +120,42 @@ namespace ServiceLib.Common
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void CopyDirectory(string sourceDir, string destinationDir, bool recursive, string ignoredName)
|
||||||
|
{
|
||||||
|
// Get information about the source directory
|
||||||
|
var dir = new DirectoryInfo(sourceDir);
|
||||||
|
|
||||||
|
// Check if the source directory exists
|
||||||
|
if (!dir.Exists)
|
||||||
|
throw new DirectoryNotFoundException($"Source directory not found: {dir.FullName}");
|
||||||
|
|
||||||
|
// Cache directories before we start copying
|
||||||
|
DirectoryInfo[] dirs = dir.GetDirectories();
|
||||||
|
|
||||||
|
// Create the destination directory
|
||||||
|
Directory.CreateDirectory(destinationDir);
|
||||||
|
|
||||||
|
// Get the files in the source directory and copy to the destination directory
|
||||||
|
foreach (FileInfo file in dir.GetFiles())
|
||||||
|
{
|
||||||
|
if (!Utils.IsNullOrEmpty(ignoredName) && file.Name.Contains(ignoredName))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
string targetFilePath = Path.Combine(destinationDir, file.Name);
|
||||||
|
file.CopyTo(targetFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If recursive and copying subdirectories, recursively call this method
|
||||||
|
if (recursive)
|
||||||
|
{
|
||||||
|
foreach (DirectoryInfo subDir in dirs)
|
||||||
|
{
|
||||||
|
string newDestinationDir = Path.Combine(destinationDir, subDir.Name);
|
||||||
|
CopyDirectory(subDir.FullName, newDestinationDir, true, ignoredName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -204,6 +204,8 @@ namespace ServiceLib.Handler
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config.webDavItem ??= new();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace ServiceLib.Handler
|
||||||
MessageBus.Current.SendMessage(content, Global.CommandSendMsgView);
|
MessageBus.Current.SendMessage(content, Global.CommandSendMsgView);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendMessageEx(string? content )
|
public void SendMessageEx(string? content)
|
||||||
{
|
{
|
||||||
if (content.IsNullOrEmpty())
|
if (content.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
using System.Net;
|
||||||
|
using WebDav;
|
||||||
|
|
||||||
|
namespace ServiceLib.Handler
|
||||||
|
{
|
||||||
|
public sealed class WebDavHandler
|
||||||
|
{
|
||||||
|
private static readonly Lazy<WebDavHandler> _instance = new(() => new());
|
||||||
|
public static WebDavHandler Instance => _instance.Value;
|
||||||
|
|
||||||
|
private Config? _config;
|
||||||
|
private WebDavClient? _client;
|
||||||
|
private string? _lastDescription;
|
||||||
|
private string _webDir = "mywebdir";
|
||||||
|
private string _webFileName = "backup.zip";
|
||||||
|
private string _logTitle = "WebDav--";
|
||||||
|
|
||||||
|
public WebDavHandler()
|
||||||
|
{
|
||||||
|
_config = LazyConfig.Instance.Config;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> GetClient()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_config.webDavItem.url.IsNullOrEmpty()
|
||||||
|
|| _config.webDavItem.userName.IsNullOrEmpty()
|
||||||
|
|| _config.webDavItem.password.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
throw new ArgumentException("webdav parameter error or null");
|
||||||
|
}
|
||||||
|
if (_client != null)
|
||||||
|
{
|
||||||
|
_client?.Dispose();
|
||||||
|
_client = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var clientParams = new WebDavClientParams
|
||||||
|
{
|
||||||
|
BaseAddress = new Uri(_config.webDavItem.url),
|
||||||
|
Credentials = new NetworkCredential(_config.webDavItem.userName, _config.webDavItem.password)
|
||||||
|
};
|
||||||
|
_client = new WebDavClient(clientParams);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
SaveLog(ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return await Task.FromResult(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> CheckProp()
|
||||||
|
{
|
||||||
|
if (_client is null) return false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await _client.Propfind(_webDir);
|
||||||
|
if (result.IsSuccessful)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var result2 = await _client.Mkcol(_webDir); // create a directory
|
||||||
|
if (result2.IsSuccessful)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
SaveLog(result2.Description);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
SaveLog(ex);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SaveLog(string desc)
|
||||||
|
{
|
||||||
|
_lastDescription = desc;
|
||||||
|
Logging.SaveLog(_logTitle + desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SaveLog(Exception ex)
|
||||||
|
{
|
||||||
|
_lastDescription = ex.Message;
|
||||||
|
Logging.SaveLog(_logTitle, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> CheckConnection()
|
||||||
|
{
|
||||||
|
if (await GetClient() == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (await CheckProp() == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> PutFile(string fileName)
|
||||||
|
{
|
||||||
|
if (await GetClient() == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (await CheckProp() == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var fs = File.OpenRead(fileName);
|
||||||
|
var result = await _client.PutFile($"{_webDir}/{_webFileName}", fs); // upload a resource
|
||||||
|
if (result.IsSuccessful)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SaveLog(result.Description);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
SaveLog(ex);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> GetRawFile(string fileName)
|
||||||
|
{
|
||||||
|
if (await GetClient() == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (await CheckProp() == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = await _client.GetRawFile($"{_webDir}/{_webFileName}");
|
||||||
|
if (!response.IsSuccessful)
|
||||||
|
{
|
||||||
|
SaveLog(response.Description);
|
||||||
|
}
|
||||||
|
using var outputFileStream = new FileStream(fileName, FileMode.Create);
|
||||||
|
response.Stream.CopyTo(outputFileStream);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
SaveLog(ex);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetLastError() => _lastDescription ?? string.Empty;
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,6 +47,7 @@
|
||||||
public HysteriaItem hysteriaItem { get; set; }
|
public HysteriaItem hysteriaItem { get; set; }
|
||||||
public ClashUIItem clashUIItem { get; set; }
|
public ClashUIItem clashUIItem { get; set; }
|
||||||
public SystemProxyItem systemProxyItem { get; set; }
|
public SystemProxyItem systemProxyItem { get; set; }
|
||||||
|
public WebDavItem webDavItem { get; set; }
|
||||||
public List<InItem> inbound { get; set; }
|
public List<InItem> inbound { get; set; }
|
||||||
public List<KeyEventItem> globalHotkeys { get; set; }
|
public List<KeyEventItem> globalHotkeys { get; set; }
|
||||||
public List<CoreTypeItem> coreTypeItem { get; set; }
|
public List<CoreTypeItem> coreTypeItem { get; set; }
|
||||||
|
|
|
@ -248,4 +248,12 @@
|
||||||
public bool notProxyLocalAddress { get; set; } = true;
|
public bool notProxyLocalAddress { get; set; } = true;
|
||||||
public string systemProxyAdvancedProtocol { get; set; }
|
public string systemProxyAdvancedProtocol { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class WebDavItem
|
||||||
|
{
|
||||||
|
public string? url { get; set; }
|
||||||
|
public string? userName { get; set; }
|
||||||
|
public string? password { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -582,6 +582,42 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 WebDav Check 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string LvWebDavCheck {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("LvWebDavCheck", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 WebDav Password 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string LvWebDavPassword {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("LvWebDavPassword", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 WebDav Url 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string LvWebDavUrl {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("LvWebDavUrl", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 WebDav User Name 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string LvWebDavUserName {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("LvWebDavUserName", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add a custom configuration server 的本地化字符串。
|
/// 查找类似 Add a custom configuration server 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -690,6 +726,15 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Backup and Restore 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuBackupAndRestore {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuBackupAndRestore", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Check Update 的本地化字符串。
|
/// 查找类似 Check Update 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -861,6 +906,33 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Backup to local 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuLocalBackup {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuLocalBackup", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Local 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuLocalBackupAndRestore {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuLocalBackupAndRestore", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Restore from local 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuLocalRestore {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuLocalRestore", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 One-click multi test Latency and speed (Ctrl+E) 的本地化字符串。
|
/// 查找类似 One-click multi test Latency and speed (Ctrl+E) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1095,6 +1167,33 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Backup to remote (WebDAV) 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuRemoteBackup {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuRemoteBackup", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Remote (WebDAV) 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuRemoteBackupAndRestore {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuRemoteBackupAndRestore", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Restore from remote (WebDAV) 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuRemoteRestore {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuRemoteRestore", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Remove duplicate servers 的本地化字符串。
|
/// 查找类似 Remove duplicate servers 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1279,4 +1279,37 @@
|
||||||
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
||||||
<value>Custom config socks port</value>
|
<value>Custom config socks port</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuBackupAndRestore" xml:space="preserve">
|
||||||
|
<value>Backup and Restore</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuLocalBackup" xml:space="preserve">
|
||||||
|
<value>Backup to local</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuLocalRestore" xml:space="preserve">
|
||||||
|
<value>Restore from local</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoteBackup" xml:space="preserve">
|
||||||
|
<value>Backup to remote (WebDAV)</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoteRestore" xml:space="preserve">
|
||||||
|
<value>Restore from remote (WebDAV)</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuLocalBackupAndRestore" xml:space="preserve">
|
||||||
|
<value>Local</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoteBackupAndRestore" xml:space="preserve">
|
||||||
|
<value>Remote (WebDAV)</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavUrl" xml:space="preserve">
|
||||||
|
<value>WebDav Url</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavUserName" xml:space="preserve">
|
||||||
|
<value>WebDav User Name</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavPassword" xml:space="preserve">
|
||||||
|
<value>WebDav Password</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavCheck" xml:space="preserve">
|
||||||
|
<value>WebDav Check</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1276,4 +1276,37 @@
|
||||||
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
||||||
<value>自定义配置的Socks端口</value>
|
<value>自定义配置的Socks端口</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuBackupAndRestore" xml:space="preserve">
|
||||||
|
<value>备份和还原</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuLocalBackup" xml:space="preserve">
|
||||||
|
<value>备份到本地</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuLocalRestore" xml:space="preserve">
|
||||||
|
<value>从本地恢复</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoteBackup" xml:space="preserve">
|
||||||
|
<value>备份到远程 (WebDAV)</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoteRestore" xml:space="preserve">
|
||||||
|
<value>从远程恢复 (WebDAV)</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuLocalBackupAndRestore" xml:space="preserve">
|
||||||
|
<value>本地</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoteBackupAndRestore" xml:space="preserve">
|
||||||
|
<value>远程 (WebDAV)</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavUserName" xml:space="preserve">
|
||||||
|
<value>WebDav 账户</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavCheck" xml:space="preserve">
|
||||||
|
<value>WebDav 可用检查</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavPassword" xml:space="preserve">
|
||||||
|
<value>WebDav 密码</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavUrl" xml:space="preserve">
|
||||||
|
<value>WebDav 服务器地址</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1156,4 +1156,37 @@
|
||||||
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
||||||
<value>自訂配置的Socks端口</value>
|
<value>自訂配置的Socks端口</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuBackupAndRestore" xml:space="preserve">
|
||||||
|
<value>備份和還原</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuLocalBackup" xml:space="preserve">
|
||||||
|
<value>備份到本地</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuLocalRestore" xml:space="preserve">
|
||||||
|
<value>從本地恢復</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoteBackup" xml:space="preserve">
|
||||||
|
<value>備份到遠端 (WebDAV)</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoteRestore" xml:space="preserve">
|
||||||
|
<value>從遠端恢復 (WebDAV)</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuLocalBackupAndRestore" xml:space="preserve">
|
||||||
|
<value>本地</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoteBackupAndRestore" xml:space="preserve">
|
||||||
|
<value>遠端 (WebDAV)</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavUserName" xml:space="preserve">
|
||||||
|
<value>WebDav 賬戶</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavCheck" xml:space="preserve">
|
||||||
|
<value>WebDav 可用檢查</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavPassword" xml:space="preserve">
|
||||||
|
<value>WebDav 密碼</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavUrl" xml:space="preserve">
|
||||||
|
<value>WebDav 服務器地址</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -13,6 +13,7 @@
|
||||||
<PackageReference Include="ReactiveUI.Fody" Version="19.5.41" />
|
<PackageReference Include="ReactiveUI.Fody" Version="19.5.41" />
|
||||||
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
|
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
|
||||||
<PackageReference Include="Splat.NLog" Version="15.1.1" />
|
<PackageReference Include="Splat.NLog" Version="15.1.1" />
|
||||||
|
<PackageReference Include="WebDav.Client" Version="2.8.0" />
|
||||||
<PackageReference Include="YamlDotNet" Version="16.1.0" />
|
<PackageReference Include="YamlDotNet" Version="16.1.0" />
|
||||||
<PackageReference Include="QRCoder" Version="1.6.0" />
|
<PackageReference Include="QRCoder" Version="1.6.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
using ReactiveUI;
|
||||||
|
using ReactiveUI.Fody.Helpers;
|
||||||
|
using Splat;
|
||||||
|
using System.Reactive;
|
||||||
|
|
||||||
|
namespace ServiceLib.ViewModels
|
||||||
|
{
|
||||||
|
public class BackupAndRestoreViewModel : MyReactiveObject
|
||||||
|
{
|
||||||
|
public ReactiveCommand<Unit, Unit> RemoteBackupCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> RemoteRestoreCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> WebDavCheckCmd { get; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public WebDavItem SelectedSource { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public string OperationMsg { get; set; }
|
||||||
|
|
||||||
|
public BackupAndRestoreViewModel(Func<EViewAction, object?, Task<bool>>? updateView)
|
||||||
|
{
|
||||||
|
_config = LazyConfig.Instance.Config;
|
||||||
|
_updateView = updateView;
|
||||||
|
_noticeHandler = Locator.Current.GetService<NoticeHandler>();
|
||||||
|
|
||||||
|
WebDavCheckCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
|
{
|
||||||
|
await WebDavCheck();
|
||||||
|
});
|
||||||
|
|
||||||
|
RemoteBackupCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
|
{
|
||||||
|
await RemoteBackup();
|
||||||
|
});
|
||||||
|
RemoteRestoreCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
|
{
|
||||||
|
await RemoteRestore();
|
||||||
|
});
|
||||||
|
|
||||||
|
SelectedSource = JsonUtils.DeepCopy(_config.webDavItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DisplayOperationMsg(string msg = "")
|
||||||
|
{
|
||||||
|
OperationMsg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task WebDavCheck()
|
||||||
|
{
|
||||||
|
DisplayOperationMsg();
|
||||||
|
_config.webDavItem = SelectedSource;
|
||||||
|
ConfigHandler.SaveConfig(_config);
|
||||||
|
|
||||||
|
var result = await WebDavHandler.Instance.CheckConnection();
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
DisplayOperationMsg(ResUI.OperationSuccess);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DisplayOperationMsg(WebDavHandler.Instance.GetLastError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RemoteBackup()
|
||||||
|
{
|
||||||
|
DisplayOperationMsg();
|
||||||
|
var fileName = Utils.GetBackupPath($"backup_{DateTime.Now:yyyyMMddHHmmss}.zip");
|
||||||
|
var result = await CreateZipFileFromDirectory(fileName);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
var result2 = await WebDavHandler.Instance.PutFile(fileName);
|
||||||
|
if (result2)
|
||||||
|
{
|
||||||
|
DisplayOperationMsg(ResUI.OperationSuccess);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayOperationMsg(WebDavHandler.Instance.GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RemoteRestore()
|
||||||
|
{
|
||||||
|
DisplayOperationMsg();
|
||||||
|
var fileName = Utils.GetTempPath(Utils.GetGUID());
|
||||||
|
var result = await WebDavHandler.Instance.GetRawFile(fileName);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
await LocalRestore(fileName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayOperationMsg(WebDavHandler.Instance.GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> LocalBackup(string fileName)
|
||||||
|
{
|
||||||
|
DisplayOperationMsg();
|
||||||
|
var result = await CreateZipFileFromDirectory(fileName);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
DisplayOperationMsg(ResUI.OperationSuccess);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DisplayOperationMsg(WebDavHandler.Instance.GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task LocalRestore(string fileName)
|
||||||
|
{
|
||||||
|
DisplayOperationMsg();
|
||||||
|
if (Utils.IsNullOrEmpty(fileName))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//backup first
|
||||||
|
var fileBackup = Utils.GetBackupPath($"backup_{DateTime.Now:yyyyMMddHHmmss}.zip");
|
||||||
|
var result = await CreateZipFileFromDirectory(fileBackup);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
Locator.Current.GetService<MainWindowViewModel>()?.V2rayUpgrade(fileName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DisplayOperationMsg(WebDavHandler.Instance.GetLastError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> CreateZipFileFromDirectory(string fileName)
|
||||||
|
{
|
||||||
|
if (Utils.IsNullOrEmpty(fileName))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var configDir = Utils.GetConfigPath();
|
||||||
|
var configDirZipTemp = Utils.GetTempPath($"v2rayN_{DateTime.Now:yyyyMMddHHmmss}");
|
||||||
|
var configDirTemp = Path.Combine(configDirZipTemp, "guiConfigs");
|
||||||
|
|
||||||
|
await Task.Run(() => FileManager.CopyDirectory(configDir, configDirTemp, true, "cache.db"));
|
||||||
|
var ret = await Task.Run(() => FileManager.CreateFromDirectory(configDirZipTemp, fileName));
|
||||||
|
await Task.Run(() => Directory.Delete(configDirZipTemp, true));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,6 @@ using DynamicData.Binding;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using ReactiveUI.Fody.Helpers;
|
using ReactiveUI.Fody.Helpers;
|
||||||
using Splat;
|
using Splat;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
|
|
||||||
namespace ServiceLib.ViewModels
|
namespace ServiceLib.ViewModels
|
||||||
|
|
|
@ -0,0 +1,239 @@
|
||||||
|
<reactiveui:ReactiveUserControl
|
||||||
|
x:Class="v2rayN.Views.BackupAndRestoreView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:converters="clr-namespace:v2rayN.Converters"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:reactiveui="http://reactiveui.net"
|
||||||
|
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||||
|
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||||
|
d:DesignHeight="600"
|
||||||
|
d:DesignWidth="800"
|
||||||
|
x:TypeArguments="vms:BackupAndRestoreViewModel"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Popupbox.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</UserControl.Resources>
|
||||||
|
<DockPanel Margin="16">
|
||||||
|
<DockPanel Margin="8" DockPanel.Dock="Bottom">
|
||||||
|
<Button
|
||||||
|
Width="100"
|
||||||
|
Margin="8"
|
||||||
|
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
|
||||||
|
Content="{x:Static resx:ResUI.menuClose}"
|
||||||
|
DockPanel.Dock="Right"
|
||||||
|
IsCancel="True"
|
||||||
|
IsDefault="True"
|
||||||
|
Style="{StaticResource MaterialDesignFlatButton}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
x:Name="txtMsg"
|
||||||
|
Margin="8"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}" />
|
||||||
|
</DockPanel>
|
||||||
|
|
||||||
|
<StackPanel>
|
||||||
|
<materialDesign:Card Width="Auto" Margin="8">
|
||||||
|
<Grid Margin="8">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="300" />
|
||||||
|
<ColumnDefinition Width="200" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="8"
|
||||||
|
Style="{StaticResource ModuleTitle}"
|
||||||
|
Text="{x:Static resx:ResUI.menuLocalBackupAndRestore}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="8"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.menuLocalBackup}" />
|
||||||
|
<Button
|
||||||
|
x:Name="menuLocalBackup"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="8"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Content="{x:Static resx:ResUI.menuLocalBackup}"
|
||||||
|
Style="{StaticResource DefButton}" />
|
||||||
|
|
||||||
|
<Separator
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
|
Style="{StaticResource MaterialDesignLightSeparator}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="8"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.menuLocalRestore}" />
|
||||||
|
<Button
|
||||||
|
x:Name="menuLocalRestore"
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="8"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Content="{x:Static resx:ResUI.menuLocalRestore}"
|
||||||
|
Style="{StaticResource DefButton}" />
|
||||||
|
</Grid>
|
||||||
|
</materialDesign:Card>
|
||||||
|
<materialDesign:Card Width="Auto" Margin="8">
|
||||||
|
<Grid Margin="8">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="300" />
|
||||||
|
<ColumnDefinition Width="200" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="8"
|
||||||
|
Style="{StaticResource ModuleTitle}"
|
||||||
|
Text="{x:Static resx:ResUI.menuRemoteBackupAndRestore}" />
|
||||||
|
|
||||||
|
<materialDesign:PopupBox
|
||||||
|
Padding="8,0"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
StaysOpen="True"
|
||||||
|
Style="{StaticResource MaterialDesignToolForegroundPopupBox}">
|
||||||
|
<StackPanel Margin="16">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="300" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="8"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.LvWebDavUrl}" />
|
||||||
|
|
||||||
|
<TextBox
|
||||||
|
x:Name="txtWebDavUrl"
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="8"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource DefTextBox}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="8"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.LvWebDavUserName}" />
|
||||||
|
|
||||||
|
<TextBox
|
||||||
|
x:Name="txtWebDavUserName"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="8"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource DefTextBox}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="8"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.LvWebDavPassword}" />
|
||||||
|
|
||||||
|
<TextBox
|
||||||
|
x:Name="txtWebDavPassword"
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="8"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource DefTextBox}" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
x:Name="menuWebDavCheck"
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="8"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Content="{x:Static resx:ResUI.LvWebDavCheck}"
|
||||||
|
Style="{StaticResource DefButton}" />
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
</materialDesign:PopupBox>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="8"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.menuRemoteBackup}" />
|
||||||
|
<Button
|
||||||
|
x:Name="menuRemoteBackup"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="8"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Content="{x:Static resx:ResUI.menuRemoteBackup}"
|
||||||
|
Style="{StaticResource DefButton}" />
|
||||||
|
|
||||||
|
<Separator
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.ColumnSpan="3"
|
||||||
|
Style="{StaticResource MaterialDesignLightSeparator}" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="8"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.menuRemoteRestore}" />
|
||||||
|
<Button
|
||||||
|
x:Name="menuRemoteRestore"
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="8"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Content="{x:Static resx:ResUI.menuRemoteRestore}"
|
||||||
|
Style="{StaticResource DefButton}" />
|
||||||
|
</Grid>
|
||||||
|
</materialDesign:Card>
|
||||||
|
</StackPanel>
|
||||||
|
</DockPanel>
|
||||||
|
</reactiveui:ReactiveUserControl>
|
|
@ -0,0 +1,63 @@
|
||||||
|
using ReactiveUI;
|
||||||
|
using Splat;
|
||||||
|
using System.Reactive.Disposables;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace v2rayN.Views
|
||||||
|
{
|
||||||
|
public partial class BackupAndRestoreView
|
||||||
|
{
|
||||||
|
private NoticeHandler? _noticeHandler;
|
||||||
|
|
||||||
|
public BackupAndRestoreView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
menuLocalBackup.Click += MenuLocalBackup_Click;
|
||||||
|
menuLocalRestore.Click += MenuLocalRestore_Click;
|
||||||
|
|
||||||
|
ViewModel = new BackupAndRestoreViewModel(UpdateViewHandler);
|
||||||
|
|
||||||
|
_noticeHandler = Locator.Current.GetService<NoticeHandler>();
|
||||||
|
this.WhenActivated(disposables =>
|
||||||
|
{
|
||||||
|
this.Bind(ViewModel, vm => vm.OperationMsg, v => v.txtMsg.Text).DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.Bind(ViewModel, vm => vm.SelectedSource.url, v => v.txtWebDavUrl.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.SelectedSource.userName, v => v.txtWebDavUserName.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.SelectedSource.password, v => v.txtWebDavPassword.Text).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.WebDavCheckCmd, v => v.menuWebDavCheck).DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.BindCommand(ViewModel, vm => vm.RemoteBackupCmd, v => v.menuRemoteBackup).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.RemoteRestoreCmd, v => v.menuRemoteRestore).DisposeWith(disposables);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MenuRemoteRestore_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MenuLocalBackup_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (UI.SaveFileDialog(out string fileName, "Zip|*.zip") != true)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ViewModel?.LocalBackup(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MenuLocalRestore_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (UI.OpenFileDialog(out string fileName, "Zip|*.zip|All|*.*") != true)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ViewModel?.LocalRestore(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||||
|
{
|
||||||
|
return await Task.FromResult(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -186,14 +186,14 @@
|
||||||
Height="{StaticResource MenuItemHeight}"
|
Height="{StaticResource MenuItemHeight}"
|
||||||
Header="{x:Static resx:ResUI.menuClearServerStatistics}" />
|
Header="{x:Static resx:ResUI.menuClearServerStatistics}" />
|
||||||
<Separator Margin="-40,5" />
|
<Separator Margin="-40,5" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuBackupAndRestore"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuBackupAndRestore}" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
x:Name="menuOpenTheFileLocation"
|
x:Name="menuOpenTheFileLocation"
|
||||||
Height="{StaticResource MenuItemHeight}"
|
Height="{StaticResource MenuItemHeight}"
|
||||||
Header="{x:Static resx:ResUI.menuOpenTheFileLocation}" />
|
Header="{x:Static resx:ResUI.menuOpenTheFileLocation}" />
|
||||||
<!--<MenuItem
|
|
||||||
x:Name="menuImportOldGuiConfig"
|
|
||||||
Height="{StaticResource MenuItemHeight}"
|
|
||||||
Header="{x:Static resx:ResUI.menuImportOldGuiConfig}" />-->
|
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</Menu>
|
</Menu>
|
||||||
<Separator />
|
<Separator />
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace v2rayN.Views
|
||||||
{
|
{
|
||||||
private static Config _config;
|
private static Config _config;
|
||||||
private CheckUpdateView? _checkUpdateView;
|
private CheckUpdateView? _checkUpdateView;
|
||||||
|
private BackupAndRestoreView? _backupAndRestoreView;
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
|
@ -33,6 +34,7 @@ namespace v2rayN.Views
|
||||||
menuClose.Click += menuClose_Click;
|
menuClose.Click += menuClose_Click;
|
||||||
menuExit.Click += menuExit_Click;
|
menuExit.Click += menuExit_Click;
|
||||||
menuCheckUpdate.Click += MenuCheckUpdate_Click;
|
menuCheckUpdate.Click += MenuCheckUpdate_Click;
|
||||||
|
menuBackupAndRestore.Click += MenuBackupAndRestore_Click;
|
||||||
|
|
||||||
MessageBus.Current.Listen<string>(Global.CommandSendSnackMsg).Subscribe(x => DelegateSnackMsg(x));
|
MessageBus.Current.Listen<string>(Global.CommandSendSnackMsg).Subscribe(x => DelegateSnackMsg(x));
|
||||||
ViewModel = new MainWindowViewModel(UpdateViewHandler);
|
ViewModel = new MainWindowViewModel(UpdateViewHandler);
|
||||||
|
@ -188,12 +190,6 @@ namespace v2rayN.Views
|
||||||
AddHelpMenuItem();
|
AddHelpMenuItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MenuCheckUpdate_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
_checkUpdateView ??= new CheckUpdateView();
|
|
||||||
DialogHost.Show(_checkUpdateView, "RootDialog");
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Event
|
#region Event
|
||||||
|
|
||||||
private void OnProgramStarted(object state, bool timeout)
|
private void OnProgramStarted(object state, bool timeout)
|
||||||
|
@ -425,6 +421,18 @@ namespace v2rayN.Views
|
||||||
ViewModel?.ScanScreenTaskAsync(result);
|
ViewModel?.ScanScreenTaskAsync(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void MenuCheckUpdate_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
_checkUpdateView ??= new CheckUpdateView();
|
||||||
|
DialogHost.Show(_checkUpdateView, "RootDialog");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MenuBackupAndRestore_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
_backupAndRestoreView ??= new BackupAndRestoreView();
|
||||||
|
DialogHost.Show(_backupAndRestoreView, "RootDialog");
|
||||||
|
}
|
||||||
|
|
||||||
#endregion Event
|
#endregion Event
|
||||||
|
|
||||||
#region UI
|
#region UI
|
||||||
|
|
Loading…
Reference in New Issue