Files
Marvin 2f61e5dc00 Refactor ViewModels to inherit from BaseViewModel and improve UI thread handling
- Updated HookBrowserViewModel, MainViewModel, SettingsViewModel, and SyncViewModel to inherit from BaseViewModel.
- Introduced BaseViewModel with methods for running actions on the UI thread.
- Enhanced SyncViewModel to handle property changes on the UI thread.
- Refactored ExtractorService to return ExtractorResult instead of IReadOnlyList<HookDefinition>.
- Added ExtractorResult class to encapsulate extraction results, including success status and error messages.
- Implemented UIProgress class for reporting progress on the UI thread.
- Updated hook_groups.json with additional classes and methods for various categories.
- Improved error handling and logging in ExtractorService and SyncViewModel.
2026-04-20 04:26:06 +02:00

170 lines
5.0 KiB
C#

using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using gregExtractor.Models;
using gregExtractor.Services;
using gregExtractor.Utils;
namespace gregExtractor.GUI.ViewModels;
public sealed class HookBrowserRow
{
public required string Group { get; init; }
public required string Namespace { get; init; }
public required string ClassName { get; init; }
public required string MethodName { get; init; }
public required string ReturnType { get; init; }
public required bool IsVoid { get; init; }
public required string Parameters { get; init; }
}
public sealed class HookBrowserViewModel : BaseViewModel
{
private readonly ExtractorService _extractorService = new();
private HookClassifier _classifier;
private string _searchText = string.Empty;
private string _selectedGroup = "Alle";
private bool _isLoading;
public HookBrowserViewModel()
{
_classifier = HookClassifier.LoadFromFile(null, new UIProgress<string>(_ => { }));
Groups.Add("Alle");
RefreshCommand = new AsyncRelayCommand(RefreshAsync, () => !IsLoading);
}
public string SearchText
{
get => _searchText;
set
{
if (!SetProperty(ref _searchText, value))
return;
RunOnUIThread(ApplyFilter);
}
}
public string SelectedGroup
{
get => _selectedGroup;
set
{
if (!SetProperty(ref _selectedGroup, value))
return;
RunOnUIThread(ApplyFilter);
}
}
public bool IsLoading
{
get => _isLoading;
set
{
if (!SetProperty(ref _isLoading, value))
return;
RefreshCommand.NotifyCanExecuteChanged();
}
}
public ObservableCollection<string> Groups { get; } = new();
public ObservableCollection<HookBrowserRow> Rows { get; } = new();
public ObservableCollection<HookBrowserRow> FilteredRows { get; } = new();
public IAsyncRelayCommand RefreshCommand { get; }
public async Task RefreshAsync()
{
_classifier = HookClassifier.LoadFromFile(null, new UIProgress<string>(_ => { }));
string? il2CppPath = SteamLocator.FindIl2CppAssembliesPath();
if (string.IsNullOrWhiteSpace(il2CppPath))
{
RunOnUIThread(() =>
{
Rows.Clear();
FilteredRows.Clear();
});
return;
}
IsLoading = true;
try
{
var result = await _extractorService.ExtractAsync(
il2CppPath,
_classifier,
new UIProgress<string>(_ => { }),
CancellationToken.None).ConfigureAwait(false);
if (!result.IsSuccess)
{
RunOnUIThread(() =>
{
Rows.Clear();
FilteredRows.Clear();
});
return;
}
var hooks = result.Hooks;
await RunOnUIThreadAsync(() =>
{
Rows.Clear();
foreach (HookDefinition hook in hooks)
{
Rows.Add(new HookBrowserRow
{
Group = hook.Group,
Namespace = hook.Namespace,
ClassName = hook.ClassName,
MethodName = hook.MethodName,
ReturnType = hook.ReturnType,
IsVoid = hook.IsVoid,
Parameters = string.Join(", ", hook.Parameters.Select(p => $"{p.Type} {p.Name}")),
});
}
HashSet<string> groups = hooks.Select(h => h.Group).ToHashSet(StringComparer.OrdinalIgnoreCase);
Groups.Clear();
Groups.Add("Alle");
foreach (string group in groups.OrderBy(x => x, StringComparer.OrdinalIgnoreCase))
Groups.Add(group);
ApplyFilter();
});
}
finally
{
IsLoading = false;
}
}
private void ApplyFilter()
{
IEnumerable<HookBrowserRow> query = Rows;
if (!SelectedGroup.Equals("Alle", StringComparison.OrdinalIgnoreCase))
query = query.Where(x => x.Group.Equals(SelectedGroup, StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrWhiteSpace(SearchText))
{
query = query.Where(x =>
x.MethodName.Contains(SearchText, StringComparison.OrdinalIgnoreCase)
|| x.ClassName.Contains(SearchText, StringComparison.OrdinalIgnoreCase)
|| x.Namespace.Contains(SearchText, StringComparison.OrdinalIgnoreCase)
|| x.Group.Contains(SearchText, StringComparison.OrdinalIgnoreCase));
}
FilteredRows.Clear();
foreach (HookBrowserRow row in query)
FilteredRows.Add(row);
}
}