Browse Source

Remove System.Reactive from Diagnostics package as well

pull/9749/head
Max Katz 3 years ago
parent
commit
bfdd66ac5e
  1. 9
      src/Avalonia.Base/Reactive/Observable.cs
  2. 35
      src/Avalonia.Base/Reactive/SerialDisposableValue.cs
  3. 1
      src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj
  4. 17
      src/Avalonia.Diagnostics/Diagnostics/DevTools.cs
  5. 1
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/EventTreeNode.cs
  6. 2
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/LogicalTreeNode.cs
  7. 14
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs
  8. 18
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs
  9. 54
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs
  10. 1
      src/Avalonia.Diagnostics/Diagnostics/Views/LayoutExplorerView.axaml.cs
  11. 30
      src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs

9
src/Avalonia.Base/Reactive/Observable.cs

@ -44,6 +44,15 @@ internal static class Observable
}, obs.OnError, obs.OnCompleted));
});
}
public static IObservable<TSource> StartWith<TSource>(this IObservable<TSource> source, TSource value)
{
return Create<TSource>(obs =>
{
obs.OnNext(value);
return source.Subscribe(obs);
});
}
public static IObservable<TSource> Where<TSource>(this IObservable<TSource> source, Func<TSource, bool> predicate)
{

35
src/Avalonia.Base/Reactive/SerialDisposableValue.cs

@ -0,0 +1,35 @@
using System;
using System.Threading;
namespace Avalonia.Reactive;
/// <summary>
/// Represents a disposable resource whose underlying disposable resource can be replaced by another disposable resource, causing automatic disposal of the previous underlying disposable resource.
/// </summary>
internal sealed class SerialDisposableValue : IDisposable
{
private IDisposable? _current;
private bool _disposed;
public IDisposable? Disposable
{
get => _current;
set
{
_current?.Dispose();
_current = value;
if (_disposed)
{
_current?.Dispose();
_current = null;
}
}
}
public void Dispose()
{
_disposed = true;
_current?.Dispose();
}
}

1
src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj

@ -23,7 +23,6 @@
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="3.8.0" />
</ItemGroup>
<Import Project="..\..\build\EmbedXaml.props" />
<Import Project="..\..\build\Rx.props" />
<Import Project="..\..\build\BuildTargets.targets" />
<Import Project="..\..\build\ApiDiff.props" />
<Import Project="..\..\build\NullableEnable.props" />

17
src/Avalonia.Diagnostics/Diagnostics/DevTools.cs

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using Avalonia.Controls;
using Avalonia.Diagnostics.Views;
using Avalonia.Input;
@ -72,7 +71,11 @@ namespace Avalonia.Diagnostics
{
throw new ArgumentNullException(nameof(application));
}
var result = Disposable.Empty;
var openedDisposable = new SerialDisposableValue();
var result = new CompositeDisposable(2);
result.Add(openedDisposable);
// Skip if call on Design Mode
if (!Avalonia.Controls.Design.IsDesignMode
&& !s_attachedToApplication)
@ -90,13 +93,15 @@ namespace Avalonia.Diagnostics
{
s_attachedToApplication = true;
ObservableExtensions.Subscribe(application.InputManager.PreProcess.OfType<RawKeyEventArgs>(), e =>
result.Add(application.InputManager.PreProcess.Subscribe(e =>
{
if (options.Gesture.Matches(e))
if (e is RawKeyEventArgs keyEventArgs
&& keyEventArgs.Type == RawKeyEventType.KeyUp
&& options.Gesture.Matches(keyEventArgs))
{
result = Open(application, options, owner);
openedDisposable.Disposable = Open(application, options, owner);
}
});
}));
}
}

1
src/Avalonia.Diagnostics/Diagnostics/ViewModels/EventTreeNode.cs

