2025-08-30 10:01:01 +00:00
|
|
|
using System.Reactive.Concurrency;
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
namespace ServiceLib.ViewModels;
|
|
|
|
|
|
|
|
|
|
public class MainWindowViewModel : MyReactiveObject
|
2023-01-01 11:42:01 +00:00
|
|
|
{
|
2025-04-02 03:44:23 +00:00
|
|
|
#region Menu
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
//servers
|
|
|
|
|
public ReactiveCommand<Unit, Unit> AddVmessServerCmd { get; }
|
2023-04-14 12:49:36 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
public ReactiveCommand<Unit, Unit> AddVlessServerCmd { get; }
|
|
|
|
|
public ReactiveCommand<Unit, Unit> AddShadowsocksServerCmd { get; }
|
|
|
|
|
public ReactiveCommand<Unit, Unit> AddSocksServerCmd { get; }
|
|
|
|
|
public ReactiveCommand<Unit, Unit> AddHttpServerCmd { get; }
|
|
|
|
|
public ReactiveCommand<Unit, Unit> AddTrojanServerCmd { get; }
|
|
|
|
|
public ReactiveCommand<Unit, Unit> AddHysteria2ServerCmd { get; }
|
|
|
|
|
public ReactiveCommand<Unit, Unit> AddTuicServerCmd { get; }
|
|
|
|
|
public ReactiveCommand<Unit, Unit> AddWireguardServerCmd { get; }
|
2025-08-10 02:15:32 +00:00
|
|
|
public ReactiveCommand<Unit, Unit> AddAnytlsServerCmd { get; }
|
2026-02-18 14:28:43 +00:00
|
|
|
public ReactiveCommand<Unit, Unit> AddNaiveServerCmd { get; }
|
2025-04-02 03:44:23 +00:00
|
|
|
public ReactiveCommand<Unit, Unit> AddCustomServerCmd { get; }
|
2025-10-05 08:27:34 +00:00
|
|
|
public ReactiveCommand<Unit, Unit> AddPolicyGroupServerCmd { get; }
|
|
|
|
|
public ReactiveCommand<Unit, Unit> AddProxyChainServerCmd { get; }
|
2025-04-02 03:44:23 +00:00
|
|
|
public ReactiveCommand<Unit, Unit> AddServerViaClipboardCmd { get; }
|
|
|
|
|
public ReactiveCommand<Unit, Unit> AddServerViaScanCmd { get; }
|
|
|
|
|
public ReactiveCommand<Unit, Unit> AddServerViaImageCmd { get; }
|
2023-04-14 12:49:36 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
//Subscription
|
|
|
|
|
public ReactiveCommand<Unit, Unit> SubSettingCmd { get; }
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
public ReactiveCommand<Unit, Unit> SubUpdateCmd { get; }
|
|
|
|
|
public ReactiveCommand<Unit, Unit> SubUpdateViaProxyCmd { get; }
|
|
|
|
|
public ReactiveCommand<Unit, Unit> SubGroupUpdateCmd { get; }
|
|
|
|
|
public ReactiveCommand<Unit, Unit> SubGroupUpdateViaProxyCmd { get; }
|
2023-04-14 12:49:36 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
//Setting
|
|
|
|
|
public ReactiveCommand<Unit, Unit> OptionSettingCmd { get; }
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
public ReactiveCommand<Unit, Unit> RoutingSettingCmd { get; }
|
|
|
|
|
public ReactiveCommand<Unit, Unit> DNSSettingCmd { get; }
|
2025-08-11 12:01:48 +00:00
|
|
|
public ReactiveCommand<Unit, Unit> FullConfigTemplateCmd { get; }
|
2025-04-02 03:44:23 +00:00
|
|
|
public ReactiveCommand<Unit, Unit> GlobalHotkeySettingCmd { get; }
|
|
|
|
|
public ReactiveCommand<Unit, Unit> RebootAsAdminCmd { get; }
|
|
|
|
|
public ReactiveCommand<Unit, Unit> ClearServerStatisticsCmd { get; }
|
|
|
|
|
public ReactiveCommand<Unit, Unit> OpenTheFileLocationCmd { get; }
|
2024-10-18 09:35:32 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
//Presets
|
|
|
|
|
public ReactiveCommand<Unit, Unit> RegionalPresetDefaultCmd { get; }
|
2024-10-16 06:11:20 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
public ReactiveCommand<Unit, Unit> RegionalPresetRussiaCmd { get; }
|
2024-12-31 05:51:06 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
public ReactiveCommand<Unit, Unit> RegionalPresetIranCmd { get; }
|
2023-04-14 12:49:36 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
public ReactiveCommand<Unit, Unit> ReloadCmd { get; }
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
[Reactive]
|
|
|
|
|
public bool BlReloadEnabled { get; set; }
|
2024-06-28 08:14:19 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
[Reactive]
|
|
|
|
|
public bool ShowClashUI { get; set; }
|
2024-07-19 02:51:14 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
[Reactive]
|
|
|
|
|
public int TabMainSelectedIndex { get; set; }
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-11-09 03:11:23 +00:00
|
|
|
[Reactive] public bool BlIsWindows { get; set; }
|
|
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
#endregion Menu
|
2025-01-14 09:05:13 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
#region Init
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
public MainWindowViewModel(Func<EViewAction, object?, Task<bool>>? updateView)
|
|
|
|
|
{
|
2025-08-17 09:31:55 +00:00
|
|
|
_config = AppManager.Instance.Config;
|
2025-04-02 03:44:23 +00:00
|
|
|
_updateView = updateView;
|
2025-11-09 03:11:23 +00:00
|
|
|
BlIsWindows = Utils.IsWindows();
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
#region WhenAnyValue && ReactiveCommand
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
//servers
|
|
|
|
|
AddVmessServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
2025-11-02 07:25:41 +00:00
|
|
|
await AddServerAsync(EConfigType.VMess);
|
2025-04-02 03:44:23 +00:00
|
|
|
});
|
|
|
|
|
AddVlessServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
2025-11-02 07:25:41 +00:00
|
|
|
await AddServerAsync(EConfigType.VLESS);
|
2025-04-02 03:44:23 +00:00
|
|
|
});
|
|
|
|
|
AddShadowsocksServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
2025-11-02 07:25:41 +00:00
|
|
|
await AddServerAsync(EConfigType.Shadowsocks);
|
2025-04-02 03:44:23 +00:00
|
|
|
});
|
|
|
|
|
AddSocksServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
2025-11-02 07:25:41 +00:00
|
|
|
await AddServerAsync(EConfigType.SOCKS);
|
2025-04-02 03:44:23 +00:00
|
|
|
});
|
|
|
|
|
AddHttpServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
2025-11-02 07:25:41 +00:00
|
|
|
await AddServerAsync(EConfigType.HTTP);
|
2025-04-02 03:44:23 +00:00
|
|
|
});
|
|
|
|
|
AddTrojanServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
2025-11-02 07:25:41 +00:00
|
|
|
await AddServerAsync(EConfigType.Trojan);
|
2025-04-02 03:44:23 +00:00
|
|
|
});
|
|
|
|
|
AddHysteria2ServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
2025-11-02 07:25:41 +00:00
|
|
|
await AddServerAsync(EConfigType.Hysteria2);
|
2025-04-02 03:44:23 +00:00
|
|
|
});
|
|
|
|
|
AddTuicServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
2025-11-02 07:25:41 +00:00
|
|
|
await AddServerAsync(EConfigType.TUIC);
|
2025-04-02 03:44:23 +00:00
|
|
|
});
|
|
|
|
|
AddWireguardServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
2025-11-02 07:25:41 +00:00
|
|
|
await AddServerAsync(EConfigType.WireGuard);
|
2025-04-02 03:44:23 +00:00
|
|
|
});
|
2025-08-10 02:15:32 +00:00
|
|
|
AddAnytlsServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
2025-11-02 07:25:41 +00:00
|
|
|
await AddServerAsync(EConfigType.Anytls);
|
2025-08-10 02:15:32 +00:00
|
|
|
});
|
2026-02-18 14:28:43 +00:00
|
|
|
AddNaiveServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
|
|
|
|
await AddServerAsync(EConfigType.Naive);
|
|
|
|
|
});
|
2025-04-02 03:44:23 +00:00
|
|
|
AddCustomServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
2025-11-02 07:25:41 +00:00
|
|
|
await AddServerAsync(EConfigType.Custom);
|
2025-04-02 03:44:23 +00:00
|
|
|
});
|
2025-10-05 08:27:34 +00:00
|
|
|
AddPolicyGroupServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
2025-11-02 07:25:41 +00:00
|
|
|
await AddServerAsync(EConfigType.PolicyGroup);
|
2025-10-05 08:27:34 +00:00
|
|
|
});
|
|
|
|
|
AddProxyChainServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
2025-11-02 07:25:41 +00:00
|
|
|
await AddServerAsync(EConfigType.ProxyChain);
|
2025-10-05 08:27:34 +00:00
|
|
|
});
|
2025-04-02 03:44:23 +00:00
|
|
|
AddServerViaClipboardCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
|
|
|
|
await AddServerViaClipboardAsync(null);
|
|
|
|
|
});
|
|
|
|
|
AddServerViaScanCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
|
|
|
|
await AddServerViaScanAsync();
|
|
|
|
|
});
|
|
|
|
|
AddServerViaImageCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
|
|
|
|
await AddServerViaImageAsync();
|
|
|
|
|
});
|
2024-07-18 09:39:11 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
//Subscription
|
|
|
|
|
SubSettingCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
|
|
|
|
await SubSettingAsync();
|
|
|
|
|
});
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
SubUpdateCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
|
|
|
|
await UpdateSubscriptionProcess("", false);
|
|
|
|
|
});
|
|
|
|
|
SubUpdateViaProxyCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
|
|
|
|
await UpdateSubscriptionProcess("", true);
|
|
|
|
|
});
|
|
|
|
|
SubGroupUpdateCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
|
|
|
|
await UpdateSubscriptionProcess(_config.SubIndexId, false);
|
|
|
|
|
});
|
|
|
|
|
SubGroupUpdateViaProxyCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
|
|
|
|
await UpdateSubscriptionProcess(_config.SubIndexId, true);
|
|
|
|
|
});
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
//Setting
|
|
|
|
|
OptionSettingCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
|
|
|
|
await OptionSettingAsync();
|
|
|
|
|
});
|
|
|
|
|
RoutingSettingCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
|
|
|
|
await RoutingSettingAsync();
|
|
|
|
|
});
|
|
|
|
|
DNSSettingCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
|
|
|
|
await DNSSettingAsync();
|
|
|
|
|
});
|
2025-08-11 12:01:48 +00:00
|
|
|
FullConfigTemplateCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
|
|
|
|
await FullConfigTemplateAsync();
|
|
|
|
|
});
|
2025-04-02 03:44:23 +00:00
|
|
|
GlobalHotkeySettingCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
|
|
|
|
if (await _updateView?.Invoke(EViewAction.GlobalHotkeySettingWindow, null) == true)
|
2023-01-01 11:42:01 +00:00
|
|
|
{
|
2025-08-17 09:31:55 +00:00
|
|
|
NoticeManager.Instance.Enqueue(ResUI.OperationSuccess);
|
2025-04-02 03:44:23 +00:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
RebootAsAdminCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
2025-09-24 02:57:06 +00:00
|
|
|
await AppManager.Instance.RebootAsAdmin();
|
2025-04-02 03:44:23 +00:00
|
|
|
});
|
|
|
|
|
ClearServerStatisticsCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
|
|
|
|
await ClearServerStatistics();
|
|
|
|
|
});
|
|
|
|
|
OpenTheFileLocationCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
|
|
|
|
await OpenTheFileLocation();
|
|
|
|
|
});
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
ReloadCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
|
|
|
|
await Reload();
|
|
|
|
|
});
|
2024-10-16 06:11:20 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
RegionalPresetDefaultCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
|
|
|
|
await ApplyRegionalPreset(EPresetType.Default);
|
|
|
|
|
});
|
2024-10-16 06:11:20 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
RegionalPresetRussiaCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
|
|
|
|
await ApplyRegionalPreset(EPresetType.Russia);
|
|
|
|
|
});
|
2024-12-31 05:51:06 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
RegionalPresetIranCmd = ReactiveCommand.CreateFromTask(async () =>
|
|
|
|
|
{
|
|
|
|
|
await ApplyRegionalPreset(EPresetType.Iran);
|
|
|
|
|
});
|
2024-02-01 04:44:47 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
#endregion WhenAnyValue && ReactiveCommand
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-09-24 02:57:06 +00:00
|
|
|
#region AppEvents
|
|
|
|
|
|
|
|
|
|
AppEvents.ReloadRequested
|
|
|
|
|
.AsObservable()
|
|
|
|
|
.ObserveOn(RxApp.MainThreadScheduler)
|
|
|
|
|
.Subscribe(async _ => await Reload());
|
|
|
|
|
|
|
|
|
|
AppEvents.AddServerViaScanRequested
|
|
|
|
|
.AsObservable()
|
|
|
|
|
.ObserveOn(RxApp.MainThreadScheduler)
|
|
|
|
|
.Subscribe(async _ => await AddServerViaScanAsync());
|
|
|
|
|
|
|
|
|
|
AppEvents.AddServerViaClipboardRequested
|
|
|
|
|
.AsObservable()
|
|
|
|
|
.ObserveOn(RxApp.MainThreadScheduler)
|
|
|
|
|
.Subscribe(async _ => await AddServerViaClipboardAsync(null));
|
|
|
|
|
|
|
|
|
|
AppEvents.SubscriptionsUpdateRequested
|
|
|
|
|
.AsObservable()
|
|
|
|
|
.ObserveOn(RxApp.MainThreadScheduler)
|
|
|
|
|
.Subscribe(async blProxy => await UpdateSubscriptionProcess("", blProxy));
|
|
|
|
|
|
|
|
|
|
#endregion AppEvents
|
|
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
_ = Init();
|
|
|
|
|
}
|
2024-10-21 05:46:13 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
private async Task Init()
|
|
|
|
|
{
|
2025-12-24 08:01:28 +00:00
|
|
|
AppManager.Instance.ShowInTaskbar = true;
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-09-27 10:07:20 +00:00
|
|
|
//await ConfigHandler.InitBuiltinRouting(_config);
|
2025-04-02 03:44:23 +00:00
|
|
|
await ConfigHandler.InitBuiltinDNS(_config);
|
2025-08-11 12:01:48 +00:00
|
|
|
await ConfigHandler.InitBuiltinFullConfigTemplate(_config);
|
2025-08-17 09:31:55 +00:00
|
|
|
await ProfileExManager.Instance.Init();
|
|
|
|
|
await CoreManager.Instance.Init(_config, UpdateHandler);
|
|
|
|
|
TaskManager.Instance.RegUpdateTask(_config, UpdateTaskHandler);
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
if (_config.GuiItem.EnableStatistics || _config.GuiItem.DisplayRealTimeSpeed)
|
|
|
|
|
{
|
2025-08-17 09:31:55 +00:00
|
|
|
await StatisticsManager.Instance.Init(_config, UpdateStatisticsHandler);
|
2023-01-01 11:42:01 +00:00
|
|
|
}
|
2025-09-09 09:55:15 +00:00
|
|
|
await RefreshServers();
|
2023-04-14 12:49:36 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
await Reload();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion Init
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
#region Actions
|
2023-04-14 12:49:36 +00:00
|
|
|
|
2025-08-29 01:49:30 +00:00
|
|
|
private async Task UpdateHandler(bool notify, string msg)
|
2025-04-02 03:44:23 +00:00
|
|
|
{
|
2025-08-17 09:31:55 +00:00
|
|
|
NoticeManager.Instance.SendMessage(msg);
|
2025-04-02 03:44:23 +00:00
|
|
|
if (notify)
|
2023-01-01 11:42:01 +00:00
|
|
|
{
|
2025-08-17 09:31:55 +00:00
|
|
|
NoticeManager.Instance.Enqueue(msg);
|
2023-01-01 11:42:01 +00:00
|
|
|
}
|
2025-11-02 07:25:41 +00:00
|
|
|
await Task.CompletedTask;
|
2025-04-02 03:44:23 +00:00
|
|
|
}
|
2023-04-14 12:49:36 +00:00
|
|
|
|
2025-08-29 02:31:09 +00:00
|
|
|
private async Task UpdateTaskHandler(bool success, string msg)
|
2025-04-02 03:44:23 +00:00
|
|
|
{
|
2025-08-17 09:31:55 +00:00
|
|
|
NoticeManager.Instance.SendMessageEx(msg);
|
2025-04-02 03:44:23 +00:00
|
|
|
if (success)
|
2023-01-01 11:42:01 +00:00
|
|
|
{
|
2025-04-02 03:44:23 +00:00
|
|
|
var indexIdOld = _config.IndexId;
|
2025-08-29 06:46:08 +00:00
|
|
|
await RefreshServers();
|
2025-04-02 03:44:23 +00:00
|
|
|
if (indexIdOld != _config.IndexId)
|
2023-01-01 11:42:01 +00:00
|
|
|
{
|
2025-08-29 02:31:09 +00:00
|
|
|
await Reload();
|
2025-04-02 03:44:23 +00:00
|
|
|
}
|
|
|
|
|
if (_config.UiItem.EnableAutoAdjustMainLvColWidth)
|
|
|
|
|
{
|
2025-09-25 02:56:10 +00:00
|
|
|
AppEvents.AdjustMainLvColWidthRequested.Publish();
|
2023-01-01 11:42:01 +00:00
|
|
|
}
|
|
|
|
|
}
|
2025-04-02 03:44:23 +00:00
|
|
|
}
|
2023-04-14 12:49:36 +00:00
|
|
|
|
2025-08-29 03:40:08 +00:00
|
|
|
private async Task UpdateStatisticsHandler(ServerSpeedItem update)
|
2025-04-02 03:44:23 +00:00
|
|
|
{
|
2025-12-24 08:01:28 +00:00
|
|
|
if (!AppManager.Instance.ShowInTaskbar)
|
2024-08-11 07:45:55 +00:00
|
|
|
{
|
2025-04-02 03:44:23 +00:00
|
|
|
return;
|
2024-08-11 07:45:55 +00:00
|
|
|
}
|
2025-09-25 02:56:10 +00:00
|
|
|
AppEvents.DispatcherStatisticsRequested.Publish(update);
|
2025-11-02 07:25:41 +00:00
|
|
|
await Task.CompletedTask;
|
2025-04-02 03:44:23 +00:00
|
|
|
}
|
2023-04-14 12:49:36 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
#endregion Actions
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
#region Servers && Groups
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-08-29 06:46:08 +00:00
|
|
|
private async Task RefreshServers()
|
2025-04-02 03:44:23 +00:00
|
|
|
{
|
2025-09-25 02:56:10 +00:00
|
|
|
AppEvents.ProfilesRefreshRequested.Publish();
|
2025-08-29 06:46:08 +00:00
|
|
|
|
|
|
|
|
await Task.Delay(200);
|
2025-04-02 03:44:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void RefreshSubscriptions()
|
|
|
|
|
{
|
2025-09-25 02:56:10 +00:00
|
|
|
AppEvents.SubscriptionsRefreshRequested.Publish();
|
2025-04-02 03:44:23 +00:00
|
|
|
}
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
#endregion Servers && Groups
|
2023-04-14 12:49:36 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
#region Add Servers
|
|
|
|
|
|
2025-11-02 07:25:41 +00:00
|
|
|
public async Task AddServerAsync(EConfigType eConfigType)
|
2025-04-02 03:44:23 +00:00
|
|
|
{
|
|
|
|
|
ProfileItem item = new()
|
2023-01-01 11:42:01 +00:00
|
|
|
{
|
2025-04-02 03:44:23 +00:00
|
|
|
Subid = _config.SubIndexId,
|
|
|
|
|
ConfigType = eConfigType,
|
|
|
|
|
IsSub = false,
|
|
|
|
|
};
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
bool? ret = false;
|
|
|
|
|
if (eConfigType == EConfigType.Custom)
|
|
|
|
|
{
|
|
|
|
|
ret = await _updateView?.Invoke(EViewAction.AddServer2Window, item);
|
2023-01-01 11:42:01 +00:00
|
|
|
}
|
2025-10-08 09:13:54 +00:00
|
|
|
else if (eConfigType.IsGroupType())
|
2025-10-05 08:27:34 +00:00
|
|
|
{
|
|
|
|
|
ret = await _updateView?.Invoke(EViewAction.AddGroupServerWindow, item);
|
|
|
|
|
}
|
2025-04-02 03:44:23 +00:00
|
|
|
else
|
2023-01-01 11:42:01 +00:00
|
|
|
{
|
2025-04-02 03:44:23 +00:00
|
|
|
ret = await _updateView?.Invoke(EViewAction.AddServerWindow, item);
|
|
|
|
|
}
|
|
|
|
|
if (ret == true)
|
|
|
|
|
{
|
2025-08-29 06:46:08 +00:00
|
|
|
await RefreshServers();
|
2025-04-02 03:44:23 +00:00
|
|
|
if (item.IndexId == _config.IndexId)
|
2024-10-25 03:06:04 +00:00
|
|
|
{
|
2025-04-02 03:44:23 +00:00
|
|
|
await Reload();
|
2024-10-25 03:06:04 +00:00
|
|
|
}
|
2023-01-01 11:42:01 +00:00
|
|
|
}
|
2025-04-02 03:44:23 +00:00
|
|
|
}
|
2023-04-14 12:49:36 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
public async Task AddServerViaClipboardAsync(string? clipboardData)
|
|
|
|
|
{
|
|
|
|
|
if (clipboardData == null)
|
2024-10-12 07:45:21 +00:00
|
|
|
{
|
2025-04-02 03:44:23 +00:00
|
|
|
await _updateView?.Invoke(EViewAction.AddServerViaClipboard, null);
|
|
|
|
|
return;
|
2024-10-12 07:45:21 +00:00
|
|
|
}
|
2025-08-29 06:46:08 +00:00
|
|
|
var ret = await ConfigHandler.AddBatchServers(_config, clipboardData, _config.SubIndexId, false);
|
2025-04-02 03:44:23 +00:00
|
|
|
if (ret > 0)
|
2024-10-18 09:35:32 +00:00
|
|
|
{
|
2025-04-02 03:44:23 +00:00
|
|
|
RefreshSubscriptions();
|
2025-08-29 06:46:08 +00:00
|
|
|
await RefreshServers();
|
2025-08-17 09:31:55 +00:00
|
|
|
NoticeManager.Instance.Enqueue(string.Format(ResUI.SuccessfullyImportedServerViaClipboard, ret));
|
2024-10-18 09:35:32 +00:00
|
|
|
}
|
2025-04-02 03:44:23 +00:00
|
|
|
else
|
2024-10-18 09:35:32 +00:00
|
|
|
{
|
2025-08-17 09:31:55 +00:00
|
|
|
NoticeManager.Instance.Enqueue(ResUI.OperationFailed);
|
2024-10-18 09:35:32 +00:00
|
|
|
}
|
2025-04-02 03:44:23 +00:00
|
|
|
}
|
2024-10-18 09:35:32 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
public async Task AddServerViaScanAsync()
|
|
|
|
|
{
|
|
|
|
|
_updateView?.Invoke(EViewAction.ScanScreenTask, null);
|
|
|
|
|
await Task.CompletedTask;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task ScanScreenResult(byte[]? bytes)
|
|
|
|
|
{
|
2025-08-17 08:26:13 +00:00
|
|
|
var result = QRCodeUtils.ParseBarcode(bytes);
|
2025-04-02 03:44:23 +00:00
|
|
|
await AddScanResultAsync(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task AddServerViaImageAsync()
|
|
|
|
|
{
|
|
|
|
|
_updateView?.Invoke(EViewAction.ScanImageTask, null);
|
|
|
|
|
await Task.CompletedTask;
|
|
|
|
|
}
|
2024-10-18 09:35:32 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
public async Task ScanImageResult(string fileName)
|
|
|
|
|
{
|
|
|
|
|
if (fileName.IsNullOrEmpty())
|
|
|
|
|
{
|
|
|
|
|
return;
|
2024-10-18 09:35:32 +00:00
|
|
|
}
|
|
|
|
|
|
2025-08-17 08:26:13 +00:00
|
|
|
var result = QRCodeUtils.ParseBarcode(fileName);
|
2025-04-02 03:44:23 +00:00
|
|
|
await AddScanResultAsync(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task AddScanResultAsync(string? result)
|
|
|
|
|
{
|
|
|
|
|
if (result.IsNullOrEmpty())
|
|
|
|
|
{
|
2025-08-17 09:31:55 +00:00
|
|
|
NoticeManager.Instance.Enqueue(ResUI.NoValidQRcodeFound);
|
2025-04-02 03:44:23 +00:00
|
|
|
}
|
|
|
|
|
else
|
2023-01-01 11:42:01 +00:00
|
|
|
{
|
2025-08-29 06:46:08 +00:00
|
|
|
var ret = await ConfigHandler.AddBatchServers(_config, result, _config.SubIndexId, false);
|
2025-04-02 03:44:23 +00:00
|
|
|
if (ret > 0)
|
2023-01-01 11:42:01 +00:00
|
|
|
{
|
2025-04-02 03:44:23 +00:00
|
|
|
RefreshSubscriptions();
|
2025-08-29 06:46:08 +00:00
|
|
|
await RefreshServers();
|
2025-08-17 09:31:55 +00:00
|
|
|
NoticeManager.Instance.Enqueue(ResUI.SuccessfullyImportedServerViaScan);
|
2023-01-01 11:42:01 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2025-08-17 09:31:55 +00:00
|
|
|
NoticeManager.Instance.Enqueue(ResUI.OperationFailed);
|
2023-01-01 11:42:01 +00:00
|
|
|
}
|
|
|
|
|
}
|
2025-04-02 03:44:23 +00:00
|
|
|
}
|
2023-04-14 12:49:36 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
#endregion Add Servers
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
#region Subscription
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
private async Task SubSettingAsync()
|
|
|
|
|
{
|
|
|
|
|
if (await _updateView?.Invoke(EViewAction.SubSettingWindow, null) == true)
|
2023-01-01 11:42:01 +00:00
|
|
|
{
|
2025-04-02 03:44:23 +00:00
|
|
|
RefreshSubscriptions();
|
2023-01-01 11:42:01 +00:00
|
|
|
}
|
2025-04-02 03:44:23 +00:00
|
|
|
}
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
public async Task UpdateSubscriptionProcess(string subId, bool blProxy)
|
|
|
|
|
{
|
2025-08-27 09:14:24 +00:00
|
|
|
await Task.Run(async () => await SubscriptionHandler.UpdateProcess(_config, subId, blProxy, UpdateTaskHandler));
|
2025-04-02 03:44:23 +00:00
|
|
|
}
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
#endregion Subscription
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
#region Setting
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
private async Task OptionSettingAsync()
|
|
|
|
|
{
|
|
|
|
|
var ret = await _updateView?.Invoke(EViewAction.OptionSettingWindow, null);
|
|
|
|
|
if (ret == true)
|
2023-01-01 11:42:01 +00:00
|
|
|
{
|
2025-09-25 02:56:10 +00:00
|
|
|
AppEvents.InboundDisplayRequested.Publish();
|
2025-04-02 03:44:23 +00:00
|
|
|
await Reload();
|
2023-01-01 11:42:01 +00:00
|
|
|
}
|
2025-04-02 03:44:23 +00:00
|
|
|
}
|
2023-04-14 12:49:36 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
private async Task RoutingSettingAsync()
|
|
|
|
|
{
|
|
|
|
|
var ret = await _updateView?.Invoke(EViewAction.RoutingSettingWindow, null);
|
|
|
|
|
if (ret == true)
|
2023-01-01 11:42:01 +00:00
|
|
|
{
|
2025-04-02 03:44:23 +00:00
|
|
|
await ConfigHandler.InitBuiltinRouting(_config);
|
2025-09-25 02:56:10 +00:00
|
|
|
AppEvents.RoutingsMenuRefreshRequested.Publish();
|
2025-04-02 03:44:23 +00:00
|
|
|
await Reload();
|
2023-01-01 11:42:01 +00:00
|
|
|
}
|
2025-04-02 03:44:23 +00:00
|
|
|
}
|
2023-04-27 08:20:13 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
private async Task DNSSettingAsync()
|
|
|
|
|
{
|
|
|
|
|
var ret = await _updateView?.Invoke(EViewAction.DNSSettingWindow, null);
|
|
|
|
|
if (ret == true)
|
2023-04-24 03:55:26 +00:00
|
|
|
{
|
2025-04-02 03:44:23 +00:00
|
|
|
await Reload();
|
2023-04-24 03:55:26 +00:00
|
|
|
}
|
2025-04-02 03:44:23 +00:00
|
|
|
}
|
|
|
|
|
|
2025-08-11 12:01:48 +00:00
|
|
|
private async Task FullConfigTemplateAsync()
|
|
|
|
|
{
|
|
|
|
|
var ret = await _updateView?.Invoke(EViewAction.FullConfigTemplateWindow, null);
|
|
|
|
|
if (ret == true)
|
|
|
|
|
{
|
|
|
|
|
await Reload();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
private async Task ClearServerStatistics()
|
|
|
|
|
{
|
2025-08-17 09:31:55 +00:00
|
|
|
await StatisticsManager.Instance.ClearAllServerStatistics();
|
2025-08-29 06:46:08 +00:00
|
|
|
await RefreshServers();
|
2025-04-02 03:44:23 +00:00
|
|
|
}
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
private async Task OpenTheFileLocation()
|
|
|
|
|
{
|
|
|
|
|
var path = Utils.StartupPath();
|
|
|
|
|
if (Utils.IsWindows())
|
2023-04-06 02:44:29 +00:00
|
|
|
{
|
2025-04-02 03:44:23 +00:00
|
|
|
ProcUtils.ProcessStart(path);
|
2023-04-06 02:44:29 +00:00
|
|
|
}
|
2025-04-02 03:44:23 +00:00
|
|
|
else if (Utils.IsLinux())
|
2024-10-10 10:02:09 +00:00
|
|
|
{
|
2025-09-09 11:51:10 +00:00
|
|
|
ProcUtils.ProcessStart("xdg-open", path);
|
2024-10-10 10:02:09 +00:00
|
|
|
}
|
2025-11-09 02:52:46 +00:00
|
|
|
else if (Utils.IsMacOS())
|
2024-10-10 10:02:09 +00:00
|
|
|
{
|
2025-04-02 03:44:23 +00:00
|
|
|
ProcUtils.ProcessStart("open", path);
|
2024-10-10 10:02:09 +00:00
|
|
|
}
|
2025-04-02 03:44:23 +00:00
|
|
|
await Task.CompletedTask;
|
|
|
|
|
}
|
2024-10-10 10:02:09 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
#endregion Setting
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
#region core job
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2025-11-08 12:48:55 +00:00
|
|
|
private bool _hasNextReloadJob = false;
|
|
|
|
|
private readonly SemaphoreSlim _reloadSemaphore = new(1, 1);
|
|
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
public async Task Reload()
|
|
|
|
|
{
|
|
|
|
|
//If there are unfinished reload job, marked with next job.
|
2025-11-08 12:48:55 +00:00
|
|
|
if (!await _reloadSemaphore.WaitAsync(0))
|
2023-01-01 11:42:01 +00:00
|
|
|
{
|
2025-04-02 03:44:23 +00:00
|
|
|
_hasNextReloadJob = true;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2024-01-30 09:18:00 +00:00
|
|
|
|
2025-11-08 12:48:55 +00:00
|
|
|
try
|
2025-10-09 12:22:35 +00:00
|
|
|
{
|
2025-11-08 12:48:55 +00:00
|
|
|
SetReloadEnabled(false);
|
|
|
|
|
|
2026-02-28 08:31:02 +00:00
|
|
|
var profileItem = await ConfigHandler.GetDefaultServer(_config);
|
|
|
|
|
if (profileItem == null)
|
|
|
|
|
{
|
|
|
|
|
NoticeManager.Instance.Enqueue(ResUI.CheckServerSettings);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var (context, validatorResult) = await CoreConfigContextBuilder.Build(_config, profileItem);
|
|
|
|
|
var msgs = new List<string>([..validatorResult.Errors, ..validatorResult.Warnings]);
|
2025-11-08 12:48:55 +00:00
|
|
|
if (msgs.Count > 0)
|
2025-10-09 12:22:35 +00:00
|
|
|
{
|
2025-11-08 12:48:55 +00:00
|
|
|
foreach (var msg in msgs)
|
|
|
|
|
{
|
|
|
|
|
NoticeManager.Instance.SendMessage(msg);
|
|
|
|
|
}
|
|
|
|
|
NoticeManager.Instance.Enqueue(Utils.List2String(msgs.Take(10).ToList(), true));
|
2026-02-28 08:31:02 +00:00
|
|
|
if (!validatorResult.Success)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-10-09 12:22:35 +00:00
|
|
|
}
|
|
|
|
|
|
2025-11-08 12:48:55 +00:00
|
|
|
await Task.Run(async () =>
|
|
|
|
|
{
|
2026-02-28 08:31:02 +00:00
|
|
|
await LoadCore(context);
|
2025-11-08 12:48:55 +00:00
|
|
|
await SysProxyHandler.UpdateSysProxy(_config, false);
|
|
|
|
|
await Task.Delay(1000);
|
|
|
|
|
});
|
|
|
|
|
AppEvents.TestServerRequested.Publish();
|
|
|
|
|
|
2025-12-24 08:01:28 +00:00
|
|
|
var showClashUI = AppManager.Instance.IsRunningCore(ECoreType.sing_box);
|
2025-11-08 12:48:55 +00:00
|
|
|
if (showClashUI)
|
|
|
|
|
{
|
|
|
|
|
AppEvents.ProxiesReloadRequested.Publish();
|
|
|
|
|
}
|
2025-01-14 09:05:13 +00:00
|
|
|
|
2025-11-08 12:48:55 +00:00
|
|
|
ReloadResult(showClashUI);
|
2025-09-23 04:08:43 +00:00
|
|
|
}
|
2025-11-08 12:48:55 +00:00
|
|
|
finally
|
2024-08-11 07:45:55 +00:00
|
|
|
{
|
2025-11-08 12:48:55 +00:00
|
|
|
SetReloadEnabled(true);
|
|
|
|
|
_reloadSemaphore.Release();
|
|
|
|
|
//If there is a next reload job, execute it.
|
|
|
|
|
if (_hasNextReloadJob)
|
|
|
|
|
{
|
|
|
|
|
_hasNextReloadJob = false;
|
|
|
|
|
await Reload();
|
|
|
|
|
}
|
2024-08-11 07:45:55 +00:00
|
|
|
}
|
2025-04-02 03:44:23 +00:00
|
|
|
}
|
2024-08-11 07:45:55 +00:00
|
|
|
|
2025-09-23 04:08:43 +00:00
|
|
|
private void ReloadResult(bool showClashUI)
|
2025-04-02 03:44:23 +00:00
|
|
|
{
|
2025-11-07 13:06:43 +00:00
|
|
|
RxApp.MainThreadScheduler.Schedule(() =>
|
|
|
|
|
{
|
|
|
|
|
ShowClashUI = showClashUI;
|
|
|
|
|
TabMainSelectedIndex = showClashUI ? TabMainSelectedIndex : 0;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SetReloadEnabled(bool enabled)
|
|
|
|
|
{
|
|
|
|
|
RxApp.MainThreadScheduler.Schedule(() => BlReloadEnabled = enabled);
|
2025-04-02 03:44:23 +00:00
|
|
|
}
|
2023-01-01 11:42:01 +00:00
|
|
|
|
2026-02-28 08:31:02 +00:00
|
|
|
private async Task LoadCore(CoreConfigContext? context)
|
2025-04-02 03:44:23 +00:00
|
|
|
{
|
2026-02-28 08:31:02 +00:00
|
|
|
await CoreManager.Instance.LoadCore(context);
|
2025-04-02 03:44:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion core job
|
2024-10-16 06:11:20 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
#region Presets
|
2024-10-16 06:11:20 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
public async Task ApplyRegionalPreset(EPresetType type)
|
|
|
|
|
{
|
|
|
|
|
await ConfigHandler.ApplyRegionalPreset(_config, type);
|
|
|
|
|
await ConfigHandler.InitRouting(_config);
|
2025-09-25 02:56:10 +00:00
|
|
|
AppEvents.RoutingsMenuRefreshRequested.Publish();
|
2024-10-16 06:11:20 +00:00
|
|
|
|
2025-04-02 03:44:23 +00:00
|
|
|
await ConfigHandler.SaveConfig(_config);
|
2025-11-02 13:04:23 +00:00
|
|
|
await new UpdateService(_config, UpdateTaskHandler).UpdateGeoFileAll();
|
2025-04-02 03:44:23 +00:00
|
|
|
await Reload();
|
2023-01-01 11:42:01 +00:00
|
|
|
}
|
2025-04-02 03:44:23 +00:00
|
|
|
|
|
|
|
|
#endregion Presets
|
2025-01-30 09:10:05 +00:00
|
|
|
}
|