Skip to content

Commit c9e4a5b

Browse files
Improved async behaviour so the UI thread isn't blocked.
1 parent 76d1341 commit c9e4a5b

3 files changed

Lines changed: 127 additions & 99 deletions

File tree

DazContentInstaller/Models/InstalledArchiveTree.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace DazContentInstaller.Models;
88

99
public class InstalledArchiveTree : ObservableCollection<TreeNode>
1010
{
11-
public void LoadArchive(Archive archive)
11+
public TreeNode LoadArchive(Archive archive)
1212
{
1313
var root = new TreeNode(archive.ArchiveName, archive.Id, null);
1414
Add(root);
@@ -22,6 +22,7 @@ public void LoadArchive(Archive archive)
2222
}
2323

2424
SortTree(root);
25+
return root;
2526
}
2627

2728
private static void SortTree(TreeNode node)

DazContentInstaller/ViewModels/MainWindowViewModel.cs

Lines changed: 125 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Reactive;
77
using System.Threading.Tasks;
88
using Avalonia.Media;
9+
using Avalonia.Threading;
910
using DazContentInstaller.Database;
1011
using DazContentInstaller.Extensions;
1112
using DazContentInstaller.Models;
@@ -155,33 +156,40 @@ private void ClearLoadedArchives()
155156
public async Task LoadAssetLibrariesAsync()
156157
{
157158
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
158-
var libraries = await dbContext.AssetLibraries.ToListAsync();
159159
AssetLibraries.Clear();
160-
AssetLibraries.AddRange(libraries);
161-
CurrentSelectedAssetLibrary = libraries.OrderByDescending(d => d.IsDefault).FirstOrDefault();
160+
await Task.Run(async () =>
161+
{
162+
await foreach (var library in dbContext.AssetLibraries.AsAsyncEnumerable())
163+
AssetLibraries.Add(library);
164+
});
165+
166+
CurrentSelectedAssetLibrary = AssetLibraries.OrderByDescending(d => d.IsDefault).FirstOrDefault();
162167
}
163168

164169
public async Task LoadInstalledArchivesAsync()
165170
{
166171
InstalledArchivesTree.Clear();
172+
DisplayedInstalledArchives.Clear();
173+
InstalledAssetsCount = 0;
167174

168-
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
169-
var archivesQuery = dbContext.Archives
170-
.Where(d => d.Status == ArchiveStatus.Installed);
171-
172-
if (CurrentSelectedAssetLibrary is not null)
173-
archivesQuery = archivesQuery.Where(d => d.AssetLibraryId == CurrentSelectedAssetLibrary.Id);
174-
175-
var archives = await archivesQuery
176-
.Include(d => d.AssetFiles)
177-
.OrderBy(d => d.ArchiveName)
178-
.ToListAsync();
179-
180-
InstalledAssetsCount = archives.Count;
181-
foreach (var archive in archives)
182-
InstalledArchivesTree.LoadArchive(archive);
175+
await Task.Run(async () =>
176+
{
177+
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
178+
var archivesQuery = dbContext.Archives
179+
.Where(d => d.Status == ArchiveStatus.Installed);
180+
if (CurrentSelectedAssetLibrary is not null)
181+
archivesQuery = archivesQuery.Where(d => d.AssetLibraryId == CurrentSelectedAssetLibrary.Id);
183182

184-
FilterInstalledAssetsTree(InstalledAssetsSearch);
183+
await foreach (var archive in archivesQuery.OrderBy(d => d.ArchiveName.ToLower()).AsAsyncEnumerable())
184+
{
185+
var files = await dbContext.AssetFiles.Where(d => d.ArchiveId == archive.Id).ToListAsync();
186+
archive.AssetFiles = files;
187+
188+
var node = InstalledArchivesTree.LoadArchive(archive);
189+
DisplayedInstalledArchives.Add(node);
190+
InstalledAssetsCount = InstalledArchivesTree.Count;
191+
}
192+
});
185193
}
186194

187195
private void RemoveLoadedArchive(LoadedArchive loadedArchiveOld)
@@ -197,49 +205,53 @@ private async Task InstallArchives()
197205
var archivesToInstall =
198206
SelectedArchives.Count > 0 ? SelectedArchives.ToList() : LoadedArchives.ToList();
199207

200-
StatusProgress = 0;
201208
IProgress<string> messageProgress = new Progress<string>(s => StatusText = s);
202-
StatusBarColor = Brushes.DodgerBlue;
203209
IProgress<double> percentageProgress = new Progress<double>(s => StatusProgress = (int)s);
210+
StatusProgress = 0;
211+
StatusBarColor = Brushes.DodgerBlue;
204212

