Compare commits
10 Commits
ba36b621e5
...
36e3dfdfa8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36e3dfdfa8 | ||
|
|
e8896bfb05 | ||
|
|
147a6c4078 | ||
|
|
5e72ef9667 | ||
|
|
93e428edc4 | ||
|
|
9887cb6414 | ||
|
|
3023971cf8 | ||
|
|
936602eb0c | ||
|
|
683f6e7a9d | ||
|
|
141943d11a |
@@ -1,8 +1,7 @@
|
||||
# ClashN
|
||||
A clash client for Windows, supports [Clash core](https://github.com/Dreamacro/clash) and [Clash.Meta core](https://github.com/MetaCubeX/Clash.Meta)
|
||||
A clash client for Windows, supports [Mihomo core](https://github.com/MetaCubeX/Mihomo)
|
||||
|
||||
[](https://github.com/2dust/clashn/commits/master)
|
||||
[](https://www.codefactor.io/repository/github/2dust/clashn)
|
||||
[](https://github.com/2dust/clashn/releases)
|
||||
|
||||
### How to use
|
||||
@@ -19,10 +18,8 @@ A clash client for Windows, supports [Clash core](https://github.com/Dreamacro/c
|
||||
|
||||
|
||||
### Requirements
|
||||
- Microsoft [.NET 6.0 Desktop Runtime](https://dotnet.microsoft.com/en-us/download/dotnet/6.0/runtime) (or download this file directly: [windowsdesktop-runtime-6.0.22-win-x64.exe](https://download.visualstudio.microsoft.com/download/pr/66a7c4c6-8401-4799-864f-9afddf5a7733/4052f458f0266e25ab1b9c7959ca245f/windowsdesktop-runtime-6.0.22-win-x64.exe
|
||||
))
|
||||
- Clash core [https://github.com/Dreamacro/clash/releases](https://github.com/Dreamacro/clash/releases)
|
||||
- Clash.Meta core [https://github.com/MetaCubeX/Clash.Meta/releases](https://github.com/MetaCubeX/Clash.Meta/releases)
|
||||
- Microsoft [.NET 8.0 Desktop Runtime](https://dotnet.microsoft.com/en-us/download/dotnet/8.0/runtime)
|
||||
- Mihomo core [https://github.com/MetaCubeX/Mihomo/releases](https://github.com/MetaCubeX/Mihomo/releases)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
""
|
||||
};
|
||||
|
||||
public static readonly List<string> coreTypes = new List<string> { "Clash", "ClashPremium", "ClashMeta", };
|
||||
public static readonly List<string> coreTypes = new List<string> { "Clash", "ClashPremium", "ClashMeta", "Mihomo" };
|
||||
|
||||
public static readonly List<string> allowSelectType = new List<string> { "selector", "urltest", "loadbalance", "fallback" };
|
||||
|
||||
|
||||
@@ -498,7 +498,7 @@ namespace ClashN.Handler
|
||||
}
|
||||
if (profileItem.coreType is null)
|
||||
{
|
||||
profileItem.coreType = CoreKind.ClashMeta;
|
||||
profileItem.coreType = CoreKind.Mihomo;
|
||||
}
|
||||
if (!config.ProfileItems.Exists(it => it.indexId == profileItem.indexId))
|
||||
{
|
||||
@@ -558,7 +558,7 @@ namespace ClashN.Handler
|
||||
{
|
||||
groupId = groupId,
|
||||
url = clipboardData,
|
||||
coreType = CoreKind.ClashMeta,
|
||||
coreType = CoreKind.Mihomo,
|
||||
address = string.Empty,
|
||||
enabled = true,
|
||||
remarks = "clash_subscription"
|
||||
@@ -582,7 +582,7 @@ namespace ClashN.Handler
|
||||
{
|
||||
groupId = groupId,
|
||||
url = query["url"] ?? string.Empty,
|
||||
coreType = CoreKind.ClashMeta,
|
||||
coreType = CoreKind.Mihomo,
|
||||
address = string.Empty,
|
||||
enabled = true,
|
||||
remarks = "clash_subscription"
|
||||
@@ -600,7 +600,7 @@ namespace ClashN.Handler
|
||||
{
|
||||
groupId = groupId,
|
||||
url = "",
|
||||
coreType = CoreKind.ClashMeta,
|
||||
coreType = CoreKind.Mihomo,
|
||||
address = string.Empty,
|
||||
enabled = false,
|
||||
remarks = "clash_local_file"
|
||||
|
||||
@@ -302,12 +302,12 @@ namespace ClashN.Handler
|
||||
});
|
||||
}
|
||||
|
||||
public List<ProxiesItem> GetClashProxyGroups()
|
||||
public List<ProxiesItem>? GetClashProxyGroups()
|
||||
{
|
||||
try
|
||||
{
|
||||
var fileContent = LazyConfig.Instance.ProfileContent;
|
||||
if (!fileContent.ContainsKey("proxy-groups"))
|
||||
if (fileContent is null || fileContent?.ContainsKey("proxy-groups") == false)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -106,8 +106,9 @@ namespace ClashN.Handler
|
||||
if (!string.IsNullOrEmpty(result))
|
||||
{
|
||||
var serverStatItem = config_.GetProfileItem(config_.IndexId);
|
||||
|
||||
ParseOutput(result, out ulong up, out ulong down);
|
||||
if (up + down > 0)
|
||||
if (serverStatItem != null && (up + down) > 0)
|
||||
{
|
||||
serverStatItem.uploadRemote += up;
|
||||
serverStatItem.downloadRemote += down;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
Clash = 1,
|
||||
ClashMeta = 2,
|
||||
ClashPremium = 3,
|
||||
Mihomo = 4,
|
||||
Mihomo = 4,
|
||||
ClashN = 99
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,6 @@ using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -86,16 +85,19 @@ namespace ClashN
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="strJson"></param>
|
||||
/// <returns></returns>
|
||||
public static T FromJson<T>(string strJson)
|
||||
public static T? FromJson<T>(string? strJson)
|
||||
{
|
||||
try
|
||||
{
|
||||
T obj = JsonConvert.DeserializeObject<T>(strJson);
|
||||
return obj;
|
||||
if (string.IsNullOrEmpty(strJson))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
return JsonConvert.DeserializeObject<T>(strJson);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return JsonConvert.DeserializeObject<T>("");
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,14 +106,25 @@ namespace ClashN
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToJson(Object obj)
|
||||
public static string ToJson(object? obj, bool indented = true)
|
||||
{
|
||||
string result = string.Empty;
|
||||
try
|
||||
{
|
||||
result = JsonConvert.SerializeObject(obj,
|
||||
if (obj == null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
if (indented)
|
||||
{
|
||||
result = JsonConvert.SerializeObject(obj,
|
||||
Formatting.Indented,
|
||||
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
|
||||
}
|
||||
else
|
||||
{
|
||||
result = JsonConvert.SerializeObject(obj, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -599,7 +612,7 @@ namespace ClashN
|
||||
}
|
||||
return Path.Combine(startupPath, fileName);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取启动了应用程序的数据文件的路径
|
||||
/// </summary>
|
||||
@@ -895,18 +908,7 @@ namespace ClashN
|
||||
/// <returns></returns>
|
||||
public static T DeepCopy<T>(T obj)
|
||||
{
|
||||
object retval;
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
BinaryFormatter bf = new BinaryFormatter();
|
||||
//序列化成流
|
||||
bf.Serialize(ms, obj);
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
//反序列化成对象
|
||||
retval = bf.Deserialize(ms);
|
||||
ms.Close();
|
||||
}
|
||||
return (T)retval;
|
||||
return FromJson<T>(ToJson(obj, false))!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -14,9 +14,11 @@ namespace ClashN.ViewModels
|
||||
private NoticeHandler? _noticeHandler;
|
||||
|
||||
public ReactiveCommand<Unit, Unit> CheckUpdateCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> CheckUpdateClashCoreCmd { get; }
|
||||
|
||||
//public ReactiveCommand<Unit, Unit> CheckUpdateClashCoreCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> CheckUpdateMihomoCoreCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> CheckUpdateGeoDataCmd { get; }
|
||||
|
||||
//public ReactiveCommand<Unit, Unit> CheckUpdateGeoDataCmd { get; }
|
||||
|
||||
public HelpViewModel()
|
||||
{
|
||||
@@ -27,35 +29,35 @@ namespace ClashN.ViewModels
|
||||
{
|
||||
CheckUpdateN();
|
||||
});
|
||||
CheckUpdateClashCoreCmd = ReactiveCommand.Create(() =>
|
||||
{
|
||||
CheckUpdateCore(CoreKind.Clash);
|
||||
});
|
||||
//CheckUpdateClashCoreCmd = ReactiveCommand.Create(() =>
|
||||
//{
|
||||
// CheckUpdateCore(CoreKind.Clash);
|
||||
//});
|
||||
CheckUpdateMihomoCoreCmd = ReactiveCommand.Create(() =>
|
||||
{
|
||||
CheckUpdateCore(CoreKind.Mihomo);
|
||||
});
|
||||
CheckUpdateGeoDataCmd = ReactiveCommand.Create(() =>
|
||||
{
|
||||
CheckUpdateGeoData();
|
||||
});
|
||||
}
|
||||
|
||||
private void CheckUpdateGeoData()
|
||||
{
|
||||
void _updateUI(bool success, string msg)
|
||||
{
|
||||
_noticeHandler?.SendMessage(msg);
|
||||
if (success)
|
||||
{
|
||||
Locator.Current.GetService<MainWindowViewModel>()?.MyAppExit(false);
|
||||
}
|
||||
};
|
||||
UpdateHandle update = new UpdateHandle();
|
||||
update.UpdateGeoFile(GeoKind.GEO_IP, _config, _updateUI);
|
||||
update.UpdateGeoFile(GeoKind.GEO_SITE, _config, _updateUI);
|
||||
//CheckUpdateGeoDataCmd = ReactiveCommand.Create(() =>
|
||||
//{
|
||||
// CheckUpdateGeoData();
|
||||
//});
|
||||
}
|
||||
|
||||
//private void CheckUpdateGeoData()
|
||||
//{
|
||||
// void _updateUI(bool success, string msg)
|
||||
// {
|
||||
// _noticeHandler?.SendMessage(msg);
|
||||
// if (success)
|
||||
// {
|
||||
// Locator.Current.GetService<MainWindowViewModel>()?.MyAppExit(false);
|
||||
// }
|
||||
// };
|
||||
// UpdateHandle update = new UpdateHandle();
|
||||
// update.UpdateGeoFile(GeoKind.GEO_IP, _config, _updateUI);
|
||||
// update.UpdateGeoFile(GeoKind.GEO_SITE, _config, _updateUI);
|
||||
//}
|
||||
|
||||
private void CheckUpdateN()
|
||||
{
|
||||
void _updateUI(bool success, string msg)
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace ClashN.ViewModels
|
||||
private NoticeHandler? _noticeHandler;
|
||||
private StatisticsHandler? statistics;
|
||||
private readonly PaletteHelper _paletteHelper = new PaletteHelper();
|
||||
private bool blFirst = true;
|
||||
|
||||
#region Views
|
||||
|
||||
@@ -137,6 +138,7 @@ namespace ClashN.ViewModels
|
||||
Application.Current.Dispatcher.Invoke((Action)(() =>
|
||||
{
|
||||
ShowHideWindow(false);
|
||||
blFirst = false;
|
||||
}));
|
||||
});
|
||||
}
|
||||
@@ -220,7 +222,8 @@ namespace ClashN.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
ShowHideWindow(true);
|
||||
if (!blFirst)
|
||||
ShowHideWindow(true);
|
||||
|
||||
Locator.Current.GetService<ProfilesViewModel>()?.AddProfilesViaClipboard(true);
|
||||
}));
|
||||
|
||||
@@ -162,7 +162,7 @@ namespace ClashN.ViewModels
|
||||
{
|
||||
item = new()
|
||||
{
|
||||
coreType = CoreKind.ClashMeta
|
||||
coreType = CoreKind.Mihomo
|
||||
};
|
||||
}
|
||||
else
|
||||
|
||||
@@ -96,43 +96,6 @@
|
||||
</DockPanel>
|
||||
</materialDesign:Card>
|
||||
|
||||
<materialDesign:Card
|
||||
Width="300"
|
||||
Margin="8"
|
||||
Padding="16"
|
||||
materialDesign:UniformCornerRadius="8">
|
||||
<DockPanel>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Margin="16,16,16,4"
|
||||
Style="{StaticResource TabItemTitle}"
|
||||
Text="Update Clash Core" />
|
||||
|
||||
<Separator Grid.Row="1" Style="{StaticResource MaterialDesignLightSeparator}" />
|
||||
|
||||
<DockPanel Grid.Row="2" HorizontalAlignment="Right">
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Margin="8"
|
||||
Style="{StaticResource MaterialDesignCaptionTextBlock}"
|
||||
Text="" />
|
||||
<Button
|
||||
x:Name="btnCheckUpdateClashCore"
|
||||
Width="100"
|
||||
Content="{x:Static resx:ResUI.TbHelpCheck}"
|
||||
DockPanel.Dock="Right"
|
||||
Style="{StaticResource DefButton}" />
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</materialDesign:Card>
|
||||
|
||||
<materialDesign:Card
|
||||
Width="300"
|
||||
Margin="8"
|
||||
@@ -169,44 +132,6 @@
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</materialDesign:Card>
|
||||
|
||||
|
||||
<materialDesign:Card
|
||||
Width="300"
|
||||
Margin="8"
|
||||
Padding="16"
|
||||
materialDesign:UniformCornerRadius="8">
|
||||
<DockPanel>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Margin="16,16,16,4"
|
||||
Style="{StaticResource TabItemTitle}"
|
||||
Text="Update Geo Data" />
|
||||
|
||||
<Separator Grid.Row="1" Style="{StaticResource MaterialDesignLightSeparator}" />
|
||||
|
||||
<DockPanel Grid.Row="2" HorizontalAlignment="Right">
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Margin="8"
|
||||
Style="{StaticResource MaterialDesignCaptionTextBlock}"
|
||||
Text="" />
|
||||
<Button
|
||||
x:Name="btnCheckUpdateGeo"
|
||||
Width="100"
|
||||
Content="{x:Static resx:ResUI.TbHelpCheck}"
|
||||
DockPanel.Dock="Right"
|
||||
Style="{StaticResource DefButton}" />
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</materialDesign:Card>
|
||||
</WrapPanel>
|
||||
</ScrollViewer>
|
||||
</DockPanel>
|
||||
|
||||
@@ -17,9 +17,9 @@ namespace ClashN.Views
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.BindCommand(ViewModel, vm => vm.CheckUpdateCmd, v => v.btnCheckUpdateN).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.CheckUpdateClashCoreCmd, v => v.btnCheckUpdateClashCore).DisposeWith(disposables);
|
||||
//this.BindCommand(ViewModel, vm => vm.CheckUpdateClashCoreCmd, v => v.btnCheckUpdateClashCore).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.CheckUpdateMihomoCoreCmd, v => v.btnCheckUpdateMihomoCore).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.CheckUpdateGeoDataCmd, v => v.btnCheckUpdateGeo).DisposeWith(disposables);
|
||||
//this.BindCommand(ViewModel, vm => vm.CheckUpdateGeoDataCmd, v => v.btnCheckUpdateGeo).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:conv="clr-namespace:ClashN.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:ClashN.Views"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:reactiveui="http://reactiveui.net"
|
||||
@@ -19,7 +18,7 @@
|
||||
x:TypeArguments="vms:MainWindowViewModel"
|
||||
Background="{DynamicResource MaterialDesignPaper}"
|
||||
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
ShowInTaskbar="True"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Auto"
|
||||
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
|
||||
TextOptions.TextFormattingMode="Display"
|
||||
@@ -31,53 +30,52 @@
|
||||
SnackbarMessageQueue="{Binding ElementName=MainSnackbar, Path=MessageQueue}"
|
||||
Style="{StaticResource MaterialDesignEmbeddedDialogHost}">
|
||||
<Grid>
|
||||
<Grid Grid.Column="0">
|
||||
<TabControl Padding="2,0" Style="{StaticResource MaterialDesignNavigatilRailTabControl}">
|
||||
<materialDesign:NavigationRailAssist.FloatingContent>
|
||||
<StackPanel
|
||||
<TabControl Padding="2,0" Style="{StaticResource MaterialDesignNavigatilRailTabControl}">
|
||||
<materialDesign:NavigationRailAssist.FloatingContent>
|
||||
<StackPanel
|
||||
Width="auto"
|
||||
Height="auto"
|
||||
Margin="4">
|
||||
<Grid Width="80" Margin="0,8,0,8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<materialDesign:PackIcon
|
||||
<Grid Width="80" Margin="0,8,0,8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<materialDesign:PackIcon
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Kind="ArrowUpThin" />
|
||||
<TextBlock
|
||||
<TextBlock
|
||||
x:Name="txtSpeedUpload"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Margin="8,0,0,0"
|
||||
Padding="0,0,4,0"
|
||||
Style="{StaticResource ToolbarItem}" />
|
||||
<materialDesign:PackIcon
|
||||
<materialDesign:PackIcon
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Kind="ArrowDownThin" />
|
||||
<TextBlock
|
||||
<TextBlock
|
||||
x:Name="txtSpeedDownload"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Margin="8,0,0,0"
|
||||
Padding="0,0,4,0"
|
||||
Style="{StaticResource ToolbarItem}" />
|
||||
</Grid>
|
||||
<Button
|
||||
</Grid>
|
||||
<Button
|
||||
x:Name="btnReload"
|
||||
Content="{materialDesign:PackIcon Kind=Reload}"
|
||||
Style="{StaticResource MaterialDesignFloatingActionMiniButton}"
|
||||
Style="{StaticResource MaterialDesignFlatLightBgButton}"
|
||||
ToolTip="{x:Static resx:ResUI.TbReloadCore}" />
|
||||
</StackPanel>
|
||||
</materialDesign:NavigationRailAssist.FloatingContent>
|
||||
<!--<TabItem
|
||||
</StackPanel>
|
||||
</materialDesign:NavigationRailAssist.FloatingContent>
|
||||
<!--<TabItem
|
||||
x:Name="dashboardTabItem"
|
||||
Height="auto"
|
||||
Style="{StaticResource MyMaterialDesignNavigationRailTabItem}">
|
||||
@@ -97,224 +95,223 @@
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>-->
|
||||
<TabItem x:Name="proxiesTabItem" Style="{StaticResource MyMaterialDesignNavigationRailTabItem}">
|
||||
<TabItem.Header>
|
||||
<StackPanel Width="auto" Height="auto">
|
||||
<materialDesign:PackIcon
|
||||
<TabItem x:Name="proxiesTabItem" Style="{StaticResource MyMaterialDesignNavigationRailTabItem}">
|
||||
<TabItem.Header>
|
||||
<StackPanel Width="auto" Height="auto">
|
||||
<materialDesign:PackIcon
|
||||
Width="24"
|
||||
Height="24"
|
||||
HorizontalAlignment="Center"
|
||||
Kind="ArrowDecisionOutline" />
|
||||
<TextBlock
|
||||
<TextBlock
|
||||
HorizontalAlignment="Center"
|
||||
Style="{StaticResource TabItemTitle}"
|
||||
Text="{x:Static resx:ResUI.TbProxies}" />
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="profilesTabItem" Style="{StaticResource MyMaterialDesignNavigationRailTabItem}">
|
||||
<TabItem.Header>
|
||||
<StackPanel Width="auto" Height="auto">
|
||||
<materialDesign:PackIcon
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="profilesTabItem" Style="{StaticResource MyMaterialDesignNavigationRailTabItem}">
|
||||
<TabItem.Header>
|
||||
<StackPanel Width="auto" Height="auto">
|
||||
<materialDesign:PackIcon
|
||||
Width="24"
|
||||
Height="24"
|
||||
HorizontalAlignment="Center"
|
||||
Kind="Server" />
|
||||
<TextBlock
|
||||
<TextBlock
|
||||
HorizontalAlignment="Center"
|
||||
Style="{StaticResource TabItemTitle}"
|
||||
Text="{x:Static resx:ResUI.TbProfiles}" />
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="logsTabItem" Style="{StaticResource MyMaterialDesignNavigationRailTabItem}">
|
||||
<TabItem.Header>
|
||||
<StackPanel Width="auto" Height="auto">
|
||||
<materialDesign:PackIcon
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="logsTabItem" Style="{StaticResource MyMaterialDesignNavigationRailTabItem}">
|
||||
<TabItem.Header>
|
||||
<StackPanel Width="auto" Height="auto">
|
||||
<materialDesign:PackIcon
|
||||
Width="24"
|
||||
Height="24"
|
||||
HorizontalAlignment="Center"
|
||||
Kind="MessageTextOutline" />
|
||||
<TextBlock
|
||||
<TextBlock
|
||||
HorizontalAlignment="Center"
|
||||
Style="{StaticResource TabItemTitle}"
|
||||
Text="{x:Static resx:ResUI.TbLogs}" />
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="connectionsTabItem" Style="{StaticResource MyMaterialDesignNavigationRailTabItem}">
|
||||
<TabItem.Header>
|
||||
<StackPanel Width="auto" Height="auto">
|
||||
<materialDesign:PackIcon
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="connectionsTabItem" Style="{StaticResource MyMaterialDesignNavigationRailTabItem}">
|
||||
<TabItem.Header>
|
||||
<StackPanel Width="auto" Height="auto">
|
||||
<materialDesign:PackIcon
|
||||
Width="24"
|
||||
Height="24"
|
||||
HorizontalAlignment="Center"
|
||||
Kind="LanConnect" />
|
||||
<TextBlock
|
||||
<TextBlock
|
||||
HorizontalAlignment="Center"
|
||||
Style="{StaticResource TabItemTitle}"
|
||||
Text="{x:Static resx:ResUI.TbConnections}" />
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="settingsTabItem" Style="{StaticResource MyMaterialDesignNavigationRailTabItem}">
|
||||
<TabItem.Header>
|
||||
<StackPanel Width="auto" Height="auto">
|
||||
<materialDesign:PackIcon
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="settingsTabItem" Style="{StaticResource MyMaterialDesignNavigationRailTabItem}">
|
||||
<TabItem.Header>
|
||||
<StackPanel Width="auto" Height="auto">
|
||||
<materialDesign:PackIcon
|
||||
Width="24"
|
||||
Height="24"
|
||||
HorizontalAlignment="Center"
|
||||
Kind="SettingsOutline" />
|
||||
<TextBlock
|
||||
<TextBlock
|
||||
HorizontalAlignment="Center"
|
||||
Style="{StaticResource TabItemTitle}"
|
||||
Text="{x:Static resx:ResUI.TbSettings}" />
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="helpTabItem" Style="{StaticResource MyMaterialDesignNavigationRailTabItem}">
|
||||
<TabItem.Header>
|
||||
<StackPanel Width="auto" Height="auto">
|
||||
<materialDesign:PackIcon
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="helpTabItem" Style="{StaticResource MyMaterialDesignNavigationRailTabItem}">
|
||||
<TabItem.Header>
|
||||
<StackPanel Width="auto" Height="auto">
|
||||
<materialDesign:PackIcon
|
||||
Width="24"
|
||||
Height="24"
|
||||
HorizontalAlignment="Center"
|
||||
Kind="HelpCircleOutline" />
|
||||
<TextBlock
|
||||
<TextBlock
|
||||
HorizontalAlignment="Center"
|
||||
Style="{StaticResource TabItemTitle}"
|
||||
Text="{x:Static resx:ResUI.TbHelp}" />
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="promotionTabItem" Style="{StaticResource MyMaterialDesignNavigationRailTabItem}">
|
||||
<TabItem.Header>
|
||||
<StackPanel Width="auto" Height="auto">
|
||||
<materialDesign:PackIcon
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="promotionTabItem" Style="{StaticResource MyMaterialDesignNavigationRailTabItem}">
|
||||
<TabItem.Header>
|
||||
<StackPanel Width="auto" Height="auto">
|
||||
<materialDesign:PackIcon
|
||||
Width="24"
|
||||
Height="24"
|
||||
HorizontalAlignment="Center"
|
||||
Kind="VolumeHigh" />
|
||||
<TextBlock
|
||||
<TextBlock
|
||||
HorizontalAlignment="Center"
|
||||
Style="{StaticResource TabItemTitle}"
|
||||
Text="{x:Static resx:ResUI.TbPromotion}" />
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
|
||||
<tb:TaskbarIcon
|
||||
<tb:TaskbarIcon
|
||||
x:Name="tbNotify"
|
||||
IconSource="/ClashN.ico"
|
||||
NoLeftClickDelay="True">
|
||||
<tb:TaskbarIcon.ContextMenu>
|
||||
<ContextMenu Style="{StaticResource DefMenu}">
|
||||
<MenuItem x:Name="menuSystemProxyClear">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon
|
||||
<tb:TaskbarIcon.ContextMenu>
|
||||
<ContextMenu Style="{StaticResource DefMenu}">
|
||||
<MenuItem x:Name="menuSystemProxyClear">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon
|
||||
x:Name="menuSystemProxyClear2"
|
||||
Margin="0,0,8,0"
|
||||
Kind="Check" />
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxyClear}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
<MenuItem x:Name="menuSystemProxySet">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxyClear}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
<MenuItem x:Name="menuSystemProxySet">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon
|
||||
x:Name="menuSystemProxySet2"
|
||||
Margin="0,0,8,0"
|
||||
Kind="Check" />
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxySet}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
<MenuItem x:Name="menuSystemProxyNothing">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxySet}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
<MenuItem x:Name="menuSystemProxyNothing">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon
|
||||
x:Name="menuSystemProxyNothing2"
|
||||
Margin="0,0,8,0"
|
||||
Kind="Check" />
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxyNothing}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
<MenuItem x:Name="menuSystemProxyPac">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxyNothing}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
<MenuItem x:Name="menuSystemProxyPac">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon
|
||||
x:Name="menuSystemProxyPac2"
|
||||
Margin="0,0,8,0"
|
||||
Kind="Check" />
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxyPac}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxyPac}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
|
||||
<MenuItem x:Name="menuModeRule">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon
|
||||
<MenuItem x:Name="menuModeRule">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon
|
||||
x:Name="menuModeRule2"
|
||||
Margin="0,0,8,0"
|
||||
Kind="Check" />
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuModeRule}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
<MenuItem x:Name="menuModeGlobal">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuModeRule}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
<MenuItem x:Name="menuModeGlobal">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon
|
||||
x:Name="menuModeGlobal2"
|
||||
Margin="0,0,8,0"
|
||||
Kind="Check" />
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuModeGlobal}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
<MenuItem x:Name="menuModeDirect">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuModeGlobal}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
<MenuItem x:Name="menuModeDirect">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon
|
||||
x:Name="menuModeDirect2"
|
||||
Margin="0,0,8,0"
|
||||
Kind="Check" />
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuModeDirect}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
<MenuItem x:Name="menuModeNothing">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuModeDirect}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
<MenuItem x:Name="menuModeNothing">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon
|
||||
x:Name="menuModeNothing2"
|
||||
Margin="0,0,8,0"
|
||||
Kind="Check" />
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuModeNothing}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuModeNothing}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
|
||||
<Separator />
|
||||
<MenuItem x:Name="menuAddProfileViaScan" Header="{x:Static resx:ResUI.menuAddProfileViaScan}" />
|
||||
<MenuItem x:Name="menuSubUpdate" Header="{x:Static resx:ResUI.menuSubUpdate}" />
|
||||
<MenuItem x:Name="menuSubUpdateViaProxy" Header="{x:Static resx:ResUI.menuSubUpdateViaProxy}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
<Separator />
|
||||
<MenuItem x:Name="menuAddProfileViaScan" Header="{x:Static resx:ResUI.menuAddProfileViaScan}" />
|
||||
<MenuItem x:Name="menuSubUpdate" Header="{x:Static resx:ResUI.menuSubUpdate}" />
|
||||
<MenuItem x:Name="menuSubUpdateViaProxy" Header="{x:Static resx:ResUI.menuSubUpdateViaProxy}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
x:Name="menuExit"
|
||||
Click="menuExit_Click"
|
||||
Header="{x:Static resx:ResUI.menuExit}" />
|
||||
</ContextMenu>
|
||||
</tb:TaskbarIcon.ContextMenu>
|
||||
</tb:TaskbarIcon>
|
||||
<materialDesign:Snackbar x:Name="MainSnackbar" MessageQueue="{materialDesign:MessageQueue}" />
|
||||
</Grid>
|
||||
</ContextMenu>
|
||||
</tb:TaskbarIcon.ContextMenu>
|
||||
</tb:TaskbarIcon>
|
||||
<materialDesign:Snackbar x:Name="MainSnackbar" MessageQueue="{materialDesign:MessageQueue}" />
|
||||
</Grid>
|
||||
</materialDesign:DialogHost>
|
||||
</reactiveui:ReactiveWindow>
|
||||
@@ -2,32 +2,32 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWPF>true</UseWPF>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<ApplicationIcon>ClashN.ico</ApplicationIcon>
|
||||
<Copyright>Copyright © 2019-2023 (GPLv3)</Copyright>
|
||||
<FileVersion>2.17</FileVersion>
|
||||
<Copyright>Copyright © 2019-2024 (GPLv3)</Copyright>
|
||||
<FileVersion>2.19</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MaterialDesignThemes" Version="4.7.1" />
|
||||
<PackageReference Include="MaterialDesignThemes" Version="4.9.0" />
|
||||
<PackageReference Include="Hardcodet.NotifyIcon.Wpf" Version="1.1.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="NHotkey" Version="2.1.0" />
|
||||
<PackageReference Include="NHotkey.Wpf" Version="2.1.0" />
|
||||
<PackageReference Include="NHotkey" Version="2.1.1" />
|
||||
<PackageReference Include="NHotkey.Wpf" Version="2.1.1" />
|
||||
<PackageReference Include="QRCoder.Xaml" Version="1.4.3" />
|
||||
<PackageReference Include="TaskScheduler" Version="2.10.1" />
|
||||
<PackageReference Include="YamlDotNet" Version="13.0.2" />
|
||||
<PackageReference Include="YamlDotNet" Version="13.7.1" />
|
||||
<PackageReference Include="ZXing.Net.Bindings.Windows.Compatibility" Version="0.16.12" />
|
||||
<PackageReference Include="ReactiveUI.Fody" Version="18.3.1" />
|
||||
<PackageReference Include="ReactiveUI.Validation" Version="3.0.1" />
|
||||
<PackageReference Include="ReactiveUI.WPF" Version="18.3.1" />
|
||||
<PackageReference Include="Splat.NLog" Version="14.6.8" />
|
||||
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||
<PackageReference Include="ReactiveUI.Fody" Version="19.5.39" />
|
||||
<PackageReference Include="ReactiveUI.Validation" Version="3.1.7" />
|
||||
<PackageReference Include="ReactiveUI.WPF" Version="19.5.39" />
|
||||
<PackageReference Include="Splat.NLog" Version="14.8.12" />
|
||||
<PackageReference Include="System.Reactive" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<Copyright>Copyright © 2019-2020 (GPLv3)</Copyright>
|
||||
|
||||
Reference in New Issue
Block a user