Skip to content

Commit

Permalink
Merge pull request #1323 from unoplatform/dev/dr/selectionTracking
Browse files Browse the repository at this point in the history
fix(mvux): Fix misc selection issues
  • Loading branch information
dr1rrb authored Mar 28, 2023
2 parents cbc8010 + b4cd152 commit d64f0f1
Show file tree
Hide file tree
Showing 18 changed files with 459 additions and 226 deletions.
5 changes: 5 additions & 0 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,13 @@
</PropertyGroup>

<PropertyGroup Condition="$(_IsUWP)">
<DefineConstants>$(DefineConstants);__WINDOWS__</DefineConstants>
<TargetPlatformVersion>10.0.19041.0</TargetPlatformVersion>
</PropertyGroup>

<PropertyGroup Condition="$(_IsWinUI)">
<DefineConstants>$(DefineConstants);__WINDOWS__</DefineConstants>
</PropertyGroup>

<PropertyGroup>
<IsCoreProject>False</IsCoreProject>
Expand Down
8 changes: 4 additions & 4 deletions src/Uno.Extensions.Reactive.Testing/ConstraintParts/Items.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ public static ItemsChanged Remove<T>(int at, params T[] items)
public static ItemsChanged Remove<T>(int at, IEnumerable<T> items)
=> ItemsChanged.Remove(at, items);

public static ItemsChanged Replace<T>(int at, IEnumerable<T> oldItems, IEnumerable<T> newItems)
=> ItemsChanged.Replace(at, oldItems, newItems);
public static ItemsChanged Replace<T>(int at, IEnumerable<T> oldItems, IEnumerable<T> newItems, bool isReplaceOfSameEntities = true)
=> ItemsChanged.Replace(at, oldItems, newItems, isReplaceOfSameEntities);

public static ItemsChanged Replace<T>(int at, T oldItem, T newItem)
=> ItemsChanged.Replace(at, oldItem, newItem);
public static ItemsChanged Replace<T>(int at, T oldItem, T newItem, bool isReplaceOfSameEntity = true)
=> ItemsChanged.Replace(at, oldItem, newItem, isReplaceOfSameEntity);

public static ItemsChanged Move<T>(int from, int to, params T[] items)
=> ItemsChanged.Move(from, to, items);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ public static ItemsChanged Remove<T>(int index, params T[] items)
public static ItemsChanged Remove<T>(int index, IEnumerable<T> items)
=> new(RichNotifyCollectionChangedEventArgs.RemoveSome<T>(items.ToList(), index));

public static ItemsChanged Replace<T>(int index, IEnumerable<T> oldItems, IEnumerable<T> newItems)
=> new(RichNotifyCollectionChangedEventArgs.ReplaceSome<T>(oldItems.ToList(), newItems.ToList(), index));
public static ItemsChanged Replace<T>(int index, IEnumerable<T> oldItems, IEnumerable<T> newItems, bool isReplaceOfSameEntities)
=> new(RichNotifyCollectionChangedEventArgs.ReplaceSome<T>(oldItems.ToList(), newItems.ToList(), index, isReplaceOfSameEntities));

public static ItemsChanged Replace<T>(int index, T oldItem, T newItem)
=> new(RichNotifyCollectionChangedEventArgs.Replace<T>(oldItem, newItem, index));
public static ItemsChanged Replace<T>(int index, T oldItem, T newItem, bool isReplaceOfSameEntity)
=> new(RichNotifyCollectionChangedEventArgs.Replace<T>(oldItem, newItem, index, isReplaceOfSameEntity));

public static ItemsChanged Move<T>(int oldIndex, int newIndex, params T[] items)
=> new(RichNotifyCollectionChangedEventArgs.MoveSome<T>(items.ToList(), oldIndex, newIndex));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
#define __SKIA__

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
Expand All @@ -7,7 +9,9 @@
using Windows.Foundation;
using Microsoft.UI.Xaml.Automation.Peers;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Data;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Uno.Extensions.Equality;
using Uno.Extensions.Reactive.Testing;
using Uno.UI.RuntimeTests;

Expand All @@ -19,9 +23,11 @@ public partial class Given_BindableCollection_Selection : FeedTests
{
public partial class Given_BindableCollection_Selection_Model
{
public IListState<int> Items => ListState.Value(this, () => ImmutableList.Create(41, 42, 43));
public IListState<MyItem> Items => ListState.Value(this, () => ImmutableList.Create<MyItem>(new(41), new(42), new(43)));
}

public partial record MyItem([property:Key] int Value, int Version = 1);

[TestMethod]
[InjectedPointer(PointerDeviceType.Mouse)]
#if !__SKIA__
Expand All @@ -33,7 +39,7 @@ public async Task When_SelectSingleFromView_ListView()

InputInjectorHelper.Current.Tap(items[1]);

await UIHelper.WaitFor(async ct => await vm.Items.GetSelectedItem(ct) == 42, CT);
await UIHelper.WaitFor(async ct => (await vm.Items.GetSelectedItem(ct))?.Value == 42, CT);
}

