* feat(P2-003): migrate all 10 dialog Windows from WPF/AdonisUI to Avalonia Resolves #16 [P2-003] Migrate all 11 XAML view windows to Avalonia Window. Views migrated (XAML + code-behind): - About: root Window, AdonisUI namespace/styles removed - AesManager: root Window, BoolToVisibility→IsVisible, ListView→DataGrid - AudioPlayer: root Window, CSCore TODO stubs, OpenFileDialog TODO stub - BackupManager: root Window, IsNotZeroConverter for IsEnabled binding - CustomDir: root Window, AdonisUI removals - DirectorySelector: root Window, AdonisUI removals, Visibility→IsVisible - ImageMerger: root Window, BitmapImage→Avalonia Bitmap, WPF dialogs→TODO stubs - SearchView: root Window, ListView+GridView→DataGrid x2, ContextMenus - SettingsView: root Window, DataTriggers→IsVisible/HyperlinkButton/converters, SelectedItemChanged→SelectionChanged, VistaFolderBrowserDialog→TODO stub - UpdateView: root Window, adonisControls:SplitButton→SplitButton+MenuFlyout Support: - FModel.csproj: add Avalonia.Controls.DataGrid v11.3.12 - Add IsNotZeroConverter (Avalonia.Data.Converters IValueConverter) * chore(P2-003): apply post-push refinements to migrated view files * fix: address review findings from Avalonia migration code review Critical: - MainWindow.xaml.cs: unsubscribe all PropertyChanged handlers in OnClosing to prevent memory leak and use-after-free on restart (C2) - MainWindow.xaml.cs: remove ConfigureAwait(false) from async void OnLoaded — continuation must stay on Avalonia UI thread (C1) Major: - MainWindow.xaml: replace WPF KeyboardNavigation.TabNavigation with Avalonia IsTabStop="False" on the feature-preview CheckBox (M3) - MainWindow.xaml.cs: guard PixelDensity against zero in OnLoaded (m2) - MainWindow.xaml.cs: add _syncingSelection re-entrancy guard to SyncSelection to prevent infinite SelectionChanged event loop (m4) - App.xaml.cs: add try/catch inside ShowErrorDialog async lambda to prevent silent exception swallowing; add TaskScheduler.UnobservedTaskException handler in OnFrameworkInitializationCompleted (M1, S1) - App.xaml.cs: remove redundant Environment.Exit(0) from AppExit handler (m1) - Helper.cs: null-guard GetWindow<T> return value; add comment re: Show() race (S2) Views (review fixes): - SettingsView.xaml.cs: replace TryBrowse/OnBrowseMappings stubs with real StorageProvider implementations (OpenFolderPickerAsync, OpenFilePickerAsync) - ImageMerger.xaml.cs: fix async void + MemoryStream disposal in OnExport - UpdateView.xaml: fix Grid nesting of ItemsControl + empty-state TextBlock; add IsNotZeroConverter-based empty-state visibility - CustomDir.xaml/cs, DirectorySelector.xaml/cs: cancel button handlers - Converters: migrate System.Windows.Data IValueConverter usings to Avalonia.Data.Converters for BoolToToggleConverter, EndpointToTypeConverter, EnumToStringConverter, IsNotZeroConverter, SizeToStringConverter * fix: address second-round review findings C1 - SettingsView.xaml.cs: replace WPF editor ShowDialog() calls with async void stubs + TODO(P2-016) comments; DictionaryEditor and EndpointEditor are not yet migrated to Avalonia so these used the WPF synchronous ShowDialog() which is unavailable and returns the wrong type C2 - UpdateView.xaml: add TODO noting CommitsView is still a WPF System.Windows.Data.ListCollectionView; once UpdateViewModel is migrated the Count binding should be replaced with a dedicated HasNoCommits bool property for reliable INPC notification M1+S1 - Helper.cs: null-guard GetOpenedWindow result in OpenWindow<T> to prevent NRE if the window deregisters between IsWindowOpen and the dereference M2 - MainWindow.xaml.cs: add TODO tech-debt comment on the double UpdateStatusLabel dispatch when Kind changes; note consolidation into a single UpdateStatusUI() for a later pass M3 - ImageMerger.xaml.cs: replace ContinueWith(..., FromCurrentSync- Context()) with try/finally after await Task.Run; eliminates the synchronization-context capture hazard when called via ConfigureAwait m1 - App.xaml.cs: UnobservedTaskException now calls ShowErrorDialog for unexpected faults; silently absorbs OperationCanceledException; SetObserved() moved before the early-return guard m2 - IsNotZeroConverter.cs: fix 2-space indentation to 4-space to match rest of codebase m3 - EndpointToTypeConverter.cs: replace misleading NotImplemented- Exception with ArgumentException carrying a descriptive message * fix: address third-round review findings - App.xaml.cs: check all InnerExceptions for OperationCanceledException, not just InnerException[0], so a mixed AggregateException is never silently absorbed (m1) - Helper.cs: add Dispatcher.UIThread.RunJobs() between Show() and the window-registry lookup in GetWindow<T> to close the registration race on first open (S1); also add missing System.Collections.Generic using that caused a pre-existing IEnumerable<> CS0246 error - SettingsView.xaml.cs: clarify EndpointEditor TODO comments — original WPF code used ShowDialog() (modal), so migration target is ShowDialog(this), not Show() (m2) * fix: add missing System.Linq using in App.xaml.cs InnerExceptions.All() is a LINQ extension method. The project has no implicit usings, so the explicit using was required. The build check after the previous commit only grepped for Helper.cs errors, so the CS1061 on App.xaml.cs was not caught until the follow-up review. * fix: address PR reviewer findings across six view files C1 - AudioPlayer.xaml: replace undeclared adonisUi:Brushes.ForegroundBrush DynamicResource (compile error) with Fill="White", consistent with all other icon paths in the file. C2 - SettingsView.xaml.cs: fix OnBrowseMappings storing into non-existent UserSettings.Default.MappingsPath; now sets _applicationView.SettingsView.MappingEndpoint.FilePath which is the property the XAML TextBox is bound to (compile error + silent data loss). C3 - UpdateView.xaml: remove WPF-only ItemsControl.GroupStyle / GroupStyle / GroupItem / HeaderStringFormat block (XAML parse failure on Avalonia). Date grouping will be re-added alongside the CommitsView ViewModel migration (see existing TODO). Also fix FallbackValue=False → 0 so IsNotZeroConverter receives the expected int type when the binding target can't be resolved. M1 - ImageMerger.xaml.cs (UpButton case): remove spurious SelectedItems.Add(indices) call which was adding the raw int[] to the selected-items collection. Items are already marked IsSelected=true inside the move loop; the Add call was a no-op at best and a runtime inconsistency at worst. M2 - DirectorySelector.xaml: remove self-referential Width={Binding ActualWidth, ElementName=OkGuysButWhoFuckingAsked} (control binding its own width to itself — produces binding warnings and has no useful effect; layout is determined by content/padding). m1 - SearchView.xaml.cs: restore WPF DataTrigger behavior — subscribe to PropertyChanged on each SearchViewModel and update the corresponding TextBox.Watermark when HasRegexEnabled toggles, giving 'Write your regex pattern...' vs 'Write your pattern...' hint text. * fix: unsubscribe PropertyChanged handlers in SearchView on close SearchVm and RefVm are application-lifetime singletons. Subscribing anonymous lambdas capturing 'this' (the window's TextBox fields) meant each closed-and-reopened SearchView was kept permanently alive by the singletons' PropertyChanged invocation lists. Fix: promote the handlers to named local functions, cache the VM references at construction time, and unsubscribe both handlers in the Closed event so the window becomes eligible for GC immediately after it is closed. Also adds the required 'using System.ComponentModel' for the PropertyChangedEventArgs parameter type. * fix: migrate WPF converters to Avalonia.Data.Converters interfaces CaseInsensitiveStringEqualsConverter: replace System.Windows.Data.IValueConverter with Avalonia.Data.Converters.IValueConverter. Avalonia cannot call WPF converter implementations, so any SettingsView.xaml binding using this converter would fail silently at runtime. Also null-guards value/parameter before calling .ToString() to avoid NREs on binding fallback values. MultiParameterConverter: replace System.Windows.Data.IMultiValueConverter with Avalonia.Data.Converters.IMultiValueConverter. The Avalonia interface takes IList<object?> rather than object[], so update the signature accordingly. Return values.ToArray() to preserve the same object[] snapshot that the WPF values.Clone() call produced, keeping CommandParameter multi-binding callers in SearchView.xaml working. Avalonia's IMultiValueConverter has no ConvertBack, so that method is removed. |
||
|---|---|---|
| .github | ||
| .vscode | ||
| CUE4Parse@06fbf1aced | ||
| FModel | ||
| .editorconfig | ||
| .gitignore | ||
| .gitmodules | ||
| LICENSE | ||
| NOTICE | ||
| README.md | ||
FModel Linux — Unreal Engine Archives Explorer for Linux
This is an unofficial Linux port of FModel, originally created by Asval (4sval) and contributors. It is not affiliated with or endorsed by the upstream project or its maintainers. Please do not report Linux-port-specific issues upstream.
Description
FModel Linux is a Linux port of FModel — an archive explorer for Unreal Engine games. It uses CUE4Parse as its core parsing library, providing robust support for the latest UE4 and UE5 archive formats, along with a comprehensive set of tools for previewing and converting game packages.
This fork replaces the Windows-only WPF UI stack with Avalonia UI and removes other Windows-specific dependencies to enable native Linux support. It is maintained by r6e.
Installation
Installation instructions for the Linux port are available in the project wiki (work in progress).
For the upstream Windows release, refer to the official FModel installation guide.
Supporting the Upstream Project
This fork does not accept donations. If you find FModel valuable, please consider supporting the original FModel project and its contributors.
License
FModel Linux is a derivative work licensed under GPL-3. The original FModel project is copyright © Asval and FModel contributors. Licenses of third-party libraries used are listed in NOTICE.