205-
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
206-
207-
var archivesToInstallNames = archivesToInstall.Select(GetLoadedArchiveName).ToArray();
208-
var existingArchives = await dbContext.Archives
209-
.Where(a => archivesToInstallNames.Contains(a.ArchiveName))
210-
.Include(a => a.AssetFiles)
211-
.ToListAsync();
212-
213-
existingArchives = existingArchives.Where(e => archivesToInstall.Any(a =>
214-
a.ContainedFiles.Count == e.AssetFiles.Count && GetLoadedArchiveName(a).Equals(e.ArchiveName))).ToList();
215-
216-
var loadedArchivesToSkip = archivesToInstall
217-
.IntersectBy(existingArchives.Select(d => d.ArchiveName), GetLoadedArchiveName).ToList();
218-
loadedArchivesToSkip.ForEach(d => d.ArchiveStatus = ArchiveStatus.Duplicate);
219-
220-
archivesToInstall = archivesToInstall.Except(loadedArchivesToSkip).ToList();
221-
using var installer = new DazArchiveInstaller(archivesToInstall, _settingsService.CurrentSettings);
222-
223-
await foreach (var archive in installer.InstallArchivesAsync(CurrentSelectedAssetLibrary.Path, messageProgress,
224-
percentageProgress))
213+
await Task.Run(async () =>
225214
{
226-
var dbArchive = new Archive
215+
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
216+
217+
var archivesToInstallNames = archivesToInstall.Select(GetLoadedArchiveName).ToArray();
218+
var existingArchives = await dbContext.Archives
219+
.Where(a => archivesToInstallNames.Contains(a.ArchiveName))
220+
.Include(a => a.AssetFiles)
221+
.ToListAsync();
222+
223+
existingArchives = existingArchives.Where(e => archivesToInstall.Any(a =>
224+
a.ContainedFiles.Count == e.AssetFiles.Count && GetLoadedArchiveName(a).Equals(e.ArchiveName)))
225+
.ToList();
226+
227+
var loadedArchivesToSkip = archivesToInstall
228+
.IntersectBy(existingArchives.Select(d => d.ArchiveName), GetLoadedArchiveName).ToList();
229+
loadedArchivesToSkip.ForEach(d => d.ArchiveStatus = ArchiveStatus.Duplicate);
230+
231+
archivesToInstall = archivesToInstall.Except(loadedArchivesToSkip).ToList();
232+
using var installer = new DazArchiveInstaller(archivesToInstall, _settingsService.CurrentSettings);
233+
await foreach (var archive in installer.InstallArchivesAsync(CurrentSelectedAssetLibrary.Path,
234+
messageProgress,
235+
percentageProgress))
227236
{
228-
ArchiveName = archive.Name,
229-
ArchiveSize = archive.FileSizeBytes,
230-
Status = ArchiveStatus.Installed,
231-
CustomAssetsBasePath = archive.CustomAssetBaseDirectory,
232-
AssetLibraryId = CurrentSelectedAssetLibrary.Id
233-
};
234-
235-
dbArchive.AssetFiles.AddRange(archive.ContainedFiles);
236-
dbContext.Archives.Add(dbArchive);
237-
await dbContext.SaveChangesAsync();
238-
239-
LoadedArchives.Remove(archive);
240-
await LoadInstalledArchivesAsync();
241-
}
237+
var dbArchive = new Archive
238+
{
239+
ArchiveName = archive.Name,
240+
ArchiveSize = archive.FileSizeBytes,
241+
Status = ArchiveStatus.Installed,
242+
CustomAssetsBasePath = archive.CustomAssetBaseDirectory,
243+
AssetLibraryId = CurrentSelectedAssetLibrary.Id
244+
};
245+
246+
dbArchive.AssetFiles.AddRange(archive.ContainedFiles);
247+
dbContext.Archives.Add(dbArchive);
248+
await dbContext.SaveChangesAsync();
249+
250+
Dispatcher.UIThread.Post(() => LoadedArchives.Remove(archive));
251+
}
252+
});
242253

254+
await LoadInstalledArchivesAsync();
243255
messageProgress.Report($"Installed {archivesToInstall.Count} archives");
244256
percentageProgress.Report(100);
245257
StatusBarColor = Brushes.Green;
@@ -267,41 +279,49 @@ private async Task UninstallArchiveAsync()
267279
if (archives.Count < 1)
268280
return;
269281

