diff --git a/v2rayN/ServiceLib/ViewModels/ProfilesBaseViewModel.cs b/v2rayN/ServiceLib/ViewModels/ProfilesBaseViewModel.cs new file mode 100644 index 00000000..778ea4b2 --- /dev/null +++ b/v2rayN/ServiceLib/ViewModels/ProfilesBaseViewModel.cs @@ -0,0 +1,232 @@ +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 _lstProfile = new(); + protected string _serverFilter = string.Empty; + protected Dictionary _dicHeaderSort = new(); + + #endregion + + #region Observable properties + + public IObservableCollection ProfileItems { get; } = new ObservableCollectionExtended(); + + public IObservableCollection SubItems { get; } = new ObservableCollectionExtended(); + + [Reactive] + public ProfileItemModel SelectedProfile { get; set; } + + public IList SelectedProfiles { get; set; } + + [Reactive] + public SubItem SelectedSub { get; set; } + + [Reactive] + public string ServerFilter { get; set; } + + #endregion + + protected ProfilesBaseViewModel(Func>? 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(); + + _lstProfile = JsonUtils.Deserialize>(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?> 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 +} diff --git a/v2rayN/ServiceLib/ViewModels/ProfilesSelectViewModel.cs b/v2rayN/ServiceLib/ViewModels/ProfilesSelectViewModel.cs index a9ab2dd4..f0c58d27 100644 --- a/v2rayN/ServiceLib/ViewModels/ProfilesSelectViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/ProfilesSelectViewModel.cs @@ -10,125 +10,27 @@ using DynamicData.Binding; using ReactiveUI; using ReactiveUI.Fody.Helpers; using Splat; +using ServiceLib.Base; namespace ServiceLib.ViewModels; -public class ProfilesSelectViewModel : MyReactiveObject +public class ProfilesSelectViewModel(Func>? updateView) : ProfilesBaseViewModel(updateView) { #region private prop - private List _lstProfile; - private string _serverFilter = string.Empty; - private Dictionary _dicHeaderSort = new(); private string _subIndexId = string.Empty; #endregion private prop - #region ObservableCollection - - public IObservableCollection ProfileItems { get; } = new ObservableCollectionExtended(); - - public IObservableCollection SubItems { get; } = new ObservableCollectionExtended(); - - [Reactive] - public ProfileItemModel SelectedProfile { get; set; } - - public IList SelectedProfiles { get; set; } - - [Reactive] - public SubItem SelectedSub { get; set; } - - [Reactive] - public string ServerFilter { get; set; } - - #endregion ObservableCollection - #region Init - - public ProfilesSelectViewModel(Func>? updateView) + protected override async Task Initialize() { - _config = AppManager.Instance.Config; - _updateView = updateView; _subIndexId = _config.SubIndexId ?? string.Empty; - #region WhenAnyValue && ReactiveCommand - - this.WhenAnyValue( - x => x.SelectedSub, - y => y != null && !y.Remarks.IsNullOrEmpty() && _subIndexId != y.Id) - .Subscribe(async c => await SubSelectedChangedAsync(c)); - - this.WhenAnyValue( - x => x.ServerFilter, - y => y != null && _serverFilter != y) - .Subscribe(async c => await ServerFilterChanged(c)); - - #endregion WhenAnyValue && ReactiveCommand - - #region AppEvents - - AppEvents.ProfilesRefreshRequested - .AsObservable() - .ObserveOn(RxApp.MainThreadScheduler) - .Subscribe(async _ => await RefreshServersBiz()); - - AppEvents.DispatcherStatisticsRequested - .AsObservable() - .ObserveOn(RxApp.MainThreadScheduler) - .Subscribe(UpdateStatistics); - - #endregion AppEvents - - _ = Init(); + await base.Initialize(); } - - private async Task Init() - { - SelectedProfile = new(); - SelectedSub = new(); - - await RefreshSubscriptions(); - await RefreshServers(); - } - #endregion Init #region Actions - public 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); - - //if (SelectedProfile?.IndexId == item.IndexId) - //{ - // var temp = JsonUtils.DeepCopy(item); - // _profileItems.Replace(item, temp); - // SelectedProfile = temp; - //} - //else - //{ - // _profileItems.Replace(item, JsonUtils.DeepCopy(item)); - //} - } - } - catch - { - } - } - public bool CanOk() { return SelectedProfile != null && !SelectedProfile.IndexId.IsNullOrEmpty(); @@ -147,120 +49,6 @@ public class ProfilesSelectViewModel : MyReactiveObject #region Servers && Groups - private async Task SubSelectedChangedAsync(bool c) - { - if (!c) - { - return; - } - _subIndexId = SelectedSub?.Id; - - await RefreshServers(); - - await _updateView?.Invoke(EViewAction.ProfilesFocus, null); - } - - private async Task ServerFilterChanged(bool c) - { - if (!c) - { - return; - } - _serverFilter = ServerFilter; - if (_serverFilter.IsNullOrEmpty()) - { - await RefreshServers(); - } - } - - public async Task RefreshServers() - { - await RefreshServersBiz(); - } - - private async Task RefreshServersBiz() - { - var lstModel = await GetProfileItemsEx(_subIndexId, _serverFilter); - _lstProfile = JsonUtils.Deserialize>(JsonUtils.Serialize(lstModel)) ?? []; - - ProfileItems.Clear(); - ProfileItems.AddRange(lstModel); - if (lstModel.Count > 0) - { - var selected = lstModel.FirstOrDefault(t => t.IndexId == _config.IndexId); - if (selected != null) - { - SelectedProfile = selected; - } - else - { - SelectedProfile = lstModel.First(); - } - } - - await _updateView?.Invoke(EViewAction.DispatcherRefreshServersBiz, null); - } - - public async Task RefreshSubscriptions() - { - SubItems.Clear(); - - SubItems.Add(new SubItem { Remarks = ResUI.AllGroupServers }); - - foreach (var item in await AppManager.Instance.SubItems()) - { - SubItems.Add(item); - } - if (_subIndexId != null && SubItems.FirstOrDefault(t => t.Id == _subIndexId) != null) - { - SelectedSub = SubItems.FirstOrDefault(t => t.Id == _subIndexId); - } - else - { - SelectedSub = SubItems.First(); - } - } - - private async Task?> GetProfileItemsEx(string subid, string filter) - { - var lstModel = await AppManager.Instance.ProfileItems(_subIndexId, filter); - - //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 async Task GetProfileItem() { if (string.IsNullOrEmpty(SelectedProfile?.IndexId)) @@ -277,8 +65,9 @@ public class ProfilesSelectViewModel : MyReactiveObject return item; } - public async Task SortServer(string colName) + public Task SortServer(string colName) { + _ = colName; //if (colName.IsNullOrEmpty()) //{ // return; @@ -292,7 +81,23 @@ public class ProfilesSelectViewModel : MyReactiveObject //} //_dicHeaderSort[colName] = !asc; //await RefreshServers(); + return Task.CompletedTask; } #endregion Servers && Groups + + #region overrides + + protected override string GetCurrentSubIndexId() + { + return _subIndexId; + } + protected override void SetCurrentSubIndexId(string? id) + { + _subIndexId = id ?? string.Empty; + } + + protected override bool ShouldSetDefaultServer => false; + + #endregion overrides } diff --git a/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs b/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs index f5aeac21..dce27dd1 100644 --- a/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs @@ -7,40 +7,23 @@ using DynamicData.Binding; using ReactiveUI; using ReactiveUI.Fody.Helpers; using Splat; +using ServiceLib.Base; namespace ServiceLib.ViewModels; -public class ProfilesViewModel : MyReactiveObject +public class ProfilesViewModel : ProfilesBaseViewModel { #region private prop - private List _lstProfile; - private string _serverFilter = string.Empty; - private Dictionary _dicHeaderSort = new(); private SpeedtestService? _speedtestService; #endregion private prop #region ObservableCollection - public IObservableCollection ProfileItems { get; } = new ObservableCollectionExtended(); - - public IObservableCollection SubItems { get; } = new ObservableCollectionExtended(); - - [Reactive] - public ProfileItemModel SelectedProfile { get; set; } - - public IList SelectedProfiles { get; set; } - - [Reactive] - public SubItem SelectedSub { get; set; } - [Reactive] public SubItem SelectedMoveToGroup { get; set; } - [Reactive] - public string ServerFilter { get; set; } - #endregion ObservableCollection #region Menu @@ -89,175 +72,61 @@ public class ProfilesViewModel : MyReactiveObject #region Init - public ProfilesViewModel(Func>? updateView) + public ProfilesViewModel(Func>? updateView) : base(updateView) { - _config = AppManager.Instance.Config; - _updateView = updateView; - #region WhenAnyValue && ReactiveCommand var canEditRemove = this.WhenAnyValue( x => x.SelectedProfile, selectedSource => selectedSource != null && !selectedSource.IndexId.IsNullOrEmpty()); - this.WhenAnyValue( - x => x.SelectedSub, - y => y != null && !y.Remarks.IsNullOrEmpty() && _config.SubIndexId != y.Id) - .Subscribe(async c => await SubSelectedChangedAsync(c)); this.WhenAnyValue( x => x.SelectedMoveToGroup, y => y != null && !y.Remarks.IsNullOrEmpty()) .Subscribe(async c => await MoveToGroup(c)); - this.WhenAnyValue( - x => x.ServerFilter, - y => y != null && _serverFilter != y) - .Subscribe(async c => await ServerFilterChanged(c)); - //servers delete - EditServerCmd = ReactiveCommand.CreateFromTask(async () => - { - await EditServerAsync(EConfigType.Custom); - }, canEditRemove); - RemoveServerCmd = ReactiveCommand.CreateFromTask(async () => - { - await RemoveServerAsync(); - }, canEditRemove); - RemoveDuplicateServerCmd = ReactiveCommand.CreateFromTask(async () => - { - await RemoveDuplicateServer(); - }); - CopyServerCmd = ReactiveCommand.CreateFromTask(async () => - { - await CopyServer(); - }, canEditRemove); - SetDefaultServerCmd = ReactiveCommand.CreateFromTask(async () => - { - await SetDefaultServer(); - }, canEditRemove); - ShareServerCmd = ReactiveCommand.CreateFromTask(async () => - { - await ShareServerAsync(); - }, canEditRemove); - SetDefaultMultipleServerXrayRandomCmd = ReactiveCommand.CreateFromTask(async () => - { - await SetDefaultMultipleServer(ECoreType.Xray, EMultipleLoad.Random); - }, canEditRemove); - SetDefaultMultipleServerXrayRoundRobinCmd = ReactiveCommand.CreateFromTask(async () => - { - await SetDefaultMultipleServer(ECoreType.Xray, EMultipleLoad.RoundRobin); - }, canEditRemove); - SetDefaultMultipleServerXrayLeastPingCmd = ReactiveCommand.CreateFromTask(async () => - { - await SetDefaultMultipleServer(ECoreType.Xray, EMultipleLoad.LeastPing); - }, canEditRemove); - SetDefaultMultipleServerXrayLeastLoadCmd = ReactiveCommand.CreateFromTask(async () => - { - await SetDefaultMultipleServer(ECoreType.Xray, EMultipleLoad.LeastLoad); - }, canEditRemove); - SetDefaultMultipleServerSingBoxLeastPingCmd = ReactiveCommand.CreateFromTask(async () => - { - await SetDefaultMultipleServer(ECoreType.sing_box, EMultipleLoad.LeastPing); - }, canEditRemove); + EditServerCmd = ReactiveCommand.CreateFromTask(EditServerAsync, canEditRemove); + RemoveServerCmd = ReactiveCommand.CreateFromTask(RemoveServerAsync, canEditRemove); + RemoveDuplicateServerCmd = ReactiveCommand.CreateFromTask(RemoveDuplicateServer); + CopyServerCmd = ReactiveCommand.CreateFromTask(CopyServer, canEditRemove); + SetDefaultServerCmd = ReactiveCommand.CreateFromTask(SetDefaultServer, canEditRemove); + ShareServerCmd = ReactiveCommand.CreateFromTask(ShareServerAsync, canEditRemove); + SetDefaultMultipleServerXrayRandomCmd = ReactiveCommand.CreateFromTask(() => + SetDefaultMultipleServer(ECoreType.Xray, EMultipleLoad.Random), canEditRemove); + SetDefaultMultipleServerXrayRoundRobinCmd = ReactiveCommand.CreateFromTask(() => + SetDefaultMultipleServer(ECoreType.Xray, EMultipleLoad.RoundRobin), canEditRemove); + SetDefaultMultipleServerXrayLeastPingCmd = ReactiveCommand.CreateFromTask(() => + SetDefaultMultipleServer(ECoreType.Xray, EMultipleLoad.LeastPing), canEditRemove); + SetDefaultMultipleServerXrayLeastLoadCmd = ReactiveCommand.CreateFromTask(() => + SetDefaultMultipleServer(ECoreType.Xray, EMultipleLoad.LeastLoad), canEditRemove); + SetDefaultMultipleServerSingBoxLeastPingCmd = ReactiveCommand.CreateFromTask(() => + SetDefaultMultipleServer(ECoreType.sing_box, EMultipleLoad.LeastPing), canEditRemove); //servers move - MoveTopCmd = ReactiveCommand.CreateFromTask(async () => - { - await MoveServer(EMove.Top); - }, canEditRemove); - MoveUpCmd = ReactiveCommand.CreateFromTask(async () => - { - await MoveServer(EMove.Up); - }, canEditRemove); - MoveDownCmd = ReactiveCommand.CreateFromTask(async () => - { - await MoveServer(EMove.Down); - }, canEditRemove); - MoveBottomCmd = ReactiveCommand.CreateFromTask(async () => - { - await MoveServer(EMove.Bottom); - }, canEditRemove); + MoveTopCmd = ReactiveCommand.CreateFromTask(() => MoveServer(EMove.Top), canEditRemove); + MoveUpCmd = ReactiveCommand.CreateFromTask(() => MoveServer(EMove.Up), canEditRemove); + MoveDownCmd = ReactiveCommand.CreateFromTask(() => MoveServer(EMove.Down), canEditRemove); + MoveBottomCmd = ReactiveCommand.CreateFromTask(() => MoveServer(EMove.Bottom), canEditRemove); //servers ping - MixedTestServerCmd = ReactiveCommand.CreateFromTask(async () => - { - await ServerSpeedtest(ESpeedActionType.Mixedtest); - }); - TcpingServerCmd = ReactiveCommand.CreateFromTask(async () => - { - await ServerSpeedtest(ESpeedActionType.Tcping); - }, canEditRemove); - RealPingServerCmd = ReactiveCommand.CreateFromTask(async () => - { - await ServerSpeedtest(ESpeedActionType.Realping); - }, canEditRemove); - SpeedServerCmd = ReactiveCommand.CreateFromTask(async () => - { - await ServerSpeedtest(ESpeedActionType.Speedtest); - }, canEditRemove); - SortServerResultCmd = ReactiveCommand.CreateFromTask(async () => - { - await SortServer(EServerColName.DelayVal.ToString()); - }); - RemoveInvalidServerResultCmd = ReactiveCommand.CreateFromTask(async () => - { - await RemoveInvalidServerResult(); - }); + MixedTestServerCmd = ReactiveCommand.CreateFromTask(() => ServerSpeedtest(ESpeedActionType.Mixedtest)); + TcpingServerCmd = ReactiveCommand.CreateFromTask(() => ServerSpeedtest(ESpeedActionType.Tcping), canEditRemove); + RealPingServerCmd = ReactiveCommand.CreateFromTask(() => ServerSpeedtest(ESpeedActionType.Realping), canEditRemove); + SpeedServerCmd = ReactiveCommand.CreateFromTask(() => ServerSpeedtest(ESpeedActionType.Speedtest), canEditRemove); + SortServerResultCmd = ReactiveCommand.CreateFromTask(() => SortServer(EServerColName.DelayVal.ToString())); + RemoveInvalidServerResultCmd = ReactiveCommand.CreateFromTask(RemoveInvalidServerResult); //servers export - Export2ClientConfigCmd = ReactiveCommand.CreateFromTask(async () => - { - await Export2ClientConfigAsync(false); - }, canEditRemove); - Export2ClientConfigClipboardCmd = ReactiveCommand.CreateFromTask(async () => - { - await Export2ClientConfigAsync(true); - }, canEditRemove); - Export2ShareUrlCmd = ReactiveCommand.CreateFromTask(async () => - { - await Export2ShareUrlAsync(false); - }, canEditRemove); - Export2ShareUrlBase64Cmd = ReactiveCommand.CreateFromTask(async () => - { - await Export2ShareUrlAsync(true); - }, canEditRemove); + Export2ClientConfigCmd = ReactiveCommand.CreateFromTask(() => Export2ClientConfigAsync(false), canEditRemove); + Export2ClientConfigClipboardCmd = ReactiveCommand.CreateFromTask(() => Export2ClientConfigAsync(true), canEditRemove); + Export2ShareUrlCmd = ReactiveCommand.CreateFromTask(() => Export2ShareUrlAsync(false), canEditRemove); + Export2ShareUrlBase64Cmd = ReactiveCommand.CreateFromTask(() => Export2ShareUrlAsync(true), canEditRemove); //Subscription - AddSubCmd = ReactiveCommand.CreateFromTask(async () => - { - await EditSubAsync(true); - }); - EditSubCmd = ReactiveCommand.CreateFromTask(async () => - { - await EditSubAsync(false); - }); + AddSubCmd = ReactiveCommand.CreateFromTask(() => EditSubAsync(true)); + EditSubCmd = ReactiveCommand.CreateFromTask(() => EditSubAsync(false)); #endregion WhenAnyValue && ReactiveCommand - - #region AppEvents - - AppEvents.ProfilesRefreshRequested - .AsObservable() - .ObserveOn(RxApp.MainThreadScheduler) - .Subscribe(async _ => await RefreshServersBiz()); - - AppEvents.DispatcherStatisticsRequested - .AsObservable() - .ObserveOn(RxApp.MainThreadScheduler) - .Subscribe(async result => await UpdateStatistics(result)); - - #endregion AppEvents - - _ = Init(); - } - - private async Task Init() - { - SelectedProfile = new(); - SelectedSub = new(); - SelectedMoveToGroup = new(); - - await RefreshSubscriptions(); - await RefreshServers(); } #endregion Init @@ -269,18 +138,18 @@ public class ProfilesViewModel : MyReactiveObject Locator.Current.GetService()?.Reload(); } - public async Task SetSpeedTestResult(SpeedTestResult result) + public Task SetSpeedTestResult(SpeedTestResult result) { if (result.IndexId.IsNullOrEmpty()) { NoticeManager.Instance.SendMessageEx(result.Delay); NoticeManager.Instance.Enqueue(result.Delay); - return; + return Task.CompletedTask; } var item = ProfileItems.FirstOrDefault(it => it.IndexId == result.IndexId); if (item == null) { - return; + return Task.CompletedTask; } if (result.Delay.IsNotEmpty()) @@ -294,166 +163,17 @@ public class ProfilesViewModel : MyReactiveObject item.SpeedVal = result.Speed ?? string.Empty; } //_profileItems.Replace(item, JsonUtils.DeepCopy(item)); - } - - public async Task 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); - - //if (SelectedProfile?.IndexId == item.IndexId) - //{ - // var temp = JsonUtils.DeepCopy(item); - // _profileItems.Replace(item, temp); - // SelectedProfile = temp; - //} - //else - //{ - // _profileItems.Replace(item, JsonUtils.DeepCopy(item)); - //} - } - } - catch - { - } + return Task.CompletedTask; } #endregion Actions - #region Servers && Groups - - private async Task SubSelectedChangedAsync(bool c) + protected override async Task Initialize() { - if (!c) - { - return; - } - _config.SubIndexId = SelectedSub?.Id; - - await RefreshServers(); - - await _updateView?.Invoke(EViewAction.ProfilesFocus, null); + await base.Initialize(); + SelectedMoveToGroup = new(); } - private async Task ServerFilterChanged(bool c) - { - if (!c) - { - return; - } - _serverFilter = ServerFilter; - if (_serverFilter.IsNullOrEmpty()) - { - await RefreshServers(); - } - } - - public async Task RefreshServers() - { - AppEvents.ProfilesRefreshRequested.OnNext(Unit.Default); - - await Task.Delay(200); - } - - private async Task RefreshServersBiz() - { - var lstModel = await GetProfileItemsEx(_config.SubIndexId, _serverFilter); - _lstProfile = JsonUtils.Deserialize>(JsonUtils.Serialize(lstModel)) ?? []; - - ProfileItems.Clear(); - ProfileItems.AddRange(lstModel); - if (lstModel.Count > 0) - { - var selected = lstModel.FirstOrDefault(t => t.IndexId == _config.IndexId); - if (selected != null) - { - SelectedProfile = selected; - } - else - { - SelectedProfile = lstModel.First(); - } - } - - await _updateView?.Invoke(EViewAction.DispatcherRefreshServersBiz, null); - } - - public async Task RefreshSubscriptions() - { - SubItems.Clear(); - - SubItems.Add(new SubItem { Remarks = ResUI.AllGroupServers }); - - foreach (var item in await AppManager.Instance.SubItems()) - { - SubItems.Add(item); - } - if (_config.SubIndexId != null && SubItems.FirstOrDefault(t => t.Id == _config.SubIndexId) != null) - { - SelectedSub = SubItems.FirstOrDefault(t => t.Id == _config.SubIndexId); - } - else - { - SelectedSub = SubItems.First(); - } - } - - private async Task?> GetProfileItemsEx(string subid, string filter) - { - var lstModel = await AppManager.Instance.ProfileItems(_config.SubIndexId, filter); - - 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; - } - - #endregion Servers && Groups - #region Add Servers private async Task?> GetProfileItems(bool latest) @@ -484,7 +204,7 @@ public class ProfilesViewModel : MyReactiveObject return lstSelected; } - public async Task EditServerAsync(EConfigType eConfigType) + public async Task EditServerAsync() { if (string.IsNullOrEmpty(SelectedProfile?.IndexId)) { @@ -496,7 +216,7 @@ public class ProfilesViewModel : MyReactiveObject NoticeManager.Instance.Enqueue(ResUI.PleaseSelectServer); return; } - eConfigType = item.ConfigType; + var eConfigType = item.ConfigType; bool? ret = false; if (eConfigType == EConfigType.Custom) @@ -517,6 +237,11 @@ public class ProfilesViewModel : MyReactiveObject } } + public Task EditServerAsync(EConfigType _) + { + return EditServerAsync(); + } + public async Task RemoveServerAsync() { var lstSelected = await GetProfileItems(true); @@ -651,7 +376,7 @@ public class ProfilesViewModel : MyReactiveObject } _dicHeaderSort.TryAdd(colName, true); - _dicHeaderSort.TryGetValue(colName, out bool asc); + _dicHeaderSort.TryGetValue(colName, out var asc); if (await ConfigHandler.SortServers(_config, _config.SubIndexId, colName, asc) != 0) { return; @@ -733,13 +458,14 @@ public class ProfilesViewModel : MyReactiveObject return; } - _speedtestService ??= new SpeedtestService(_config, async (SpeedTestResult result) => + _speedtestService ??= new SpeedtestService(_config, (SpeedTestResult result) => { RxApp.MainThreadScheduler.Schedule(result, (scheduler, result) => { _ = SetSpeedTestResult(result); return Disposable.Empty; }); + return Task.CompletedTask; }); _speedtestService?.RunLoop(actionType, lstSelected); } @@ -853,4 +579,27 @@ public class ProfilesViewModel : MyReactiveObject } #endregion Subscription + + #region overrides + + protected override string GetCurrentSubIndexId() + { + return _config.SubIndexId; + } + + protected override void SetCurrentSubIndexId(string? id) + { + _config.SubIndexId = id; + } + + public override async Task RefreshServers() + { + AppEvents.ProfilesRefreshRequested.OnNext(Unit.Default); + await Task.Delay(200); + await base.RefreshServers(); + } + + protected override bool ShouldSetDefaultServer => true; + + #endregion overrides }