mirror of
https://github.com/2dust/v2rayN.git
synced 2026-11-08 13:35:01 +03:00
@@ -102,6 +102,21 @@ public static class ConfigHandler
|
||||
config.UiItem ??= new();
|
||||
config.UiItem.MainColumnItem ??= [];
|
||||
config.UiItem.WindowSizeItem ??= [];
|
||||
if (config.UiItem.FrozenColumnCount == null)
|
||||
{
|
||||
var lvColumnItem = config.UiItem.MainColumnItem.OrderBy(t => t.Index).ToList();
|
||||
if (lvColumnItem.Count == 0
|
||||
|| (lvColumnItem.Count >= 2
|
||||
&& lvColumnItem[0].Name.Equals("ConfigType")
|
||||
&& lvColumnItem[1].Name.Equals("Remarks")))
|
||||
{
|
||||
config.UiItem.FrozenColumnCount = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
config.UiItem.FrozenColumnCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (config.UiItem.CurrentLanguage.IsNullOrEmpty())
|
||||
{
|
||||
|
||||
@@ -97,6 +97,7 @@ public class UIItem
|
||||
public List<ColumnItem> MainColumnItem { get; set; }
|
||||
public List<WindowSizeItem> WindowSizeItem { get; set; }
|
||||
public bool HideColumnIpInfo { get; set; }
|
||||
public int? FrozenColumnCount { get; set; }
|
||||
}
|
||||
|
||||
public class ConstItem
|
||||
|
||||
Generated
+46
-10
@@ -996,15 +996,6 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Columns 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuColumns {
|
||||
get {
|
||||
return ResourceManager.GetString("menuColumns", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Close Connection 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -1041,6 +1032,15 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Currently frozen first {0} column(s) 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuCurrentlyFrozenColumns {
|
||||
get {
|
||||
return ResourceManager.GetString("menuCurrentlyFrozenColumns", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Latency Test 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -1185,6 +1185,15 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Freeze up to this column 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuFreezeToThisColumn {
|
||||
get {
|
||||
return ResourceManager.GetString("menuFreezeToThisColumn", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Full Config Template Setting 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -1230,6 +1239,15 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Hide this column 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuHideThisColumn {
|
||||
get {
|
||||
return ResourceManager.GetString("menuHideThisColumn", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Import Rules From Clipboard 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -1806,6 +1824,15 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Show columns 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuShowColumns {
|
||||
get {
|
||||
return ResourceManager.GetString("menuShowColumns", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Show or hide the main window 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -1995,6 +2022,15 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Unfreeze all columns 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuUnfreezeAllColumns {
|
||||
get {
|
||||
return ResourceManager.GetString("menuUnfreezeAllColumns", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 {0} Website 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -4913,7 +4949,7 @@ namespace ServiceLib.Resx {
|
||||
return ResourceManager.GetString("TbSettingsTunAutoRoute", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 DNS mode 的本地化字符串。
|
||||
/// </summary>
|
||||
|
||||
@@ -1917,8 +1917,8 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
||||
<data name="FillCorrectFakeIPv6Range" xml:space="preserve">
|
||||
<value>Enter a valid IPv6 CIDR range with at least two addresses, for example fc00::/18.</value>
|
||||
</data>
|
||||
<data name="menuColumns" xml:space="preserve">
|
||||
<value>Columns</value>
|
||||
<data name="menuShowColumns" xml:space="preserve">
|
||||
<value>Show columns</value>
|
||||
</data>
|
||||
<data name="TbWarp" xml:space="preserve">
|
||||
<value>Warp</value>
|
||||
@@ -1926,4 +1926,16 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
||||
<data name="LvPreResolve" xml:space="preserve">
|
||||
<value>Pre-resolve server domains</value>
|
||||
</data>
|
||||
</root>
|
||||
<data name="menuFreezeToThisColumn" xml:space="preserve">
|
||||
<value>Freeze up to this column</value>
|
||||
</data>
|
||||
<data name="menuUnfreezeAllColumns" xml:space="preserve">
|
||||
<value>Unfreeze all columns</value>
|
||||
</data>
|
||||
<data name="menuCurrentlyFrozenColumns" xml:space="preserve">
|
||||
<value>Currently frozen first {0} column(s)</value>
|
||||
</data>
|
||||
<data name="menuHideThisColumn" xml:space="preserve">
|
||||
<value>Hide this column</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1909,8 +1909,8 @@
|
||||
<data name="FillCorrectFakeIPv6Range" xml:space="preserve">
|
||||
<value>请输入至少包含两个地址的有效 IPv6 网段,例如 fc00::/18。</value>
|
||||
</data>
|
||||
<data name="menuColumns" xml:space="preserve">
|
||||
<value>列</value>
|
||||
<data name="menuShowColumns" xml:space="preserve">
|
||||
<value>显示列</value>
|
||||
</data>
|
||||
<data name="TbWarp" xml:space="preserve">
|
||||
<value>Warp</value>
|
||||
@@ -1918,4 +1918,16 @@
|
||||
<data name="LvPreResolve" xml:space="preserve">
|
||||
<value>预解析节点域名</value>
|
||||
</data>
|
||||
</root>
|
||||
<data name="menuFreezeToThisColumn" xml:space="preserve">
|
||||
<value>冻结至此列</value>
|
||||
</data>
|
||||
<data name="menuUnfreezeAllColumns" xml:space="preserve">
|
||||
<value>取消所有冻结</value>
|
||||
</data>
|
||||
<data name="menuCurrentlyFrozenColumns" xml:space="preserve">
|
||||
<value>当前已冻结前 {0} 列</value>
|
||||
</data>
|
||||
<data name="menuHideThisColumn" xml:space="preserve">
|
||||
<value>隐藏此列</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -16,48 +16,6 @@
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<conv:DelayColorConverter x:Key="DelayColorConverter" />
|
||||
|
||||
<ControlTheme x:Key="{x:Type DataGridColumnChooser}" TargetType="DataGridColumnChooser">
|
||||
<Setter Property="ItemTemplate">
|
||||
<Setter.Value>
|
||||
<DataTemplate x:DataType="DataGridColumnChooserItem">
|
||||
<CheckBox
|
||||
Margin="0,2"
|
||||
Content="{Binding Header}"
|
||||
IsChecked="{Binding IsVisible, Mode=TwoWay}"
|
||||
IsEnabled="{Binding CanUserHide}" />
|
||||
</DataTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="ItemsPanel">
|
||||
<Setter.Value>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Spacing="4" />
|
||||
</ItemsPanelTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Button Classes="IconButton Success" ToolTip.Tip="{TemplateBinding ToolTip.Tip}">
|
||||
<Button.Flyout>
|
||||
<Flyout Placement="BottomEdgeAlignedLeft">
|
||||
<Border
|
||||
MaxWidth="260"
|
||||
MaxHeight="360"
|
||||
Padding="8">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||
<ItemsPresenter />
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</Flyout>
|
||||
</Button.Flyout>
|
||||
<ContentPresenter Content="{TemplateBinding Header}" ContentTemplate="{TemplateBinding HeaderTemplate}" />
|
||||
</Button>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</ControlTheme>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<DockPanel>
|
||||
@@ -111,25 +69,6 @@
|
||||
PlaceholderText="{x:Static resx:ResUI.MsgServerTitle}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.MsgServerTitle}" />
|
||||
|
||||
<Button
|
||||
x:Name="btnAutofitColumnWidth"
|
||||
Margin="{StaticResource MarginLr4}"
|
||||
Classes="IconButton Success"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}">
|
||||
<Button.Content>
|
||||
<PathIcon Data="{StaticResource SemiIconExpand}" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<DataGridColumnChooser
|
||||
Margin="{StaticResource MarginLr4}"
|
||||
DataGrid="{Binding ElementName=lstProfiles}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuColumns}">
|
||||
<DataGridColumnChooser.Header>
|
||||
<PathIcon Data="{StaticResource SemiIconSetting}" />
|
||||
</DataGridColumnChooser.Header>
|
||||
</DataGridColumnChooser>
|
||||
|
||||
<Button
|
||||
x:Name="btnFastRealPing"
|
||||
Margin="{StaticResource MarginLr4}"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Avalonia.Controls.DataGridDragDrop;
|
||||
using Avalonia.VisualTree;
|
||||
using DialogHostAvalonia;
|
||||
using v2rayN.Desktop.Common;
|
||||
|
||||
@@ -17,12 +18,12 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
|
||||
_config = AppManager.Instance.Config;
|
||||
|
||||
menuSelectAll.Click += menuSelectAll_Click;
|
||||
btnAutofitColumnWidth.Click += BtnAutofitColumnWidth_Click;
|
||||
txtServerFilter.KeyDown += TxtServerFilter_KeyDown;
|
||||
lstProfiles.KeyDown += LstProfiles_KeyDown;
|
||||
lstProfiles.SelectionChanged += lstProfiles_SelectionChanged;
|
||||
lstProfiles.DoubleTapped += LstProfiles_DoubleTapped;
|
||||
lstProfiles.Sorting += LstProfiles_Sorting;
|
||||
SetupColumnHeaderContextMenu();
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
@@ -315,11 +316,6 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
|
||||
}
|
||||
}
|
||||
|
||||
private void BtnAutofitColumnWidth_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
AutofitColumnWidth();
|
||||
}
|
||||
|
||||
private void AutofitColumnWidth()
|
||||
{
|
||||
try
|
||||
@@ -401,6 +397,7 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
|
||||
}
|
||||
}
|
||||
}
|
||||
lstProfiles.FrozenColumnCount = _config.UiItem.FrozenColumnCount ?? 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -427,6 +424,7 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
|
||||
{
|
||||
try
|
||||
{
|
||||
_config.UiItem.FrozenColumnCount = lstProfiles.FrozenColumnCount;
|
||||
List<ColumnItem> lvColumnItem = [];
|
||||
foreach (var item2 in lstProfiles.Columns)
|
||||
{
|
||||
@@ -449,6 +447,120 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupColumnHeaderContextMenu()
|
||||
{
|
||||
lstProfiles.AddHandler(PointerPressedEvent, (sender, e) =>
|
||||
{
|
||||
if (e.GetCurrentPoint(lstProfiles).Properties.IsRightButtonPressed)
|
||||
{
|
||||
var header = (e.Source as Visual)?.FindAncestorOfType<DataGridColumnHeader>();
|
||||
if (header?.OwningColumn != null)
|
||||
{
|
||||
e.Handled = true;
|
||||
ShowColumnHeaderContextMenu(header, header.OwningColumn);
|
||||
}
|
||||
}
|
||||
}, RoutingStrategies.Tunnel);
|
||||
}
|
||||
|
||||
private void ShowColumnHeaderContextMenu(DataGridColumnHeader header, DataGridColumn column)
|
||||
{
|
||||
var menu = new ContextMenu();
|
||||
var colTitle = column.Header?.ToString() ?? string.Empty;
|
||||
|
||||
var visibleColumns = lstProfiles.Columns
|
||||
.Where(c => c.IsVisible)
|
||||
.OrderBy(c => c.DisplayIndex < 0 ? int.MaxValue : c.DisplayIndex)
|
||||
|
||||
.ToList();
|
||||
var targetIndex = visibleColumns.IndexOf(column);
|
||||
var targetCount = targetIndex >= 0 ? targetIndex + 1 : 0;
|
||||
|
||||
var autofitColumnWidthColumn = new MenuItem
|
||||
{
|
||||
Header = ResUI.menuProfileAutofitColumnWidth,
|
||||
};
|
||||
autofitColumnWidthColumn.Click += (s, ev) =>
|
||||
{
|
||||
AutofitColumnWidth();
|
||||
};
|
||||
|
||||
var hideColumn = new MenuItem
|
||||
{
|
||||
Header = ResUI.menuHideThisColumn,
|
||||
IsEnabled = column.IsVisible,
|
||||
};
|
||||
hideColumn.Click += (s, ev) =>
|
||||
{
|
||||
column.IsVisible = false;
|
||||
};
|
||||
|
||||
var showColumns = new MenuItem
|
||||
{
|
||||
Header = ResUI.menuShowColumns,
|
||||
};
|
||||
var dgColumnLst = lstProfiles.Columns.OrderBy(c => c.DisplayIndex < 0 ? int.MaxValue : c.DisplayIndex).ToList();
|
||||
foreach (var col in dgColumnLst)
|
||||
{
|
||||
var columnItem = new MenuItem
|
||||
{
|
||||
Header = col.Header,
|
||||
IsChecked = col.IsVisible,
|
||||
IsEnabled = col.CanUserHide,
|
||||
Padding = new Thickness(6, 2),
|
||||
StaysOpenOnClick = true,
|
||||
ToggleType = MenuItemToggleType.CheckBox,
|
||||
};
|
||||
columnItem.Click += (_, _) => col.IsVisible = columnItem.IsChecked;
|
||||
showColumns.Items.Add(columnItem);
|
||||
}
|
||||
|
||||
var freezeToHereStr = ResUI.menuFreezeToThisColumn;
|
||||
if (!string.IsNullOrEmpty(colTitle))
|
||||
{
|
||||
freezeToHereStr += $" ({colTitle})";
|
||||
}
|
||||
var freezeToHere = new MenuItem
|
||||
{
|
||||
Header = freezeToHereStr,
|
||||
IsEnabled = targetCount > 0,
|
||||
};
|
||||
freezeToHere.Click += (s, ev) =>
|
||||
{
|
||||
lstProfiles.FrozenColumnCount = targetCount;
|
||||
};
|
||||
|
||||
var unfreezeAll = new MenuItem
|
||||
{
|
||||
Header = ResUI.menuUnfreezeAllColumns,
|
||||
IsEnabled = lstProfiles.FrozenColumnCount > 0,
|
||||
};
|
||||
unfreezeAll.Click += (s, ev) =>
|
||||
{
|
||||
lstProfiles.FrozenColumnCount = 0;
|
||||
};
|
||||
|
||||
var statusItemStr = string.Format(ResUI.menuCurrentlyFrozenColumns, lstProfiles.FrozenColumnCount);
|
||||
var statusItem = new MenuItem
|
||||
{
|
||||
Header = statusItemStr,
|
||||
IsEnabled = false,
|
||||
};
|
||||
|
||||
menu.Items.Add(autofitColumnWidthColumn);
|
||||
menu.Items.Add(new Separator());
|
||||
menu.Items.Add(hideColumn);
|
||||
menu.Items.Add(showColumns);
|
||||
menu.Items.Add(new Separator());
|
||||
menu.Items.Add(freezeToHere);
|
||||
menu.Items.Add(unfreezeAll);
|
||||
menu.Items.Add(new Separator());
|
||||
menu.Items.Add(statusItem);
|
||||
|
||||
header.ContextMenu = menu;
|
||||
menu.Open(header);
|
||||
}
|
||||
|
||||
#endregion UI
|
||||
|
||||
private sealed class ProfileRowDropHandler(ProfilesViewModel viewModel) : IDataGridRowDropHandler
|
||||
|
||||
Reference in New Issue
Block a user