[TestMethod]
Expand All @@ -50,7 +56,37 @@ public async Task When_SelectMultipleFromView_ListView()

await UIHelper.WaitFor(async ct =>
{
return (await vm.Items.GetSelectedItems(ct)).SequenceEqual(new[] { 41, 42 });
return (await vm.Items.GetSelectedItems(ct)).SequenceEqual(new MyItem[] { new(41), new(42) });
}, CT);
}

[TestMethod]
[InjectedPointer(PointerDeviceType.Mouse)]
#if !__SKIA__
[Ignore("Pointer injection not supported yet on this platform")]
#endif
public async Task When_EditSingleSelectedItem_Then_SelectionPreserved()
{
var (vm, lv, items) = await SetupListView(ListViewSelectionMode.Single);

InputInjectorHelper.Current.Tap(items[1]);

await UIHelper.WaitFor(async ct =>
{
// Selection is preserved on ...
return lv.SelectedItem is MyItem { Value: 42 } // ... the ListView ...
&& ((ISelectionInfo)lv.ItemsSource).IsSelected(1) // ... the BindableCollection ...
&& await vm.Items.GetSelectedItem(ct) is { Value: 42 }; // ... and the Feed!
}, CT);

await vm.Model.Items.Update(items => items.Replace(items[1], items[1] with { Version = 2 }), CT);

await UIHelper.WaitFor(async ct =>
{
// Selection is preserved on ...
return lv.SelectedItem is MyItem { Value: 42, Version: 2 } // ... the ListView ...
&& ((ISelectionInfo)lv.ItemsSource).IsSelected(1) // ... the BindableCollection ...
&& await vm.Items.GetSelectedItem(ct) is { Value: 42, Version: 2 }; // ... and the Feed!
}, CT);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,23 +182,24 @@ async ValueTask SetSelected(SelectionInfo info, CancellationToken ct)
=> await state.UpdateMessage(msg => msg.Selected(info).Set(BindableViewModelBase.BindingSource, collection), ct);

async ValueTask Edit(Func<IDifferentialCollectionNode, IDifferentialCollectionNode> change, CancellationToken ct)
=> await state.UpdateMessage(msg =>
{
// Note: The change might have been computed on an older version of the collection
// We are NOT validating this. It means that we cou;d get an out-of-range for remove for instance.

var currentItems = msg.CurrentData.SomeOrDefault();
var currentHead = currentItems switch
=> await state.UpdateMessage(
msg =>
{
IDifferentialCollection diffCollection => diffCollection.Head,
null => new EmptyNode(),
_ => new ResetNode<T>(currentItems)
};
var newHead = change(currentHead);
var newItems = new DifferentialImmutableList<T>(newHead) as IImmutableList<T>;

msg.Data(newItems).Set(BindableViewModelBase.BindingSource, collection);
},
// Note: The change might have been computed on an older version of the collection
// We are NOT validating this. It means that we cou;d get an out-of-range for remove for instance.

var currentItems = msg.CurrentData.SomeOrDefault();
var currentHead = currentItems switch
{
IDifferentialCollection diffCollection => diffCollection.Head,
null => new EmptyNode(),
_ => new ResetNode<T>(currentItems)
};
var newHead = change(currentHead);
var newItems = new DifferentialImmutableList<T>(newHead) as IImmutableList<T>;

msg.Data(newItems).Set(BindableViewModelBase.BindingSource, collection);
},
ct);

return collection;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public BranchStrategy(DataStructure dataStructure, uint dataLevel, CollectionAna

// Init the flat tracking view (ie. the flatten view of the groups that can be consumed directly by the ICollectionView properties)
var flatCollectionChanged = new FlatCollectionChangedFacet(() => view ?? throw new InvalidOperationException("The owner provider must be resolved lazily!"));
var flatSelectionFacet = new SelectionFacet(source, () => view ?? throw new InvalidOperationException("The owner provider must be resolved lazily!"));
var flatSelectionFacet = new SelectionFacet(source, flatCollectionChanged, () => view ?? throw new InvalidOperationException("The owner provider must be resolved lazily!"));
var flatPaginationFacet = new PaginationFacet(source, flatCollectionChanged, extendedPropertiesFacet);

// Init the groups tracking
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public LeafStrategy(DataStructure dataStructure, CollectionAnalyzer diffAnalyzer
if (_isRoot) // I.e. Collection is not grouped
{
var paginationFacet = new PaginationFacet(source, collectionChangedFacet, extendedPropertiesFacet);
var selectionFacet = new SelectionFacet(source, () => view ?? throw new InvalidOperationException("The owner provider must be resolved lazily!"));
var selectionFacet = new SelectionFacet(source, collectionChangedFacet, () => view ?? throw new InvalidOperationException("The owner provider must be resolved lazily!"));
var editionFacet = new EditionFacet(source, collectionFacet);

view = new BasicView(collectionFacet, collectionChangedFacet, extendedPropertiesFacet, selectionFacet, paginationFacet, editionFacet);
Expand Down
Loading

0 comments on commit d64f0f1

Please sign in to comment.