270-
var archiveIds = archives.Select(a => a.Id).ToArray();
271-
var deleteFileExceptions = await dbContext.AssetFiles
272-
.Where(f => !archiveIds.Contains(f.ArchiveId) && f.InstalledPath != null)
273-
.ToListAsync();
282+
await Task.Run(async () =>
283+
{
284+
IProgress<string> messageProgress = new Progress<string>(s => StatusText = s);
285+
IProgress<double> percentageProgress = new Progress<double>(s => StatusProgress = (int)s);
286+
StatusBarColor = Brushes.DodgerBlue;
287+
StatusProgress = 0;
274288

275-
deleteFileExceptions = deleteFileExceptions
276-
.Where(e => archives.SelectMany(a => a.AssetFiles)
277-
.Any(f => f.InstalledPath!.Equals(e.InstalledPath, StringComparison.OrdinalIgnoreCase)))
278-
.Distinct().ToList();
289+
messageProgress.Report($"Reading {selectedInstallArchiveIds.Length} archives to uninstall...");
279290

280-
IProgress<string> messageProgress = new Progress<string>(s => StatusText = s);
281-
IProgress<double> percentageProgress = new Progress<double>(s => StatusProgress = (int)s);
282-
StatusBarColor = Brushes.DodgerBlue;
283-
StatusProgress = 0;
284-
var increment = Math.Ceiling(100D / archives.Count);
291+
var archiveIds = archives.Select(a => a.Id).ToArray();
292+
var deleteFileExceptions = await dbContext.AssetFiles
293+
.Where(f => !archiveIds.Contains(f.ArchiveId) && f.InstalledPath != null)
294+
.ToListAsync();
285295

286-
var index = 0;
287-
foreach (var archive in archives)
288-
{
289-
index++;
290-
var uninstaller = new DazArchiveUninstaller(archive);
291-
await uninstaller.UninstallArchiveAsync(deleteFileExceptions.Select(d => d.InstalledPath!).ToHashSet());
296+
deleteFileExceptions = deleteFileExceptions
297+
.Where(e => archives.SelectMany(a => a.AssetFiles)
298+
.Any(f => f.InstalledPath!.Equals(e.InstalledPath, StringComparison.OrdinalIgnoreCase)))
299+
.Distinct().ToList();
292300

293-
dbContext.Archives.Remove(archive);
294-
await dbContext.SaveChangesAsync();
301+
var increment = Math.Ceiling(100D / archives.Count);
295302

296-
messageProgress.Report($"Uninstalled {archive.ArchiveName}");
297-
percentageProgress.Report(index * increment);
298-
await Task.Yield();
299-
}
303+
var index = 0;
304+
305+
foreach (var archive in archives)
306+
{
307+
index++;
308+
var uninstaller = new DazArchiveUninstaller(archive);
309+
await uninstaller.UninstallArchiveAsync(deleteFileExceptions.Select(d => d.InstalledPath!).ToHashSet());
310+
311+
dbContext.Archives.Remove(archive);
312+
await dbContext.SaveChangesAsync();
313+
314+
messageProgress.Report($"Uninstalled {archive.ArchiveName}");
315+
percentageProgress.Report(index * increment);
316+
await Task.Yield();
317+
}
318+
319+
messageProgress.Report($"Uninstalled {archives.Count} archives");
320+
percentageProgress.Report(100);
321+
StatusBarColor = Brushes.Green;
322+
});
300323

301324
await LoadInstalledArchivesAsync();
302-
messageProgress.Report($"Uninstalled {archives.Count} archives");
303-
percentageProgress.Report(100);
304-
StatusBarColor = Brushes.Green;
305325
}
306326

307327
public async Task LoadArchiveFilesAsync(List<string> filePaths)
@@ -311,20 +331,27 @@ public async Task LoadArchiveFilesAsync(List<string> filePaths)
311331
StatusBarColor = Brushes.DodgerBlue;
312332

313333
var index = 0;
314-
foreach (var path in filePaths)
315-
{
316-
index++;
317-
var existingStatusProgress = index * 100;
318-
IProgress<string> messageProgress = new Progress<string>(s => StatusText = s);
319-
var percentageProgress = new Progress<int>(p => StatusProgress = existingStatusProgress + p);
320-
321-
using var loader = new DazArchiveLoader(path);
322-
var result = await loader.LoadArchiveAsync(messageProgress, percentageProgress);
323334

324-
LoadedArchives.AddRange(result.Where(d => d.ContainedFiles.Count > 0));
325-
UpdateInstallButton();
326-
messageProgress.Report($"Finished loading {Path.GetFileName(path)}");
327-
}
335+
await Task.Run(async () =>
336+
{
337+
foreach (var path in filePaths)
338+
{
339+
index++;
340+
var existingStatusProgress = index * 100;
341+
IProgress<string> messageProgress = new Progress<string>(s => StatusText = s);
342+
var percentageProgress = new Progress<int>(p => StatusProgress = existingStatusProgress + p);
343+
344+
using var loader = new DazArchiveLoader(path);
345+
var result = await loader.LoadArchiveAsync(messageProgress, percentageProgress);
346+
347+
Dispatcher.UIThread.Post(() =>
348+
{
349+
LoadedArchives.AddRange(result.Where(d => d.ContainedFiles.Count > 0));
350+
UpdateInstallButton();
351+
});
352+
messageProgress.Report($"Finished loading {Path.GetFileName(path)}");
353+
}
354+
});
328355

329356
StatusBarMax = 100;
330357
StatusBarColor = Brushes.Green;
@@ -336,6 +363,7 @@ private void FilterInstalledAssetsTree(string? searchTerm)
336363
if (string.IsNullOrWhiteSpace(searchTerm))
337364
{
338365
DisplayedInstalledArchives.AddRange(InstalledArchivesTree);
366+
339367
return;
340368
}
341369

DazContentInstaller/Views/MainWindow.axaml.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,6 @@ private async void Control_OnLoaded(object? sender, RoutedEventArgs e)
104104
return;
105105

106106
await ViewModel.LoadAssetLibrariesAsync();
107-
await ViewModel.LoadInstalledArchivesAsync();
108107
}
109108
catch (Exception ex)
110109
{

0 commit comments

Comments
 (0)