OpenUtau icon indicating copy to clipboard operation
OpenUtau copied to clipboard

Improve loading popup consistency and visuals

Open Kabinet0 opened this issue 7 months ago • 4 comments

  • 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

Kabinet0 avatar May 24 '25 04:05 Kabinet0

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.

stakira avatar May 24 '25 09:05 stakira

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)

Kabinet0 avatar May 24 '25 13:05 Kabinet0

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.

stakira avatar Jun 01 '25 04:06 stakira

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.

Kabinet0 avatar Jun 01 '25 18:06 Kabinet0