Improve loading popup consistency and visuals
-
Made a lot of loading logic async so the UI can keep rendering while loading
-
Fixed broken rendering of the loading popup
-
Made loading popup only appear after 100ms of load time to avoid flashing
-
Improved aesthetics of loading popup
https://github.com/user-attachments/assets/9a73e1a8-729c-4136-b40b-7073ffeed5a7
https://github.com/user-attachments/assets/d3b9bab4-27f5-4571-96a1-ea4f002b75aa
This is very interesting. But you can't through stuff in tasks and expect them to automatically work safely. I'm fine with the menu loadings but let's not touch project loading.
I don't disagree, but the only part of the loading sequence that actually runs on a separate thread is what's within Task.Run() in OpenProjectAsync
await Task.Run(() => {
Core.Format.Formats.LoadProject(files);
DocManager.Inst.ExecuteCmd(new VoiceColorRemappingNotification(-1, true));
this.RaisePropertyChanged(nameof(Title));
});
All the other methods in the project opening chain (despite being async) are still executed on the main UI thread as usual, since they originate from the main thread.
Admittedly I just threw a small snippet of whatever worked into Task.Run(). The core of the issue is that to render a new popup, like the one created for loading, you need to relinquish control to Avalonia at least once to allow it to draw the window's contents. Technically you don't need to await loading logic, you could instead choose to await 5 miliseconds of delay or something, so long as the OpenProjectAsync() method awaits something long enough the popup should render correctly. (5ms seems inconsistent though, and avalonia seemingly only sometimes has time to render the popup, might need more) I used loading logic that looked safe, but I understand that it's hard to guarantee that the logic I chose will remain thread safe in the future.
Moving forward there are a few options.
- We could try to enforce that some function like
Core.Format.Formats.LoadProject();stays thread safe, and only Task.Run() that one method. (We could even make that more granular by making LoadProject() itself async, and only threading a portion of it) - We could also throw in a few milliseconds of delay.
- We could of course also revert some changes, at the cost of the loading popup not rendering correctly. (The window still opens, but it remains transparent and won't have any content)
Yea I'm aware how the loading popup is having issue, etc. TBH, I'd rather just freeze the UI thread for a moment without any loading window, just to keep things simple. The dotnet tasks are so easy to grow into a spagetti mess.
Apologies for the force push, there was some confusion on my part with upstream changes. Everything should be good now.
Though I personally think the extra effort in maintaining an async project loading system is worth it, I respect your decision. I've reverted the project loading changes and removed the popup when opening a project.