@ -4,6 +4,7 @@ using Avalonia.Diagnostics.Views;
using Avalonia.Interactivity;
using Avalonia.Threading;
using Avalonia.VisualTree;
using Avalonia.Reactive;
namespace Avalonia.Diagnostics.ViewModels
{

2
src/Avalonia.Diagnostics/Diagnostics/ViewModels/LogicalTreeNode.cs

@ -1,10 +1,10 @@
using System;
using System.Reactive.Disposables;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.LogicalTree;
using Lifetimes = Avalonia.Controls.ApplicationLifetimes;
using System.Linq;
using Avalonia.Reactive;
namespace Avalonia.Diagnostics.ViewModels
{

14
src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs

@ -1,11 +1,11 @@
using System;
using System.ComponentModel;
using System.Reactive.Linq;
using Avalonia.Controls;
using Avalonia.Diagnostics.Models;
using Avalonia.Input;
using Avalonia.Metadata;
using Avalonia.Threading;
using Avalonia.Reactive;
namespace Avalonia.Diagnostics.ViewModels
{
@ -50,15 +50,15 @@ namespace Avalonia.Diagnostics.ViewModels
}
else
{
#nullable disable
_pointerOverSubscription = InputManager.Instance.PreProcess
.OfType<Input.Raw.RawPointerEventArgs>()
_pointerOverSubscription = InputManager.Instance!.PreProcess
.Subscribe(e =>
{
PointerOverRoot = e.Root;
PointerOverElement = e.Root.InputHitTest(e.Position);
if (e is Input.Raw.RawPointerEventArgs pointerEventArgs)
{
PointerOverRoot = pointerEventArgs.Root;
PointerOverElement = pointerEventArgs.Root.InputHitTest(pointerEventArgs.Position);
}
});
#nullable restore
}
Console = new ConsoleViewModel(UpdateConsoleContext);
}

18
src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs

@ -1,11 +1,11 @@
using System;
using System.Collections.Specialized;
using System.Reactive;
using System.Reactive.Linq;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.LogicalTree;
using Avalonia.Media;
using Avalonia.Reactive;
namespace Avalonia.Diagnostics.ViewModels
{
@ -28,18 +28,8 @@ namespace Avalonia.Diagnostics.ViewModels
{
ElementName = control.Name;
var removed = Observable.FromEventPattern<LogicalTreeAttachmentEventArgs>(
x => control.DetachedFromLogicalTree += x,
x => control.DetachedFromLogicalTree -= x);
var classesChanged = Observable.FromEventPattern<
NotifyCollectionChangedEventHandler,
NotifyCollectionChangedEventArgs>(
x => control.Classes.CollectionChanged += x,
x => control.Classes.CollectionChanged -= x)
.TakeUntil(removed);
_classesSubscription = classesChanged.Select(_ => Unit.Default)
.StartWith(Unit.Default)
_classesSubscription = ((IObservable<object?>)control.Classes.GetWeakCollectionChangedObservable())
.StartWith(null)
.Subscribe(_ =>
{
if (control.Classes.Count > 0)

54
src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs

@ -1,12 +1,11 @@
using System;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Controls.Diagnostics;
using Avalonia.Controls.Primitives;
using Avalonia.Styling;
using Avalonia.VisualTree;
using Avalonia.Reactive;
using Lifetimes = Avalonia.Controls.ApplicationLifetimes;
using System.Linq;
@ -61,9 +60,12 @@ namespace Avalonia.Diagnostics.ViewModels
IPopupHostProvider popupHostProvider,
string? providerName = null)
{
return Observable.FromEvent<IPopupHost?>(
x => popupHostProvider.PopupHostChanged += x,
x => popupHostProvider.PopupHostChanged -= x)
return Observable.Create<IPopupHost?>(observer =>
{
void Handler(IPopupHost? args) => observer.OnNext(args);
popupHostProvider.PopupHostChanged += Handler;
return Disposable.Create(() => popupHostProvider.PopupHostChanged -= Handler);
})
.StartWith(popupHostProvider.PopupHost)
.Select(popupHost =>
{
@ -80,29 +82,39 @@ namespace Avalonia.Diagnostics.ViewModels
{
Popup p => GetPopupHostObservable(p),
Control c => Observable.CombineLatest(
c.GetObservable(Control.ContextFlyoutProperty),
c.GetObservable(Control.ContextMenuProperty),
c.GetObservable(FlyoutBase.AttachedFlyoutProperty),
c.GetObservable(ToolTipDiagnostics.ToolTipProperty),
c.GetObservable(Button.FlyoutProperty),
(ContextFlyout, ContextMenu, AttachedFlyout, ToolTip, ButtonFlyout) =>
new IObservable<IPopupHostProvider?>[]
{
c.GetObservable(Control.ContextFlyoutProperty),
c.GetObservable(Control.ContextMenuProperty),
c.GetObservable(FlyoutBase.AttachedFlyoutProperty),
c.GetObservable(ToolTipDiagnostics.ToolTipProperty),
c.GetObservable(Button.FlyoutProperty)
})
.Select(
items =>
{
if (ContextMenu != null)
var contextFlyout = items[0];
var contextMenu = (ContextMenu?)items[1];
var attachedFlyout = items[2];
var toolTip = items[3];
var buttonFlyout = items[4];
if (contextMenu != null)
//Note: ContextMenus are special since all the items are added as visual children.
//So we don't need to go via Popup
return Observable.Return<PopupRoot?>(new PopupRoot(ContextMenu));
return Observable.Return<PopupRoot?>(new PopupRoot(contextMenu));
if (ContextFlyout != null)
return GetPopupHostObservable(ContextFlyout, "ContextFlyout");
if (contextFlyout != null)
return GetPopupHostObservable(contextFlyout, "ContextFlyout");
if (AttachedFlyout != null)
return GetPopupHostObservable(AttachedFlyout, "AttachedFlyout");
if (attachedFlyout != null)
return GetPopupHostObservable(attachedFlyout, "AttachedFlyout");
if (ToolTip != null)
return GetPopupHostObservable(ToolTip, "ToolTip");
if (toolTip != null)
return GetPopupHostObservable(toolTip, "ToolTip");
if (ButtonFlyout != null)
return GetPopupHostObservable(ButtonFlyout, "Flyout");
if (buttonFlyout != null)
return GetPopupHostObservable(buttonFlyout, "Flyout");
return Observable.Return<PopupRoot?>(null);
})

1
src/Avalonia.Diagnostics/Diagnostics/Views/LayoutExplorerView.axaml.cs

@ -4,6 +4,7 @@ using Avalonia.Controls.Shapes;
using Avalonia.Diagnostics.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.VisualTree;
using Avalonia.Reactive;
namespace Avalonia.Diagnostics.Views
{

30
src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using Avalonia.Controls;
using Avalonia.Controls.Diagnostics;
using Avalonia.Controls.Primitives;
@ -13,13 +12,13 @@ using Avalonia.Markup.Xaml;
using Avalonia.Styling;
using Avalonia.Themes.Simple;
using Avalonia.VisualTree;
using Avalonia.Reactive;
namespace Avalonia.Diagnostics.Views
{
internal class MainWindow : Window, IStyleHost
{
private readonly IDisposable? _keySubscription;
private readonly IDisposable? _pointerSubscription;
private readonly IDisposable? _inputSubscription;
private readonly Dictionary<Popup, IDisposable> _frozenPopupStates;
private AvaloniaObject? _root;
private PixelPoint _lastPointerPosition;
@ -33,15 +32,19 @@ namespace Avalonia.Diagnostics.Views
if (Theme is null && this.FindResource(typeof(Window)) is ControlTheme windowTheme)
Theme = windowTheme;
_keySubscription = InputManager.Instance?.Process
.OfType<RawKeyEventArgs>()
.Where(x => x.Type == RawKeyEventType.KeyDown)
.Subscribe(RawKeyDown);
_pointerSubscription = InputManager.Instance?.Process
.OfType<RawPointerEventArgs>()
.Subscribe(x => _lastPointerPosition = ((Visual)x.Root).PointToScreen(x.Position));
_inputSubscription = InputManager.Instance?.Process
.Subscribe(x =>
{
if (x is RawPointerEventArgs pointerEventArgs)
{
_lastPointerPosition = ((Visual)x.Root).PointToScreen(pointerEventArgs.Position);
}
else if (x is RawKeyEventArgs keyEventArgs && keyEventArgs.Type == RawKeyEventType.KeyDown)
{
RawKeyDown(keyEventArgs);
}
});
_frozenPopupStates = new Dictionary<Popup, IDisposable>();
EventHandler? lh = default;
@ -94,8 +97,7 @@ namespace Avalonia.Diagnostics.Views
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
_keySubscription?.Dispose();
_pointerSubscription?.Dispose();
_inputSubscription?.Dispose();
foreach (var state in _frozenPopupStates)
{

Loading…
Cancel
Save