mirror of
https://github.com/2dust/v2rayN.git
synced 2025-10-14 04:19:12 +00:00
commit
406dc3a297
3 changed files with 88 additions and 63 deletions
|
@ -1,5 +1,6 @@
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using ReactiveUI.Fody.Helpers;
|
using ReactiveUI.Fody.Helpers;
|
||||||
|
@ -9,7 +10,7 @@ namespace ServiceLib.ViewModels;
|
||||||
public class MsgViewModel : MyReactiveObject
|
public class MsgViewModel : MyReactiveObject
|
||||||
{
|
{
|
||||||
private readonly ConcurrentQueue<string> _queueMsg = new();
|
private readonly ConcurrentQueue<string> _queueMsg = new();
|
||||||
private readonly int _numMaxMsg = 500;
|
private readonly int _numMaxMsg = 500; // 仅用于限制队列,不做显示裁剪
|
||||||
private bool _lastMsgFilterNotAvailable;
|
private bool _lastMsgFilterNotAvailable;
|
||||||
private bool _blLockShow = false;
|
private bool _blLockShow = false;
|
||||||
|
|
||||||
|
@ -26,63 +27,45 @@ public class MsgViewModel : MyReactiveObject
|
||||||
MsgFilter = _config.MsgUIItem.MainMsgFilter ?? string.Empty;
|
MsgFilter = _config.MsgUIItem.MainMsgFilter ?? string.Empty;
|
||||||
AutoRefresh = _config.MsgUIItem.AutoRefresh ?? true;
|
AutoRefresh = _config.MsgUIItem.AutoRefresh ?? true;
|
||||||
|
|
||||||
this.WhenAnyValue(
|
this.WhenAnyValue(x => x.MsgFilter).Subscribe(c => DoMsgFilter());
|
||||||
x => x.MsgFilter)
|
this.WhenAnyValue(x => x.AutoRefresh, y => y == true)
|
||||||
.Subscribe(c => DoMsgFilter());
|
.Subscribe(c => { _config.MsgUIItem.AutoRefresh = AutoRefresh; });
|
||||||
|
|
||||||
this.WhenAnyValue(
|
|
||||||
x => x.AutoRefresh,
|
|
||||||
y => y == true)
|
|
||||||
.Subscribe(c => { _config.MsgUIItem.AutoRefresh = AutoRefresh; });
|
|
||||||
|
|
||||||
AppEvents.SendMsgViewRequested
|
AppEvents.SendMsgViewRequested
|
||||||
.AsObservable()
|
.AsObservable()
|
||||||
//.ObserveOn(RxApp.MainThreadScheduler)
|
.Subscribe(async content => await AppendQueueMsg(content));
|
||||||
.Subscribe(async content => await AppendQueueMsg(content));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AppendQueueMsg(string msg)
|
private async Task AppendQueueMsg(string msg)
|
||||||
{
|
{
|
||||||
//if (msg == Global.CommandClearMsg)
|
if (AutoRefresh == false) return;
|
||||||
//{
|
await EnqueueQueueMsg(msg);
|
||||||
// ClearMsg();
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
if (AutoRefresh == false)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_ = EnqueueQueueMsg(msg);
|
|
||||||
|
|
||||||
if (_blLockShow)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!_config.UiItem.ShowInTaskbar)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (_blLockShow || !_config.UiItem.ShowInTaskbar) return;
|
||||||
_blLockShow = true;
|
_blLockShow = true;
|
||||||
|
|
||||||
await Task.Delay(500);
|
await Task.Delay(500);
|
||||||
var txt = string.Join("", _queueMsg.ToArray());
|
|
||||||
await _updateView?.Invoke(EViewAction.DispatcherShowMsg, txt);
|
var sbDelta = new StringBuilder();
|
||||||
|
while (_queueMsg.TryDequeue(out var line))
|
||||||
|
{
|
||||||
|
sbDelta.Append(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
var delta = sbDelta.ToString();
|
||||||
|
if (delta.Length > 0)
|
||||||
|
await _updateView?.Invoke(EViewAction.DispatcherShowMsg, delta);
|
||||||
|
|
||||||
_blLockShow = false;
|
_blLockShow = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task EnqueueQueueMsg(string msg)
|
private async Task EnqueueQueueMsg(string msg)
|
||||||
{
|
{
|
||||||
//filter msg
|
|
||||||
if (MsgFilter.IsNotEmpty() && !_lastMsgFilterNotAvailable)
|
if (MsgFilter.IsNotEmpty() && !_lastMsgFilterNotAvailable)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!Regex.IsMatch(msg, MsgFilter))
|
if (!Regex.IsMatch(msg, MsgFilter)) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -91,26 +74,17 @@ public class MsgViewModel : MyReactiveObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Enqueue
|
while (_queueMsg.Count > _numMaxMsg)
|
||||||
if (_queueMsg.Count > _numMaxMsg)
|
_queueMsg.TryDequeue(out _);
|
||||||
{
|
|
||||||
for (int k = 0; k < _queueMsg.Count - _numMaxMsg; k++)
|
|
||||||
{
|
|
||||||
_queueMsg.TryDequeue(out _);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_queueMsg.Enqueue(msg);
|
_queueMsg.Enqueue(msg);
|
||||||
if (!msg.EndsWith(Environment.NewLine))
|
if (!msg.EndsWith(Environment.NewLine))
|
||||||
{
|
|
||||||
_queueMsg.Enqueue(Environment.NewLine);
|
_queueMsg.Enqueue(Environment.NewLine);
|
||||||
}
|
|
||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearMsg()
|
public void ClearMsg() => _queueMsg.Clear();
|
||||||
{
|
|
||||||
_queueMsg.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DoMsgFilter()
|
private void DoMsgFilter()
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,12 +5,15 @@ using Avalonia.ReactiveUI;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using v2rayN.Desktop.Common;
|
using v2rayN.Desktop.Common;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class MsgView : ReactiveUserControl<MsgViewModel>
|
public partial class MsgView : ReactiveUserControl<MsgViewModel>
|
||||||
{
|
{
|
||||||
private readonly ScrollViewer _scrollViewer;
|
private readonly ScrollViewer _scrollViewer;
|
||||||
|
private const int _maxLines = 320; // 实际保留的行数
|
||||||
|
private const int _trimLines = 350; // 超过此阈值时裁剪
|
||||||
private int _lastShownLength = 0;
|
private int _lastShownLength = 0;
|
||||||
|
|
||||||
public MsgView()
|
public MsgView()
|
||||||
|
@ -32,8 +35,7 @@ public partial class MsgView : ReactiveUserControl<MsgViewModel>
|
||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.DispatcherShowMsg:
|
case EViewAction.DispatcherShowMsg:
|
||||||
if (obj is null)
|
if (obj is null) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
ShowMsg(obj),
|
ShowMsg(obj),
|
||||||
|
@ -46,16 +48,20 @@ public partial class MsgView : ReactiveUserControl<MsgViewModel>
|
||||||
private void ShowMsg(object msg)
|
private void ShowMsg(object msg)
|
||||||
{
|
{
|
||||||
var newText = msg?.ToString() ?? string.Empty;
|
var newText = msg?.ToString() ?? string.Empty;
|
||||||
|
txtMsg.Text += newText;
|
||||||
|
|
||||||
if (txtMsg.Text is { } old && newText.Length >= _lastShownLength && newText.AsSpan(0, _lastShownLength).SequenceEqual(old))
|
var lines = txtMsg.Text.Split(Environment.NewLine);
|
||||||
|
if (lines.Length > _trimLines)
|
||||||
{
|
{
|
||||||
var delta = newText.AsSpan(_lastShownLength);
|
var sb = new StringBuilder();
|
||||||
if (!delta.IsEmpty)
|
int start = lines.Length - _maxLines;
|
||||||
txtMsg.Text += delta.ToString();
|
for (int i = start; i < lines.Length; i++)
|
||||||
}
|
{
|
||||||
else
|
sb.Append(lines[i]);
|
||||||
{
|
if (i < lines.Length - 1)
|
||||||
txtMsg.Text = newText;
|
sb.Append(Environment.NewLine);
|
||||||
|
}
|
||||||
|
txtMsg.Text = sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
_lastShownLength = txtMsg.Text.Length;
|
_lastShownLength = txtMsg.Text.Length;
|
||||||
|
@ -70,6 +76,7 @@ public partial class MsgView : ReactiveUserControl<MsgViewModel>
|
||||||
{
|
{
|
||||||
ViewModel?.ClearMsg();
|
ViewModel?.ClearMsg();
|
||||||
txtMsg.Text = "";
|
txtMsg.Text = "";
|
||||||
|
_lastShownLength = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void menuMsgViewSelectAll_Click(object? sender, RoutedEventArgs e)
|
private void menuMsgViewSelectAll_Click(object? sender, RoutedEventArgs e)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
|
using System.Text;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
@ -7,6 +8,9 @@ namespace v2rayN.Views;
|
||||||
|
|
||||||
public partial class MsgView
|
public partial class MsgView
|
||||||
{
|
{
|
||||||
|
private const int _maxLines = 320;
|
||||||
|
private const int _trimLines = 350;
|
||||||
|
|
||||||
public MsgView()
|
public MsgView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
@ -47,12 +51,52 @@ public partial class MsgView
|
||||||
|
|
||||||
private void ShowMsg(object msg)
|
private void ShowMsg(object msg)
|
||||||
{
|
{
|
||||||
|
var incoming = msg?.ToString() ?? string.Empty;
|
||||||
|
var old = txtMsg.Text ?? string.Empty;
|
||||||
|
|
||||||
txtMsg.BeginChange();
|
txtMsg.BeginChange();
|
||||||
txtMsg.Text = msg.ToString();
|
|
||||||
|
if (incoming.Length >= old.Length && incoming.AsSpan(0, old.Length).SequenceEqual(old))
|
||||||
|
{
|
||||||
|
var delta = incoming.AsSpan(old.Length);
|
||||||
|
if (!delta.IsEmpty)
|
||||||
|
txtMsg.AppendText(delta.ToString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 兼容增量:如果不是全量覆盖场景,直接把 incoming 当作增量追加
|
||||||
|
if (old.Length == 0)
|
||||||
|
{
|
||||||
|
txtMsg.Text = incoming;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
txtMsg.AppendText(incoming);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 行数超过阈值才裁剪到 _maxLines
|
||||||
|
var lines = txtMsg.Text.Split(Environment.NewLine);
|
||||||
|
if (lines.Length > _trimLines)
|
||||||
|
{
|
||||||
|
var start = lines.Length - _maxLines;
|
||||||
|
if (start < 0) start = 0;
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
for (int i = start; i < lines.Length; i++)
|
||||||
|
{
|
||||||
|
sb.Append(lines[i]);
|
||||||
|
if (i < lines.Length - 1)
|
||||||
|
sb.Append(Environment.NewLine);
|
||||||
|
}
|
||||||
|
txtMsg.Text = sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
if (togScrollToEnd.IsChecked ?? true)
|
if (togScrollToEnd.IsChecked ?? true)
|
||||||
{
|
{
|
||||||
txtMsg.ScrollToEnd();
|
txtMsg.ScrollToEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
txtMsg.EndChange();
|
txtMsg.EndChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue