Skip to content

Commit

Permalink
Merge pull request #30 from Cysharp/hadashiA/remove-change-kind
Browse files Browse the repository at this point in the history
Add a dedicated event type for SynchronizedView
  • Loading branch information
neuecc authored Feb 22, 2024
2 parents bdbb5c0 + f02eba2 commit f5bf911
Show file tree
Hide file tree
Showing 27 changed files with 342 additions and 384 deletions.
24 changes: 15 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -278,15 +278,15 @@ public class SampleScript : MonoBehaviour
this.root = root;
}

public void OnCollectionChanged(ChangedKind changedKind, int value, GameObject view, in NotifyCollectionChangedEventArgs<int> eventArgs)
public void OnCollectionChanged(in SynchronizedViewChangedEventArgs<int, GameObject> eventArgs)
{
if (changedKind == ChangedKind.Add)
if (eventArgs.Action == NotifyCollectionChangedAction.Add)
{
view.transform.SetParent(root.transform);
eventArgs.NewView.transform.SetParent(root.transform);
}
else if (changedKind == ChangedKind.Remove)
else if (NotifyCollectionChangedAction.Remove)
{
GameObject.Destroy(view);
GameObject.Destroy(eventArgs.OldView);
}
}

Expand Down Expand Up @@ -336,7 +336,7 @@ public interface ISynchronizedView<T, TView> : IReadOnlyCollection<(T Value, TVi

void AttachFilter(ISynchronizedViewFilter<T, TView> filter);
void ResetFilter(Action<T, TView>? resetAction);
INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged();
INotifyCollectionChangedSynchronizedView<T, TView> ToNotifyCollectionChanged();
}
```

Expand Down Expand Up @@ -385,12 +385,18 @@ public interface ISynchronizedViewFilter<T, TView>
bool IsMatch(T value, TView view);
void WhenTrue(T value, TView view);
void WhenFalse(T value, TView view);
void OnCollectionChanged(ChangedKind changedKind, T value, TView view, in NotifyCollectionChangedEventArgs<T> eventArgs);
void OnCollectionChanged(in SynchronizedViewChangedEventArgs<T, TView> eventArgs);
}

public enum ChangedKind
public readonly struct SynchronizedViewChangedEventArgs<T, TView>
{
Add, Remove, Move
public readonly NotifyCollectionChangedAction Action = action;
public readonly T NewValue = newValue;
public readonly T OldValue = oldValue;
public readonly TView NewView = newView;
public readonly TView OldView = oldView;
public readonly int NewViewIndex = newViewIndex;
public readonly int OldViewIndex = oldViewIndex;
}
```

Expand Down
28 changes: 15 additions & 13 deletions sandbox/ConsoleApp/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Specialized;
using R3;
using System.Linq;
using ObservableCollections;
Expand Down Expand Up @@ -64,25 +65,26 @@ public void WhenFalse(int value, ViewModel view)
view.Value = $"@{value} (odd)";
}

public void OnCollectionChanged(
ChangedKind changedKind,
int value,
ViewModel view,
in NotifyCollectionChangedEventArgs<int> eventArgs)
public void OnCollectionChanged(in SynchronizedViewChangedEventArgs<int, ViewModel> eventArgs)
{
switch (changedKind)
switch (eventArgs.Action)
{
case ChangedKind.Add:
view.Value += " Add";
case NotifyCollectionChangedAction.Add:
eventArgs.NewView.Value += " Add";
break;
case ChangedKind.Remove:
view.Value += " Remove";
case NotifyCollectionChangedAction.Remove:
eventArgs.OldView.Value += " Remove";
break;
case ChangedKind.Move:
view.Value += $" Move {eventArgs.OldStartingIndex} {eventArgs.NewStartingIndex}";
case NotifyCollectionChangedAction.Move:
eventArgs.NewView.Value += $" Move {eventArgs.OldViewIndex} {eventArgs.NewViewIndex}";
break;
case NotifyCollectionChangedAction.Replace:
eventArgs.NewView.Value += $" Replace {eventArgs.NewViewIndex}";
break;
case NotifyCollectionChangedAction.Reset:
break;
default:
throw new ArgumentOutOfRangeException(nameof(changedKind), changedKind, null);
throw new ArgumentOutOfRangeException(nameof(eventArgs.Action), eventArgs.Action, null);
}
}
}
96 changes: 59 additions & 37 deletions src/ObservableCollections/ISynchronizedViewFilter.cs
Original file line number Diff line number Diff line change
@@ -1,48 +1,54 @@
using System;
using System.Collections.Specialized;

