mirror of
https://github.com/MaxiFan/TunnelX.git
synced 2026-05-17 21:14:37 +03:00
204 lines
6.0 KiB
C#
204 lines
6.0 KiB
C#
using System.Collections.ObjectModel;
|
|
using System.Windows;
|
|
using Application = System.Windows.Application;
|
|
using OpenFileDialog = Microsoft.Win32.OpenFileDialog;
|
|
using AppTunnel.Models;
|
|
using AppTunnel.Services;
|
|
|
|
namespace AppTunnel.ViewModels;
|
|
|
|
public partial class MainViewModel
|
|
{
|
|
#region App Management
|
|
|
|
public void LoadInstalledApps()
|
|
{
|
|
Task.Run(() =>
|
|
{
|
|
var apps = AppDiscoveryService.GetInstalledApps();
|
|
Application.Current?.Dispatcher.Invoke(() =>
|
|
{
|
|
AvailableApps.Clear();
|
|
foreach (var app in apps)
|
|
AvailableApps.Add(new AppItemViewModel(app));
|
|
RefreshAllFilters();
|
|
});
|
|
});
|
|
}
|
|
|
|
private void FilterAvailableApps()
|
|
{
|
|
var filtered = string.IsNullOrWhiteSpace(SearchText)
|
|
? AvailableApps
|
|
: new ObservableCollection<AppItemViewModel>(
|
|
AvailableApps.Where(a =>
|
|
a.DisplayName.Contains(SearchText, StringComparison.OrdinalIgnoreCase) ||
|
|
a.ExecutableName.Contains(SearchText, StringComparison.OrdinalIgnoreCase) ||
|
|
a.ExecutablePath.Contains(SearchText, StringComparison.OrdinalIgnoreCase)));
|
|
|
|
// Exclude apps already in tunnel list
|
|
var tunnelExes = TunnelApps.Select(a => a.ExecutablePath).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
|
FilteredAvailableApps = new ObservableCollection<AppItemViewModel>(
|
|
filtered.Where(a => !tunnelExes.Contains(a.ExecutablePath)));
|
|
}
|
|
|
|
private void FilterTunnelApps()
|
|
{
|
|
if (string.IsNullOrWhiteSpace(TunnelSearchText))
|
|
{
|
|
FilteredTunnelApps = new ObservableCollection<AppItemViewModel>(TunnelApps);
|
|
}
|
|
else
|
|
{
|
|
FilteredTunnelApps = new ObservableCollection<AppItemViewModel>(
|
|
TunnelApps.Where(a =>
|
|
a.DisplayName.Contains(TunnelSearchText, StringComparison.OrdinalIgnoreCase) ||
|
|
a.ExecutableName.Contains(TunnelSearchText, StringComparison.OrdinalIgnoreCase) ||
|
|
a.ExecutablePath.Contains(TunnelSearchText, StringComparison.OrdinalIgnoreCase)));
|
|
}
|
|
}
|
|
|
|
private void RefreshAllFilters()
|
|
{
|
|
FilterAvailableApps();
|
|
FilterTunnelApps();
|
|
}
|
|
|
|
private void AddCustomApp()
|
|
{
|
|
var dialog = new OpenFileDialog
|
|
{
|
|
Filter = "Applications (*.exe)|*.exe",
|
|
Title = "انتخاب برنامه"
|
|
};
|
|
|
|
if (dialog.ShowDialog() == true)
|
|
{
|
|
var app = AppDiscoveryService.GetAppFromPath(dialog.FileName);
|
|
if (app != null)
|
|
{
|
|
var vm = new AppItemViewModel(app) { IsEnabled = true };
|
|
TunnelApps.Add(vm);
|
|
|
|
if (IsConnected)
|
|
_trafficRouter.AddTargetApp(app.ExecutableName);
|
|
|
|
RefreshAllFilters();
|
|
SaveTunnelApps();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void AddAppToTunnel(AppItemViewModel app)
|
|
{
|
|
if (TunnelApps.Any(a => a.ExecutablePath.Equals(app.ExecutablePath, StringComparison.OrdinalIgnoreCase)))
|
|
return;
|
|
|
|
var tunnelApp = new AppItemViewModel(new TunnelApp
|
|
{
|
|
DisplayName = app.DisplayName,
|
|
ExecutablePath = app.ExecutablePath,
|
|
ExecutableName = app.ExecutableName,
|
|
Icon = app.Icon,
|
|
IsEnabled = true
|
|
}) { IsEnabled = true };
|
|
|
|
TunnelApps.Add(tunnelApp);
|
|
|
|
if (IsConnected)
|
|
_trafficRouter.AddTargetApp(app.ExecutableName);
|
|
|
|
RefreshAllFilters();
|
|
OnPropertyChanged(nameof(EnabledAppsCount));
|
|
SaveTunnelApps();
|
|
}
|
|
|
|
private void RemoveApp(object? param)
|
|
{
|
|
if (param is AppItemViewModel app)
|
|
{
|
|
TunnelApps.Remove(app);
|
|
_trafficRouter.RemoveTargetApp(app.ExecutableName);
|
|
RefreshAllFilters();
|
|
OnPropertyChanged(nameof(EnabledAppsCount));
|
|
SaveTunnelApps();
|
|
}
|
|
}
|
|
|
|
private void ToggleApp(object? param)
|
|
{
|
|
if (param is AppItemViewModel app)
|
|
{
|
|
app.IsEnabled = !app.IsEnabled;
|
|
Logger.Info($"[APP-SWITCH] '{app.ExecutableName}' => {(app.IsEnabled ? "ON" : "OFF")} (connected={IsConnected})");
|
|
OnPropertyChanged(nameof(EnabledAppsCount));
|
|
if (IsConnected)
|
|
{
|
|
if (app.IsEnabled)
|
|
_trafficRouter.AddTargetApp(app.ExecutableName);
|
|
else
|
|
_trafficRouter.RemoveTargetApp(app.ExecutableName);
|
|
}
|
|
SaveTunnelApps();
|
|
}
|
|
}
|
|
|
|
private void AddExcludedDestination()
|
|
{
|
|
var entry = ExcludeInput?.Trim();
|
|
if (string.IsNullOrWhiteSpace(entry)) return;
|
|
if (ExcludedDestinations.Contains(entry, StringComparer.OrdinalIgnoreCase)) return;
|
|
|
|
ExcludedDestinations.Add(entry);
|
|
ExcludeInput = "";
|
|
|
|
if (IsConnected)
|
|
_trafficRouter.AddExcludedDestination(entry);
|
|
|
|
SaveExcludes();
|
|
}
|
|
|
|
private void RemoveExcludedDestination(object? param)
|
|
{
|
|
if (param is string entry)
|
|
{
|
|
ExcludedDestinations.Remove(entry);
|
|
|
|
if (IsConnected)
|
|
_trafficRouter.RemoveExcludedDestination(entry);
|
|
|
|
SaveExcludes();
|
|
}
|
|
}
|
|
|
|
private void AddIncludedDestination()
|
|
{
|
|
var entry = IncludeInput?.Trim();
|
|
if (string.IsNullOrWhiteSpace(entry)) return;
|
|
if (IncludedDestinations.Contains(entry, StringComparer.OrdinalIgnoreCase)) return;
|
|
|
|
IncludedDestinations.Add(entry);
|
|
IncludeInput = "";
|
|
|
|
if (IsConnected)
|
|
_trafficRouter.AddIncludedDestination(entry);
|
|
|
|
SaveIncludes();
|
|
}
|
|
|
|
private void RemoveIncludedDestination(object? param)
|
|
{
|
|
if (param is string entry)
|
|
{
|
|
IncludedDestinations.Remove(entry);
|
|
|
|
if (IsConnected)
|
|
_trafficRouter.RemoveIncludedDestination(entry);
|
|
|
|
SaveIncludes();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|