mirror of
https://github.com/2dust/v2rayN.git
synced 2026-09-26 16:42:08 +03:00
Fix ViewModel and UI (#10093)
* Fix avalonia ScrollToEnd * Refactor ViewModel
This commit is contained in:
@@ -73,18 +73,16 @@ public class BulkObservableCollection<T> : ObservableCollection<T>
|
||||
|
||||
public void ReplaceRange(IEnumerable<T>? collection)
|
||||
{
|
||||
if (collection == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_suppressNotification = true;
|
||||
try
|
||||
{
|
||||
Items.Clear();
|
||||
foreach (var item in collection)
|
||||
if (collection != null)
|
||||
{
|
||||
Items.Add(item);
|
||||
foreach (var item in collection)
|
||||
{
|
||||
Items.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
||||
@@ -12,7 +12,11 @@ public class TaskManager
|
||||
_config = config;
|
||||
_updateFunc = updateFunc;
|
||||
|
||||
Task.Run(ScheduledTasks);
|
||||
_ = Task.Factory.StartNew(
|
||||
ScheduledTasks,
|
||||
CancellationToken.None,
|
||||
TaskCreationOptions.LongRunning,
|
||||
TaskScheduler.Default);
|
||||
}
|
||||
|
||||
private async Task ScheduledTasks()
|
||||
|
||||
@@ -17,7 +17,11 @@ public class StatisticsSingboxService
|
||||
_updateFunc = updateFunc;
|
||||
_exitFlag = false;
|
||||
|
||||
_ = Task.Run(Run);
|
||||
_ = Task.Factory.StartNew(
|
||||
Run,
|
||||
CancellationToken.None,
|
||||
TaskCreationOptions.LongRunning,
|
||||
TaskScheduler.Default);
|
||||
}
|
||||
|
||||
private async Task Init()
|
||||
|
||||
@@ -15,7 +15,11 @@ public class StatisticsXrayService
|
||||
_updateFunc = updateFunc;
|
||||
_exitFlag = false;
|
||||
|
||||
_ = Task.Run(Run);
|
||||
_ = Task.Factory.StartNew(
|
||||
Run,
|
||||
CancellationToken.None,
|
||||
TaskCreationOptions.LongRunning,
|
||||
TaskScheduler.Default);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
|
||||
@@ -218,8 +218,7 @@ public partial class AddGroupServerViewModel : MyReactiveObject, ICloseable
|
||||
|
||||
public async Task UpdatePreviewList()
|
||||
{
|
||||
AllProfilePreviewItemsObs.Clear();
|
||||
AllProfilePreviewItemsObs.AddRange(await GroupProfileManager.GetChildProfileItemsByProtocolExtra(GetUpdatedProtocolExtra()));
|
||||
AllProfilePreviewItemsObs.ReplaceRange(await GroupProfileManager.GetChildProfileItemsByProtocolExtra(GetUpdatedProtocolExtra()));
|
||||
}
|
||||
|
||||
private async Task SaveServerAsync()
|
||||
|
||||
@@ -36,14 +36,10 @@ public partial class CheckUpdateViewModel : MyReactiveObject
|
||||
EnableCheckPreReleaseUpdate = _config.CheckUpdateItem.CheckPreReleaseUpdate;
|
||||
EnableUpdateViaProxy = _config.CheckUpdateItem.UpdateViaProxy;
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.EnableCheckPreReleaseUpdate,
|
||||
y => y == true)
|
||||
.Subscribe(c => _ = OnCheckPreReleaseUpdateChanged());
|
||||
this.WhenAnyValue(x => x.EnableCheckPreReleaseUpdate)
|
||||
.SubscribeAsync(async _ => await OnCheckPreReleaseUpdateChanged());
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.EnableUpdateViaProxy,
|
||||
y => y == true)
|
||||
this.WhenAnyValue(x => x.EnableUpdateViaProxy)
|
||||
.Subscribe(c => _ = OnUpdateViaProxyChanged());
|
||||
|
||||
RefreshCheckUpdateItems();
|
||||
@@ -57,8 +53,7 @@ public partial class CheckUpdateViewModel : MyReactiveObject
|
||||
|
||||
models.Add(GetGeoFileCheckUpdateModel());
|
||||
|
||||
CheckUpdateModels.Clear();
|
||||
CheckUpdateModels.AddRange(models);
|
||||
CheckUpdateModels.ReplaceRange(models);
|
||||
}
|
||||
|
||||
private CheckUpdateModel GetCheckUpdateModel(ECoreType coreType)
|
||||
|
||||
@@ -59,8 +59,6 @@ public partial class ClashConnectionsViewModel : MyReactiveObject
|
||||
|
||||
public async Task RefreshConnections(List<ConnectionItem>? connections)
|
||||
{
|
||||
ConnectionItems.Clear();
|
||||
|
||||
var dtNow = DateTime.Now;
|
||||
var lstModel = new List<ClashConnectionModel>();
|
||||
foreach (var item in connections ?? [])
|
||||
@@ -85,12 +83,8 @@ public partial class ClashConnectionsViewModel : MyReactiveObject
|
||||
|
||||
lstModel.Add(model);
|
||||
}
|
||||
if (lstModel.Count <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ConnectionItems.AddRange(lstModel);
|
||||
ConnectionItems.ReplaceRange(lstModel);
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
@@ -257,19 +257,19 @@ public partial class MainWindowViewModel : MyReactiveObject
|
||||
AppEvents.AddServerViaClipboardRequested
|
||||
.AsObservable()
|
||||
.ObserveOn(RxSchedulers.MainThreadScheduler)
|
||||
.Subscribe(async _ => await AddServerViaClipboardAsync(null));
|
||||
.SubscribeAsync(async _ => await AddServerViaClipboardAsync(null));
|
||||
|
||||
AppEvents.HasUpdateNotified
|
||||
.AsObservable()
|
||||
.ObserveOn(RxSchedulers.MainThreadScheduler)
|
||||
.Subscribe(async bl => BlNewUpdate = bl);
|
||||
.Subscribe(bl => BlNewUpdate = bl);
|
||||
|
||||
#endregion AppEvents
|
||||
|
||||
ProfilesViewModel.RefreshServersRequested
|
||||
.AsObservable()
|
||||
.ObserveOn(RxSchedulers.MainThreadScheduler)
|
||||
.Subscribe(async _ => await RefreshServers());
|
||||
.SubscribeAsync(async _ => await RefreshServers());
|
||||
|
||||
var vmReloadRequestedList = new List<IObservable<RxVoid>>
|
||||
{
|
||||
@@ -282,23 +282,23 @@ public partial class MainWindowViewModel : MyReactiveObject
|
||||
{
|
||||
reloadRequested
|
||||
.ObserveOn(RxSchedulers.MainThreadScheduler)
|
||||
.Subscribe(async _ => await Reload());
|
||||
.SubscribeAsync(async _ => await Reload());
|
||||
}
|
||||
|
||||
StatusBarViewModel.AddServerViaScanRequested
|
||||
.AsObservable()
|
||||
.ObserveOn(RxSchedulers.MainThreadScheduler)
|
||||
.Subscribe(async _ => await AddServerViaScanAsync());
|
||||
.SubscribeAsync(async _ => await AddServerViaScanAsync());
|
||||
|
||||
StatusBarViewModel.AddServerViaClipboardRequested
|
||||
.AsObservable()
|
||||
.ObserveOn(RxSchedulers.MainThreadScheduler)
|
||||
.Subscribe(async _ => await AddServerViaClipboardAsync(null));
|
||||
.SubscribeAsync(async _ => await AddServerViaClipboardAsync(null));
|
||||
|
||||
StatusBarViewModel.ShowHideWindowRequested
|
||||
.AsObservable()
|
||||
.ObserveOn(RxSchedulers.MainThreadScheduler)
|
||||
.Subscribe(async blShow =>
|
||||
.SubscribeAsync(async blShow =>
|
||||
{
|
||||
await ShowHideWindowInteraction.HandleSafe(blShow);
|
||||
});
|
||||
@@ -306,12 +306,12 @@ public partial class MainWindowViewModel : MyReactiveObject
|
||||
StatusBarViewModel.SetDefaultServerRequested
|
||||
.AsObservable()
|
||||
.ObserveOn(RxSchedulers.MainThreadScheduler)
|
||||
.Subscribe(async indexId => await ProfilesViewModel.SetDefaultServer(indexId));
|
||||
.SubscribeAsync(async indexId => await ProfilesViewModel.SetDefaultServer(indexId));
|
||||
|
||||
StatusBarViewModel.SubscriptionsUpdateRequested
|
||||
.AsObservable()
|
||||
.ObserveOn(RxSchedulers.MainThreadScheduler)
|
||||
.Subscribe(async blProxy => await UpdateSubscriptionProcess("", blProxy));
|
||||
.SubscribeAsync(async blProxy => await UpdateSubscriptionProcess("", blProxy));
|
||||
|
||||
_ = Init();
|
||||
}
|
||||
|
||||
@@ -22,18 +22,16 @@ public partial class MsgViewModel : MyReactiveObject
|
||||
AutoRefresh = _config.MsgUIItem.AutoRefresh ?? true;
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.MsgFilter)
|
||||
.Subscribe(c => DoMsgFilter());
|
||||
x => x.MsgFilter)
|
||||
.Subscribe(c => DoMsgFilter());
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.AutoRefresh,
|
||||
y => y == true)
|
||||
.Subscribe(c => _config.MsgUIItem.AutoRefresh = AutoRefresh);
|
||||
this.WhenAnyValue(x => x.AutoRefresh)
|
||||
.Subscribe(_ => _config.MsgUIItem.AutoRefresh = AutoRefresh);
|
||||
|
||||
AppEvents.SendMsgViewRequested
|
||||
.AsObservable()
|
||||
//.ObserveOn(RxSchedulers.MainThreadScheduler)
|
||||
.Subscribe(content => _ = AppendQueueMsg(content));
|
||||
.AsObservable()
|
||||
//.ObserveOn(RxSchedulers.MainThreadScheduler)
|
||||
.Subscribe(content => _ = AppendQueueMsg(content));
|
||||
}
|
||||
|
||||
public void FlushQueueMsg()
|
||||
@@ -74,9 +72,9 @@ public partial class MsgViewModel : MyReactiveObject
|
||||
{
|
||||
try
|
||||
{
|
||||
await DispatcherShowMsgInteraction.HandleSafe(sb.ToString());
|
||||
await DispatcherShowMsgInteraction.Handle(sb.ToString());
|
||||
}
|
||||
catch (Exception)
|
||||
catch
|
||||
{
|
||||
_queueMsg.Enqueue(sb.ToString());
|
||||
}
|
||||
|
||||
@@ -61,24 +61,22 @@ public partial class ProfilesSelectViewModel : MyReactiveObject, ICloseable
|
||||
SelectFinish();
|
||||
});
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.SelectedSub,
|
||||
y => y != null && !y.Remarks.IsNullOrEmpty() && _subIndexId != y.Id)
|
||||
.Subscribe(async c => await SubSelectedChangedAsync(c));
|
||||
this.WhenAnyValue(x => x.SelectedSub)
|
||||
.Where(y => y != null && !y.Remarks.IsNullOrEmpty() && _subIndexId != y.Id)
|
||||
.SubscribeAsync(async _ => await SubSelectedChangedAsync());
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.ServerFilter,
|
||||
y => y != null && _serverFilter != y)
|
||||
.Subscribe(async c => await ServerFilterChanged(c));
|
||||
this.WhenAnyValue(x => x.ServerFilter)
|
||||
.Where(y => y != null && _serverFilter != y)
|
||||
.SubscribeAsync(async _ => await ServerFilterChanged());
|
||||
|
||||
// React to ConfigType filter changes
|
||||
this.WhenAnyValue(x => x.FilterExclude)
|
||||
.Skip(1)
|
||||
.Subscribe(async _ => await RefreshServersBiz());
|
||||
.SubscribeAsync(async _ => await RefreshServersBiz());
|
||||
|
||||
this.WhenAnyValue(x => x.FilterConfigTypes)
|
||||
.Skip(1)
|
||||
.Subscribe(async _ => await RefreshServersBiz());
|
||||
.SubscribeAsync(async _ => await RefreshServersBiz());
|
||||
|
||||
#endregion WhenAnyValue && ReactiveCommand
|
||||
|
||||
@@ -128,12 +126,8 @@ public partial class ProfilesSelectViewModel : MyReactiveObject, ICloseable
|
||||
|
||||
#region Servers && Groups
|
||||
|
||||
private async Task SubSelectedChangedAsync(bool c)
|
||||
private async Task SubSelectedChangedAsync()
|
||||
{
|
||||
if (!c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_subIndexId = SelectedSub?.Id;
|
||||
|
||||
await RefreshServers();
|
||||
@@ -141,12 +135,8 @@ public partial class ProfilesSelectViewModel : MyReactiveObject, ICloseable
|
||||
await ProfilesFocusInteraction.HandleSafe(RxVoid.Default);
|
||||
}
|
||||
|
||||
private async Task ServerFilterChanged(bool c)
|
||||
private async Task ServerFilterChanged()
|
||||
{
|
||||
if (!c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_serverFilter = ServerFilter;
|
||||
if (_serverFilter.IsNullOrEmpty())
|
||||
{
|
||||
@@ -163,8 +153,7 @@ public partial class ProfilesSelectViewModel : MyReactiveObject, ICloseable
|
||||
{
|
||||
var lstModel = await GetProfileItemsEx(_subIndexId, _serverFilter);
|
||||
|
||||
ProfileItems.Clear();
|
||||
ProfileItems.AddRange(lstModel);
|
||||
ProfileItems.ReplaceRange(lstModel);
|
||||
if (lstModel.Count > 0)
|
||||
{
|
||||
var selected = lstModel.FirstOrDefault(t => t.IndexId == _config.IndexId);
|
||||
@@ -177,8 +166,7 @@ public partial class ProfilesSelectViewModel : MyReactiveObject, ICloseable
|
||||
var subItems = await AppManager.Instance.SubItems();
|
||||
subItems.Insert(0, new SubItem { Remarks = ResUI.AllGroupServers });
|
||||
|
||||
SubItems.Clear();
|
||||
SubItems.AddRange(subItems);
|
||||
SubItems.ReplaceRange(subItems);
|
||||
|
||||
SelectedSub = (_config.SubIndexId.IsNotEmpty()
|
||||
? subItems.FirstOrDefault(t => t.Id == _config.SubIndexId)
|
||||
@@ -298,8 +286,7 @@ public partial class ProfilesSelectViewModel : MyReactiveObject, ICloseable
|
||||
: ProfileItems.OrderByDescending(KeySelector, comparer);
|
||||
|
||||
var list = sorted.ToList();
|
||||
ProfileItems.Clear();
|
||||
ProfileItems.AddRange(list);
|
||||
ProfileItems.ReplaceRange(list);
|
||||
|
||||
_dicHeaderSort[colName] = !asc;
|
||||
|
||||
|
||||
@@ -103,19 +103,16 @@ public partial class ProfilesViewModel : MyReactiveObject
|
||||
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.SelectedSub)
|
||||
.Where(y => y != null && !y.Remarks.IsNullOrEmpty() && _config.SubIndexId != y.Id)
|
||||
.SubscribeAsync(async _ => await SubSelectedChangedAsync());
|
||||
this.WhenAnyValue(x => x.SelectedMoveToGroup)
|
||||
.Where(y => y != null && !y.Remarks.IsNullOrEmpty())
|
||||
.SubscribeAsync(async _ => await MoveToGroup());
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.ServerFilter,
|
||||
y => y != null && _serverFilter != y)
|
||||
.Subscribe(async c => await ServerFilterChanged(c));
|
||||
this.WhenAnyValue(x => x.ServerFilter)
|
||||
.Where(y => y != null && _serverFilter != y)
|
||||
.SubscribeAsync(async _ => await ServerFilterChanged());
|
||||
|
||||
//servers delete
|
||||
EditServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
@@ -249,7 +246,7 @@ public partial class ProfilesViewModel : MyReactiveObject
|
||||
AppEvents.DispatcherStatisticsRequested
|
||||
.AsObservable()
|
||||
.ObserveOn(RxSchedulers.MainThreadScheduler)
|
||||
.Subscribe(async result => await UpdateStatistics(result));
|
||||
.SubscribeAsync(async result => await UpdateStatistics(result));
|
||||
|
||||
#endregion AppEvents
|
||||
|
||||
@@ -335,12 +332,8 @@ public partial class ProfilesViewModel : MyReactiveObject
|
||||
|
||||
#region Servers && Groups
|
||||
|
||||
private async Task SubSelectedChangedAsync(bool c)
|
||||
private async Task SubSelectedChangedAsync()
|
||||
{
|
||||
if (!c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_config.SubIndexId = SelectedSub?.Id;
|
||||
|
||||
await RefreshServers();
|
||||
@@ -348,12 +341,8 @@ public partial class ProfilesViewModel : MyReactiveObject
|
||||
await ProfilesFocusInteraction.HandleSafe(RxVoid.Default);
|
||||
}
|
||||
|
||||
private async Task ServerFilterChanged(bool c)
|
||||
private async Task ServerFilterChanged()
|
||||
{
|
||||
if (!c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_serverFilter = ServerFilter;
|
||||
if (_serverFilter.IsNullOrEmpty())
|
||||
{
|
||||
@@ -375,8 +364,7 @@ public partial class ProfilesViewModel : MyReactiveObject
|
||||
var lstModel = await GetProfileItemsEx(_config.SubIndexId, _serverFilter);
|
||||
_lstProfile = JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(lstModel)) ?? [];
|
||||
|
||||
ProfileItems.Clear();
|
||||
ProfileItems.AddRange(lstModel ?? []);
|
||||
ProfileItems.ReplaceRange(lstModel ?? []);
|
||||
if (lstModel?.Count > 0)
|
||||
{
|
||||
ProfileItemModel? selected = null;
|
||||
@@ -397,8 +385,7 @@ public partial class ProfilesViewModel : MyReactiveObject
|
||||
var subItems = await AppManager.Instance.SubItems();
|
||||
subItems.Insert(0, new SubItem { Remarks = ResUI.AllGroupServers });
|
||||
|
||||
SubItems.Clear();
|
||||
SubItems.AddRange(subItems);
|
||||
SubItems.ReplaceRange(subItems);
|
||||
|
||||
SelectedSub = (_config.SubIndexId.IsNotEmpty()
|
||||
? subItems.FirstOrDefault(t => t.Id == _config.SubIndexId)
|
||||
@@ -672,13 +659,8 @@ public partial class ProfilesViewModel : MyReactiveObject
|
||||
}
|
||||
|
||||
//move server
|
||||
private async Task MoveToGroup(bool c)
|
||||
private async Task MoveToGroup()
|
||||
{
|
||||
if (!c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var lstSelected = await GetProfileItems(true);
|
||||
if (lstSelected == null)
|
||||
{
|
||||
@@ -901,7 +883,7 @@ public partial class ProfilesViewModel : MyReactiveObject
|
||||
if (await AppManager.Instance.WindowDialog.ShowDialogAsync(subEditViewModel) == true)
|
||||
{
|
||||
await RefreshSubscriptions();
|
||||
await SubSelectedChangedAsync(true);
|
||||
await SubSelectedChangedAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -920,7 +902,7 @@ public partial class ProfilesViewModel : MyReactiveObject
|
||||
await ConfigHandler.DeleteSubItem(_config, item.Id);
|
||||
|
||||
await RefreshSubscriptions();
|
||||
await SubSelectedChangedAsync(true);
|
||||
await SubSelectedChangedAsync();
|
||||
}
|
||||
|
||||
#endregion Subscription
|
||||
|
||||
@@ -100,8 +100,6 @@ public partial class RoutingRuleSettingViewModel : MyReactiveObject, ICloseable
|
||||
|
||||
public void RefreshRulesItems()
|
||||
{
|
||||
RulesItems.Clear();
|
||||
|
||||
var models = new List<RulesItemModel>();
|
||||
foreach (var item in _rules)
|
||||
{
|
||||
@@ -120,7 +118,7 @@ public partial class RoutingRuleSettingViewModel : MyReactiveObject, ICloseable
|
||||
};
|
||||
models.Add(it);
|
||||
}
|
||||
RulesItems.AddRange(models);
|
||||
RulesItems.ReplaceRange(models);
|
||||
}
|
||||
|
||||
public async Task RuleEditAsync(bool blNew)
|
||||
|
||||
@@ -61,10 +61,10 @@ public partial class RoutingSettingViewModel : MyReactiveObject
|
||||
x => x.DomainStrategy4Singbox)
|
||||
.Skip(1)
|
||||
.DistinctUntilChanged()
|
||||
.Subscribe(x =>
|
||||
.SubscribeAsync(async x =>
|
||||
{
|
||||
IsModified = true;
|
||||
_ = SaveSettingsAsync();
|
||||
await SaveSettingsAsync();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -83,7 +83,6 @@ public partial class RoutingSettingViewModel : MyReactiveObject
|
||||
|
||||
public async Task RefreshRoutingItems()
|
||||
{
|
||||
RoutingItems.Clear();
|
||||
var models = new List<RoutingItemModel>();
|
||||
|
||||
var routings = await AppManager.Instance.RoutingItems();
|
||||
@@ -102,7 +101,7 @@ public partial class RoutingSettingViewModel : MyReactiveObject
|
||||
};
|
||||
models.Add(it);
|
||||
}
|
||||
RoutingItems.AddRange(models);
|
||||
RoutingItems.ReplaceRange(models);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -123,26 +123,21 @@ public partial class StatusBarViewModel : MyReactiveObject
|
||||
|
||||
#region WhenAnyValue && ReactiveCommand
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.SelectedRouting,
|
||||
y => y != null && !y.Remarks.IsNullOrEmpty())
|
||||
.Subscribe(async c => await RoutingSelectedChangedAsync(c));
|
||||
this.WhenAnyValue(x => x.SelectedRouting)
|
||||
.Where(y => y != null && !y.Remarks.IsNullOrEmpty())
|
||||
.SubscribeAsync(async _ => await RoutingSelectedChangedAsync());
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.SelectedServer,
|
||||
y => y != null && !y.Text.IsNullOrEmpty())
|
||||
.Subscribe(ServerSelectedChanged);
|
||||
this.WhenAnyValue(x => x.SelectedServer)
|
||||
.Where(y => y != null && !y.Text.IsNullOrEmpty())
|
||||
.Subscribe(_ => ServerSelectedChanged());
|
||||
|
||||
SystemProxySelected = (int)_config.SystemProxyItem.SysProxyType;
|
||||
this.WhenAnyValue(
|
||||
x => x.SystemProxySelected,
|
||||
y => y >= 0)
|
||||
.Subscribe(async c => await DoSystemProxySelected(c));
|
||||
this.WhenAnyValue(x => x.SystemProxySelected)
|
||||
.Where(y => y >= 0)
|
||||
.SubscribeAsync(async _ => await DoSystemProxySelected());
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.EnableTun,
|
||||
y => y == true)
|
||||
.Subscribe(async c => await DoEnableTun(c));
|
||||
this.WhenAnyValue(x => x.EnableTun)
|
||||
.SubscribeAsync(async _ => await DoEnableTun());
|
||||
|
||||
CopyProxyCmdToClipboardCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
@@ -207,12 +202,12 @@ public partial class StatusBarViewModel : MyReactiveObject
|
||||
AppEvents.DispatcherStatisticsRequested
|
||||
.AsObservable()
|
||||
.ObserveOn(RxSchedulers.MainThreadScheduler)
|
||||
.Subscribe(async result => await UpdateStatistics(result));
|
||||
.SubscribeAsync(async result => await UpdateStatistics(result));
|
||||
|
||||
AppEvents.SysProxyChangeRequested
|
||||
.AsObservable()
|
||||
.ObserveOn(RxSchedulers.MainThreadScheduler)
|
||||
.Subscribe(async result => await SetListenerType(result));
|
||||
.SubscribeAsync(async result => await SetListenerType(result));
|
||||
|
||||
#endregion AppEvents
|
||||
|
||||
@@ -300,19 +295,14 @@ public partial class StatusBarViewModel : MyReactiveObject
|
||||
var models = lstModel.Select(it => new ComboItem { ID = it.IndexId, Text = it.GetSummary() }).ToList();
|
||||
|
||||
BlServers = true;
|
||||
Servers.Clear();
|
||||
Servers.AddRange(models);
|
||||
Servers.ReplaceRange(models);
|
||||
|
||||
// Update the ItemsSource before SelectedItem so a collection reset does not clear the tray selection.
|
||||
SelectedServer = models.FirstOrDefault(it => it.ID == _config.IndexId) ?? new();
|
||||
}
|
||||
|
||||
private void ServerSelectedChanged(bool c)
|
||||
private void ServerSelectedChanged()
|
||||
{
|
||||
if (!c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (SelectedServer == null)
|
||||
{
|
||||
return;
|
||||
@@ -402,19 +392,13 @@ public partial class StatusBarViewModel : MyReactiveObject
|
||||
{
|
||||
var routings = await AppManager.Instance.RoutingItems();
|
||||
|
||||
RoutingItems.Clear();
|
||||
RoutingItems.AddRange(routings);
|
||||
RoutingItems.ReplaceRange(routings);
|
||||
|
||||
SelectedRouting = routings.FirstOrDefault(t => t.IsActive == true);
|
||||
}
|
||||
|
||||
private async Task RoutingSelectedChangedAsync(bool c)
|
||||
private async Task RoutingSelectedChangedAsync()
|
||||
{
|
||||
if (!c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (SelectedRouting == null)
|
||||
{
|
||||
return;
|
||||
@@ -434,12 +418,8 @@ public partial class StatusBarViewModel : MyReactiveObject
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DoSystemProxySelected(bool c)
|
||||
private async Task DoSystemProxySelected()
|
||||
{
|
||||
if (!c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_config.SystemProxyItem.SysProxyType == (ESysProxyType)SystemProxySelected)
|
||||
{
|
||||
return;
|
||||
@@ -447,7 +427,7 @@ public partial class StatusBarViewModel : MyReactiveObject
|
||||
await SetListenerType((ESysProxyType)SystemProxySelected);
|
||||
}
|
||||
|
||||
private async Task DoEnableTun(bool c)
|
||||
private async Task DoEnableTun()
|
||||
{
|
||||
if (_config.TunModeItem.EnableTun == EnableTun)
|
||||
{
|
||||
|
||||
@@ -55,8 +55,7 @@ public partial class SubSettingViewModel : MyReactiveObject
|
||||
|
||||
public async Task RefreshSubItems()
|
||||
{
|
||||
SubItems.Clear();
|
||||
SubItems.AddRange(await AppManager.Instance.SubItems());
|
||||
SubItems.ReplaceRange(await AppManager.Instance.SubItems());
|
||||
}
|
||||
|
||||
public async Task EditSubAsync(bool blNew)
|
||||
|
||||
@@ -22,6 +22,7 @@ global using ReactiveUI;
|
||||
global using ReactiveUI.Avalonia;
|
||||
global using ReactiveUI.Primitives;
|
||||
global using ReactiveUI.Primitives.Disposables;
|
||||
global using ReactiveUI.Primitives.Extensions;
|
||||
global using ReactiveUI.SourceGenerators;
|
||||
global using ServiceLib;
|
||||
global using ServiceLib.Base;
|
||||
|
||||
@@ -35,39 +35,38 @@ public partial class ThemeSettingViewModel : MyReactiveObject
|
||||
CurrentLanguage = _config.UiItem.CurrentLanguage;
|
||||
|
||||
this.WhenAnyValue(x => x.CurrentTheme)
|
||||
.Subscribe(c =>
|
||||
.Where(y => y.IsNotEmpty())
|
||||
.SubscribeAsync(async _ =>
|
||||
{
|
||||
if (_config.UiItem.CurrentTheme != CurrentTheme)
|
||||
{
|
||||
_config.UiItem.CurrentTheme = CurrentTheme;
|
||||
ModifyTheme();
|
||||
_ = ConfigHandler.SaveConfig(_config);
|
||||
await ConfigHandler.SaveConfig(_config);
|
||||
}
|
||||
});
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.CurrentFontSize,
|
||||
y => y > 0)
|
||||
.Subscribe(c =>
|
||||
this.WhenAnyValue(x => x.CurrentFontSize)
|
||||
.Where(y => y > 0)
|
||||
.SubscribeAsync(async _ =>
|
||||
{
|
||||
if (_config.UiItem.CurrentFontSize != CurrentFontSize && CurrentFontSize >= Global.MinFontSize)
|
||||
{
|
||||
_config.UiItem.CurrentFontSize = CurrentFontSize;
|
||||
ModifyFontSize();
|
||||
_ = ConfigHandler.SaveConfig(_config);
|
||||
await ConfigHandler.SaveConfig(_config);
|
||||
}
|
||||
});
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.CurrentLanguage,
|
||||
y => y != null && !y.IsNullOrEmpty())
|
||||
.Subscribe(c =>
|
||||
this.WhenAnyValue(x => x.CurrentLanguage)
|
||||
.Where(y => !y.IsNullOrEmpty())
|
||||
.SubscribeAsync(async _ =>
|
||||
{
|
||||
if (CurrentLanguage.IsNotEmpty() && _config.UiItem.CurrentLanguage != CurrentLanguage)
|
||||
{
|
||||
_config.UiItem.CurrentLanguage = CurrentLanguage;
|
||||
Thread.CurrentThread.CurrentUICulture = new(CurrentLanguage);
|
||||
_ = ConfigHandler.SaveConfig(_config);
|
||||
await ConfigHandler.SaveConfig(_config);
|
||||
NoticeManager.Instance.Enqueue(ResUI.NeedRebootTips);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -50,6 +50,9 @@ public partial class MsgView : ReactiveUserControl<MsgViewModel>
|
||||
if (togScrollToEnd.IsChecked ?? true)
|
||||
{
|
||||
txtMsg.ScrollToEnd();
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
txtMsg.ScrollTo(txtMsg.LineCount, 0, AvaloniaEdit.Rendering.VisualYPosition.TextBottom, txtMsg.Bounds.Height, 0),
|
||||
DispatcherPriority.Background);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ global using ReactiveUI;
|
||||
global using ReactiveUI.Builder;
|
||||
global using ReactiveUI.Primitives;
|
||||
global using ReactiveUI.Primitives.Disposables;
|
||||
global using ReactiveUI.Primitives.Extensions;
|
||||
global using ReactiveUI.SourceGenerators;
|
||||
global using ServiceLib;
|
||||
global using ServiceLib.Base;
|
||||
|
||||
@@ -55,23 +55,21 @@ public partial class ThemeSettingViewModel : MyReactiveObject
|
||||
CurrentFontSize = _config.UiItem.CurrentFontSize;
|
||||
CurrentLanguage = _config.UiItem.CurrentLanguage;
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.CurrentTheme,
|
||||
y => y != null && !y.IsNullOrEmpty())
|
||||
.Subscribe(c =>
|
||||
this.WhenAnyValue(x => x.CurrentTheme)
|
||||
.Where(y => y != null && !y.IsNullOrEmpty())
|
||||
.SubscribeAsync(async _ =>
|
||||
{
|
||||
if (_config.UiItem.CurrentTheme != CurrentTheme)
|
||||
{
|
||||
_config.UiItem.CurrentTheme = CurrentTheme;
|
||||
ModifyTheme();
|
||||
_ = ConfigHandler.SaveConfig(_config);
|
||||
await ConfigHandler.SaveConfig(_config);
|
||||
}
|
||||
});
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.SelectedSwatch,
|
||||
y => y != null && !y.Name.IsNullOrEmpty())
|
||||
.Subscribe(c =>
|
||||
this.WhenAnyValue(x => x.SelectedSwatch)
|
||||
.Where(y => y != null && !y.Name.IsNullOrEmpty())
|
||||
.SubscribeAsync(async _ =>
|
||||
{
|
||||
if (SelectedSwatch == null
|
||||
|| SelectedSwatch.Name.IsNullOrEmpty()
|
||||
@@ -84,33 +82,31 @@ public partial class ThemeSettingViewModel : MyReactiveObject
|
||||
{
|
||||
_config.UiItem.ColorPrimaryName = SelectedSwatch?.Name;
|
||||
ChangePrimaryColor(SelectedSwatch.ExemplarHue.Color);
|
||||
_ = ConfigHandler.SaveConfig(_config);
|
||||
await ConfigHandler.SaveConfig(_config);
|
||||
}
|
||||
});
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.CurrentFontSize,
|
||||
y => y > 0)
|
||||
.Subscribe(c =>
|
||||
this.WhenAnyValue(x => x.CurrentFontSize)
|
||||
.Where(y => y > 0)
|
||||
.SubscribeAsync(async _ =>
|
||||
{
|
||||
if (_config.UiItem.CurrentFontSize != CurrentFontSize)
|
||||
{
|
||||
_config.UiItem.CurrentFontSize = CurrentFontSize;
|
||||
ModifyFontSize();
|
||||
_ = ConfigHandler.SaveConfig(_config);
|
||||
await ConfigHandler.SaveConfig(_config);
|
||||
}
|
||||
});
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.CurrentLanguage,
|
||||
y => y != null && !y.IsNullOrEmpty())
|
||||
.Subscribe(c =>
|
||||
this.WhenAnyValue(x => x.CurrentLanguage)
|
||||
.Where(y => y != null && !y.IsNullOrEmpty())
|
||||
.SubscribeAsync(async _ =>
|
||||
{
|
||||
if (CurrentLanguage.IsNotEmpty() && _config.UiItem.CurrentLanguage != CurrentLanguage)
|
||||
{
|
||||
_config.UiItem.CurrentLanguage = CurrentLanguage;
|
||||
Thread.CurrentThread.CurrentUICulture = new(CurrentLanguage);
|
||||
_ = ConfigHandler.SaveConfig(_config);
|
||||
await ConfigHandler.SaveConfig(_config);
|
||||
NoticeManager.Instance.Enqueue(ResUI.NeedRebootTips);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user