Skip to content

Commit b0519c2

Browse files
committed
fixed downloading
1 parent 31cb0f7 commit b0519c2

File tree

9 files changed

+108
-89
lines changed

9 files changed

+108
-89
lines changed

src/Addons/Providers/DownloadableAddonsProvider.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Common.Client.Helpers;
33
using Common.Client.Interfaces;
44
using Common.Client.Tools;
5+
using Common.Entities;
56
using Common.Enums;
67
using Common.Helpers;
78
using Common.Interfaces;
@@ -22,7 +23,7 @@ public sealed class DownloadableAddonsProvider : IDownloadableAddonsProvider
2223
private readonly InstalledAddonsProvider _installedAddonsProvider;
2324
private readonly ILogger _logger;
2425

25-
private Dictionary<AddonTypeEnum, Dictionary<AddonVersion, IDownloadableAddon>>? _cache;
26+
private Dictionary<AddonTypeEnum, Dictionary<AddonVersion, DownloadableAddonEntity>>? _cache;
2627

2728
private static readonly SemaphoreSlim _semaphore = new(1);
2829

@@ -103,7 +104,7 @@ public async Task<bool> CreateCacheAsync(bool createNew)
103104

104105

105106
/// <inheritdoc/>
106-
public ImmutableList<IDownloadableAddon> GetDownloadableAddons(AddonTypeEnum addonType)
107+
public ImmutableList<DownloadableAddonEntity> GetDownloadableAddons(AddonTypeEnum addonType)
107108
{
108109
if (_cache is null)
109110
{
@@ -157,7 +158,7 @@ public ImmutableList<IDownloadableAddon> GetDownloadableAddons(AddonTypeEnum add
157158

158159
/// <inheritdoc/>
159160
public async Task DownloadAddonAsync(
160-
IDownloadableAddon addon,
161+
DownloadableAddonEntity addon,
161162
CancellationToken cancellationToken
162163
)
163164
{

src/Avalonia.Desktop/Controls/DownloadsControl.axaml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
88
xmlns:vm="clr-namespace:Avalonia.Desktop.ViewModels"
99
xmlns:helpers="clr-namespace:Avalonia.Desktop.Helpers"
10+
xmlns:misc="clr-namespace:Avalonia.Desktop.Misc"
1011
x:DataType="vm:DownloadsViewModel"
1112
x:Class="Avalonia.Desktop.Controls.DownloadsControl">
1213

@@ -42,13 +43,11 @@
4243

4344
</Grid>
4445

45-
<DataGrid Name="DownloadableList"
46-
Grid.Row="1" Grid.Column="0"
47-
Margin="0"
48-
Padding="2"
46+
<DataGrid Grid.Row="1" Grid.Column="0"
47+
Margin="0" Padding="2"
4948
ItemsSource="{Binding DownloadableList}"
50-
SelectedItem="{Binding SelectedDownloadable}"
51-
SelectionChanged="OnDownloadableListSelectionChanged"
49+
SelectionMode="Extended"
50+
misc:DataGridSelectedItemsProperty.SelectedItems="{Binding SelectedDownloads}"
5251
GridLinesVisibility="Horizontal"
5352
IsReadOnly="True"
5453
CornerRadius="4"
Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using Avalonia.Controls;
2-
using Common.Entities;
32

43
namespace Avalonia.Desktop.Controls;
54

@@ -9,12 +8,4 @@ public DownloadsControl()
98
{
109
InitializeComponent();
1110
}
12-
13-
private void OnDownloadableListSelectionChanged(object? sender, SelectionChangedEventArgs e)
14-
{
15-
foreach (var a in DownloadableList.SelectedItems)
16-
{
17-
_ = DownloadableList.SelectedItems.Add((DownloadableAddonEntity)a);
18-
}
19-
}
2011
}

src/Avalonia.Desktop/MainWindow.axaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
MinWidth="1300"
1717
MinHeight="700"
1818
ExtendClientAreaToDecorationsHint="True"
19-
Background="{DynamicResource Background}">
19+
Background="{DynamicResource Background}"
20+
ClipToBounds="True">
2021

2122
<Window.Resources>
2223
<ResourceDictionary>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using Avalonia.Controls;
2+
using Avalonia.Data;
3+
using System.Collections;
4+
5+
namespace Avalonia.Desktop.Misc;
6+
7+
public sealed class DataGridSelectedItemsProperty
8+
{
9+
public static readonly AttachedProperty<IList?> SelectedItemsProperty =
10+
AvaloniaProperty.RegisterAttached<DataGridSelectedItemsProperty, DataGrid, IList?>(
11+
"SelectedItems",
12+
defaultBindingMode: BindingMode.TwoWay);
13+
14+
public static IList? GetSelectedItems(AvaloniaObject obj) => obj.GetValue(SelectedItemsProperty);
15+
16+
public static void SetSelectedItems(AvaloniaObject obj, IList? value) => obj.SetValue(SelectedItemsProperty, value);
17+
18+
// 2) When the attached property is set, hook/unhook SelectionChanged
19+
static DataGridSelectedItemsProperty()
20+
{
21+
_ = SelectedItemsProperty.Changed.AddClassHandler<DataGrid>((grid, e) =>
22+
{
23+
grid.SelectionChanged -= OnSelectionChanged;
24+
25+
if (e.NewValue is IList list)
26+
{
27+
list.Clear();
28+
29+
foreach (var item in grid.SelectedItems)
30+
{
31+
_ = list.Add(item);
32+
}
33+
34+
grid.SelectionChanged += OnSelectionChanged;
35+
}
36+
});
37+
}
38+
39+
private static void OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
40+
{
41+
if (sender is DataGrid grid &&
42+
GetSelectedItems(grid) is IList list)
43+
{
44+
list.Clear();
45+
46+
foreach (var item in grid.SelectedItems)
47+
{
48+
_ = list.Add(item);
49+
}
50+
}
51+
}
52+
}

src/Avalonia.Desktop/ViewModels/DownloadsViewModel.cs

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using CommunityToolkit.Mvvm.Input;
1111
using Microsoft.Extensions.Logging;
1212
using System.Collections.Immutable;
13+
using System.Collections.ObjectModel;
1314

1415
namespace Avalonia.Desktop.ViewModels;
1516

@@ -26,21 +27,14 @@ public sealed partial class DownloadsViewModel : ObservableObject
2627

2728
#region Binding Properties
2829

29-
[ObservableProperty]
30-
[NotifyCanExecuteChangedFor(nameof(CancelDownloadCommand))]
31-
private bool _isInProgress;
32-
33-
[ObservableProperty]
34-
private bool _hasUpdates;
35-
3630
/// <summary>
3731
/// List of downloadable addons
3832
/// </summary>
39-
public ImmutableList<IDownloadableAddon> DownloadableList
33+
public ImmutableList<DownloadableAddonEntity> DownloadableList
4034
{
4135
get
4236
{
43-
IEnumerable<IDownloadableAddon> result;
37+
IEnumerable<DownloadableAddonEntity> result;
4438

4539
if (FilterSelectedItem is FilterItemEnum.All)
4640
{
@@ -85,29 +79,10 @@ public ImmutableList<IDownloadableAddon> DownloadableList
8579
/// </summary>
8680
public float ProgressBarValue { get; set; }
8781

88-
/// <summary>
89-
/// Currently selected downloadable campaign, map or mod
90-
/// </summary>
91-
[ObservableProperty]
92-
[NotifyPropertyChangedFor(nameof(SelectedDownloadableDescription))]
93-
[NotifyPropertyChangedFor(nameof(DownloadButtonText))]
94-
[NotifyCanExecuteChangedFor(nameof(DownloadAddonCommand))]
95-
private DownloadableAddonEntity? _selectedDownloadable;
96-
97-
/// <summary>
98-
/// Currently selected downloadable campaign, map or mod
99-
/// </summary>
100-
[ObservableProperty]
101-
[NotifyPropertyChangedFor(nameof(DownloadButtonText))]
102-
private List<DownloadableAddonEntity>? _selectedDownloadableList;
103-
104-
[ObservableProperty]
105-
private string _progressMessage = string.Empty;
106-
10782
/// <summary>
10883
/// Description of the selected addon
10984
/// </summary>
110-
public string SelectedDownloadableDescription => SelectedDownloadable is null ? string.Empty : SelectedDownloadable.ToMarkdownString();
85+
public string SelectedDownloadableDescription => string.Empty; /*SelectedDownloadable is null ? string.Empty : SelectedDownloadable.ToMarkdownString();*/
11186

11287
/// <summary>
11388
/// Text of the download button
@@ -116,19 +91,35 @@ public string DownloadButtonText
11691
{
11792
get
11893
{
119-
if (SelectedDownloadableList is null or [])
94+
if (SelectedDownloads is null or [])
12095
{
12196
return "Download";
12297
}
12398
else
12499
{
125-
return $"Download ({SelectedDownloadableList.Sum(x => x.FileSize).ToSizeString()})";
100+
return $"Download ({SelectedDownloads.Sum(x => x.FileSize).ToSizeString()})";
126101
}
127102
}
128103
}
129104

130105
public List<FilterItemEnum> FilterItems => [.. Enum.GetValues<FilterItemEnum>()];
131106

107+
[ObservableProperty]
108+
[NotifyCanExecuteChangedFor(nameof(CancelDownloadCommand))]
109+
private bool _isInProgress;
110+
111+
[ObservableProperty]
112+
private bool _hasUpdates;
113+
114+
/// <summary>
115+
/// Currently selected downloadable campaigns, maps or mods
116+
/// </summary>
117+
[ObservableProperty]
118+
private ObservableCollection<DownloadableAddonEntity> _selectedDownloads = [];
119+
120+
[ObservableProperty]
121+
private string _progressMessage = string.Empty;
122+
132123
[ObservableProperty]
133124
[NotifyPropertyChangedFor(nameof(DownloadableList))]
134125
private FilterItemEnum _filterSelectedItem;
@@ -160,6 +151,7 @@ ILogger logger
160151

161152
_installedAddonsProvider.AddonsChangedEvent += OnAddonChanged;
162153
_downloadableAddonsProvider.AddonDownloadedEvent += OnAddonChanged;
154+
SelectedDownloads.CollectionChanged += OnSelectedDownloadsChanged;
163155
}
164156

165157

@@ -204,7 +196,7 @@ private async Task UpdateAsync(bool? createNew)
204196

205197
OnPropertyChanged(nameof(DownloadableList));
206198

207-
SelectedDownloadable = null;
199+
SelectedDownloads.Clear();
208200
}
209201
catch (Exception ex)
210202
{
@@ -223,14 +215,17 @@ private async Task UpdateAsync(bool? createNew)
223215
[RelayCommand(CanExecute = nameof(DownloadSelectedAddonCanExecute))]
224216
private async Task DownloadAddon()
225217
{
218+
DownloadableAddonEntity? _currentDownloadable = null;
219+
226220
try
227221
{
228-
if (SelectedDownloadableList is null or [])
222+
223+
if (SelectedDownloads is null or [])
229224
{
230225
return;
231226
}
232227

233-
List<DownloadableAddonEntity> filesToDownload = [.. SelectedDownloadableList];
228+
List<DownloadableAddonEntity> filesToDownload = [.. SelectedDownloads];
234229

235230
IsInProgress = true;
236231

@@ -242,6 +237,8 @@ private async Task DownloadAddon()
242237

243238
foreach (var item in filesToDownload)
244239
{
240+
_currentDownloadable = item;
241+
245242
if (_cancellationTokenSource.IsCancellationRequested)
246243
{
247244
ThrowHelper.ThrowOperationCanceledException();
@@ -268,7 +265,7 @@ private async Task DownloadAddon()
268265
NotificationType.Error
269266
);
270267

271-
_logger.LogCritical(ex, $"=== Error while downloading addon {SelectedDownloadable?.DownloadUrl} ===");
268+
_logger.LogCritical(ex, $"=== Error while downloading addon {_currentDownloadable?.DownloadUrl} ===");
272269
}
273270
finally
274271
{
@@ -279,7 +276,7 @@ private async Task DownloadAddon()
279276
ProgressMessage = string.Empty;
280277
}
281278
}
282-
private bool DownloadSelectedAddonCanExecute => SelectedDownloadable is not null;
279+
private bool DownloadSelectedAddonCanExecute => true; /*SelectedDownloadable is not null;*/
283280

284281

285282
/// <summary>
@@ -319,6 +316,13 @@ private void OnAddonChanged(IGame game, AddonTypeEnum? addonType)
319316
OnPropertyChanged(nameof(DownloadableList));
320317
}
321318

319+
private void OnSelectedDownloadsChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
320+
{
321+
OnPropertyChanged(nameof(SelectedDownloadableDescription));
322+
OnPropertyChanged(nameof(DownloadButtonText));
323+
DownloadAddonCommand.NotifyCanExecuteChanged();
324+
}
325+
322326
public enum FilterItemEnum
323327
{
324328
All,

src/Common.Client/Interfaces/IDownloadableAddonsProvider.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
using Common.Enums;
1+
using Common.Entities;
2+
using Common.Enums;
23
using Common.Helpers;
3-
using Common.Interfaces;
44
using System.Collections.Immutable;
55

66
namespace Common.Client.Interfaces;
@@ -19,13 +19,13 @@ public interface IDownloadableAddonsProvider
1919
/// </summary>
2020
/// <param name="addon">Addon</param>
2121
/// <param name="cancellationToken">Cancellation token</param>
22-
Task DownloadAddonAsync(IDownloadableAddon addon, CancellationToken cancellationToken);
22+
Task DownloadAddonAsync(DownloadableAddonEntity addon, CancellationToken cancellationToken);
2323

2424
/// <summary>
2525
/// Get a list of downloadable addons
2626
/// </summary>
2727
/// <param name="addonType">Addon type</param>
28-
ImmutableList<IDownloadableAddon> GetDownloadableAddons(AddonTypeEnum addonType);
28+
ImmutableList<DownloadableAddonEntity> GetDownloadableAddons(AddonTypeEnum addonType);
2929

3030
/// <summary>
3131
/// Create downloadable addons cache

src/Common.Common/Entities/DownloadableAddonEntity.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
using Common.Enums;
22
using Common.Helpers;
3-
using Common.Interfaces;
43
using System.Text;
54
using System.Text.Json.Serialization;
65

76
namespace Common.Entities;
87

9-
public sealed class DownloadableAddonEntity : IDownloadableAddon
8+
public sealed class DownloadableAddonEntity
109
{
1110
[JsonPropertyName("Id")]
1211
public required string Id { get; set; }

src/Common.Common/Interfaces/IDownloadableAddon.cs

Lines changed: 0 additions & 28 deletions
This file was deleted.

0 commit comments

Comments
 (0)