public static ICell <IReadOnlyList <T> > AsCell <T>(this IReactiveCollection <T> collection) { return(new AnonymousCell <IReadOnlyList <T> >(action => { return collection.update.Subscribe(_ => { action(collection); }); }, () => collection)); }
public static IScrollViewLayout VariableViewSizeLayout <TData>( IReactiveCollection <TData> data, Func <TData, float> viewSizeFactory, LinearLayoutSettings settings) { return(LinearVariableSizeLayout.Create(data, viewSizeFactory, settings)); }
public static IDisposable BindOptionsTo(this Dropdown input, IReactiveCollection <string> options) { var addSubscription = options.ObserveAdd().Subscribe(x => { var newOption = new Dropdown.OptionData { text = x.Value }; input.options.Insert(x.Index, newOption); }); var updateSubscription = options.ObserveReplace().Subscribe(x => { var existingOption = input.options[x.Index]; existingOption.text = x.NewValue; }); var removeSubscription = options.ObserveRemove().Subscribe(x => input.options.RemoveAt(x.Index)); input.options.Clear(); foreach (var option in options) { var newOption = new Dropdown.OptionData { text = option }; input.options.Add(newOption); } return(new CompositeDisposable(addSubscription, updateSubscription, removeSubscription).AddTo(input)); }
public static void ForEachReverse <T>(this IReactiveCollection <T> collection, Action <T> action) { for (var i = collection.Count - 1; i >= 0; i--) { action(collection[i]); } }
/// <summary> /// Call methods 'onAdd' and 'onRemove' whenever an object is added or /// removed from a collection. This class correctly handles both when /// a collection is initialized, as well as when the collection is Reset. /// </summary> /// <param name="onAdd">A method to be called when an object is added /// to the collection.</param> /// <param name="onRemove">A method to be called when an object is removed /// from the collection.</param> /// <returns>A Disposable that deactivates this behavior.</returns> public static IDisposable ActOnEveryObject <T>(this IReactiveCollection <T> This, Action <T> onAdd, Action <T> onRemove) where T : IReactiveObject { foreach (var v in This) { onAdd(v); } var changingDisp = This.Changing .Where(x => x.Action == NotifyCollectionChangedAction.Reset) .Subscribe( _ => This.ForEach(x => onRemove(x))); var changedDisp = This.Changed.Subscribe(x => { switch (x.Action) { case NotifyCollectionChangedAction.Add: foreach (T v in x.NewItems) { onAdd(v); } break; case NotifyCollectionChangedAction.Replace: foreach (T v in x.OldItems) { onRemove(v); } foreach (T v in x.NewItems) { onAdd(v); } break; case NotifyCollectionChangedAction.Remove: foreach (T v in x.OldItems) { onRemove(v); } break; case NotifyCollectionChangedAction.Reset: foreach (T v in This) { onAdd(v); } break; default: break; } }); return(Disposable.Create(() => { changingDisp.Dispose(); changedDisp.Dispose(); This.ForEach(x => onRemove(x)); })); }
public static IDisposable AffectEach <T>(this IReactiveCollection <T> collection, Action <IConnectionSink, T> affect) where T : class { var itemConnectionsDict = new Dictionary <T, Connections>(); collection.BindEach(item => { var itemConnections = new Connections(); if (itemConnectionsDict.ContainsKey(item)) { UnityEngine.Debug.LogError("it seems item is already loaded, this function wont work if elements repeated in the collection"); return; } affect(itemConnections, item); itemConnectionsDict[item] = itemConnections; }, item => { itemConnectionsDict.TakeKey(item).DisconnectAll(); }); return(new AnonymousDisposable(() => { foreach (var connections in itemConnectionsDict.Values) { connections.DisconnectAll(); } })); }
public static IObservable <TValue> GetValues <TKey, TValue>(this IReactiveCollection <DictionaryChangedNotification <TKey, TValue> > reactiveCollection, TKey key) where TKey : notnull { return(reactiveCollection.Changes .Where(x => x.Current.ContainsKey(key)) .Select(x => x.Current[key])); }
public static IDisposable BindCollection <T>(this IReactiveCollection <T> list, Action <ReactiveCollectionEvent <T> > action) { action(new ReactiveCollectionEvent <T> { type = ReactiveCollectionEventType.Reset, newData = list }); return(list.update.Subscribe(action)); }
public void RefillFromPos <TData>(int i, IReactiveCollection <TData> data, Func <TData, float> viewSizeFactory) { var curr = data; float accum = 0; if (i == 0) { endPoints.Clear(); } else { endPoints.RemoveRange(i, endPoints.Count - i); accum = endPoints[i - 1]; } endPoints.Capacity = curr.Count; for (int j = i; j < curr.Count; j++) { accum += viewSizeFactory(curr[j]); endPoints.Add(accum); } // Update bounding size size.value = (endPoints.Count > 0 ? endPoints[endPoints.Count - 1] : 0) + settings.bottomShift; needUpdate.Send(); }
public static LinearVariableSizeLayout Create <TData>(IReactiveCollection <TData> data, Func <TData, float> viewSizeFactory, LinearLayoutSettings settings) { var layout = new LinearVariableSizeLayout(settings); layout.settings = settings; layout.directionSign = settings.direction == LayoutDirection.Horizontal ? 1 : -1; layout.addConnection = data.update.Subscribe(e => { switch (e.type) { case ReactiveCollectionEventType.Reset: layout.RefillFromPos(0, data, viewSizeFactory); break; case ReactiveCollectionEventType.Insert: case ReactiveCollectionEventType.Remove: case ReactiveCollectionEventType.Set: layout.RefillFromPos(e.position, data, viewSizeFactory); break; } }); layout.RefillFromPos(0, data, viewSizeFactory); return(layout); }
public ReactiveObservableCollectionWrapper(IReactiveCollection <Series> list) : base(DefaultConfiguration) { this.disposables = new List <IDisposable>(); this.disposables.Add(list.ItemsAdded.Subscribe(i => this.Add(i))); this.disposables.Add(list.ItemsRemoved.Subscribe(i => this.Remove(i))); }
public ReactiveObservableCollectionWrapper(IReactiveCollection<Series> list) : base(DefaultConfiguration) { this.disposables = new List<IDisposable>(); this.disposables.Add(list.ItemsAdded.Subscribe(i => this.Add(i))); this.disposables.Add(list.ItemsRemoved.Subscribe(i => this.Remove(i))); }
public static IDisposable Present <T, TView>( this IReactiveCollection <T> coll, List <TView> views, Action <T, TView> show ) where TView : ReusableView { var connections = new DoubleDisposable(); void UpdateView(int index) { var c = coll; var view = views[index]; if (c.Count <= index) { view.SetActiveSafe(false); view.DisconnectAll(); } else { view.DisconnectAll(); view.SetActiveSafe(true); show(c[index], view); } } void UpdateFromIndex(int index) { for (int i = index; i < views.Count; i++) { UpdateView(i); } } connections.First = coll.update.Subscribe(e => { switch (e.type) { case ReactiveCollectionEventType.Reset: UpdateFromIndex(0); break; case ReactiveCollectionEventType.Insert: case ReactiveCollectionEventType.Remove: UpdateFromIndex(e.position); break; case ReactiveCollectionEventType.Set: UpdateView(e.position); break; } }); connections.Second = new AnonymousDisposable(() => views.ForEach(v => v.DisconnectAll())); UpdateFromIndex(0); return(connections); }
// public void Ctor(HandModel handModel) // { // _model = handModel; // } public void Init() { _cards = new ReactiveCollection <CardPresenter>(); RandomSetter.interactable = true; RandomSetter .OnClickAsObservable() .Subscribe(_ => _cards[_id++ % _cards.Count].SetRandomValue()) .AddTo(this); _cards .ObserveAdd() .Throttle(TimeSpan.FromMilliseconds(250)) .Subscribe(c => RebuildCardPosition()) .AddTo(this); _cards .ObserveRemove() .Throttle(TimeSpan.FromMilliseconds(50)) .Subscribe(c => RebuildCardPosition()) .AddTo(this); _cards .ObserveAdd() .Subscribe(c => AddDragDrop(c.Value)) .AddTo(this); foreach (var cc in FindObjectsOfType <CardPresenter>()) { var cardModel = new CardModel(_assetDbService); cc.Ctor(cardModel); _cards.Add(cc); } _arc = new Arc3() { p0 = Arc3Root.gameObject.transform.InverseTransformPoint(Arc3Root.GetChild(0).transform.position), p1 = Arc3Root.gameObject.transform.InverseTransformPoint(Arc3Root.GetChild(1).transform.position), p2 = Arc3Root.gameObject.transform.InverseTransformPoint(Arc3Root.GetChild(2).transform.position), }; // _model.IsDead // .Where(isDead => isDead) // .Subscribe(_ => // { // _model = null; // Destroy(gameObject); // }) // .AddTo(this);; // // AddDragDrop(this); }
public static ICell <T> AtIndex <T>(this IReactiveCollection <T> collection, int index) { return(new AnonymousCell <T>(action => { return collection.AsCell().ListenUpdates(coll => { action(coll.Count > index ? coll[index] : default(T)); }); }, () => { var coll = collection; return coll.Count > index ? coll[index] : default(T); })); }
public static TableConnectionsAndComponents <TView, TData> PresentWithLayout <TData, TView>( this IReactiveCollection <TData> data, RectTransform rect, PrefabRef <TView> prefab, Action <TData, TView> fillFactory, IScrollViewLayout layout = null, // Linear layout is default TableDelegates <TView> delegates = null, PresentOptions options = PresentOptions.UseChildWithSameTypeAsView) where TView : ReusableView { var components = CreateBasicTableComponents(data, rect, fillFactory, prefab: prefab, layout: layout, delegates: delegates, options: options | PresentOptions.NeedLayout); components.viewPort = new AllVisibleViewPort(); return(ControlItemVisibilityAndRecycle(components)); }
public static IDisposable BindOptionsTo <T>(this TMP_Dropdown input, IReactiveCollection <T> options, Func <T, string> textLocator, Func <T, Sprite> spriteLocator = null) { var addSubscription = options.ObserveAdd().Subscribe(x => { var newOption = new TMP_Dropdown.OptionData { text = textLocator(x.Value) }; if (spriteLocator != null) { newOption.image = spriteLocator(x.Value); } input.options.Insert(x.Index, newOption); }); var updateSubscription = options.ObserveReplace().Subscribe(x => { var existingOption = input.options[x.Index]; existingOption.text = textLocator(x.NewValue); if (spriteLocator != null) { existingOption.image = spriteLocator(x.NewValue); } }); var removeSubscription = options.ObserveRemove().Subscribe(x => input.options.RemoveAt(x.Index)); input.options.Clear(); foreach (var option in options) { var newOption = new TMP_Dropdown.OptionData { text = textLocator(option) }; if (spriteLocator != null) { newOption.image = spriteLocator(option); } input.options.Add(newOption); } return(new CompositeDisposable(addSubscription, updateSubscription, removeSubscription).AddTo(input)); }
public DebugLayout ScrollSingleSelection <T>( IReactiveCollection <T> collection, ICellRW <T> selected, Func <T, string> toString, float takeRelativeLayoutSize = 1) { var currentSelected = InstantiateInLayout(factory.titlePrefab).GetComponentInChildren <Text>(); currentSelected.SetTextContent(selected.Select(v => $"current: {toString(v)}")); var scroll = InstantiateInLayout(factory.scrollPrefab, new DebugLayoutOptions { flexibleSpace = takeRelativeLayoutSize }); Rui.PresentInScrollWithLayout(collection, scroll, show: (s, button) => { button.Show(toString(s), selected.Select(v => object.ReferenceEquals(v, s)), button.connectionSink); button.button.ClickStream().Subscribe(() => selected.value = s); }, prefab: PrefabRef.ToPrefabRef(factory.buttonPrefab), layout: Rui.LinearLayout(forceMainSize: 80)); return(this); }
/// <summary> /// Sets the collection to be processed by this behaviour /// </summary> /// <param name="collection"></param> public void SetCollection(IReactiveCollection <T> collection) { // Delete previous collection and views ClearSubscriptions(); DestroyAllViews(); subscriptions = new CompositeDisposable(); collection.ObserveAdd().Subscribe(evt => ProcessAdd(evt.Value)).AddTo(subscriptions); collection.ObserveRemove().Subscribe(evt => ProcessRemove(evt.Value)).AddTo(subscriptions); collection.ObserveReset().Subscribe(ProcessReset).AddTo(subscriptions); // Add all initial objects foreach (var model in collection) { ProcessAdd(model); } }
public DebugLayout ScrollSingleSelection( IReactiveCollection <string> collection, ICellRW <string> selected, float takeRelativeLayoutSize = 1) { var currentSelected = InstantiateInLayout(factory.titlePrefab).GetComponentInChildren <Text>(); currentSelected.SetTextContent(selected.Select(v => $"current: {v}")); var scroll = InstantiateInLayout(factory.scrollPrefab, new DebugLayoutOptions { flexibleSpace = takeRelativeLayoutSize }); Rui.PresentInScrollWithLayout(collection, scroll, PrefabRef.ToPrefabRef(factory.buttonPrefab), (s, button) => { button.Show(s, selected.Select(v => v == s), button.connectionSink); button.addConnection = button.button.ClickStream().Subscribe(() => selected.value = s); }, layout: Rui.LinearLayout(forceMainSize: 80)); return(this); }
public static SimplePresentComponents <TView, T> Present <T, TView>( this IReactiveCollection <T> coll, Transform parent, PrefabRef <TView> prefab = default, Action <T, TView> show = null, Func <T, IEventStream> updater = null, Func <T, PrefabRef <TView> > prefabSelector = null, IViewPool <TView, T> pool = null, PresentOptions options = PresentOptions.UseChildWithSameTypeAsView, TableDelegates <TView> delegates = null ) where TView : ReusableView { var components = CreateBasicTableComponents(coll, parent, show, pool, prefab, prefabSelector, null, delegates, updater, options); var viewStorage = components.viewLoader; components.addConnection = coll.update.Subscribe(e => { switch (e.type) { case ReactiveCollectionEventType.Reset: viewStorage.UnloadAll(); viewStorage.ReloadAll(e.newData); break; case ReactiveCollectionEventType.Insert: viewStorage.LoadView(e.position, e.newItem); break; case ReactiveCollectionEventType.Remove: viewStorage.UnloadView(e.position); break; case ReactiveCollectionEventType.Set: viewStorage.UnloadView(e.position); viewStorage.LoadView(e.position, e.newItem); break; } }); viewStorage.ReloadAll(coll); // TODO think about how destroy should work components.addConnection = new AnonymousDisposable(() => components.viewLoader.UnloadAll()); components.animationsEnabled = true; return(components); }
public static IDisposable BindOptionsTo(this Dropdown input, IReactiveCollection <Dropdown.OptionData> options) { var addSubscription = options.ObserveAdd().Subscribe(x => input.options.Insert(x.Index, x.Value)); var removeSubscription = options.ObserveRemove().Subscribe(x => input.options.RemoveAt(x.Index)); var updateSubscription = options.ObserveReplace().Subscribe(x => { input.options.RemoveAt(x.Index); input.options.Insert(x.Index, x.NewValue); }); input.options.Clear(); foreach (var option in options) { input.options.Add(option); } return(new CompositeDisposable(addSubscription, updateSubscription, removeSubscription).AddTo(input)); }
//同步选项信息到viewmodel 多选 manualState手动设置按钮状态 单选或者复选按钮 点下去 再移开 状态还是选中状态 但是list无法获取 //manual 需要添加selection 控制器 public void SelectedItemsIdx(IReactiveCollection <int> selectedItemsIdx, bool manualState = true) { var g = gObject; g.onClickItem.Add((item) => { var selections = g.GetSelection(); diffSyncList(selections, selectedItemsIdx); if (manualState) { for (int i = 0; i < g.numItems; i++) { var com = g.GetChildAt(i).asCom; if (com != null) { var ctrl = com.GetController("selection"); if (ctrl != null) { ctrl.SetSelectedPage("up"); } } } foreach (var idx in selectedItemsIdx) { var child = g.GetChildAt(g.ItemIndexToChildIndex(idx)); var com = g.GetChildAt(idx).asCom; if (com != null) { var ctrl = child.asCom.GetController("selection"); if (ctrl != null) { ctrl.SetSelectedPage("down"); } } } } }); { var selections = g.GetSelection(); diffSyncList(selections, selectedItemsIdx); } }
public static IObservable <IReactiveCollection <T> > AnyChange <T>(this IReactiveCollection <T> This) { if (This == null) { return(Observable.Empty <IReactiveCollection <T> >()); } return(This.Changed .Select(_ => This) .Merge(This.ItemChanged .Select(_ => This)) .Merge(This.ItemsAdded .Select(_ => This)) .Merge(This.ItemsRemoved .Select(_ => This)) .Merge(This.ItemsMoved .Select(_ => This)) .Merge(This.ShouldReset .Select(_ => This)) .StartWith(This)); }
public static TableConnectionsAndComponents <TView, TData> PresentInScrollWithLayout <TData, TView>( this IReactiveCollection <TData> data, ReactiveScrollRect scroll, PrefabRef <TView> prefab = default, Action <TData, TView> show = null, Func <TData, PrefabRef <TView> > prefabSelector = null, IScrollViewLayout layout = null, // Linear layout is default TableDelegates <TView> delegates = null, PresentOptions options = PresentOptions.UseChildWithSameTypeAsView ) where TView : ReusableView { var components = CreateBasicTableComponents( data, scroll.scroll.content, show, prefab: prefab, prefabSelector: prefabSelector, layout: layout, delegates: delegates, options: options | PresentOptions.NeedLayout); return(PresentInScrollWithLayout(components, scroll)); }
/// <summary> /// Apply AutoPersistence to all objects in a collection. Items that are /// no longer in the collection won't be persisted anymore. /// </summary> /// <param name="doPersist">The asynchronous method to call to save the /// object to disk.</param> /// <param name="manualSaveSignal">When invoked, the object will be saved /// regardless of whether it has changed.</param> /// <param name="interval">The interval to save the object on. Note that /// if an object is constantly changing, it is possible that it will never /// be saved.</param> /// <returns>A Disposable to disable automatic persistence.</returns> public static IDisposable AutoPersistCollection <T, TDontCare>(this IReactiveCollection <T> This, Func <T, IObservable <Unit> > doPersist, IObservable <TDontCare> manualSaveSignal, TimeSpan?interval = null) where T : IReactiveObject { var disposerList = new Dictionary <T, IDisposable>(); var disp = This.ActOnEveryObject( x => { if (disposerList.ContainsKey(x)) { return; } disposerList[x] = x.AutoPersist(doPersist, manualSaveSignal, interval); }, x => { disposerList[x].Dispose(); disposerList.Remove(x); }); return(Disposable.Create(() => { disp.Dispose(); disposerList.Values.ForEach(x => x.Dispose()); })); }
public static IEventStream <T> MergeCollectionOfStreams <T>(this IReactiveCollection <IEventStream <T> > collection) { return(new AnonymousEventStream <T>(action => { var connections = new Connections(); var disposable = new DoubleDisposable { First = connections, }; disposable.Second = // TODO It can be done more effectively then asCell call but much more complex collection.AsCell().Bind(coll => { connections.DisconnectAll(); if (disposable.disposed) { return; } connections.AddRange(coll.Select(item => item.Subscribe(action))); }); return disposable; })); }
public static IDisposable BindEach <T>(this IReactiveCollection <T> collection, Action <T> onInsert, Action <T> onRemove) { foreach (var item in collection) { onInsert(item); } return(collection.update.Subscribe(rce => { switch (rce.type) { case ReactiveCollectionEventType.Insert: onInsert(rce.newItem); break; case ReactiveCollectionEventType.Set: onInsert(rce.newItem); onRemove(rce.oldItem); break; case ReactiveCollectionEventType.Remove: onRemove(rce.oldItem); break; case ReactiveCollectionEventType.Reset: foreach (var item in rce.oldData) { onRemove(item); } foreach (var item in rce.newData) { onInsert(item); } break; } })); }
public static IDisposable BindEach <T>(this IReactiveCollection <T> collection, Action <T> action) { foreach (var item in collection) { action(item); } return(collection.update.Subscribe(rce => { switch (rce.type) { case ReactiveCollectionEventType.Insert: case ReactiveCollectionEventType.Set: action(rce.newItem); break; case ReactiveCollectionEventType.Reset: foreach (var item in collection) { action(item); } break; } })); }
public void Show(IReactiveCollection <Planet> planets, IReactiveCollection <RocketInstance> rockets, ICell <int> playerPlanetId) { // Present function is a very powerful tool // It allows to show any dynamic collection it can: // * Automate loading and destruction // * Automate object pooling // * Show UI data with different layouts // * Show UI data in scroll views with reusable cells (when only visible elements are loaded) // * some other usefull features ... // Here is the simplest case of Present planets.Present( root, prefabSelector: data => Resources.Load <PlanetView>(data.config.name), show: (data, view) => view.Show(data, playerPlanetId.value == data.id), delegates: ExplosionOnDeath <PlanetView>(GameResources.instance.planetDeathFx) ); rockets.Present( root, prefabSelector: data => PrefabRef <RocketView> .ByName("Missile" + data.config.name), show: (data, view) => view.Show(data), delegates: ExplosionOnDeath <RocketView>(GameResources.instance.rocketExplosionFx) ); }
public static IReactiveCollection <ListChangedNotification <TResult> > Select <TSource, TResult>(this IReactiveCollection <ICollectionChangedNotification <TSource> > source, Func <TSource, TResult> selector) { return(source.Select(selector, EqualityComparer <TResult> .Default)); }