namespace ObservableCollections
{
public readonly struct SynchronizedViewChangedEventArgs<T, TView>(
NotifyCollectionChangedAction action,
T newValue = default!,
T oldValue = default!,
TView newView = default!,
TView oldView = default!,
int newViewIndex = -1,
int oldViewIndex = -1)
{
public readonly NotifyCollectionChangedAction Action = action;
public readonly T NewValue = newValue;
public readonly T OldValue = oldValue;
public readonly TView NewView = newView;
public readonly TView OldView = oldView;
public readonly int NewViewIndex = newViewIndex;
public readonly int OldViewIndex = oldViewIndex;
}

public interface ISynchronizedViewFilter<T, TView>
{
bool IsMatch(T value, TView view);
void WhenTrue(T value, TView view);
void WhenFalse(T value, TView view);
void OnCollectionChanged(ChangedKind changedKind, T value, TView view, in NotifyCollectionChangedEventArgs<T> eventArgs);
}

public enum ChangedKind
{
Add, Remove, Move
void OnCollectionChanged(in SynchronizedViewChangedEventArgs<T, TView> eventArgs);
}

public class SynchronizedViewFilter<T, TView> : ISynchronizedViewFilter<T, TView>
public class SynchronizedViewFilter<T, TView>(
Func<T, TView, bool> isMatch,
Action<T, TView>? whenTrue,
Action<T, TView>? whenFalse,
Action<SynchronizedViewChangedEventArgs<T, TView>>? onCollectionChanged)
: ISynchronizedViewFilter<T, TView>
{
public static readonly ISynchronizedViewFilter<T, TView> Null = new NullViewFilter();

readonly Func<T, TView, bool> isMatch;
readonly Action<T, TView>? whenTrue;
readonly Action<T, TView>? whenFalse;
readonly Action<ChangedKind, T, TView>? onCollectionChanged;

public SynchronizedViewFilter(Func<T, TView, bool> isMatch, Action<T, TView>? whenTrue, Action<T, TView>? whenFalse, Action<ChangedKind, T, TView>? onCollectionChanged)
{
this.isMatch = isMatch;
this.whenTrue = whenTrue;
this.whenFalse = whenFalse;
this.onCollectionChanged = onCollectionChanged;
}

public bool IsMatch(T value, TView view) => isMatch(value, view);
public void WhenFalse(T value, TView view) => whenFalse?.Invoke(value, view);
public void WhenTrue(T value, TView view) => whenTrue?.Invoke(value, view);
public void OnCollectionChanged(ChangedKind changedKind, T value, TView view, in NotifyCollectionChangedEventArgs<T> eventArgs) => onCollectionChanged?.Invoke(changedKind, value, view);
public void OnCollectionChanged(in SynchronizedViewChangedEventArgs<T, TView> eventArgs) => onCollectionChanged?.Invoke(eventArgs);

class NullViewFilter : ISynchronizedViewFilter<T, TView>
{
public bool IsMatch(T value, TView view) => true;
public void WhenFalse(T value, TView view) { }
public void WhenTrue(T value, TView view) { }
public void OnCollectionChanged(ChangedKind changedKind, T value, TView view, in NotifyCollectionChangedEventArgs<T> eventArgs) { }
public void OnCollectionChanged(in SynchronizedViewChangedEventArgs<T, TView> eventArgs) { }
}
}

Expand All @@ -58,7 +64,7 @@ public static void AttachFilter<T, TView>(this ISynchronizedView<T, TView> sourc
source.AttachFilter(new SynchronizedViewFilter<T, TView>(isMatch, whenTrue, whenFalse, null));
}

public static void AttachFilter<T, TView>(this ISynchronizedView<T, TView> source, Func<T, TView, bool> isMatch, Action<T, TView>? whenTrue, Action<T, TView>? whenFalse, Action<ChangedKind, T, TView>? onCollectionChanged)
public static void AttachFilter<T, TView>(this ISynchronizedView<T, TView> source, Func<T, TView, bool> isMatch, Action<T, TView>? whenTrue, Action<T, TView>? whenFalse, Action<SynchronizedViewChangedEventArgs<T, TView>>? onCollectionChanged)
{
source.AttachFilter(new SynchronizedViewFilter<T, TView>(isMatch, whenTrue, whenFalse, onCollectionChanged));
}
Expand All @@ -67,13 +73,14 @@ public static bool IsNullFilter<T, TView>(this ISynchronizedViewFilter<T, TView>
{
return filter == SynchronizedViewFilter<T, TView>.Null;
}

internal static void InvokeOnAdd<T, TView>(this ISynchronizedViewFilter<T, TView> filter, (T value, TView view) value, in NotifyCollectionChangedEventArgs<T> eventArgs)


internal static void InvokeOnAdd<T, TView>(this ISynchronizedViewFilter<T, TView> filter, (T value, TView view) value, int index)
{
InvokeOnAdd(filter, value.value, value.view, eventArgs);
filter.InvokeOnAdd(value.value, value.view, index);
}

internal static void InvokeOnAdd<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view, in NotifyCollectionChangedEventArgs<T> eventArgs)
internal static void InvokeOnAdd<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view, int index)
{
if (filter.IsMatch(value, view))
{
Expand All @@ -83,27 +90,42 @@ internal static void InvokeOnAdd<T, TView>(this ISynchronizedViewFilter<T, TView
{
filter.WhenFalse(value, view);
}
filter.OnCollectionChanged(ChangedKind.Add, value, view, eventArgs);
filter.OnCollectionChanged(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Add, newValue: value, newView: view, newViewIndex: index));
}

internal static void InvokeOnRemove<T, TView>(this ISynchronizedViewFilter<T, TView> filter, (T value, TView view) value, int oldIndex)
{
filter.InvokeOnRemove(value.value, value.view, oldIndex);
}

internal static void InvokeOnRemove<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view, int oldIndex)
{
filter.OnCollectionChanged(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Remove, oldValue: value, oldView: view, oldViewIndex: oldIndex));
}

