Browse Source

Add back requested event for TopLevel

pull/9856/head
Emmanuel Hansen 4 years ago
parent
commit
5936f52b2c
  1. 19
      src/Android/Avalonia.Android/AvaloniaMainActivity.cs
  2. 14
      src/Android/Avalonia.Android/IAndroidNavigationService.cs
  3. 28
      src/Android/Avalonia.Android/Platform/AndroidSystemNavigationManager.cs
  4. 7
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
  5. 18
      src/Avalonia.Base/Platform/SystemNavigationManager.cs
  6. 56
      src/Avalonia.Controls/TopLevel.cs

19
src/Android/Avalonia.Android/AvaloniaMainActivity.cs

@ -1,18 +1,14 @@
using System; using System;
using Android.App; using Android.App;
using Android.Content; using Android.Content;
using Android.Content.Res;
using Android.OS; using Android.OS;
using Android.Runtime; using Android.Runtime;
using Android.Views; using Android.Views;
using AndroidX.AppCompat.App; using AndroidX.AppCompat.App;
using AndroidX.Lifecycle;
using AndroidRect = Android.Graphics.Rect;
namespace Avalonia.Android namespace Avalonia.Android
{ {
public abstract class AvaloniaMainActivity : AppCompatActivity, IActivityResultHandler public abstract class AvaloniaMainActivity : AppCompatActivity, IActivityResultHandler, IActivityNavigationService
{ {
internal static object ViewContent; internal static object ViewContent;
@ -56,9 +52,18 @@ namespace Avalonia.Android
} }
} }
public override void OnConfigurationChanged(Configuration newConfig) public event EventHandler<AndroidBackRequestedEventArgs> BackRequested;
public override void OnBackPressed()
{ {
base.OnConfigurationChanged(newConfig); var eventArgs = new AndroidBackRequestedEventArgs();
BackRequested?.Invoke(this, eventArgs);
if (!eventArgs.Handled)
{
base.OnBackPressed();
}
} }
protected override void OnDestroy() protected override void OnDestroy()

14
src/Android/Avalonia.Android/IAndroidNavigationService.cs

@ -0,0 +1,14 @@
using System;
namespace Avalonia.Android
{
public interface IActivityNavigationService
{
event EventHandler<AndroidBackRequestedEventArgs> BackRequested;
}
public class AndroidBackRequestedEventArgs : EventArgs
{
public bool Handled { get; set; }
}
}

28
src/Android/Avalonia.Android/Platform/AndroidSystemNavigationManager.cs

@ -0,0 +1,28 @@
using System;
using Avalonia.Interactivity;
using Avalonia.Platform;
namespace Avalonia.Android.Platform
{
internal class AndroidSystemNavigationManager : ISystemNavigationManager
{
public event EventHandler<RoutedEventArgs> BackRequested;
public AndroidSystemNavigationManager(IActivityNavigationService? navigationService)
{
if(navigationService != null)
{
navigationService.BackRequested += OnBackRequested;
}
}
private void OnBackRequested(object sender, AndroidBackRequestedEventArgs e)
{
var routedEventArgs = new RoutedEventArgs();
BackRequested?.Invoke(this, routedEventArgs);
e.Handled = routedEventArgs.Handled;
}
}
}

7
src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

