Skip to content

Commit 07b7b03

Browse files
authored
Merge pull request #2841 from Nexus-Mods/feat/toggle-commands-open-collection
Support opening Collection page from collection EnabledStates buttons
2 parents e116107 + 9d0bc19 commit 07b7b03

File tree

5 files changed

+176
-70
lines changed

5 files changed

+176
-70
lines changed

src/NexusMods.App.UI/Pages/CollectionDownload/CollectionComponents.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ protected override void Dispose(bool disposing)
116116
_isDisposed = true;
117117
if (disposing)
118118
{
119-
Disposable.Dispose(CommandDownload, IsDownloading, _canDownload, _buttonText, _downloadStatus, _activationDisposable);
119+
Disposable.Dispose(_activationDisposable,IsDownloading, CommandDownload, _canDownload, _buttonText, _downloadStatus);
120120
}
121121
}
122122

@@ -184,7 +184,7 @@ protected override void Dispose(bool disposing)
184184
_isDisposed = true;
185185
if (disposing)
186186
{
187-
Disposable.Dispose(CommandOpenModal, ButtonText, _activationDisposable);
187+
Disposable.Dispose(_activationDisposable, CommandOpenModal, ButtonText);
188188
}
189189
}
190190

@@ -239,7 +239,7 @@ protected override void Dispose(bool disposing)
239239

240240
if (disposing)
241241
{
242-
Disposable.Dispose(CommandInstall, _canInstall, _buttonText, _isInstalled, _activationDisposable);
242+
Disposable.Dispose(_activationDisposable, CommandInstall, _canInstall, _buttonText, _isInstalled);
243243
}
244244
}
245245

src/NexusMods.App.UI/Pages/LoadoutPage/CollectionLoadoutViewModel.cs

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -184,31 +184,25 @@ public CollectionLoadoutViewModel(
184184

185185
Adapter.MessageSubject.SubscribeAwait(async (message, _) =>
186186
{
187-
var toggleableItems = message.Ids
188-
.Select(loadoutItemId => LoadoutItem.Load(connection.Db, loadoutItemId))
189-
.Where(item => !(NexusCollectionItemLoadoutGroup.IsRequired.TryGetValue(item, out var isRequired) && isRequired))
190-
.ToArray();
191-
192-
if (toggleableItems.Length == 0) return;
193-
194-
// We only enable if all items are disabled, otherwise we disable
195-
var shouldEnable = toggleableItems.All(loadoutItem => loadoutItem.IsDisabled);
196-
197-
using var tx = connection.BeginTransaction();
187+
// Toggle item state
188+
if (message.IsT0){
189+
await LoadoutViewModel.ToggleItemEnabledState(message.AsT0.Ids, connection);
190+
return;
191+
}
198192

199-
foreach (var id in toggleableItems)
193+
// Open collection
194+
if (message.IsT1)
200195
{
201-
if (shouldEnable)
202-
{
203-
tx.Retract(id, LoadoutItem.Disabled, Null.Instance);
204-
}
205-
else
206-
{
207-
tx.Add(id, LoadoutItem.Disabled, Null.Instance);
208-
}
196+
var data = message.AsT1;
197+
LoadoutViewModel.OpenItemCollectionPage(
198+
data.Ids,
199+
data.NavigationInformation,
200+
pageContext.LoadoutId,
201+
GetWorkspaceController(),
202+
connection
203+
);
204+
return;
209205
}
210-
211-
await tx.Commit();
212206

213207
}, awaitOperation: AwaitOperation.Parallel, configureAwait: false).AddTo(disposables);
214208
});