internal static void InvokeOnMove<T, TView>(this ISynchronizedViewFilter<T, TView> filter, (T value, TView view) value, int index, int oldIndex)
{
InvokeOnMove(filter, value.value, value.view, index, oldIndex);
}

internal static void InvokeOnRemove<T, TView>(this ISynchronizedViewFilter<T, TView> filter, (T value, TView view) value, in NotifyCollectionChangedEventArgs<T> eventArgs)
internal static void InvokeOnMove<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view, int index, int oldIndex)
{
InvokeOnRemove(filter, value.value, value.view, eventArgs);
filter.OnCollectionChanged(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Move, newValue: value, newView: view, newViewIndex: index, oldViewIndex: oldIndex));
}

internal static void InvokeOnRemove<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view, in NotifyCollectionChangedEventArgs<T> eventArgs)
internal static void InvokeOnReplace<T, TView>(this ISynchronizedViewFilter<T, TView> filter, (T value, TView view) value, (T value, TView view) oldValue, int index, int oldIndex = -1)
{
filter.OnCollectionChanged(ChangedKind.Remove, value, view, eventArgs);
filter.InvokeOnReplace(value.value, value.view, oldValue.value, oldValue.view, index, oldIndex);
}

internal static void InvokeOnMove<T, TView>(this ISynchronizedViewFilter<T, TView> filter, (T value, TView view) value, in NotifyCollectionChangedEventArgs<T> eventArgs)
internal static void InvokeOnReplace<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view, T oldValue, TView oldView, int index, int oldIndex = -1)
{
InvokeOnMove(filter, value.value, value.view, eventArgs);
filter.OnCollectionChanged(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Replace, newValue: value, newView: view, oldValue: oldValue, oldView: oldView, newViewIndex: index, oldViewIndex: oldIndex >= 0 ? oldIndex : index));
}

internal static void InvokeOnMove<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view, in NotifyCollectionChangedEventArgs<T> eventArgs)
internal static void InvokeOnReset<T, TView>(this ISynchronizedViewFilter<T, TView> filter)
{
filter.OnCollectionChanged(ChangedKind.Move, value, view, eventArgs);
filter.OnCollectionChanged(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset));
}

internal static void InvokeOnAttach<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view)
Expand All @@ -118,4 +140,4 @@ internal static void InvokeOnAttach<T, TView>(this ISynchronizedViewFilter<T, TV
}
}
}
}
}
4 changes: 2 additions & 2 deletions src/ObservableCollections/Internal/FreezedView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAd
var (value, view) = list[i];
if (invokeAddEventForCurrentElements)
{
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, i));
filter.InvokeOnAdd(value, view, i);
}
else
{
Expand Down Expand Up @@ -161,7 +161,7 @@ public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAd
var (value, view) = array[i];
if (invokeAddEventForCurrentElements)
{
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, i));
filter.InvokeOnAdd(value, view, i);
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,25 +58,30 @@ public IEnumerator<TView> GetEnumerator()
public void WhenTrue(T value, TView view) => currentFilter.WhenTrue(value, view);
public void WhenFalse(T value, TView view) => currentFilter.WhenFalse(value, view);

public void OnCollectionChanged(ChangedKind changedKind, T value, TView view, in NotifyCollectionChangedEventArgs<T> eventArgs)
public void OnCollectionChanged(in SynchronizedViewChangedEventArgs<T, TView> args)
{
currentFilter.OnCollectionChanged(changedKind, value, view, in eventArgs);
currentFilter.OnCollectionChanged(args);

switch (changedKind)
switch (args.Action)
{
case ChangedKind.Add:
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, view, eventArgs.NewStartingIndex));
case NotifyCollectionChangedAction.Add:
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, args.NewView, args.NewViewIndex));
PropertyChanged?.Invoke(this, CountPropertyChangedEventArgs);
return;
case ChangedKind.Remove:
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, view, eventArgs.OldStartingIndex));
break;
case NotifyCollectionChangedAction.Remove:
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, args.OldView, args.OldViewIndex));
PropertyChanged?.Invoke(this, CountPropertyChangedEventArgs);
break;
case NotifyCollectionChangedAction.Reset:
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
PropertyChanged?.Invoke(this, CountPropertyChangedEventArgs);
break;
case ChangedKind.Move:
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, view, eventArgs.NewStartingIndex, eventArgs.OldStartingIndex));
case NotifyCollectionChangedAction.Replace:
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, args.NewView, args.OldView, args.NewViewIndex));
break;
case NotifyCollectionChangedAction.Move:
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, args.NewView, args.NewViewIndex, args.OldViewIndex));
break;
default:
throw new ArgumentOutOfRangeException(nameof(changedKind), changedKind, null);
}
}
}
Expand Down
Loading

0 comments on commit f5bf911

Please sign in to comment.