Files
MaxFan 8283b9d6d1 Prepare release v1.2.27
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-17 19:20:44 +03:30

874 lines
53 KiB
XML

<Window x:Class="AppTunnel.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:AppTunnel.Converters"
xmlns:views="clr-namespace:AppTunnel.Views"
xmlns:vm="clr-namespace:AppTunnel.ViewModels"
xmlns:model="clr-namespace:AppTunnel.Models"
Title="TunnelX — Split Traffic Per App"
Width="620" Height="760"
MinWidth="580" MinHeight="680"
WindowStartupLocation="CenterScreen"
WindowStyle="None"
AllowsTransparency="True"
Background="Transparent"
FlowDirection="RightToLeft"
MouseLeftButtonDown="OnTitleBarMouseDown">
<Window.Resources>
<conv:BoolToColorConverter x:Key="BoolToColor"/>
<conv:StringToColorConverter x:Key="StringToColor"/>
<conv:InverseBoolConverter x:Key="InverseBool"/>
<conv:BoolToVisibilityConverter x:Key="BoolToVis"/>
<conv:InverseBoolToVisibilityConverter x:Key="InverseBoolToVis"/>
<conv:TextToFlowDirectionConverter x:Key="TextToFlowDirection"/>
</Window.Resources>
<!-- Main Container with rounded corners and shadow -->
<Border x:Name="OuterBorder" Background="{StaticResource BackgroundBrush}"
CornerRadius="12"
BorderBrush="{StaticResource CardBrush}"
BorderThickness="1"
Cursor="Arrow"
SizeChanged="OnOuterBorderSizeChanged">
<Border.Effect>
<DropShadowEffect Color="Black" BlurRadius="20" Opacity="0.5" ShadowDepth="0"/>
</Border.Effect>
<Grid>
<Grid Margin="0" FlowDirection="LeftToRight">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- ═══ MAIN CONTENT ═══ -->
<Grid Grid.Column="0" FlowDirection="RightToLeft">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- ═══ CUSTOM TITLE BAR ═══ -->
<Border Grid.Row="0" Background="{StaticResource SurfaceBrush}"
BorderBrush="#12FFFFFF"
BorderThickness="0,0,0,1"
CornerRadius="12,0,0,0" Padding="14,8">
<Grid FlowDirection="LeftToRight">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- Logo & Title -->
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center">
<!-- Tx Icon SVG -->
<Viewbox Width="30" Height="30" Margin="0,0,10,0">
<Canvas Width="48" Height="48">
<Rectangle Width="48" Height="48" RadiusX="8" RadiusY="8" Fill="{StaticResource PrimaryBrush}"/>
<TextBlock Text="Tx" FontSize="24" FontWeight="Bold"
Foreground="White" Canvas.Left="6" Canvas.Top="8"
FontFamily="Segoe UI"/>
</Canvas>
</Viewbox>
<StackPanel VerticalAlignment="Bottom" Margin="0,0,0,1">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Tunnel" FontSize="17" FontWeight="Bold"
Foreground="{StaticResource TextPrimaryBrush}"/>
<TextBlock Text="X" FontSize="17" FontWeight="Bold"
Foreground="{StaticResource AccentBrush}"/>
</StackPanel>
<TextBlock Text="Per-app split tunneling" FontSize="9"
Foreground="{StaticResource TextSecondaryBrush}"
Margin="0,-3,0,0"/>
</StackPanel>
</StackPanel>
<!-- Connection Status + Compact Health Chips -->
<StackPanel Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center">
<Border HorizontalAlignment="Center"
CornerRadius="12"
Padding="12,5"
Background="#121212"
BorderBrush="#20FFFFFF"
BorderThickness="1">
<StackPanel Orientation="Horizontal">
<Ellipse Width="9" Height="9" VerticalAlignment="Center" Margin="0,0,8,0"
Fill="{Binding StatusColor, Converter={StaticResource StringToColor}}"/>
<TextBlock Text="{Binding StatusText}"
Foreground="{StaticResource TextPrimaryBrush}"
FontSize="12"
FontWeight="SemiBold"
VerticalAlignment="Center"
MaxWidth="210"
TextTrimming="CharacterEllipsis"/>
</StackPanel>
</Border>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,5,0,0"
FlowDirection="LeftToRight">
<Border Background="#12FFFFFF" CornerRadius="8" Padding="7,2" Margin="0,0,4,0">
<TextBlock Text="{Binding HeaderCoreText}" FontSize="9"
Foreground="{StaticResource TextSecondaryBrush}"/>
</Border>
<Border Background="#12FFFFFF" CornerRadius="8" Padding="7,2" Margin="0,0,4,0">
<TextBlock Text="{Binding HeaderRouteText}" FontSize="9"
Foreground="{StaticResource TextSecondaryBrush}"/>
</Border>
<Border Background="#12FFFFFF" CornerRadius="8" Padding="7,2">
<TextBlock Text="{Binding HeaderLeakText}" FontSize="9"
Foreground="{Binding HeaderLeakColor, Converter={StaticResource StringToColor}}"/>
</Border>
</StackPanel>
</StackPanel>
<!-- Details Button -->
<Button Grid.Column="2" Content="جزئیات"
Click="OnShowLogClick"
Background="#121212"
Foreground="{StaticResource TextSecondaryBrush}"
BorderBrush="#20FFFFFF"
BorderThickness="1"
Padding="11,6"
Margin="0,0,8,0"
FontSize="11"
Cursor="Hand"
VerticalAlignment="Center">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="8" Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#22FFFFFF"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
<!-- Window Controls: Minimize → Close (standard Windows order) -->
<StackPanel Grid.Column="3" Orientation="Horizontal">
<Button Content="—" Click="OnMinimizeClick"
ToolTip="کوچک کردن به System Tray"
Style="{StaticResource WindowControlButton}"
Width="36" Height="28" FontSize="16" Padding="0,-4,0,0"/>
<Button Content="✕" Click="OnCloseClick"
ToolTip="خروج از برنامه"
Style="{StaticResource WindowControlButton}"
Width="36" Height="28" FontSize="14" Margin="4,0,0,0"/>
</StackPanel>
</Grid>
</Border>
<!-- ═══ MAIN CONTENT ═══ -->
<Grid Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TabControl Grid.Row="0" Style="{StaticResource ModernTabControl}" Margin="8,6,8,6">
<!-- ███ TAB 1: CONNECTION ███ -->
<TabItem Style="{StaticResource ModernTabItem}" ToolTip="وضعیت اتصال VPN و کنترل اتصال">
<TabItem.Header>
<StackPanel>
<TextBlock Text="⚡" FontSize="13" HorizontalAlignment="Center"/>
<TextBlock Text="اتصال VPN" FontSize="11" FontWeight="Medium" TextAlignment="Center"/>
</StackPanel>
</TabItem.Header>
<views:ConnectionTabView/>
</TabItem>
<TabItem Style="{StaticResource ModernTabItem}" ToolTip="انتخاب برنامه‌هایی که باید از تونل عبور کنند">
<TabItem.Header>
<StackPanel>
<TextBlock Text="📱" FontSize="13" HorizontalAlignment="Center"/>
<TextBlock Text="برنامه‌ها" FontSize="11" FontWeight="Medium" TextAlignment="Center"/>
</StackPanel>
</TabItem.Header>
<views:AppsTabView/>
</TabItem>
<TabItem Style="{StaticResource ModernTabItem}" ToolTip="تنظیمات عمومی تونل و DNS">
<TabItem.Header>
<StackPanel>
<TextBlock Text="⚙" FontSize="13" HorizontalAlignment="Center"/>
<TextBlock Text="تنظیمات" FontSize="11" FontWeight="Medium" TextAlignment="Center"/>
</StackPanel>
</TabItem.Header>
<views:SettingsTabView/>
</TabItem>
<!-- ███ TAB 3: ROUTING RULES ███ -->
<TabItem Style="{StaticResource ModernTabItem}" ToolTip="قوانین Include و Exclude مسیرها">
<TabItem.Header>
<StackPanel>
<TextBlock Text="🧭" FontSize="13" HorizontalAlignment="Center"/>
<TextBlock Text="قوانین مسیر" FontSize="11" FontWeight="Medium" TextAlignment="Center"/>
</StackPanel>
</TabItem.Header>
<ScrollViewer VerticalScrollBarVisibility="Auto" Padding="0,10,0,0">
<StackPanel HorizontalAlignment="Stretch" Margin="16,0">
<Border Background="#121212" BorderBrush="#18FFFFFF" BorderThickness="1"
CornerRadius="10" Padding="12,8" Margin="0,0,0,10">
<StackPanel>
<TextBlock Text="قوانین مسیر"
FontSize="13"
FontWeight="SemiBold"
Foreground="{StaticResource TextPrimaryBrush}"/>
<TextBlock Text="مقصدهای مستقیم و مقصدهای اجباری تونل را اینجا مدیریت کنید."
TextWrapping="Wrap"
FontSize="10"
Margin="0,2,0,0"
Foreground="{StaticResource TextSecondaryBrush}"/>
</StackPanel>
</Border>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<!-- Info Card -->
<Border Style="{StaticResource CardPanel}" Margin="0,0,0,8" BorderBrush="#2247A3F3">
<StackPanel>
<TextBlock Text="🚫 مستقیم بماند" FontSize="13" FontWeight="SemiBold"
Foreground="{StaticResource TextPrimaryBrush}" Margin="0,0,0,4"/>
<TextBlock TextWrapping="Wrap" Foreground="{StaticResource TextSecondaryBrush}" FontSize="10"
Text="این مقصدها از تونل عبور نمی‌کنند."/>
</StackPanel>
</Border>
<!-- Tip for Excludes -->
<Border Background="#1247A3F3" BorderBrush="#2647A3F3" BorderThickness="1"
CornerRadius="9" Padding="10,7" Margin="0,0,0,8">
<StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,0,0,3">
<TextBlock Text="💡" FontSize="11" Margin="0,0,5,0"/>
<TextBlock Text="نمونه کاربرد" FontSize="10" FontWeight="SemiBold"
Foreground="#47A3F3"/>
</StackPanel>
<TextBlock Text="سایت‌های داخلی یا سرورهای بازی را مستقیم نگه دارید."
TextWrapping="Wrap" FontSize="10" LineHeight="15"
Foreground="{StaticResource TextSecondaryBrush}"/>
</StackPanel>
</Border>
<!-- Add Entry -->
<Border Style="{StaticResource CardPanel}" Margin="0,0,0,8">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Style="{StaticResource ModernTextBox}"
Text="{Binding ExcludeInput, UpdateSourceTrigger=PropertyChanged}"
Tag="دامنه یا آی‌پی (مثلاً google.com یا 1.2.3.4)"
FlowDirection="LeftToRight"
FontSize="12" Padding="9,6"
Margin="0,0,7,0">
<TextBox.InputBindings>
<KeyBinding Key="Enter" Command="{Binding AddExcludeCommand}"/>
</TextBox.InputBindings>
</TextBox>
<Button Grid.Column="1" Style="{StaticResource PrimaryButton}"
Content="افزودن"
Command="{Binding AddExcludeCommand}"
FontSize="11" Padding="12,6"/>
</Grid>
</Border>
<!-- Exclude List -->
<Border Style="{StaticResource CardPanel}" BorderBrush="#2247A3F3">
<DockPanel>
<TextBlock DockPanel.Dock="Top" FontSize="12" FontWeight="SemiBold"
Foreground="{StaticResource TextPrimaryBrush}" Margin="0,0,0,6"
Text="آدرس‌های مستقیم"/>
<ListView ItemsSource="{Binding ExcludedDestinations}"
Background="Transparent"
BorderThickness="0"
FlowDirection="LeftToRight"
Cursor="Arrow"
PreviewMouseWheel="OnNestedScrollPreviewMouseWheel"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemTemplate>
<DataTemplate>
<Border Background="#11FFFFFF" CornerRadius="7"
Padding="9,5" Margin="0,2" Cursor="Arrow">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="🚫"
VerticalAlignment="Center" Margin="0,0,8,0"/>
<TextBlock Grid.Column="1" Text="{Binding}"
Foreground="{StaticResource TextPrimaryBrush}"
FontSize="12" VerticalAlignment="Center"
FlowDirection="LeftToRight"/>
<Button Grid.Column="2" Style="{StaticResource DangerButton}"
Content="حذف" FontSize="10" Padding="7,3"
Command="{Binding DataContext.RemoveExcludeCommand,
RelativeSource={RelativeSource AncestorType=Window}}"
CommandParameter="{Binding}"/>
</Grid>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
</DockPanel>
</Border>
</StackPanel>
<Border Grid.Column="1" Width="1" Background="#18FFFFFF" Margin="0,2"/>
<StackPanel Grid.Column="2">
<!-- Include Info -->
<Border Style="{StaticResource CardPanel}" Margin="0,0,0,8" BorderBrush="#2233C481">
<StackPanel>
<TextBlock Text="✅ از تونل عبور کند" FontSize="13" FontWeight="SemiBold"
Foreground="{StaticResource TextPrimaryBrush}" Margin="0,0,0,4"/>
<TextBlock TextWrapping="Wrap" Foreground="{StaticResource TextSecondaryBrush}" FontSize="10"
Text="این مقصدها همیشه از تونل عبور می‌کنند."/>
</StackPanel>
</Border>
<!-- Add Include Entry -->
<Border Style="{StaticResource CardPanel}" Margin="0,0,0,8">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Style="{StaticResource ModernTextBox}"
Text="{Binding IncludeInput, UpdateSourceTrigger=PropertyChanged}"
Tag="دامنه یا آی‌پی (مثلاً example.com یا 1.2.3.4)"
FlowDirection="LeftToRight"
FontSize="12" Padding="9,6"
Margin="0,0,7,0">
<TextBox.InputBindings>
<KeyBinding Key="Enter" Command="{Binding AddIncludeCommand}"/>
</TextBox.InputBindings>
</TextBox>
<Button Grid.Column="1" Style="{StaticResource PrimaryButton}"
Content="افزودن"
Command="{Binding AddIncludeCommand}"
FontSize="11" Padding="12,6"/>
</Grid>
</Border>
<!-- Include List -->
<Border Style="{StaticResource CardPanel}" BorderBrush="#2233C481">
<DockPanel>
<TextBlock DockPanel.Dock="Top" FontSize="12" FontWeight="SemiBold"
Foreground="{StaticResource TextPrimaryBrush}" Margin="0,0,0,6"
Text="آدرس‌های اجباری"/>
<ListView ItemsSource="{Binding IncludedDestinations}"
Background="Transparent"
BorderThickness="0"
FlowDirection="LeftToRight"
Cursor="Arrow"
PreviewMouseWheel="OnNestedScrollPreviewMouseWheel"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemTemplate>
<DataTemplate>
<Border Background="#11FFFFFF" CornerRadius="7"
Padding="9,5" Margin="0,2" Cursor="Arrow">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="✅"
VerticalAlignment="Center" Margin="0,0,8,0"/>
<TextBlock Grid.Column="1" Text="{Binding}"
Foreground="{StaticResource TextPrimaryBrush}"
FontSize="12" VerticalAlignment="Center"
FlowDirection="LeftToRight"/>
<Button Grid.Column="2" Style="{StaticResource DangerButton}"
Content="حذف" FontSize="10" Padding="7,3"
Command="{Binding DataContext.RemoveIncludeCommand,
RelativeSource={RelativeSource AncestorType=Window}}"
CommandParameter="{Binding}"/>
</Grid>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
</DockPanel>
</Border>
</StackPanel>
</Grid>
</StackPanel>
</ScrollViewer>
</TabItem>
<!-- ███ TAB 5: TRAFFIC MONITOR ███ -->
<TabItem Style="{StaticResource ModernTabItem}" ToolTip="نمایش ترافیک، تاریخچه و آمار اتصال">
<TabItem.Header>
<StackPanel>
<TextBlock Text="📊" FontSize="13" HorizontalAlignment="Center"/>
<TextBlock Text="ترافیک/تاریخچه" FontSize="10.5" FontWeight="Medium" TextAlignment="Center"/>
</StackPanel>
</TabItem.Header>
<ScrollViewer VerticalScrollBarVisibility="Auto" Padding="0,12,0,0">
<StackPanel HorizontalAlignment="Stretch" Margin="16,0">
<!-- Summary Card -->
<Border Style="{StaticResource CardPanel}" BorderBrush="#22E8803A">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" HorizontalAlignment="Center">
<TextBlock Text="⏱ مدت" FontSize="11"
Foreground="{StaticResource TextSecondaryBrush}"
HorizontalAlignment="Center"/>
<TextBlock Text="{Binding ConnectionDuration}" FontSize="20"
FontWeight="Bold" Foreground="{StaticResource AccentBrush}"
HorizontalAlignment="Center" Margin="0,6,0,0"
FlowDirection="LeftToRight"/>
</StackPanel>
<StackPanel Grid.Column="1" HorizontalAlignment="Center">
<TextBlock Text="🌐 IP" FontSize="11"
Foreground="{StaticResource TextSecondaryBrush}"
HorizontalAlignment="Center"/>
<TextBlock Text="{Binding VpnIp}" FontSize="14"
FontWeight="SemiBold" Foreground="{StaticResource SuccessBrush}"
HorizontalAlignment="Center" Margin="0,6,0,0"
FlowDirection="LeftToRight"/>
</StackPanel>
<StackPanel Grid.Column="2" HorizontalAlignment="Center">
<TextBlock Text="📊 تونل" FontSize="11"
Foreground="{StaticResource TextSecondaryBrush}"
HorizontalAlignment="Center"/>
<TextBlock Text="{Binding TotalTraffic}" FontSize="14"
FontWeight="SemiBold" Foreground="{StaticResource WarningBrush}"
HorizontalAlignment="Center" Margin="0,6,0,0"
FlowDirection="LeftToRight"/>
</StackPanel>
<StackPanel Grid.Column="3" HorizontalAlignment="Center">
<TextBlock Text="📡 خارج تونل" FontSize="11"
Foreground="{StaticResource TextSecondaryBrush}"
HorizontalAlignment="Center"/>
<TextBlock Text="{Binding DirectTraffic}" FontSize="14"
FontWeight="SemiBold" Foreground="{StaticResource TextPrimaryBrush}"
HorizontalAlignment="Center" Margin="0,6,0,0"
FlowDirection="LeftToRight"/>
</StackPanel>
</Grid>
</Border>
<!-- Split Tunnel Health -->
<Border Style="{StaticResource CardPanel}" BorderBrush="#2233C481">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" HorizontalAlignment="Center">
<TextBlock Text="Leak" FontSize="10" Foreground="{StaticResource TextSecondaryBrush}"
HorizontalAlignment="Center"/>
<TextBlock Text="{Binding HealthLeakText}" FontSize="13" FontWeight="SemiBold"
Foreground="{Binding HeaderLeakColor, Converter={StaticResource StringToColor}}"
HorizontalAlignment="Center" FlowDirection="LeftToRight"/>
</StackPanel>
<StackPanel Grid.Column="1" HorizontalAlignment="Center">
<TextBlock Text="DNS" FontSize="10" Foreground="{StaticResource TextSecondaryBrush}"
HorizontalAlignment="Center"/>
<TextBlock Text="{Binding HealthDnsText}" FontSize="13" FontWeight="SemiBold"
Foreground="{StaticResource AccentBrush}"
HorizontalAlignment="Center" FlowDirection="LeftToRight"/>
</StackPanel>
<StackPanel Grid.Column="2" HorizontalAlignment="Center">
<TextBlock Text="IPv6" FontSize="10" Foreground="{StaticResource TextSecondaryBrush}"
HorizontalAlignment="Center"/>
<TextBlock Text="{Binding HealthIpv6Text}" FontSize="13" FontWeight="SemiBold"
Foreground="{StaticResource WarningBrush}"
HorizontalAlignment="Center" FlowDirection="LeftToRight"/>
</StackPanel>
<StackPanel Grid.Column="3" HorizontalAlignment="Center">
<TextBlock Text="Route" FontSize="10" Foreground="{StaticResource TextSecondaryBrush}"
HorizontalAlignment="Center"/>
<TextBlock Text="{Binding HealthRoutesText}" FontSize="13" FontWeight="SemiBold"
Foreground="{StaticResource TextPrimaryBrush}"
HorizontalAlignment="Center" FlowDirection="LeftToRight"/>
</StackPanel>
</Grid>
</Border>
<Expander Header="📜 تاریخچه اتصالات"
IsExpanded="False"
Foreground="{StaticResource TextPrimaryBrush}"
Background="#121212"
BorderBrush="#18FFFFFF"
Padding="10,6"
Margin="0,0,0,8">
<views:HistoryTabView/>
</Expander>
<!-- Per-App Traffic -->
<Border Style="{StaticResource CardPanel}" BorderBrush="#2247A3F3">
<StackPanel>
<TextBlock Style="{StaticResource SectionHeader}"
Text="مصرف تونل به تفکیک برنامه"/>
<Grid Margin="0,6,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="8"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Background="#11FFFFFF" CornerRadius="8" Padding="10,7">
<StackPanel Orientation="Horizontal" FlowDirection="LeftToRight">
<TextBlock Text="اپ‌های تونل: " FontSize="11"
Foreground="{StaticResource TextSecondaryBrush}"/>
<TextBlock Text="{Binding AppTrafficTotal}" FontSize="11" FontWeight="SemiBold"
Foreground="{StaticResource AccentBrush}"/>
</StackPanel>
</Border>
<Border Grid.Column="2" Background="#11FFFFFF" CornerRadius="8" Padding="10,7">
<StackPanel Orientation="Horizontal" FlowDirection="LeftToRight">
<TextBlock Text="سایر تونل: " FontSize="11"
Foreground="{StaticResource TextSecondaryBrush}"/>
<TextBlock Text="{Binding OtherTunnelTraffic}" FontSize="11" FontWeight="SemiBold"
Foreground="{StaticResource WarningBrush}"/>
</StackPanel>
</Border>
</Grid>
<ItemsControl ItemsSource="{Binding TunnelApps}" Cursor="Arrow">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Background="#11FFFFFF" CornerRadius="8"
Padding="12,10" Margin="0,3" Cursor="Arrow">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="{Binding Icon}"
Width="24" Height="24" Margin="0,0,10,0"/>
<StackPanel Grid.Column="1" VerticalAlignment="Center">
<TextBlock Text="{Binding DisplayName}"
Foreground="{StaticResource TextPrimaryBrush}"
FontSize="13"/>
<StackPanel Orientation="Horizontal" Margin="0,2,0,0"
FlowDirection="LeftToRight">
<TextBlock Text="↑ " Foreground="{StaticResource WarningBrush}"
FontSize="10"/>
<TextBlock Text="{Binding BytesSent, StringFormat={}{0:N0} B ↑}"
Foreground="{StaticResource WarningBrush}"
FontSize="10" Margin="0,0,10,0"/>
<TextBlock Text="{Binding BytesReceived, StringFormat={}{0:N0} B ↓}"
Foreground="{StaticResource SuccessBrush}"
FontSize="10"/>
</StackPanel>
</StackPanel>
<TextBlock Grid.Column="2" Text="{Binding TrafficDisplay}"
Foreground="{StaticResource AccentBrush}"
FontSize="14" FontWeight="SemiBold"
VerticalAlignment="Center"
FlowDirection="LeftToRight"/>
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!-- Empty state -->
<TextBlock Text="هنوز برنامه‌ای اضافه نشده. از تب «برنامه‌ها» اضافه کنید."
Foreground="{StaticResource TextSecondaryBrush}"
FontSize="13" HorizontalAlignment="Center"
Margin="0,20">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding TunnelApps.Count}" Value="0">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</TabItem>
</TabControl>
</Grid>
<!-- ═══ FOOTER ═══ -->
<Border Grid.Row="2"
Background="#121212"
BorderBrush="#18FFFFFF"
BorderThickness="0,1,0,0"
CornerRadius="0,0,0,12"
Padding="12,6">
<Grid VerticalAlignment="Center" FlowDirection="RightToLeft">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="12"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"
Orientation="Horizontal"
FlowDirection="RightToLeft"
HorizontalAlignment="Right"
VerticalAlignment="Center">
<TextBlock Text="ساخته شده توسط Maxifan"
FontSize="10"
FontWeight="SemiBold"
Foreground="{StaticResource TextPrimaryBrush}"
VerticalAlignment="Center"/>
<Border Background="#18E8803A"
CornerRadius="8"
Padding="7,2"
Margin="8,0,0,0"
VerticalAlignment="Center">
<TextBlock Text="{Binding AppVersion}"
FontSize="9"
Foreground="{StaticResource AccentBrush}"
VerticalAlignment="Center"/>
</Border>
<TextBlock Text="TunnelX"
Foreground="{StaticResource TextSecondaryBrush}"
FontSize="10"
TextTrimming="CharacterEllipsis"
VerticalAlignment="Center"
Margin="8,0,0,0"/>
</StackPanel>
<StackPanel Grid.Column="3"
Orientation="Horizontal"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FlowDirection="RightToLeft">
<Button Content="بروزرسانی"
Command="{Binding OpenLatestReleaseCommand}"
Visibility="{Binding IsUpdateAvailable, Converter={StaticResource BoolToVis}}"
Style="{StaticResource PrimaryButton}"
Padding="10,4"
FontSize="10"
Margin="0,0,0,0"
VerticalAlignment="Center"
ToolTip="دانلود نسخه جدید از صفحه Releases در GitHub"/>
<Button Content="راهنما"
Click="OnShowHelpClick"
Style="{StaticResource SecondaryButton}"
Padding="9,4"
FontSize="10"
Margin="8,0,0,0"
VerticalAlignment="Center"
ToolTip="راهنما و عیب‌یابی"/>
<Button Content="GitHub"
Command="{Binding OpenGitHubCommand}"
Style="{StaticResource SecondaryButton}"
Padding="9,4"
FontSize="10"
Margin="8,0,0,0"
VerticalAlignment="Center"
ToolTip="باز کردن صفحه GitHub پروژه TunnelX"/>
</StackPanel>
</Grid>
</Border>
</Grid> <!-- end main content column -->
<!-- ═══ LOG PANEL (RIGHT SIDE) ═══ -->
<Border x:Name="LogPanel" Grid.Column="1" Visibility="Collapsed"
Background="{StaticResource SurfaceBrush}"
BorderBrush="{StaticResource CardBrush}" BorderThickness="1,0,0,0">
<Grid Width="350">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Log Header -->
<Border Grid.Row="0" Padding="12,10" Background="#11FFFFFF">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="🔍 جزئیات عملکرد" FontSize="13" FontWeight="SemiBold"
Foreground="{StaticResource TextPrimaryBrush}" VerticalAlignment="Center"/>
<ComboBox x:Name="LogFilterCombo"
Grid.Column="1"
SelectedIndex="0"
SelectionChanged="OnLogFilterChanged"
Margin="0,0,6,0"
MinWidth="86"
Style="{StaticResource DarkComboBox}">
<ComboBoxItem Content="همه" Tag="All"/>
<ComboBoxItem Content="خطا" Tag="Error"/>
<ComboBoxItem Content="هشدار" Tag="Warn"/>
<ComboBoxItem Content="DNS" Tag="Dns"/>
<ComboBoxItem Content="Route" Tag="Route"/>
</ComboBox>
<StackPanel Grid.Column="2" Orientation="Horizontal">
<Button Content="🗑" ToolTip="پاک کردن" Click="OnLogClearClick"
Style="{StaticResource SecondaryButton}"
Padding="8,4" FontSize="12" Margin="0,0,4,0"/>
<Button Content="⚠" ToolTip="کپی آخرین خطا یا هشدار" Click="OnLogCopyLastErrorClick"
Style="{StaticResource SecondaryButton}"
Padding="8,4" FontSize="12" Margin="0,0,4,0"/>
<Button Content="📋" ToolTip="کپی کردن" Click="OnLogCopyClick"
Style="{StaticResource SecondaryButton}"
Padding="8,4" FontSize="12"/>
</StackPanel>
</Grid>
</Border>
<!-- Log Content -->
<TextBox x:Name="LogTextBox" Grid.Row="1"
Background="{StaticResource SurfaceBrush}"
Foreground="{StaticResource TextPrimaryBrush}"
BorderThickness="0"
FontFamily="Consolas"
FontSize="11"
Padding="8"
IsReadOnly="True"
TextWrapping="Wrap"
FlowDirection="LeftToRight"
VerticalScrollBarVisibility="Auto"/>
</Grid>
</Border>
</Grid>
<!-- Toast Notification Overlay -->
<Border x:Name="ToastPanel"
Background="#E0303030" CornerRadius="8"
Padding="14,8" Margin="0,0,0,16"
HorizontalAlignment="Center" VerticalAlignment="Bottom"
Visibility="Collapsed"
IsHitTestVisible="False">
<Border.Effect>
<DropShadowEffect Color="Black" BlurRadius="12" Opacity="0.4" ShadowDepth="2"/>
</Border.Effect>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="ToastIcon" Text="✅" FontSize="14" VerticalAlignment="Center" Margin="0,0,8,0"/>
<TextBlock x:Name="ToastMessage" Text="" FontSize="12"
Foreground="{StaticResource TextPrimaryBrush}" VerticalAlignment="Center"/>
</StackPanel>
</Border>
<!-- Startup Loading Overlay — dismissed quickly while app discovery continues in the background. -->
<Border x:Name="LoadingOverlay" CornerRadius="12"
Background="{StaticResource BackgroundBrush}"
FlowDirection="LeftToRight">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<!-- Logo -->
<Viewbox Width="60" Height="60" HorizontalAlignment="Center" Margin="0,0,0,20">
<Canvas Width="48" Height="48">
<Rectangle Width="48" Height="48" RadiusX="8" RadiusY="8"
Fill="{StaticResource PrimaryBrush}"/>
<TextBlock Text="Tx" FontSize="24" FontWeight="Bold"
Foreground="White" Canvas.Left="6" Canvas.Top="8"
FontFamily="Segoe UI"/>
</Canvas>
</Viewbox>
<!-- App name -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,0,0,6">
<TextBlock Text="Tunnel" FontSize="24" FontWeight="Bold"
Foreground="{StaticResource TextPrimaryBrush}"/>
<TextBlock Text="X" FontSize="24" FontWeight="Bold"
Foreground="{StaticResource AccentBrush}"/>
</StackPanel>
<TextBlock Text="Split Traffic Per App" FontSize="11"
HorizontalAlignment="Center"
Foreground="{StaticResource TextSecondaryBrush}"
Margin="0,0,0,28"/>
<!-- Indeterminate progress bar -->
<ProgressBar IsIndeterminate="True" Width="220" Height="3"
BorderThickness="0"
Foreground="{StaticResource AccentBrush}"
Background="#22FFFFFF"/>
<!-- Status text -->
<TextBlock x:Name="LoadingStatusText"
Text="در حال بارگذاری..."
FontSize="11" HorizontalAlignment="Center"
Foreground="{StaticResource TextSecondaryBrush}"
Margin="0,14,0,0"/>
</StackPanel>
</Border>
</Grid>
</Border>
</Window>