@ -31,7 +31,8 @@ using Android.Graphics.Drawables;
namespace Avalonia.Android.Platform.SkiaPlatform namespace Avalonia.Android.Platform.SkiaPlatform
{ {
class TopLevelImpl : IAndroidView, ITopLevelImpl, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo, class TopLevelImpl : IAndroidView, ITopLevelImpl, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo,
ITopLevelImplWithTextInputMethod, ITopLevelImplWithNativeControlHost, ITopLevelImplWithStorageProvider ITopLevelImplWithTextInputMethod, ITopLevelImplWithNativeControlHost, ITopLevelImplWithStorageProvider,
ITopLevelWithSystemNavigationManager
{ {
private readonly IGlPlatformSurface _gl; private readonly IGlPlatformSurface _gl;
private readonly IFramebufferPlatformSurface _framebuffer; private readonly IFramebufferPlatformSurface _framebuffer;
@ -57,6 +58,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform
NativeControlHost = new AndroidNativeControlHostImpl(avaloniaView); NativeControlHost = new AndroidNativeControlHostImpl(avaloniaView);
StorageProvider = new AndroidStorageProvider((Activity)avaloniaView.Context); StorageProvider = new AndroidStorageProvider((Activity)avaloniaView.Context);
SystemNavigationManager = new AndroidSystemNavigationManager(avaloniaView.Context as IActivityNavigationService);
} }
public virtual Point GetAvaloniaPointFromEvent(MotionEvent e, int pointerIndex) => public virtual Point GetAvaloniaPointFromEvent(MotionEvent e, int pointerIndex) =>
@ -300,6 +303,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public IStorageProvider StorageProvider { get; } public IStorageProvider StorageProvider { get; }
public ISystemNavigationManager SystemNavigationManager { get; }
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel)
{ {
if (TransparencyLevel != transparencyLevel) if (TransparencyLevel != transparencyLevel)

18
src/Avalonia.Base/Platform/SystemNavigationManager.cs

@ -0,0 +1,18 @@
using System;
using Avalonia.Interactivity;
using Avalonia.Metadata;
namespace Avalonia.Platform
{
[Unstable]
public interface ITopLevelWithSystemNavigationManager
{
ISystemNavigationManager SystemNavigationManager { get; }
}
[Unstable]
public interface ISystemNavigationManager
{
public event EventHandler<RoutedEventArgs>? BackRequested;
}
}

56
src/Avalonia.Controls/TopLevel.cs

@ -7,6 +7,7 @@ using Avalonia.Controls.Primitives;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Input.Raw; using Avalonia.Input.Raw;
using Avalonia.Input.TextInput; using Avalonia.Input.TextInput;
using Avalonia.Interactivity;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.Logging; using Avalonia.Logging;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
@ -76,6 +77,12 @@ namespace Avalonia.Controls
public static readonly StyledProperty<IBrush> TransparencyBackgroundFallbackProperty = public static readonly StyledProperty<IBrush> TransparencyBackgroundFallbackProperty =
AvaloniaProperty.Register<TopLevel, IBrush>(nameof(TransparencyBackgroundFallback), Brushes.White); AvaloniaProperty.Register<TopLevel, IBrush>(nameof(TransparencyBackgroundFallback), Brushes.White);
/// <summary>
/// Defines the <see cref="BackRequested"/> event.
/// </summary>
public static readonly RoutedEvent<RoutedEventArgs> BackRequestedEvent =
RoutedEvent.Register<TopLevel, RoutedEventArgs>(nameof(BackRequested), RoutingStrategies.Bubble);
private static readonly WeakEvent<IResourceHost, ResourcesChangedEventArgs> private static readonly WeakEvent<IResourceHost, ResourcesChangedEventArgs>
ResourcesChangedWeakEvent = WeakEvent.Register<IResourceHost, ResourcesChangedEventArgs>( ResourcesChangedWeakEvent = WeakEvent.Register<IResourceHost, ResourcesChangedEventArgs>(
(s, h) => s.ResourcesChanged += h, (s, h) => s.ResourcesChanged += h,
@ -89,6 +96,7 @@ namespace Avalonia.Controls
private readonly IGlobalStyles? _globalStyles; private readonly IGlobalStyles? _globalStyles;
private readonly PointerOverPreProcessor? _pointerOverPreProcessor; private readonly PointerOverPreProcessor? _pointerOverPreProcessor;
private readonly IDisposable? _pointerOverPreProcessorSubscription; private readonly IDisposable? _pointerOverPreProcessorSubscription;
private readonly IDisposable? _backGestureSubscription;
private Size _clientSize; private Size _clientSize;
private Size? _frameSize; private Size? _frameSize;
private WindowTransparencyLevel _actualTransparencyLevel; private WindowTransparencyLevel _actualTransparencyLevel;
@ -205,6 +213,44 @@ namespace Avalonia.Controls
_pointerOverPreProcessor = new PointerOverPreProcessor(this); _pointerOverPreProcessor = new PointerOverPreProcessor(this);
_pointerOverPreProcessorSubscription = _inputManager?.PreProcess.Subscribe(_pointerOverPreProcessor); _pointerOverPreProcessorSubscription = _inputManager?.PreProcess.Subscribe(_pointerOverPreProcessor);
if(impl is ITopLevelWithSystemNavigationManager topLevelWithSystemNavigation)
{
topLevelWithSystemNavigation.SystemNavigationManager.BackRequested += (s, e) =>
{
e.RoutedEvent = BackRequestedEvent;
RaiseEvent(e);
};
}
var backKeyGesture = new KeyGesture(Key.Left, KeyModifiers.Alt);
_backGestureSubscription = _inputManager?.PreProcess.OfType<RawInputEventArgs>().Subscribe(e =>
{
bool backRequested = false;
if (e is RawKeyEventArgs rawKeyEventArgs && rawKeyEventArgs.Type == RawKeyEventType.KeyDown)
{
var keyEvent = new KeyEventArgs()
{
KeyModifiers = (KeyModifiers)rawKeyEventArgs.Modifiers,
Key = rawKeyEventArgs.Key
};
backRequested = backKeyGesture.Matches(keyEvent);
}
else if(e is RawPointerEventArgs pointerEventArgs)
{
backRequested = pointerEventArgs.Type == RawPointerEventType.XButton1Down;
}
if (backRequested)
{
var backRequestedEventArgs = new RoutedEventArgs(BackRequestedEvent);
RaiseEvent(backRequestedEventArgs);
e.Handled = backRequestedEventArgs.Handled;
}
});
} }
/// <summary> /// <summary>
@ -263,6 +309,15 @@ namespace Avalonia.Controls
set => SetValue(TransparencyBackgroundFallbackProperty, value); set => SetValue(TransparencyBackgroundFallbackProperty, value);
} }
/// <summary>
/// Occurs when physical Back Button is pressed or a back navigation has been requested.
/// </summary>
public event EventHandler<RoutedEvent> BackRequested
{
add { AddHandler(BackRequestedEvent, value); }
remove { RemoveHandler(BackRequestedEvent, value); }
}
public ILayoutManager LayoutManager public ILayoutManager LayoutManager
{ {
get get
@ -382,6 +437,7 @@ namespace Avalonia.Controls
_pointerOverPreProcessor?.OnCompleted(); _pointerOverPreProcessor?.OnCompleted();
_pointerOverPreProcessorSubscription?.Dispose(); _pointerOverPreProcessorSubscription?.Dispose();
_backGestureSubscription?.Dispose();
PlatformImpl = null; PlatformImpl = null;

Loading…
Cancel
Save