using Avalonia.Controls; using Avalonia.Interactivity; using FluentAvalonia.UI.Media.Animation; using FluentAvalonia.UI.Navigation; using Toolkit.Foundation; using Toolkit.UI.Controls.Avalonia; namespace Toolkit.Avalonia; public class FrameHandler : INavigateHandler, INavigateBackHandler { public Task Handle(NavigateEventArgs args) { if (args.Region is Frame frame) { frame.NavigationPageFactory ??= new NavigationPageFactory(); if (args.Template is Control control) { void NavigatedTo(Control sender) { async void HandleNavigatedTo(object? _, NavigationEventArgs __) { async void HandleNavigatingFrom(object? _, NavigatingCancelEventArgs args) { sender.RemoveHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom); control.Unloaded -= HandleUnloaded; async void HandleNavigatedFrom(object? _, NavigationEventArgs args) { sender.RemoveHandler(Frame.NavigatedFromEvent, HandleNavigatedFrom); if (sender.DataContext is object content) { if (content is IDeactivated deactivated) { await deactivated.OnDeactivated(); } if (content is not IBackStack) { if (content is IDisposable disposable) { disposable.Dispose(); } } } } sender.AddHandler(Frame.NavigatedFromEvent, HandleNavigatedFrom); if (sender.DataContext is object content) { if (content is IConfirmation confirmation && !await confirmation.Confirm()) { args.Cancel = true; } if (!args.Cancel) { if (content is IDeactivating deactivating) { await deactivating.OnDeactivating(); } } } } sender.AddHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom); if (sender.DataContext is object content) { if (content is IInitializer initializer) { await initializer.Initialize(); } if (content is IActivated activated) { await activated.OnActivated(); } } async void HandleUnloaded(object? _, RoutedEventArgs __) { sender.RemoveHandler(Frame.NavigatedToEvent, HandleNavigatedTo); sender.RemoveHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom); control.Unloaded -= HandleUnloaded; if (control.DataContext is object content) { if (content is IDeactivated deactivated) { await deactivated.OnDeactivated(); } if (content is IDisposable disposable) { disposable.Dispose(); } } } sender.Unloaded += HandleUnloaded; } sender.AddHandler(Frame.NavigatedToEvent, HandleNavigatedTo); } control.DataContext = args.Content; NavigatedTo(control); FrameNavigationOptions navigationOptions = new(); if (args.Parameters is not null) { if (args.Parameters.TryGetValue("Transition", out object? transition)) { switch ($"{transition}") { case "FromLeft": case "FromRight": case "FromTop": case "FromBottom": navigationOptions.TransitionInfoOverride = new SlideNavigationTransitionInfo { Effect = Enum.Parse($"{transition}") }; break; } if (args.Parameters.TryGetValue("NavigationStackEnabled", out object? navigationStackEnabled)) { if (navigationStackEnabled is bool value) { navigationOptions.IsNavigationStackEnabled = value; } } } } frame.NavigateFromObject(control, navigationOptions); } } return Task.CompletedTask; } public Task Handle(NavigateBackEventArgs args) { if (args.Context is Frame frame) { frame.GoBack(); } return Task.CompletedTask; } }