src/NexusMods.App.UI/Pages/LoadoutPage/LoadoutComponents.cs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using NexusMods.Abstractions.UI;
55
using NexusMods.Abstractions.UI.Extensions;
66
using NexusMods.App.UI.Controls;
7+
using NexusMods.App.UI.Controls.Navigation;
78
using NexusMods.App.UI.Extensions;
89
using NexusMods.MnemonicDB.Abstractions;
910
using ObservableCollections;
@@ -42,12 +43,12 @@ protected override void Dispose(bool disposing)
4243
{
4344
if (!_isDisposed)
4445
{
46+
_isDisposed = true;
47+
4548
if (disposing)
4649
{
4750
Disposable.Dispose(_idsObservable ?? Disposable.Empty);
4851
}
49-
50-
_isDisposed = true;
5152
}
5253

5354
base.Dispose(disposing);
@@ -56,16 +57,22 @@ protected override void Dispose(bool disposing)
5657

5758
public sealed class ParentCollectionDisabled : ReactiveR3Object, IItemModelComponent<ParentCollectionDisabled>, IComparable<ParentCollectionDisabled>
5859
{
60+
public ReactiveCommand<NavigationInformation, NavigationInformation> ButtonCommand { get; } = new(info => info);
61+
5962
public int CompareTo(ParentCollectionDisabled? other) => 0;
6063
}
6164

6265
public sealed class LockedEnabledState : ReactiveR3Object, IItemModelComponent<LockedEnabledState>, IComparable<LockedEnabledState>
6366
{
67+
public ReactiveCommand<NavigationInformation, NavigationInformation> ButtonCommand { get; } = new(info => info);
68+
6469
public int CompareTo(LockedEnabledState? other) => 0;
6570
}
6671

6772
public sealed class MixLockedAndParentDisabled : ReactiveR3Object, IItemModelComponent<MixLockedAndParentDisabled>, IComparable<MixLockedAndParentDisabled>
6873
{
74+
public ReactiveCommand<NavigationInformation, NavigationInformation> ButtonCommand { get; } = new(info => info);
75+
6976
public int CompareTo(MixLockedAndParentDisabled? other) => 0;
7077
}
7178

@@ -90,8 +97,7 @@ public int CompareTo(EnabledStateToggle? other)
9097

9198
private readonly IDisposable _activationDisposable;
9299

93-
public EnabledStateToggle(
94-
ValueComponent<bool?> valueComponent)
100+
public EnabledStateToggle(ValueComponent<bool?> valueComponent)
95101
{
96102
_valueComponent = valueComponent;
97103

@@ -106,12 +112,12 @@ protected override void Dispose(bool disposing)
106112
{
107113
if (!_isDisposed)
108114
{
115+
_isDisposed = true;
116+
109117
if (disposing)
110118
{
111119
Disposable.Dispose(_activationDisposable, _valueComponent);
112-
}
113-
114-
_isDisposed = true;
120+
}
115121
}
116122

117123
base.Dispose(disposing);

src/NexusMods.App.UI/Pages/LoadoutPage/LoadoutViewModel.cs

Lines changed: 136 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
using NexusMods.MnemonicDB.Abstractions.ElementComparers;
2121
using NexusMods.MnemonicDB.Abstractions.TxFunctions;
2222
using ObservableCollections;
23+
using OneOf;
2324
using R3;
2425
using ReactiveUI;
2526
using ReactiveUI.Fody.Helpers;
@@ -150,38 +151,21 @@ public LoadoutViewModel(IWindowManager windowManager, IServiceProvider servicePr
150151
Adapter.Activate().AddTo(disposables);
151152

152153
Adapter.MessageSubject.SubscribeAwait(async (message, _) =>
153-
{
154-
var toggleableItems = message.Ids
155-
.Select(loadoutItemId => LoadoutItem.Load(connection.Db, loadoutItemId))
156-
// Exclude collection required items
157-
.Where(item => !(NexusCollectionItemLoadoutGroup.IsRequired.TryGetValue(item, out var isRequired) && isRequired))
158-
// Exclude items that are part of a collection that is disabled
159-
.Where(item => !(item.Parent.TryGetAsCollectionGroup(out var collectionGroup)
160-
&& collectionGroup.AsLoadoutItemGroup().AsLoadoutItem().IsDisabled)
161-
)
162-
.ToArray();
163-
164-
if (toggleableItems.Length == 0) return;
165-
166-
// We only enable if all items are disabled, otherwise we disable
167-
var shouldEnable = toggleableItems.All(loadoutItem => loadoutItem.IsDisabled);
168-
169-
using var tx = connection.BeginTransaction();
154+
{
155+
// Toggle item state
156+
if (message.IsT0){
157+
await ToggleItemEnabledState(message.AsT0.Ids, connection);
158+
return;
159+
}
170160

171-
foreach (var id in toggleableItems)
161+
// Open collection
162+
if (message.IsT1)
172163
{
173-
if (shouldEnable)
174-
{
175-
tx.Retract(id, LoadoutItem.Disabled, Null.Instance);
176-
}
177-
else
178-
{
179-
tx.Add(id, LoadoutItem.Disabled, Null.Instance);
180-
}
164+
var data = message.AsT1;
165+
OpenItemCollectionPage(data.Ids, data.NavigationInformation, loadoutId, GetWorkspaceController(), connection);
166+
return;
181167
}
182168

183-
await tx.Commit();
184-
185169
}, awaitOperation: AwaitOperation.Parallel, configureAwait: false).AddTo(disposables);
186170

187171
// Compute the target group for the ViewFilesCommand
@@ -208,6 +192,87 @@ public LoadoutViewModel(IWindowManager windowManager, IServiceProvider servicePr
208192
});
209193
}
210194

195+
internal static async Task ToggleItemEnabledState(LoadoutItemId[] ids, IConnection connection)
196+
{
197+
var toggleableItems = ids
198+
.Select(loadoutItemId => LoadoutItem.Load(connection.Db, loadoutItemId))
199+
// Exclude collection required items
200+
.Where(item => !(NexusCollectionItemLoadoutGroup.IsRequired.TryGetValue(item, out var isRequired) && isRequired))
201+
// Exclude items that are part of a collection that is disabled
202+
.Where(item => !(item.Parent.TryGetAsCollectionGroup(out var collectionGroup)
203+
&& collectionGroup.AsLoadoutItemGroup().AsLoadoutItem().IsDisabled)
204+
)
205+
.ToArray();
206+
207+
if (toggleableItems.Length == 0) return;
208+
209+
// We only enable if all items are disabled, otherwise we disable
210+
var shouldEnable = toggleableItems.All(loadoutItem => loadoutItem.IsDisabled);
211+
212+
using var tx = connection.BeginTransaction();
213+
214+
foreach (var id in toggleableItems)
215+
{
216+
if (shouldEnable)
217+
{
218+
tx.Retract(id, LoadoutItem.Disabled, Null.Instance);
219+
}
220+
else
221+
{
222+
tx.Add(id, LoadoutItem.Disabled, Null.Instance);
223+
}
224+
}
225+
226+
await tx.Commit();
227+
}
228+
229+
internal static void OpenItemCollectionPage(
230+
LoadoutItemId[] ids,
231+
NavigationInformation navInfo,
232+
LoadoutId loadoutId,
233+
IWorkspaceController workspaceController,
234+
IConnection connection)
235+
{
236+
if (ids.Length == 0) return;
237+
238+
// Open the collection page for the first item
239+
var firstItemId = ids.First();
240+
241+
var parentGroup = LoadoutItem.Load(connection.Db, firstItemId).Parent;
242+
if (!parentGroup.TryGetAsCollectionGroup(out var collectionGroup)) return;
243+
244+
if (collectionGroup.TryGetAsNexusCollectionLoadoutGroup(out var nexusCollectionGroup))
245+
{
246+
var nexusCollPageData = new PageData
247+
{
248+
FactoryId = CollectionLoadoutPageFactory.StaticId,
249+
Context = new CollectionLoadoutPageContext
250+
{
251+
LoadoutId = loadoutId,
252+
GroupId = nexusCollectionGroup.Id,
253+
},
254+
};
255+
var nexusPageBehavior = workspaceController.GetOpenPageBehavior(nexusCollPageData, navInfo);
256+
workspaceController.OpenPage(workspaceController.ActiveWorkspaceId, nexusCollPageData, nexusPageBehavior);
257+
258+
return;
259+
}
260+
261+
var pageData = new PageData
262+
{
263+
FactoryId = LoadoutPageFactory.StaticId,
264+
Context = new LoadoutPageContext
265+
{
266+
LoadoutId = loadoutId,
267+
GroupScope = collectionGroup.AsLoadoutItemGroup().LoadoutItemGroupId,
268+
},
269+
};
270+
var behavior = workspaceController.GetOpenPageBehavior(pageData, navInfo);
271+
workspaceController.OpenPage(workspaceController.ActiveWorkspaceId, pageData, behavior);
272+
273+
return;
274+
}
275+
211276
private static async Task ToggleCollectionGroup(Optional<LoadoutItemGroupId> collectionGroupId, bool shouldEnable, IConnection connection)
212277
{
213278
if (!collectionGroupId.HasValue) return;
@@ -229,13 +294,16 @@ private static IEnumerable<LoadoutItemId> GetLoadoutItemIds(CompositeItemModel<E
229294
}
230295
}
231296

232-
public readonly record struct ToggleEnableState(LoadoutItemId[] Ids, bool ShouldEnable);
297+
public readonly record struct ToggleEnableStateMessage(LoadoutItemId[] Ids);
298+
299+
public readonly record struct OpenCollectionMessage(LoadoutItemId[] Ids, NavigationInformation NavigationInformation);
300+
233301

234302
public class LoadoutTreeDataGridAdapter :
235303
TreeDataGridAdapter<CompositeItemModel<EntityId>, EntityId>,
236-
ITreeDataGirdMessageAdapter<ToggleEnableState>
304+
ITreeDataGirdMessageAdapter<OneOf<ToggleEnableStateMessage, OpenCollectionMessage>>
237305
{
238-
public Subject<ToggleEnableState> MessageSubject { get; } = new();
306+
public Subject<OneOf<ToggleEnableStateMessage, OpenCollectionMessage>> MessageSubject { get; } = new();
239307

240308
private readonly ILoadoutDataProvider[] _loadoutDataProviders;
241309
private readonly LoadoutFilter _loadoutFilter;
@@ -261,11 +329,45 @@ protected override void BeforeModelActivationHook(CompositeItemModel<EntityId> m
261329
factory: static (self, itemModel, component) => component.CommandToggle.Subscribe((self, itemModel, component), static (_, tuple) =>
262330
{
263331
var (self, itemModel, component) = tuple;
264-
var isEnabled = component.Value.Value;
265332
var ids = GetLoadoutItemIds(itemModel).ToArray();
266-
var shouldEnable = !isEnabled ?? false;
267333

268-
self.MessageSubject.OnNext(new ToggleEnableState(ids, shouldEnable));
334+
self.MessageSubject.OnNext(new ToggleEnableStateMessage(ids));
335+
})
336+
);
337+
338+
model.SubscribeToComponentAndTrack<LoadoutComponents.ParentCollectionDisabled, LoadoutTreeDataGridAdapter>(
339+
key: LoadoutColumns.EnabledState.ParentCollectionDisabledComponentKey,
340+
state: this,
341+
factory: static (self, itemModel, component) => component.ButtonCommand.Subscribe((self, itemModel, component), static (navInfo, tuple) =>
342+
{
343+
var (self, itemModel, component) = tuple;
344+
var ids = GetLoadoutItemIds(itemModel).ToArray();
345+
346+
self.MessageSubject.OnNext(new OpenCollectionMessage(ids, navInfo));
347+
})
348+
);
349+
350+
model.SubscribeToComponentAndTrack<LoadoutComponents.LockedEnabledState, LoadoutTreeDataGridAdapter>(
351+
key: LoadoutColumns.EnabledState.LockedEnabledStateComponentKey,
352+
state: this,
353+
factory: static (self, itemModel, component) => component.ButtonCommand.Subscribe((self, itemModel, component), static (navInfo, tuple) =>
354+
{
355+
var (self, itemModel, component) = tuple;
356+
var ids = GetLoadoutItemIds(itemModel).ToArray();
357+
358+
self.MessageSubject.OnNext(new OpenCollectionMessage(ids, navInfo));
359+
})
360+
);
361+
362+
model.SubscribeToComponentAndTrack<LoadoutComponents.MixLockedAndParentDisabled, LoadoutTreeDataGridAdapter>(
363+
key: LoadoutColumns.EnabledState.MixLockedAndParentDisabledComponentKey,
364+
state: this,
365+
factory: static (self, itemModel, component) => component.ButtonCommand.Subscribe((self, itemModel, component), static (navInfo, tuple) =>
366+
{
367+
var (self, itemModel, component) = tuple;
368+
var ids = GetLoadoutItemIds(itemModel).ToArray();
369+
370+
self.MessageSubject.OnNext(new OpenCollectionMessage(ids, navInfo));
269371
})
270372
);
271373
}

0 commit comments

Comments
 (0)