mirror of
https://github.com/2dust/v2rayN.git
synced 2025-10-27 18:42:52 +00:00
232 lines
7.2 KiB
C#
232 lines
7.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reactive;
|
|
using System.Reactive.Linq;
|
|
using System.Threading.Tasks;
|
|
using DynamicData;
|
|
using DynamicData.Binding;
|
|
using ReactiveUI;
|
|
using ReactiveUI.Fody.Helpers;
|
|
using ServiceLib.Base;
|
|
|
|
namespace ServiceLib.ViewModels;
|
|
|
|
public abstract class ProfilesBaseViewModel : MyReactiveObject
|
|
{
|
|
#region protected fields
|
|
|
|
protected List<ProfileItem> _lstProfile = new();
|
|
protected string _serverFilter = string.Empty;
|
|
protected Dictionary<string, bool> _dicHeaderSort = new();
|
|
|
|
#endregion
|
|
|
|
#region Observable properties
|
|
|
|
public IObservableCollection<ProfileItemModel> ProfileItems { get; } = new ObservableCollectionExtended<ProfileItemModel>();
|
|
|
|
public IObservableCollection<SubItem> SubItems { get; } = new ObservableCollectionExtended<SubItem>();
|
|
|
|
[Reactive]
|
|
public ProfileItemModel SelectedProfile { get; set; }
|
|
|
|
public IList<ProfileItemModel> SelectedProfiles { get; set; }
|
|
|
|
[Reactive]
|
|
public SubItem SelectedSub { get; set; }
|
|
|
|
[Reactive]
|
|
public string ServerFilter { get; set; }
|
|
|
|
#endregion
|
|
|
|
protected ProfilesBaseViewModel(Func<EViewAction, object?, Task<bool>>? updateView)
|
|
{
|
|
_config = AppManager.Instance.Config;
|
|
_updateView = updateView;
|
|
|
|
this.WhenAnyValue(
|
|
x => x.SelectedSub,
|
|
y => y != null && !y.Remarks.IsNullOrEmpty() && GetCurrentSubIndexId() != y.Id)
|
|
.Subscribe(async c => await SubSelectedChangedAsync(c));
|
|
|
|
this.WhenAnyValue(
|
|
x => x.ServerFilter,
|
|
y => y != null && _serverFilter != y)
|
|
.Subscribe(async c => await ServerFilterChanged(c));
|
|
|
|
AppEvents.ProfilesRefreshRequested
|
|
.AsObservable()
|
|
.ObserveOn(RxApp.MainThreadScheduler)
|
|
.Subscribe(async _ => await RefreshServersBiz());
|
|
|
|
AppEvents.DispatcherStatisticsRequested
|
|
.AsObservable()
|
|
.ObserveOn(RxApp.MainThreadScheduler)
|
|
.Subscribe(UpdateStatistics);
|
|
|
|
_ = Initialize();
|
|
}
|
|
|
|
protected virtual async Task Initialize()
|
|
{
|
|
SelectedProfile = new();
|
|
SelectedSub = new();
|
|
|
|
await RefreshSubscriptions();
|
|
await RefreshServers();
|
|
}
|
|
|
|
#region Hook points
|
|
|
|
protected abstract string GetCurrentSubIndexId();
|
|
protected abstract void SetCurrentSubIndexId(string? id);
|
|
|
|
protected virtual bool ShouldSetDefaultServer => false;
|
|
|
|
public virtual async Task RefreshServers()
|
|
{
|
|
await RefreshServersBiz();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Shared actions
|
|
|
|
protected virtual async Task SubSelectedChangedAsync(bool changed)
|
|
{
|
|
if (!changed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
SetCurrentSubIndexId(SelectedSub?.Id);
|
|
|
|
await RefreshServers();
|
|
|
|
await _updateView?.Invoke(EViewAction.ProfilesFocus, null);
|
|
}
|
|
|
|
protected virtual async Task ServerFilterChanged(bool changed)
|
|
{
|
|
if (!changed)
|
|
{
|
|
return;
|
|
}
|
|
_serverFilter = ServerFilter;
|
|
if (_serverFilter.IsNullOrEmpty())
|
|
{
|
|
await RefreshServers();
|
|
}
|
|
}
|
|
|
|
protected async Task RefreshServersBiz()
|
|
{
|
|
var lstModel = await GetProfileItemsEx(GetCurrentSubIndexId(), _serverFilter) ?? new List<ProfileItemModel>();
|
|
|
|
_lstProfile = JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(lstModel)) ?? [];
|
|
|
|
ProfileItems.Clear();
|
|
ProfileItems.AddRange(lstModel);
|
|
if (lstModel.Count > 0)
|
|
{
|
|
var selected = lstModel.FirstOrDefault(t => t.IndexId == _config.IndexId);
|
|
SelectedProfile = selected ?? lstModel.First();
|
|
}
|
|
|
|
await _updateView?.Invoke(EViewAction.DispatcherRefreshServersBiz, null);
|
|
}
|
|
|
|
public virtual async Task RefreshSubscriptions()
|
|
{
|
|
SubItems.Clear();
|
|
|
|
SubItems.Add(new SubItem { Remarks = ResUI.AllGroupServers });
|
|
|
|
foreach (var item in await AppManager.Instance.SubItems())
|
|
{
|
|
SubItems.Add(item);
|
|
}
|
|
|
|
var curId = GetCurrentSubIndexId();
|
|
if (!curId.IsNullOrEmpty() && SubItems.FirstOrDefault(t => t.Id == curId) != null)
|
|
{
|
|
SelectedSub = SubItems.FirstOrDefault(t => t.Id == curId);
|
|
}
|
|
else
|
|
{
|
|
SelectedSub = SubItems.First();
|
|
}
|
|
}
|
|
|
|
protected virtual async Task<List<ProfileItemModel>?> GetProfileItemsEx(string subid, string filter)
|
|
{
|
|
var lstModel = await AppManager.Instance.ProfileItems(subid, filter);
|
|
|
|
if (ShouldSetDefaultServer)
|
|
{
|
|
await ConfigHandler.SetDefaultServer(_config, lstModel);
|
|
}
|
|
|
|
var lstServerStat = (_config.GuiItem.EnableStatistics ? StatisticsManager.Instance.ServerStat : null) ?? [];
|
|
var lstProfileExs = await ProfileExManager.Instance.GetProfileExs();
|
|
lstModel = (from t in lstModel
|
|
join t2 in lstServerStat on t.IndexId equals t2.IndexId into t2b
|
|
from t22 in t2b.DefaultIfEmpty()
|
|
join t3 in lstProfileExs on t.IndexId equals t3.IndexId into t3b
|
|
from t33 in t3b.DefaultIfEmpty()
|
|
select new ProfileItemModel
|
|
{
|
|
IndexId = t.IndexId,
|
|
ConfigType = t.ConfigType,
|
|
Remarks = t.Remarks,
|
|
Address = t.Address,
|
|
Port = t.Port,
|
|
Security = t.Security,
|
|
Network = t.Network,
|
|
StreamSecurity = t.StreamSecurity,
|
|
Subid = t.Subid,
|
|
SubRemarks = t.SubRemarks,
|
|
IsActive = t.IndexId == _config.IndexId,
|
|
Sort = t33?.Sort ?? 0,
|
|
Delay = t33?.Delay ?? 0,
|
|
Speed = t33?.Speed ?? 0,
|
|
DelayVal = t33?.Delay != 0 ? $"{t33?.Delay}" : string.Empty,
|
|
SpeedVal = t33?.Speed > 0 ? $"{t33?.Speed}" : t33?.Message ?? string.Empty,
|
|
TodayDown = t22 == null ? "" : Utils.HumanFy(t22.TodayDown),
|
|
TodayUp = t22 == null ? "" : Utils.HumanFy(t22.TodayUp),
|
|
TotalDown = t22 == null ? "" : Utils.HumanFy(t22.TotalDown),
|
|
TotalUp = t22 == null ? "" : Utils.HumanFy(t22.TotalUp)
|
|
}).OrderBy(t => t.Sort).ToList();
|
|
|
|
return lstModel;
|
|
}
|
|
|
|
public virtual void UpdateStatistics(ServerSpeedItem update)
|
|
{
|
|
if (!_config.GuiItem.EnableStatistics
|
|
|| (update.ProxyUp + update.ProxyDown) <= 0
|
|
|| DateTime.Now.Second % 3 != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
var item = ProfileItems.FirstOrDefault(it => it.IndexId == update.IndexId);
|
|
if (item != null)
|
|
{
|
|
item.TodayDown = Utils.HumanFy(update.TodayDown);
|
|
item.TodayUp = Utils.HumanFy(update.TodayUp);
|
|
item.TotalDown = Utils.HumanFy(update.TotalDown);
|
|
item.TotalUp = Utils.HumanFy(update.TotalUp);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|