From b1551150c72cac5db01b56336cdce1a3365bb177 Mon Sep 17 00:00:00 2001
From: karashiiro <49822414+karashiiro@users.noreply.github.com>
Date: Thu, 4 May 2023 20:59:26 -0700
Subject: [PATCH] feat: load the FileDialog drive list asynchronously
---
.../ImGuiFileDialog/DriveListLoader.cs | 71 +++++++++++++++++++
.../ImGuiFileDialog/FileDialog.Files.cs | 14 ++--
.../ImGuiFileDialog/FileDialog.UI.cs | 2 +-
.../Interface/ImGuiFileDialog/FileDialog.cs | 1 -
4 files changed, 81 insertions(+), 7 deletions(-)
create mode 100644 Dalamud/Interface/ImGuiFileDialog/DriveListLoader.cs
diff --git a/Dalamud/Interface/ImGuiFileDialog/DriveListLoader.cs b/Dalamud/Interface/ImGuiFileDialog/DriveListLoader.cs
new file mode 100644
index 000000000..35271a953
--- /dev/null
+++ b/Dalamud/Interface/ImGuiFileDialog/DriveListLoader.cs
@@ -0,0 +1,71 @@
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Dalamud.Interface.ImGuiFileDialog;
+
+///
+/// A drive list loader. Thread-safety guaranteed.
+///
+public class DriveListLoader
+{
+ private bool initialized;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public DriveListLoader()
+ {
+ this.Drives = ImmutableArray.Empty;
+ }
+
+ ///
+ /// Gets the drive list. This may be incomplete if the loader is still loading.
+ ///
+ public IReadOnlyList Drives { get; private set; }
+
+ ///
+ /// Gets a value indicating whether or not the loader is loading.
+ ///
+ public bool Loading { get; private set; }
+
+ ///
+ /// Loads the drive list, asynchronously.
+ ///
+ /// A representing the asynchronous operation.
+ public async Task LoadDrivesAsync()
+ {
+ this.Loading = true;
+ try
+ {
+ await this.InitDrives();
+ }
+ finally
+ {
+ this.Loading = false;
+ }
+ }
+
+ private async Task InitDrives()
+ {
+ var drives = ImmutableArray.Empty;
+ foreach (var drive in DriveInfo.GetDrives())
+ {
+ drives = drives.Add(drive);
+ if (!this.initialized)
+ {
+ // Show results as soon as they load initially, but otherwise keep
+ // the existing drive list
+ this.Drives = drives;
+ }
+
+ // Force async to avoid this being invoked synchronously unless it's awaited
+ await Task.Yield();
+ }
+
+ // Replace the whole drive list
+ this.Drives = drives;
+ this.initialized = true;
+ }
+}
diff --git a/Dalamud/Interface/ImGuiFileDialog/FileDialog.Files.cs b/Dalamud/Interface/ImGuiFileDialog/FileDialog.Files.cs
index c34d047d9..ba71c8cfa 100644
--- a/Dalamud/Interface/ImGuiFileDialog/FileDialog.Files.cs
+++ b/Dalamud/Interface/ImGuiFileDialog/FileDialog.Files.cs
@@ -12,11 +12,13 @@ public partial class FileDialog
{
private readonly object filesLock = new();
+ private readonly DriveListLoader driveListLoader = new();
+
private List files = new();
private List filteredFiles = new();
private SortingField currentSortingField = SortingField.FileName;
- private bool[] sortDescending = new[] { false, false, false, false };
+ private bool[] sortDescending = { false, false, false, false };
private enum FileStructType
{
@@ -296,12 +298,14 @@ public partial class FileDialog
}
}
+ private IEnumerable GetDrives()
+ {
+ return this.driveListLoader.Drives.Select(drive => new SideBarItem(drive.Name, drive.Name, FontAwesomeIcon.Server));
+ }
+
private void SetupSideBar()
{
- foreach (var drive in DriveInfo.GetDrives())
- {
- this.drives.Add(new SideBarItem(drive.Name, drive.Name, FontAwesomeIcon.Server));
- }
+ _ = this.driveListLoader.LoadDrivesAsync();
var personal = Path.GetDirectoryName(Environment.GetFolderPath(Environment.SpecialFolder.Personal));
diff --git a/Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs b/Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs
index c55722b4a..608ed6d6d 100644
--- a/Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs
+++ b/Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs
@@ -316,7 +316,7 @@ public partial class FileDialog
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + Scaled(5));
var idx = 0;
- foreach (var qa in this.drives.Concat(this.quickAccess).Where(qa => qa.Exists))
+ foreach (var qa in this.GetDrives().Concat(this.quickAccess).Where(qa => qa.Exists))
{
ImGui.PushID(idx++);
ImGui.SetCursorPosX(Scaled(25));
diff --git a/Dalamud/Interface/ImGuiFileDialog/FileDialog.cs b/Dalamud/Interface/ImGuiFileDialog/FileDialog.cs
index fe224be76..b0ede4fb3 100644
--- a/Dalamud/Interface/ImGuiFileDialog/FileDialog.cs
+++ b/Dalamud/Interface/ImGuiFileDialog/FileDialog.cs
@@ -52,7 +52,6 @@ public partial class FileDialog
private float footerHeight = 0;
private string selectedSideBar = string.Empty;
- private List drives = new();
private List quickAccess = new();
///