Avalonia UI#975
Conversation
This reverts commit 0ce6c7d.
There was a problem hiding this comment.
Many of the inline comments pertain to multiple locations, but there were a couple of overarching comments that I wanted to mention as well:
- There are basically no code comments. For anything that was based on existing WPF code, please copy the comment wholesale. For anything that is new functionality, add at the bare minimum a
summarystatement about what it is doing. I know that many are self-explanatory once you read the method, but those comments are used to get an understanding while coding to avoid having to look at the source for all details. - All loops, such as
for,foreach, andwhileshould have curly braces, regardless of the number of lines that are contained within. - I am seeing the use of
global::in many places and I would like to understand more about why this pattern is being used. - Unless there is ambiguity about what method or property is being invoked, you can avoid use of the
this.qualifier. - There are many places, such as large lists of constants/variables or OS-specific methods, that could do with
#regiontags. This can help break up the code into more distinct sections and allows collapsing away logical groupings.
| /// <summary> | ||
| /// UI-friendly display name for the drive | ||
| /// </summary> | ||
| public string DisplayName => GetDisplayName(); |
There was a problem hiding this comment.
This can be combined with the helper method into a cached property that utilizes the field keyword.
| DriveFormat = driveInfo.DriveFormat; | ||
| TotalSize = driveInfo.TotalSize; | ||
| VolumeLabel = driveInfo.VolumeLabel; | ||
| if (Environment.OSVersion.Platform != PlatformID.Unix) |
There was a problem hiding this comment.
If this is specific to Windows, then I'd prefer the check to say that instead. If saying "non-Unix" is actually the right way of doing something like Windows and Mac only, I would appreciate a one-line comment above this if/else that says that.
There was a problem hiding this comment.
You're right that this is effectively Windows-only. DriveInfo.VolumeLabel is only available on Windows, and modern .NET reports both Linux and macOS as PlatformID.Unix, so != PlatformID.Unix resolves to "Windows" here. I didn't switch to OperatingSystem.IsWindows() because this project also targets net20-net48, where that helper doesn't exist. I've added a comment above the if/else explaining exactly that (commit 548f0ff).
There was a problem hiding this comment.
Updated to make the check explicit (commit b76b4cb): switched != PlatformID.Unix to == PlatformID.Win32NT, which reads as "Windows" directly as you preferred. I used PlatformID.Win32NT rather than OperatingSystem.IsWindows() because that helper only exists on net5.0+, and this project also targets net20-net48; PlatformID.Win32NT is available on all of them. The comment is now a single line noting that DriveInfo.VolumeLabel is Windows-only.
| if (displayName.Length > 1) | ||
| displayName = displayName.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); |
There was a problem hiding this comment.
I don't understand why this has to be gated by a length check
| "L0MasteringRing", "L0MasteringSID", "L0Toolstamp", "L0MouldSID", "L0AdditionalMould", | ||
| "L1MasteringRing", "L1MasteringSID", "L1Toolstamp", "L1MouldSID", "L1AdditionalMould", | ||
| "L2MasteringRing", "L2MasteringSID", "L2Toolstamp", | ||
| "L3MasteringRing", "L3MasteringSID", "L3Toolstamp", |
There was a problem hiding this comment.
This feels like it should be a static readonly collection at the class level. I have been thrown off seeing this in the declaration of a foreach statement multiple times now.
There was a problem hiding this comment.
Done (commit 536e1ee) — extracted to static readonly class-level arrays so they're no longer declared inline in the foreach: TabEnabledFieldNames here, and LanguageMenuItemNames for the equivalent block in MainWindow.
| { | ||
| private readonly bool _showPcMacHybridAlways; | ||
|
|
||
| private static readonly (string Name, SiteCode Code)[] CommentFields = |
There was a problem hiding this comment.
Why are these arrays of tuples instead of a dictionary?
There was a problem hiding this comment.
They're kept as ordered arrays because display order matters — the comment/content fields render in a fixed sequence, and a Dictionary doesn't guarantee enumeration order, so switching would risk shuffling the UI. They're also small, fixed lists iterated linearly, so a dictionary's lookup benefit doesn't really apply here. If keyed lookup is needed elsewhere I could add a dictionary alongside, but the ordered array matches how they're consumed.
| parameters = Regex.Replace(parameters, $@"(^|\s)--drive=(?:""{escapedDrive}/?""|{escapedDrive}/?)(?=\s|$)", "$1"); | ||
| parameters = Regex.Replace(parameters, $@"(^|\s)--drive\s+(?:""{escapedDrive}/?""|{escapedDrive}/?)(?=\s|$)", "$1"); |
There was a problem hiding this comment.
The drive names need to be escaped for Redumper? I'm having a hard time following what these regex statements are actually doing to the resulting parameters.
There was a problem hiding this comment.
On macOS the optical drive mounts under /Volumes/, and Redumper there doesn't take the --drive argument the way it does on Windows. These statements strip any --drive=<vol> / --drive <vol> matching the mounted volume back out of the parameter string. Regex.Escape(driveName) is only there to make the volume name match literally — mounted volume names can contain spaces or regex metacharacters, so without escaping the pattern could misbehave. I can add an inline comment spelling that out.
There was a problem hiding this comment.
Added the inline comments spelling this out (commit 548f0ff): one note on Regex.Escape (mounted volume names under /Volumes/ can contain spaces or regex metacharacters, so the name is escaped to match literally), and one on the two Regex.Replace calls (they strip the mounted drive's --drive=<name> / --drive <name> argument — quoted or unquoted, optional trailing slash — because Redumper on macOS doesn't take the drive argument the way it does on Windows).
There was a problem hiding this comment.
To be clear on the two parts: the Regex.Escape and what the Regex.Replace calls do are as described above (escaping is only to match the volume name literally in the .NET regex; the replaces strip the mounted-volume --drive argument). The underlying reason the argument is stripped specifically on macOS — i.e. exactly how Redumper expects the drive to be specified there — is best confirmed by @Deterous, who authored this method; my explanation of that part is an inference rather than something I can state authoritatively.
| private static NativeMenuItem CreateNativeMenuItem(string header, Action action) | ||
| { | ||
| var item = new NativeMenuItem { Header = CleanMenuHeader(header) }; | ||
| item.Click += (_, _) => action(); | ||
| return item; | ||
| } |
There was a problem hiding this comment.
In a similar vein to the WireEvents methods, is there a reason that what is being passed in isn't just a Func or Action with the correct parameters for the event handler?
There was a problem hiding this comment.
They are delegates — the parameters are named delegate types rather than Func/Action, but functionally the same. The view model takes these callbacks (log output, user-message display, media-info window) so it can drive those UI concerns without depending on the View layer, keeping the MVVM separation. If the preference is to type them as Func<>/Action<> directly, I can switch the signatures.
| { | ||
| public partial class MainWindow : WindowBase | ||
| { | ||
| private const double ExpandedLogPanelExtraHeight = 40; |
There was a problem hiding this comment.
I'm a bit surprised that dimensions are allowed to have fractional values in Avalonia.
There was a problem hiding this comment.
Avalonia measures layout in device-independent pixels as double throughout (Width/Height/Margin etc. are all double), so fractional values are expected rather than special. The constant here is a whole number — it's just typed as double to match the layout API.
…d handler for event wiring
…-only volume label check
This PR adds an alternate UI framework for MPF based on Avalonia, allowing for Linux and macOS UI builds.
There may be some small tweaks needed before merging during my testing, but I want to open the PR now to begin the review process as this is a big change.
Thanks to 7 (@whatev-indus) for putting in the work on this, I've just helped with guidance and then cleaned it up to use SabreTools styles and build processes. I will also be responding to any PR review comments. If you want to make changes to the branch directly and cannot, ask 7 for contributor access to the repo.
This does not replace the WPF UI, currently both are built separately. The images (icon, ringcode pics) are referenced from the WPF folder, but the Strings XAML are duplicated. The new MPF.Avalonia namespace is intended to reference the MPF.Frontend namespace as much as possible, so that it can be a drop-in replacement for the old WPF UI.
It is also 7's request to have AppImage builds for Linux and other build changes required for icons and niceties on macOS, although these changes can come in a later PR (to minimize the review burden)