using System; using System.Linq; using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Media.Animation; using FluentAvalonia.UI.Navigation; using StabilityMatrix.Avalonia.Animations; using StabilityMatrix.Avalonia.Models; using StabilityMatrix.Avalonia.ViewModels; using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Services; namespace StabilityMatrix.Avalonia.Services; [Singleton( ImplType = typeof(NavigationService), InterfaceType = typeof(INavigationService) )] [Singleton( ImplType = typeof(NavigationService), InterfaceType = typeof(INavigationService) )] public class NavigationService : INavigationService { private Frame? _frame; public event EventHandler? TypedNavigation; /// public void SetFrame(Frame frame) { _frame = frame; } /// public void NavigateTo( NavigationTransitionInfo? transitionInfo = null, object? param = null ) where TViewModel : ViewModelBase { if (_frame is null) { throw new InvalidOperationException("SetFrame was not called before NavigateTo."); } if (App.Services.GetService(typeof(ISettingsManager)) is ISettingsManager settingsManager) { // Handle animation scale switch (transitionInfo) { // If the transition info is null or animation scale is 0, suppress the transition case null: case BaseTransitionInfo when settingsManager.Settings.AnimationScale == 0f: transitionInfo = new SuppressNavigationTransitionInfo(); break; case BaseTransitionInfo baseTransitionInfo: baseTransitionInfo.Duration *= settingsManager.Settings.AnimationScale; break; } } _frame.NavigateToType( typeof(TViewModel), param, new FrameNavigationOptions { IsNavigationStackEnabled = true, TransitionInfoOverride = transitionInfo ?? new SuppressNavigationTransitionInfo() } ); TypedNavigation?.Invoke( this, new TypedNavigationEventArgs { ViewModelType = typeof(TViewModel) } ); } /// public void NavigateTo( Type viewModelType, NavigationTransitionInfo? transitionInfo = null, object? param = null ) { if (!viewModelType.IsAssignableTo(typeof(ViewModelBase))) { // ReSharper disable once LocalizableElement throw new ArgumentException("Type must be a ViewModelBase.", nameof(viewModelType)); } if (_frame is null) { throw new InvalidOperationException("SetFrame was not called before NavigateTo."); } if (App.Services.GetService(typeof(ISettingsManager)) is ISettingsManager settingsManager) { // Handle animation scale switch (transitionInfo) { // If the transition info is null or animation scale is 0, suppress the transition case null: case BaseTransitionInfo when settingsManager.Settings.AnimationScale == 0f: transitionInfo = new SuppressNavigationTransitionInfo(); break; case BaseTransitionInfo baseTransitionInfo: baseTransitionInfo.Duration *= settingsManager.Settings.AnimationScale; break; } } _frame.NavigateToType( viewModelType, param, new FrameNavigationOptions { IsNavigationStackEnabled = true, TransitionInfoOverride = transitionInfo ?? new SuppressNavigationTransitionInfo() } ); TypedNavigation?.Invoke( this, new TypedNavigationEventArgs { ViewModelType = viewModelType } ); } /// public void NavigateTo(ViewModelBase viewModel, NavigationTransitionInfo? transitionInfo = null) { if (_frame is null) { throw new InvalidOperationException("SetFrame was not called before NavigateTo."); } if (App.Services.GetService(typeof(ISettingsManager)) is ISettingsManager settingsManager) { // Handle animation scale switch (transitionInfo) { // If the transition info is null or animation scale is 0, suppress the transition case null: case BaseTransitionInfo when settingsManager.Settings.AnimationScale == 0f: transitionInfo = new SuppressNavigationTransitionInfo(); break; case BaseTransitionInfo baseTransitionInfo: baseTransitionInfo.Duration *= settingsManager.Settings.AnimationScale; break; } } _frame.NavigateFromObject( viewModel, new FrameNavigationOptions { IsNavigationStackEnabled = true, TransitionInfoOverride = transitionInfo ?? new SuppressNavigationTransitionInfo() } ); TypedNavigation?.Invoke( this, new TypedNavigationEventArgs { ViewModelType = viewModel.GetType(), ViewModel = viewModel } ); } }