Files
v2rayN/v2rayN/ServiceLib/ViewModels/RoutingSettingViewModel.cs
DHR60 9664ee380e ViewModel-First (#9621)
* Interaction

* Remove view action

* ViewModel-first

* MainGirdOrientation Hot Reload

* Fix avalonia preview

* Remove CloseWindowInteraction

* Fix

* Avoid threading issues

* Fix

* ProfilesSelect

* Try fix previewer

* Remove AppEvents.ProfilesRefreshRequested

* Remove AppEvents.SubscriptionsRefreshRequested

* Remove AppEvents.ProxiesReloadRequested

* Remove AppEvents.AdjustMainLvColWidthRequested

* Remove AppEvents.SetDefaultServerRequested

* Remove AppEvents.RoutingsMenuRefreshRequested

* Remove AppEvents.TestServerRequested

* Remove AppEvents.InboundDisplayRequested

* Remove AppEvents.SubscriptionsUpdateRequested

* Remove AppEvents.ShowHideWindowRequested

* Remove AppEvents.ReloadRequested

* Remove AppEvents.AddServerRequested

* Fix
2026-07-14 09:05:05 +08:00

192 lines
5.6 KiB
C#

namespace ServiceLib.ViewModels;
public class RoutingSettingViewModel : MyReactiveObject
{
public Interaction<string, bool> ShowYesNoInteraction { get; } = new();
#region Reactive
public IObservableCollection<RoutingItemModel> RoutingItems { get; } = new ObservableCollectionExtended<RoutingItemModel>();
[Reactive]
public RoutingItemModel SelectedSource { get; set; }
public IList<RoutingItemModel> SelectedSources { get; set; }
[Reactive]
public string DomainStrategy { get; set; }
[Reactive]
public string DomainStrategy4Singbox { get; set; }
public ReactiveCommand<Unit, Unit> RoutingAdvancedAddCmd { get; }
public ReactiveCommand<Unit, Unit> RoutingAdvancedRemoveCmd { get; }
public ReactiveCommand<Unit, Unit> RoutingAdvancedSetDefaultCmd { get; }
public ReactiveCommand<Unit, Unit> RoutingAdvancedImportRulesCmd { get; }
public bool IsModified { get; set; }
#endregion Reactive
public RoutingSettingViewModel()
{
_config = AppManager.Instance.Config;
var canEditRemove = this.WhenAnyValue(
x => x.SelectedSource,
selectedSource => selectedSource != null && !selectedSource.Remarks.IsNullOrEmpty());
RoutingAdvancedAddCmd = ReactiveCommand.CreateFromTask(async () =>
{
await RoutingAdvancedEditAsync(true);
});
RoutingAdvancedRemoveCmd = ReactiveCommand.CreateFromTask(async () =>
{
await RoutingAdvancedRemoveAsync();
}, canEditRemove);
RoutingAdvancedSetDefaultCmd = ReactiveCommand.CreateFromTask(async () =>
{
await RoutingAdvancedSetDefault();
}, canEditRemove);
RoutingAdvancedImportRulesCmd = ReactiveCommand.CreateFromTask(async () =>
{
await RoutingAdvancedImportRules();
});
_ = Init();
// Auto-save DomainStrategy when changed
this.WhenAnyValue(
x => x.DomainStrategy,
x => x.DomainStrategy4Singbox)
.Skip(1)
.DistinctUntilChanged()
.Subscribe(x =>
{
IsModified = true;
_ = SaveSettingsAsync();
});
}
private async Task Init()
{
SelectedSource = new();
DomainStrategy = _config.RoutingBasicItem.DomainStrategy;
DomainStrategy4Singbox = _config.RoutingBasicItem.DomainStrategy4Singbox;
await ConfigHandler.InitBuiltinRouting(_config);
await RefreshRoutingItems();
}
#region Refresh Save
public async Task RefreshRoutingItems()
{
RoutingItems.Clear();
var models = new List<RoutingItemModel>();
var routings = await AppManager.Instance.RoutingItems();
foreach (var item in routings)
{
var it = new RoutingItemModel()
{
IsActive = item.IsActive,
RuleNum = item.RuleNum,
Id = item.Id,
Remarks = item.Remarks,
Url = item.Url,
CustomIcon = item.CustomIcon,
CustomRulesetPath4Singbox = item.CustomRulesetPath4Singbox,
Sort = item.Sort,
};
models.Add(it);
}
RoutingItems.AddRange(models);
}
/// <summary>
/// Save DomainStrategy settings
/// </summary>
public async Task SaveSettingsAsync()
{
_config.RoutingBasicItem.DomainStrategy = DomainStrategy;
_config.RoutingBasicItem.DomainStrategy4Singbox = DomainStrategy4Singbox;
await ConfigHandler.SaveConfig(_config);
}
#endregion Refresh Save
public async Task RoutingAdvancedEditAsync(bool blNew)
{
RoutingItem item;
if (blNew)
{
item = new();
}
else
{
item = await AppManager.Instance.GetRoutingItem(SelectedSource?.Id);
if (item is null)
{
return;
}
}
var routingRuleSettingViewModel = new RoutingRuleSettingViewModel(item);
if (await AppManager.Instance.WindowDialog.ShowDialogAsync(routingRuleSettingViewModel) == true)
{
await RefreshRoutingItems();
IsModified = true;
}
}
public async Task RoutingAdvancedRemoveAsync()
{
if (SelectedSource is null || SelectedSource.Remarks.IsNullOrEmpty())
{
NoticeManager.Instance.Enqueue(ResUI.PleaseSelectRules);
return;
}
if (await ShowYesNoInteraction.Handle(ResUI.RemoveServer) == false)
{
return;
}
foreach (var it in SelectedSources ?? [SelectedSource])
{
var item = await AppManager.Instance.GetRoutingItem(it?.Id);
if (item != null)
{
await ConfigHandler.RemoveRoutingItem(item);
}
}
await RefreshRoutingItems();
IsModified = true;
}
public async Task RoutingAdvancedSetDefault()
{
var item = await AppManager.Instance.GetRoutingItem(SelectedSource?.Id);
if (item is null)
{
NoticeManager.Instance.Enqueue(ResUI.PleaseSelectRules);
return;
}
if (await ConfigHandler.SetDefaultRouting(_config, item) == 0)
{
await RefreshRoutingItems();
IsModified = true;
}
}
private async Task RoutingAdvancedImportRules()
{
if (await ConfigHandler.InitRouting(_config, true) == 0)
{
await RefreshRoutingItems();
IsModified = true;
}
}
}