From 5d05c658335c8d22efe0fe4f920180b13dfa0154 Mon Sep 17 00:00:00 2001 From: Tolga YILMAZ Date: Wed, 9 Apr 2025 21:06:55 +0200 Subject: [PATCH 1/9] Initialize modern ui with avalonia --- Race Element.UI/App.axaml | 18 +++ Race Element.UI/App.axaml.cs | 35 +++++ Race Element.UI/Assets/raceelement.ico | Bin 0 -> 179947 bytes Race Element.UI/Program.cs | 24 +++ Race Element.UI/RaceElement.UI.csproj | 40 +++++ Race Element.UI/ViewLocator.cs | 38 +++++ Race Element.UI/ViewModels/DataViewModel.cs | 5 + .../ViewModels/LiveriesViewModel.cs | 5 + .../ViewModels/MainTopMenuViewModel.cs | 48 ++++++ .../ViewModels/MainWindowViewModel.cs | 38 +++++ .../ViewModels/OverlaysViewModel.cs | 5 + Race Element.UI/ViewModels/SetupsViewModel.cs | 5 + Race Element.UI/ViewModels/ToolsViewModel.cs | 5 + Race Element.UI/ViewModels/ViewModelBase.cs | 7 + Race Element.UI/Views/MainTopMenuView.axaml | 142 ++++++++++++++++++ .../Views/MainTopMenuView.axaml.cs | 17 +++ Race Element.UI/Views/MainWindow.axaml | 55 +++++++ Race Element.UI/Views/MainWindow.axaml.cs | 20 +++ .../Views/Pages/DataPageView.axaml | 23 +++ .../Views/Pages/DataPageView.axaml.cs | 17 +++ .../Views/Pages/LiveriesPageView.axaml | 23 +++ .../Views/Pages/LiveriesPageView.axaml.cs | 17 +++ .../Views/Pages/OverlaysPageView.axaml | 23 +++ .../Views/Pages/OverlaysPageView.axaml.cs | 18 +++ .../Views/Pages/SetupsPageView.axaml | 23 +++ .../Views/Pages/SetupsPageView.axaml.cs | 17 +++ .../Views/Pages/ToolsPageView.axaml | 23 +++ .../Views/Pages/ToolsPageView.axaml.cs | 17 +++ .../Views/Stylers/ActiveButtonStyler.cs | 37 +++++ .../Views/Stylers/MainWindowStyler.cs | 99 ++++++++++++ Race Element.UI/app.manifest | 18 +++ Race Element.sln | 20 +++ 32 files changed, 882 insertions(+) create mode 100644 Race Element.UI/App.axaml create mode 100644 Race Element.UI/App.axaml.cs create mode 100644 Race Element.UI/Assets/raceelement.ico create mode 100644 Race Element.UI/Program.cs create mode 100644 Race Element.UI/RaceElement.UI.csproj create mode 100644 Race Element.UI/ViewLocator.cs create mode 100644 Race Element.UI/ViewModels/DataViewModel.cs create mode 100644 Race Element.UI/ViewModels/LiveriesViewModel.cs create mode 100644 Race Element.UI/ViewModels/MainTopMenuViewModel.cs create mode 100644 Race Element.UI/ViewModels/MainWindowViewModel.cs create mode 100644 Race Element.UI/ViewModels/OverlaysViewModel.cs create mode 100644 Race Element.UI/ViewModels/SetupsViewModel.cs create mode 100644 Race Element.UI/ViewModels/ToolsViewModel.cs create mode 100644 Race Element.UI/ViewModels/ViewModelBase.cs create mode 100644 Race Element.UI/Views/MainTopMenuView.axaml create mode 100644 Race Element.UI/Views/MainTopMenuView.axaml.cs create mode 100644 Race Element.UI/Views/MainWindow.axaml create mode 100644 Race Element.UI/Views/MainWindow.axaml.cs create mode 100644 Race Element.UI/Views/Pages/DataPageView.axaml create mode 100644 Race Element.UI/Views/Pages/DataPageView.axaml.cs create mode 100644 Race Element.UI/Views/Pages/LiveriesPageView.axaml create mode 100644 Race Element.UI/Views/Pages/LiveriesPageView.axaml.cs create mode 100644 Race Element.UI/Views/Pages/OverlaysPageView.axaml create mode 100644 Race Element.UI/Views/Pages/OverlaysPageView.axaml.cs create mode 100644 Race Element.UI/Views/Pages/SetupsPageView.axaml create mode 100644 Race Element.UI/Views/Pages/SetupsPageView.axaml.cs create mode 100644 Race Element.UI/Views/Pages/ToolsPageView.axaml create mode 100644 Race Element.UI/Views/Pages/ToolsPageView.axaml.cs create mode 100644 Race Element.UI/Views/Stylers/ActiveButtonStyler.cs create mode 100644 Race Element.UI/Views/Stylers/MainWindowStyler.cs create mode 100644 Race Element.UI/app.manifest diff --git a/Race Element.UI/App.axaml b/Race Element.UI/App.axaml new file mode 100644 index 000000000..4185b397e --- /dev/null +++ b/Race Element.UI/App.axaml @@ -0,0 +1,18 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/Race Element.UI/App.axaml.cs b/Race Element.UI/App.axaml.cs new file mode 100644 index 000000000..7bf412924 --- /dev/null +++ b/Race Element.UI/App.axaml.cs @@ -0,0 +1,35 @@ +using Avalonia; +using Avalonia.Markup.Xaml; +using Avalonia.Controls.ApplicationLifetimes; +using RaceElement.UI.ViewModels; +using RaceElement.UI.Views; + +namespace RaceElement.UI; +public partial class App : Application +{ + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + } + + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + desktop.MainWindow = new MainWindow + { + DataContext = new MainWindowViewModel(), + }; + } + else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform) + { + singleViewPlatform.MainView = new MainWindow + { + DataContext = new MainWindowViewModel() + }; + } + + base.OnFrameworkInitializationCompleted(); + } + +} \ No newline at end of file diff --git a/Race Element.UI/Assets/raceelement.ico b/Race Element.UI/Assets/raceelement.ico new file mode 100644 index 0000000000000000000000000000000000000000..2223c41307f8abbf3145e52c3a5f7fb1d00b6bd2 GIT binary patch literal 179947 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 BuildAvaloniaApp() + .StartWithClassicDesktopLifetime(args); + + // Avalonia configuration, don't remove; also used by visual designer. + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .UsePlatformDetect() + .WithInterFont() + .LogToTrace() + .UseReactiveUI(); +} diff --git a/Race Element.UI/RaceElement.UI.csproj b/Race Element.UI/RaceElement.UI.csproj new file mode 100644 index 000000000..2f56fc423 --- /dev/null +++ b/Race Element.UI/RaceElement.UI.csproj @@ -0,0 +1,40 @@ + + + WinExe + net8.0 + enable + true + app.manifest + true + + + + + + + + + + + + + + + + + + + None + All + + + + + + + + + MainTopMenuView.axaml + + + diff --git a/Race Element.UI/ViewLocator.cs b/Race Element.UI/ViewLocator.cs new file mode 100644 index 000000000..7b2fea3a2 --- /dev/null +++ b/Race Element.UI/ViewLocator.cs @@ -0,0 +1,38 @@ +using System; +using RaceElement.UI.ViewModels; +using Avalonia.Controls; +using Avalonia.Controls.Templates; + +namespace RaceElement.UI; + +public class ViewLocator : IDataTemplate +{ + public Control? Build(object? param) + { + if (param is null) + return null; + + var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal); + var type = Type.GetType(name); + + if (type != null) + { + return (Control)Activator.CreateInstance(type)!; + } + + var pageName = param.GetType().FullName!.Replace("ViewModel", "PageView", StringComparison.Ordinal); + pageName =pageName.Replace("PageViews", "Views.Pages", StringComparison.Ordinal); + var pageType = Type.GetType(pageName); + + if (pageType != null) + { + return (Control)Activator.CreateInstance(pageType)!; + } + return new TextBlock { Text = "Not Found: " + name + " or " + pageName}; + } + + public bool Match(object? data) + { + return data is ViewModelBase; + } +} diff --git a/Race Element.UI/ViewModels/DataViewModel.cs b/Race Element.UI/ViewModels/DataViewModel.cs new file mode 100644 index 000000000..9152bde7f --- /dev/null +++ b/Race Element.UI/ViewModels/DataViewModel.cs @@ -0,0 +1,5 @@ +namespace RaceElement.UI.ViewModels; + +internal class DataViewModel : ViewModelBase +{ +} \ No newline at end of file diff --git a/Race Element.UI/ViewModels/LiveriesViewModel.cs b/Race Element.UI/ViewModels/LiveriesViewModel.cs new file mode 100644 index 000000000..1dbc06ada --- /dev/null +++ b/Race Element.UI/ViewModels/LiveriesViewModel.cs @@ -0,0 +1,5 @@ +namespace RaceElement.UI.ViewModels; + +internal class LiveriesViewModel : ViewModelBase +{ +} \ No newline at end of file diff --git a/Race Element.UI/ViewModels/MainTopMenuViewModel.cs b/Race Element.UI/ViewModels/MainTopMenuViewModel.cs new file mode 100644 index 000000000..fa2543aef --- /dev/null +++ b/Race Element.UI/ViewModels/MainTopMenuViewModel.cs @@ -0,0 +1,48 @@ +using ReactiveUI; +using System; +using System.Reactive; + +namespace RaceElement.UI.ViewModels; +public class MainTopMenuViewModel : ViewModelBase +{ + // Reference to the main window view model for Navigation, DI can be used to access + private MainWindowViewModel? _mainWindowViewModel; + + private string _currentPageName = "Overlays"; // Default page + + public string CurrentPageName + { + get => _currentPageName; + private set => this.RaiseAndSetIfChanged(ref _currentPageName, value); + } + + public MainTopMenuViewModel() + { + // Initialize navigation commands + NavigateToOverlaysPageCommand = ReactiveCommand.Create(() => { _mainWindowViewModel?.NavigateTo(new OverlaysViewModel()); CurrentPageName = "Overlays"; }); + NavigateToDataPageCommand = ReactiveCommand.Create(() => { _mainWindowViewModel?.NavigateTo(new DataViewModel()); CurrentPageName = "Data"; }); + NavigateToSetupsPageCommand = ReactiveCommand.Create(() => { _mainWindowViewModel?.NavigateTo(new SetupsViewModel()); CurrentPageName = "Setups"; }); + NavigateToLiveriesPageCommand = ReactiveCommand.Create(() => { _mainWindowViewModel?.NavigateTo(new LiveriesViewModel()); CurrentPageName = "Liveries"; }); + NavigateToToolsPageCommand = ReactiveCommand.Create(() => { _mainWindowViewModel?.NavigateTo(new ToolsViewModel()); CurrentPageName = "Tools"; }); + } + + // Navigation commands + public ReactiveCommand NavigateToOverlaysPageCommand { get; } + public ReactiveCommand NavigateToDataPageCommand { get; } + public ReactiveCommand NavigateToSetupsPageCommand { get; } + public ReactiveCommand NavigateToLiveriesPageCommand { get; } + public ReactiveCommand NavigateToToolsPageCommand { get; } + + // Command to close the application + public ReactiveCommand CloseApplicationCommand => ReactiveCommand.Create(() => { Environment.Exit(0); }); + + internal void SetMainWindowViewModel(MainWindowViewModel mainWindowViewModel) + { + _mainWindowViewModel = mainWindowViewModel; + } + + public bool IsCurrentPage(ViewModelBase page) + { + return _mainWindowViewModel?.CurrentPage == page; + } +} diff --git a/Race Element.UI/ViewModels/MainWindowViewModel.cs b/Race Element.UI/ViewModels/MainWindowViewModel.cs new file mode 100644 index 000000000..fedaf720e --- /dev/null +++ b/Race Element.UI/ViewModels/MainWindowViewModel.cs @@ -0,0 +1,38 @@ +using ReactiveUI; +using System.Reactive; +using Avalonia.Utilities; + +namespace RaceElement.UI.ViewModels; + +public class MainWindowViewModel : ViewModelBase +{ + public MainWindowViewModel() + { + // Initialize the current page to the overlays page + _currentPage = new OverlaysViewModel(); + + /// @todo Instead we can use Dependency injection but it has a complex setup + /// Can not simply pass this as a parameter to constructor, can be investigated later + MainTopMenu = new MainTopMenuViewModel(); + MainTopMenu.SetMainWindowViewModel(this); + } + + public void NavigateTo(ViewModelBase page) + { + // Block consequent navigation to the same page + if (CurrentPage == page) return; + + // Set the current page to the specified page + CurrentPage = page; + } + + public MainTopMenuViewModel MainTopMenu { get; set; } + + // Default to overlays page + private ViewModelBase _currentPage = new OverlaysViewModel(); + public ViewModelBase CurrentPage + { + get => _currentPage; + set => this.RaiseAndSetIfChanged(ref _currentPage, value); + } +} diff --git a/Race Element.UI/ViewModels/OverlaysViewModel.cs b/Race Element.UI/ViewModels/OverlaysViewModel.cs new file mode 100644 index 000000000..f812d9552 --- /dev/null +++ b/Race Element.UI/ViewModels/OverlaysViewModel.cs @@ -0,0 +1,5 @@ +namespace RaceElement.UI.ViewModels; + +internal class OverlaysViewModel : ViewModelBase +{ +} \ No newline at end of file diff --git a/Race Element.UI/ViewModels/SetupsViewModel.cs b/Race Element.UI/ViewModels/SetupsViewModel.cs new file mode 100644 index 000000000..9aa1535ad --- /dev/null +++ b/Race Element.UI/ViewModels/SetupsViewModel.cs @@ -0,0 +1,5 @@ +namespace RaceElement.UI.ViewModels; + +internal class SetupsViewModel : ViewModelBase +{ +} \ No newline at end of file diff --git a/Race Element.UI/ViewModels/ToolsViewModel.cs b/Race Element.UI/ViewModels/ToolsViewModel.cs new file mode 100644 index 000000000..a01899012 --- /dev/null +++ b/Race Element.UI/ViewModels/ToolsViewModel.cs @@ -0,0 +1,5 @@ +namespace RaceElement.UI.ViewModels; + +internal class ToolsViewModel : ViewModelBase +{ +} \ No newline at end of file diff --git a/Race Element.UI/ViewModels/ViewModelBase.cs b/Race Element.UI/ViewModels/ViewModelBase.cs new file mode 100644 index 000000000..0066683bf --- /dev/null +++ b/Race Element.UI/ViewModels/ViewModelBase.cs @@ -0,0 +1,7 @@ +using ReactiveUI; + +namespace RaceElement.UI.ViewModels; + +public class ViewModelBase : ReactiveObject +{ +} diff --git a/Race Element.UI/Views/MainTopMenuView.axaml b/Race Element.UI/Views/MainTopMenuView.axaml new file mode 100644 index 000000000..167b594e5 --- /dev/null +++ b/Race Element.UI/Views/MainTopMenuView.axaml @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Race Element.UI/Views/MainTopMenuView.axaml.cs b/Race Element.UI/Views/MainTopMenuView.axaml.cs new file mode 100644 index 000000000..bcbf4bc11 --- /dev/null +++ b/Race Element.UI/Views/MainTopMenuView.axaml.cs @@ -0,0 +1,17 @@ +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace RaceElement.UI.Views; + +public partial class MainTopMenuView : UserControl +{ + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + + public MainTopMenuView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/Race Element.UI/Views/MainWindow.axaml b/Race Element.UI/Views/MainWindow.axaml new file mode 100644 index 000000000..34ec178e6 --- /dev/null +++ b/Race Element.UI/Views/MainWindow.axaml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Race Element.UI/Views/MainWindow.axaml.cs b/Race Element.UI/Views/MainWindow.axaml.cs new file mode 100644 index 000000000..45a5a8d25 --- /dev/null +++ b/Race Element.UI/Views/MainWindow.axaml.cs @@ -0,0 +1,20 @@ +using Avalonia; +using Avalonia.Controls; +using RaceElement.UI.ViewModels; +using Avalonia.Input; +using Avalonia.Interactivity; + +using RaceElement.UI.Views.Stylers; + +namespace RaceElement.UI.Views; + +public partial class MainWindow : Window +{ + public MainWindow() + { + InitializeComponent(); + + // Style the main window and set the default size + MainWindowStyler.Decorate(this); + } +} diff --git a/Race Element.UI/Views/Pages/DataPageView.axaml b/Race Element.UI/Views/Pages/DataPageView.axaml new file mode 100644 index 000000000..b145099ae --- /dev/null +++ b/Race Element.UI/Views/Pages/DataPageView.axaml @@ -0,0 +1,23 @@ + + + + + + + diff --git a/Race Element.UI/Views/Pages/DataPageView.axaml.cs b/Race Element.UI/Views/Pages/DataPageView.axaml.cs new file mode 100644 index 000000000..ad49dd25b --- /dev/null +++ b/Race Element.UI/Views/Pages/DataPageView.axaml.cs @@ -0,0 +1,17 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace RaceElement.UI.Views.Pages; + +public partial class DataPageView : UserControl +{ + public DataPageView() + { + InitializeComponent(); + } + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/Race Element.UI/Views/Pages/LiveriesPageView.axaml b/Race Element.UI/Views/Pages/LiveriesPageView.axaml new file mode 100644 index 000000000..19436629b --- /dev/null +++ b/Race Element.UI/Views/Pages/LiveriesPageView.axaml @@ -0,0 +1,23 @@ + + + + + + + diff --git a/Race Element.UI/Views/Pages/LiveriesPageView.axaml.cs b/Race Element.UI/Views/Pages/LiveriesPageView.axaml.cs new file mode 100644 index 000000000..ea4641655 --- /dev/null +++ b/Race Element.UI/Views/Pages/LiveriesPageView.axaml.cs @@ -0,0 +1,17 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace RaceElement.UI.Views.Pages; + +public partial class LiveriesPageView : UserControl +{ + public LiveriesPageView() + { + InitializeComponent(); + } + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/Race Element.UI/Views/Pages/OverlaysPageView.axaml b/Race Element.UI/Views/Pages/OverlaysPageView.axaml new file mode 100644 index 000000000..230f92d73 --- /dev/null +++ b/Race Element.UI/Views/Pages/OverlaysPageView.axaml @@ -0,0 +1,23 @@ + + + + + + + diff --git a/Race Element.UI/Views/Pages/OverlaysPageView.axaml.cs b/Race Element.UI/Views/Pages/OverlaysPageView.axaml.cs new file mode 100644 index 000000000..f31925b24 --- /dev/null +++ b/Race Element.UI/Views/Pages/OverlaysPageView.axaml.cs @@ -0,0 +1,18 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace RaceElement.UI.Views.Pages; + +public partial class OverlaysPageView : UserControl +{ + public OverlaysPageView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} diff --git a/Race Element.UI/Views/Pages/SetupsPageView.axaml b/Race Element.UI/Views/Pages/SetupsPageView.axaml new file mode 100644 index 000000000..f4c553fa8 --- /dev/null +++ b/Race Element.UI/Views/Pages/SetupsPageView.axaml @@ -0,0 +1,23 @@ + + + + + + + diff --git a/Race Element.UI/Views/Pages/SetupsPageView.axaml.cs b/Race Element.UI/Views/Pages/SetupsPageView.axaml.cs new file mode 100644 index 000000000..f30d580f4 --- /dev/null +++ b/Race Element.UI/Views/Pages/SetupsPageView.axaml.cs @@ -0,0 +1,17 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace RaceElement.UI.Views.Pages; + +public partial class SetupsPageView : UserControl +{ + public SetupsPageView() + { + InitializeComponent(); + } + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/Race Element.UI/Views/Pages/ToolsPageView.axaml b/Race Element.UI/Views/Pages/ToolsPageView.axaml new file mode 100644 index 000000000..9081e8e82 --- /dev/null +++ b/Race Element.UI/Views/Pages/ToolsPageView.axaml @@ -0,0 +1,23 @@ + + + + + + + diff --git a/Race Element.UI/Views/Pages/ToolsPageView.axaml.cs b/Race Element.UI/Views/Pages/ToolsPageView.axaml.cs new file mode 100644 index 000000000..cc522beeb --- /dev/null +++ b/Race Element.UI/Views/Pages/ToolsPageView.axaml.cs @@ -0,0 +1,17 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace RaceElement.UI.Views.Pages; + +public partial class ToolsPageView : UserControl +{ + public ToolsPageView() + { + InitializeComponent(); + } + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/Race Element.UI/Views/Stylers/ActiveButtonStyler.cs b/Race Element.UI/Views/Stylers/ActiveButtonStyler.cs new file mode 100644 index 000000000..d843708c5 --- /dev/null +++ b/Race Element.UI/Views/Stylers/ActiveButtonStyler.cs @@ -0,0 +1,37 @@ +using Avalonia; +using Avalonia.Data; +using Avalonia.Data.Converters; +using Avalonia.Media; +using System; +using System.Globalization; + +namespace RaceElement.UI.Views.Stylers; + +public sealed class ActiveButtonStyler : IValueConverter +{ + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + // Current page name from binding + string currentPage = value as string; + + // Button's page name from parameter + string buttonPage = parameter as string; + + // Check if this button matches the current page + bool isSelected = currentPage == buttonPage; + + // Return appropriate value based on property type + if (targetType == typeof(Thickness)) + return isSelected ? new Thickness(2) : new Thickness(1); + + if (targetType == typeof(IBrush)) + return isSelected ? new SolidColorBrush(Colors.DarkOrange) : new SolidColorBrush(Colors.Transparent); + + return null; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return value?.Equals(true) == true ? parameter : BindingOperations.DoNothing; + } +} \ No newline at end of file diff --git a/Race Element.UI/Views/Stylers/MainWindowStyler.cs b/Race Element.UI/Views/Stylers/MainWindowStyler.cs new file mode 100644 index 000000000..34c7325dd --- /dev/null +++ b/Race Element.UI/Views/Stylers/MainWindowStyler.cs @@ -0,0 +1,99 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Interactivity; +using Avalonia.Media; +using Avalonia.Platform; + +namespace RaceElement.UI.Views.Stylers; + +/// +/// Sets the default size of the window. +/// +/// +/// +public readonly struct WindowSize(int width, int height) +{ + public readonly double DefaultWidth { get; } = width; + public readonly double DefaultHeight { get; } = height; +} + +internal class MainWindowStyler +{ + public static void Decorate(Window window) + { + _mainWindow = window; + + // Initialize a WindowSize struct with 1200 and 768 values + _windowSize = new WindowSize(1200, 768); + + // Assign the values to the mainWindow attributes + _mainWindow.Width = _windowSize.DefaultWidth; + _mainWindow.Height = _windowSize.DefaultHeight; + _mainWindow.MinWidth = _windowSize.DefaultWidth; + _mainWindow.MinHeight = _windowSize.DefaultHeight; + + // Window configuration + _mainWindow.Background = Brushes.Transparent; + _mainWindow.ExtendClientAreaToDecorationsHint = true; + _mainWindow.ExtendClientAreaChromeHints = ExtendClientAreaChromeHints.NoChrome; + _mainWindow.ExtendClientAreaTitleBarHeightHint = -1; + _mainWindow.SystemDecorations = SystemDecorations.None; + _mainWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen; + + // To make mainwindow draggable + _mainWindow.Loaded += MainWindow_Loaded; + } + + private static void MainWindow_Loaded(object? sender, RoutedEventArgs e) + { + var TopMenuBar = _mainWindow.FindControl("TopMenuBar"); + // Access TopMenuBar directly by its generated field x:Name + if (TopMenuBar != null) + { + TopMenuBar.PointerPressed += (s, args) => + { + _isDragging = true; + _lastPosition = args.GetPosition(_mainWindow); + _mainWindow.PointerReleased += PointerReleasedHandler; + _mainWindow.PointerMoved += PointerMovedHandler; + }; + } + } + + private static void PointerReleasedHandler(object? sender, PointerReleasedEventArgs e) + { + _isDragging = false; + _mainWindow.PointerReleased -= PointerReleasedHandler; + _mainWindow.PointerMoved -= PointerMovedHandler; + } + + private static void PointerMovedHandler(object? sender, PointerEventArgs e) + { + if (_isDragging) + { + var currentPoint = e.GetPosition(_mainWindow); + var offset = currentPoint - _lastPosition; + + // Fix: Use _mainWindow.Position to update the window's position + _mainWindow.Position = new PixelPoint( + _mainWindow.Position.X + (int)offset.X, + _mainWindow.Position.Y + (int)offset.Y + ); + } + } + + /// ------------------------------------------------------------------------------ + /// Private Fields + /// ------------------------------------------------------------------------------ + + // Fields to track the dragging state and last position of the pointer + private static bool _isDragging = false; + private static Point _lastPosition; + + // WindowSize struct to hold the default window size + private static WindowSize _windowSize; + + // Reference to the main window + private static Window _mainWindow; +} diff --git a/Race Element.UI/app.manifest b/Race Element.UI/app.manifest new file mode 100644 index 000000000..a18ea31ab --- /dev/null +++ b/Race Element.UI/app.manifest @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/Race Element.sln b/Race Element.sln index 8c5c2f65b..21d2309d5 100644 --- a/Race Element.sln +++ b/Race Element.sln @@ -31,6 +31,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Race Element.HUD.Common", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Race Element.Graph", "Race Element.Graph\Race Element.Graph.csproj", "{E3205DD5-EF7D-427F-916C-E95531877AD6}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RaceElement.UI", "Race Element.UI\RaceElement.UI.csproj", "{FEF1EAFA-80D0-928B-79B0-879F7FE25C67}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug Minimized|Any CPU = Debug Minimized|Any CPU @@ -260,6 +262,24 @@ Global {E3205DD5-EF7D-427F-916C-E95531877AD6}.Release|x64.Build.0 = Release|Any CPU {E3205DD5-EF7D-427F-916C-E95531877AD6}.Release|x86.ActiveCfg = Release|Any CPU {E3205DD5-EF7D-427F-916C-E95531877AD6}.Release|x86.Build.0 = Release|Any CPU + {FEF1EAFA-80D0-928B-79B0-879F7FE25C67}.Debug Minimized|Any CPU.ActiveCfg = Debug|Any CPU + {FEF1EAFA-80D0-928B-79B0-879F7FE25C67}.Debug Minimized|Any CPU.Build.0 = Debug|Any CPU + {FEF1EAFA-80D0-928B-79B0-879F7FE25C67}.Debug Minimized|x64.ActiveCfg = Debug|Any CPU + {FEF1EAFA-80D0-928B-79B0-879F7FE25C67}.Debug Minimized|x64.Build.0 = Debug|Any CPU + {FEF1EAFA-80D0-928B-79B0-879F7FE25C67}.Debug Minimized|x86.ActiveCfg = Debug|Any CPU + {FEF1EAFA-80D0-928B-79B0-879F7FE25C67}.Debug Minimized|x86.Build.0 = Debug|Any CPU + {FEF1EAFA-80D0-928B-79B0-879F7FE25C67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FEF1EAFA-80D0-928B-79B0-879F7FE25C67}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FEF1EAFA-80D0-928B-79B0-879F7FE25C67}.Debug|x64.ActiveCfg = Debug|Any CPU + {FEF1EAFA-80D0-928B-79B0-879F7FE25C67}.Debug|x64.Build.0 = Debug|Any CPU + {FEF1EAFA-80D0-928B-79B0-879F7FE25C67}.Debug|x86.ActiveCfg = Debug|Any CPU + {FEF1EAFA-80D0-928B-79B0-879F7FE25C67}.Debug|x86.Build.0 = Debug|Any CPU + {FEF1EAFA-80D0-928B-79B0-879F7FE25C67}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FEF1EAFA-80D0-928B-79B0-879F7FE25C67}.Release|Any CPU.Build.0 = Release|Any CPU + {FEF1EAFA-80D0-928B-79B0-879F7FE25C67}.Release|x64.ActiveCfg = Release|Any CPU + {FEF1EAFA-80D0-928B-79B0-879F7FE25C67}.Release|x64.Build.0 = Release|Any CPU + {FEF1EAFA-80D0-928B-79B0-879F7FE25C67}.Release|x86.ActiveCfg = Release|Any CPU + {FEF1EAFA-80D0-928B-79B0-879F7FE25C67}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 58aef3da6fe4eadb58f23be553d332fd6bd9b51f Mon Sep 17 00:00:00 2001 From: Tolga YILMAZ Date: Thu, 10 Apr 2025 21:19:56 +0200 Subject: [PATCH 2/9] Update overlays page to have a left menu --- Race Element.UI/App.axaml | 5 +- Race Element.UI/Assets/Banner.png | Bin 0 -> 13127 bytes Race Element.UI/Views/MainWindow.axaml.cs | 4 +- .../Views/Pages/OverlaysPageView.axaml | 77 ++++++++++++++++-- 4 files changed, 76 insertions(+), 10 deletions(-) create mode 100644 Race Element.UI/Assets/Banner.png diff --git a/Race Element.UI/App.axaml b/Race Element.UI/App.axaml index 4185b397e..8dcb197b2 100644 --- a/Race Element.UI/App.axaml +++ b/Race Element.UI/App.axaml @@ -10,9 +10,8 @@ - - - + + \ No newline at end of file diff --git a/Race Element.UI/Assets/Banner.png b/Race Element.UI/Assets/Banner.png new file mode 100644 index 0000000000000000000000000000000000000000..916f5a7955f88cc15af3f015d37806965b89f1bf GIT binary patch literal 13127 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 literal 0 HcmV?d00001 diff --git a/Race Element.UI/Views/MainWindow.axaml.cs b/Race Element.UI/Views/MainWindow.axaml.cs index 45a5a8d25..7ebb64150 100644 --- a/Race Element.UI/Views/MainWindow.axaml.cs +++ b/Race Element.UI/Views/MainWindow.axaml.cs @@ -5,6 +5,7 @@ using Avalonia.Interactivity; using RaceElement.UI.Views.Stylers; +using Avalonia.Styling; namespace RaceElement.UI.Views; @@ -16,5 +17,6 @@ public MainWindow() // Style the main window and set the default size MainWindowStyler.Decorate(this); - } + Application.Current.SetValue(ThemeVariantScope.ActualThemeVariantProperty, ThemeVariant.Dark); + } } diff --git a/Race Element.UI/Views/Pages/OverlaysPageView.axaml b/Race Element.UI/Views/Pages/OverlaysPageView.axaml index 230f92d73..680b7d43a 100644 --- a/Race Element.UI/Views/Pages/OverlaysPageView.axaml +++ b/Race Element.UI/Views/Pages/OverlaysPageView.axaml @@ -5,7 +5,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:controls="clr-namespace:Avalonia.Themes.Neumorphism.Controls;assembly=Avalonia.Themes.Neumorphism" xmlns:assist="clr-namespace:Avalonia.Themes.Neumorphism.Assist;assembly=Avalonia.Themes.Neumorphism" -xmlns:material="using:Material.Icons.Avalonia" +xmlns:icons="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" xmlns:vm="using:RaceElement.UI.ViewModels" x:DataType="vm:OverlaysViewModel" mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="688" @@ -13,11 +13,76 @@ x:Class="RaceElement.UI.Views.Pages.OverlaysPageView" xmlns:stylers="using:RaceElement.UI.Views.Stylers"> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From de7ed8eec35c32d28a9db8c8aa6fc2a12ea140b6 Mon Sep 17 00:00:00 2001 From: Tolga YILMAZ Date: Sat, 12 Apr 2025 17:52:20 +0200 Subject: [PATCH 3/9] Adds menus and viewmodels Adds control panel buttons and ready to be filled --- Race Element.UI/App.axaml | 4 +- Race Element.UI/Assets/LeMans-Logo.svg | 75 +++++++++++ Race Element.UI/Assets/iracing-logo.png | Bin 0 -> 34113 bytes Race Element.UI/Assets/lmu-logo.png | Bin 0 -> 1661 bytes Race Element.UI/RaceElement.UI.csproj | 3 + Race Element.UI/ViewModels/DataViewModel.cs | 6 +- .../ViewModels/LiveriesViewModel.cs | 5 +- .../ViewModels/MainTopMenuViewModel.cs | 107 ++++++++++------ .../AccelerometerViewModel.cs | 6 + .../AverageLaptimeViewModel.cs | 7 + .../ControlButtonsPanelViewModel.cs | 121 ++++++++++++++++++ .../FuelOverlayViewModel.cs | 6 + .../InputsOverlayViewModel.cs | 6 + .../LaptimeOverlayViewModel.cs | 6 + .../OverlaySettingViewModelBase.cs | 107 ++++++++++++++++ .../RelativesOverlayViewModel.cs | 6 + .../SpotterOverlayViewModel.cs | 6 + .../StandingsOverlayViewModel.cs | 6 + .../TrackMapOverlayViewModel.cs | 6 + .../ViewModels/OverlaysViewModel.cs | 33 ++++- Race Element.UI/ViewModels/SetupsViewModel.cs | 6 +- Race Element.UI/ViewModels/ToolsViewModel.cs | 6 +- Race Element.UI/ViewModels/ViewModelBase.cs | 1 - Race Element.UI/Views/MainTopMenuView.axaml | 43 ++----- Race Element.UI/Views/MainWindow.axaml.cs | 14 +- .../Views/Pages/DataPageView.axaml.cs | 4 +- .../Views/Pages/LiveriesPageView.axaml.cs | 4 +- .../AccelerometerView.axaml | 111 ++++++++++++++++ .../AccelerometerView.axaml.cs | 55 ++++++++ .../AverageLaptimeView.axaml | 18 +++ .../AverageLaptimeView.axaml.cs | 55 ++++++++ .../ControlButtonsPanelView.axaml | 46 +++++++ .../ControlButtonsPanelView.axaml.cs | 32 +++++ .../OverlaySettingPages/FuelOverlayView.axaml | 20 +++ .../FuelOverlayView.axaml.cs | 55 ++++++++ .../InputsOverlayView.axaml | 20 +++ .../InputsOverlayView.axaml.cs | 55 ++++++++ .../LaptimeOverlayView.axaml | 20 +++ .../LaptimeOverlayView.axaml.cs | 55 ++++++++ .../RelativesOverlayView.axaml | 20 +++ .../RelativesOverlayView.axaml.cs | 55 ++++++++ .../SpotterOverlayView.axaml | 20 +++ .../SpotterOverlayView.axaml.cs | 55 ++++++++ .../StandingsOverlayView.axaml | 20 +++ .../StandingsOverlayView.axaml.cs | 55 ++++++++ .../TrackMapOverlayView.axaml | 20 +++ .../TrackMapOverlayView.axaml.cs | 55 ++++++++ .../Views/Pages/OverlaysPageView.axaml | 113 ++++++++++++++-- .../Views/Pages/OverlaysPageView.axaml.cs | 31 +++-- .../Views/Pages/SetupsPageView.axaml.cs | 5 +- .../Views/Pages/ToolsPageView.axaml.cs | 4 +- .../Views/Stylers/ActiveButtonStyler.cs | 4 +- 52 files changed, 1471 insertions(+), 122 deletions(-) create mode 100644 Race Element.UI/Assets/LeMans-Logo.svg create mode 100644 Race Element.UI/Assets/iracing-logo.png create mode 100644 Race Element.UI/Assets/lmu-logo.png create mode 100644 Race Element.UI/ViewModels/OverlaySettingViewModels/AccelerometerViewModel.cs create mode 100644 Race Element.UI/ViewModels/OverlaySettingViewModels/AverageLaptimeViewModel.cs create mode 100644 Race Element.UI/ViewModels/OverlaySettingViewModels/ControlButtonsPanelViewModel.cs create mode 100644 Race Element.UI/ViewModels/OverlaySettingViewModels/FuelOverlayViewModel.cs create mode 100644 Race Element.UI/ViewModels/OverlaySettingViewModels/InputsOverlayViewModel.cs create mode 100644 Race Element.UI/ViewModels/OverlaySettingViewModels/LaptimeOverlayViewModel.cs create mode 100644 Race Element.UI/ViewModels/OverlaySettingViewModels/OverlaySettingViewModelBase.cs create mode 100644 Race Element.UI/ViewModels/OverlaySettingViewModels/RelativesOverlayViewModel.cs create mode 100644 Race Element.UI/ViewModels/OverlaySettingViewModels/SpotterOverlayViewModel.cs create mode 100644 Race Element.UI/ViewModels/OverlaySettingViewModels/StandingsOverlayViewModel.cs create mode 100644 Race Element.UI/ViewModels/OverlaySettingViewModels/TrackMapOverlayViewModel.cs create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/AccelerometerView.axaml create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/AccelerometerView.axaml.cs create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/AverageLaptimeView.axaml create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/AverageLaptimeView.axaml.cs create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/ControlButtonsPanelView.axaml create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/ControlButtonsPanelView.axaml.cs create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/FuelOverlayView.axaml create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/FuelOverlayView.axaml.cs create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/InputsOverlayView.axaml create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/InputsOverlayView.axaml.cs create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/LaptimeOverlayView.axaml create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/LaptimeOverlayView.axaml.cs create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/RelativesOverlayView.axaml create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/RelativesOverlayView.axaml.cs create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/SpotterOverlayView.axaml create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/SpotterOverlayView.axaml.cs create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/StandingsOverlayView.axaml create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/StandingsOverlayView.axaml.cs create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/TrackMapOverlayView.axaml create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/TrackMapOverlayView.axaml.cs diff --git a/Race Element.UI/App.axaml b/Race Element.UI/App.axaml index 8dcb197b2..e111adb7d 100644 --- a/Race Element.UI/App.axaml +++ b/Race Element.UI/App.axaml @@ -4,14 +4,14 @@ xmlns:materialIcons="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" x:Class="RaceElement.UI.App" xmlns:local="using:RaceElement.UI" - RequestedThemeVariant="Dark"> + RequestedThemeVariant="Light"> - + \ No newline at end of file diff --git a/Race Element.UI/Assets/LeMans-Logo.svg b/Race Element.UI/Assets/LeMans-Logo.svg new file mode 100644 index 000000000..a5bc753ac --- /dev/null +++ b/Race Element.UI/Assets/LeMans-Logo.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Race Element.UI/Assets/iracing-logo.png b/Race Element.UI/Assets/iracing-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..979b53acbde809a23f61f9e956c33818f261daad GIT binary patch literal 34113 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 P00000NkvXXu0mjfN}JKu literal 0 HcmV?d00001 diff --git a/Race Element.UI/Assets/lmu-logo.png b/Race Element.UI/Assets/lmu-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..1ae90848dacc81e144af30b3c333851f33cfcc7f GIT binary patch literal 1661 zcmah}`#akQA5GV%?b^7s)9J>vLnYYgNXU|qYSkrEm%0Rzxzwf9!cbHcU0>2S(W=+= zHI{ajxI}^olF({bHJ8>k7niWkZLTR&rN}qm*q?+O2rMlF8TmkH3Q*MuM5clBE1;df+CE6d z6#(-K>WaF(j^6=li7FrtbP88_MycX+)S}Kku?#SD1#*g1u^C`09fTMH!!p1tR`rOj zE~*Abr`46by%(>+*gHU9KOmkIN%gr9$e}{~r3=0{D-`nBqzTON!=Y~0ynG8e$?@aT zj{8GajiO-L)*7L+{9Ix7B>6V}URK;TDBXTnrovMnZMPw)6cng@{{jO6$3&|F;QrK)fQF$%ebnn%2`H zWlsyaTF~gQn^-B<-qG-CH%it;Y8+VFu;jdzote?5Sfv8dHoSwn1NW1b`GRV==}Sx~ z)f4&IRO6YL_F57KV>P&A;=->F2Ws(@ z&Y928&|&iRF*s_~Tb$7OM;(zr;g=F1S-1;3B#MCMF6JS3KFUb-)Q>T+ynvp0wmls< zI1sR^4L%vtI5nTGzAiX&I8)QN+(ei-zIjFxedc<2az#AI|AmTpptxzZ@jPj;~BvFleDlQX#A zHHGvC{qJ!|n9mORawLh`MUNcYx@Vg5Jj-0FT@Z%y;e0F75)xFwyuDx0 z)m)VA)Ele0nV;?l4cAzi=qYm^B{wk^7Cda9Bpqwpv|uqEcT7md{Wx)c-K?k@jYcnx z{fyq(&P%9U+rK*Rsvz~1GZ90#fO*J$LcV#wwHs-K zsVCmt7V@rtXXyve^sbQ1JojPfxu$&5Fe4&k$nn;_>;oC$OL@Qk?AtR~<*3^}epC5* zZ_#Av28-6iI-T{h=EwoT51cW@yB>3o!WVw4QRVM$cf}=3@~eb)r9Hu;rf{T?bK zt&)e8xHUhnoT<(V>jR7)47i*y5M0QeTAikq#=)6iK6!u0qKx+rAdZh8>EBM-} zao>hxj=59c6IKTtJAV2tL}&LU$+XHf6Md3rt{tXSpVi8ae~C>OedELf68pNolhsU zb>~h6WzIZsgasrUrN35|xfgUaq_&k4iKXn{Ezld?2Og@_zIHbjB@3foe*wSdW_p>K zDHn6b^#w$Y(XjT$$3%s+F(I4n8JwjK8!NbS4dnZqox+w< MainTopMenuView.axaml + + ControlButtonsPanelView.axaml + diff --git a/Race Element.UI/ViewModels/DataViewModel.cs b/Race Element.UI/ViewModels/DataViewModel.cs index 9152bde7f..bcbe1081f 100644 --- a/Race Element.UI/ViewModels/DataViewModel.cs +++ b/Race Element.UI/ViewModels/DataViewModel.cs @@ -1,5 +1,7 @@ -namespace RaceElement.UI.ViewModels; +using ReactiveUI; -internal class DataViewModel : ViewModelBase +namespace RaceElement.UI.ViewModels; + +public class DataViewModel : ViewModelBase { } \ No newline at end of file diff --git a/Race Element.UI/ViewModels/LiveriesViewModel.cs b/Race Element.UI/ViewModels/LiveriesViewModel.cs index 1dbc06ada..b82b88aaa 100644 --- a/Race Element.UI/ViewModels/LiveriesViewModel.cs +++ b/Race Element.UI/ViewModels/LiveriesViewModel.cs @@ -1,5 +1,6 @@ -namespace RaceElement.UI.ViewModels; +using ReactiveUI; -internal class LiveriesViewModel : ViewModelBase +namespace RaceElement.UI.ViewModels; +public class LiveriesViewModel : ViewModelBase { } \ No newline at end of file diff --git a/Race Element.UI/ViewModels/MainTopMenuViewModel.cs b/Race Element.UI/ViewModels/MainTopMenuViewModel.cs index fa2543aef..624ba6cca 100644 --- a/Race Element.UI/ViewModels/MainTopMenuViewModel.cs +++ b/Race Element.UI/ViewModels/MainTopMenuViewModel.cs @@ -1,48 +1,73 @@ -using ReactiveUI; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Controls; +using ReactiveUI; using System; using System.Reactive; namespace RaceElement.UI.ViewModels; public class MainTopMenuViewModel : ViewModelBase { - // Reference to the main window view model for Navigation, DI can be used to access - private MainWindowViewModel? _mainWindowViewModel; - - private string _currentPageName = "Overlays"; // Default page - - public string CurrentPageName - { - get => _currentPageName; - private set => this.RaiseAndSetIfChanged(ref _currentPageName, value); - } - - public MainTopMenuViewModel() - { - // Initialize navigation commands - NavigateToOverlaysPageCommand = ReactiveCommand.Create(() => { _mainWindowViewModel?.NavigateTo(new OverlaysViewModel()); CurrentPageName = "Overlays"; }); - NavigateToDataPageCommand = ReactiveCommand.Create(() => { _mainWindowViewModel?.NavigateTo(new DataViewModel()); CurrentPageName = "Data"; }); - NavigateToSetupsPageCommand = ReactiveCommand.Create(() => { _mainWindowViewModel?.NavigateTo(new SetupsViewModel()); CurrentPageName = "Setups"; }); - NavigateToLiveriesPageCommand = ReactiveCommand.Create(() => { _mainWindowViewModel?.NavigateTo(new LiveriesViewModel()); CurrentPageName = "Liveries"; }); - NavigateToToolsPageCommand = ReactiveCommand.Create(() => { _mainWindowViewModel?.NavigateTo(new ToolsViewModel()); CurrentPageName = "Tools"; }); - } - - // Navigation commands - public ReactiveCommand NavigateToOverlaysPageCommand { get; } - public ReactiveCommand NavigateToDataPageCommand { get; } - public ReactiveCommand NavigateToSetupsPageCommand { get; } - public ReactiveCommand NavigateToLiveriesPageCommand { get; } - public ReactiveCommand NavigateToToolsPageCommand { get; } - - // Command to close the application - public ReactiveCommand CloseApplicationCommand => ReactiveCommand.Create(() => { Environment.Exit(0); }); - - internal void SetMainWindowViewModel(MainWindowViewModel mainWindowViewModel) - { - _mainWindowViewModel = mainWindowViewModel; - } - - public bool IsCurrentPage(ViewModelBase page) - { - return _mainWindowViewModel?.CurrentPage == page; - } + #region PRIVATE FIELDS + + // Reference to the main window view model for Navigation, DI can be used to access + private MainWindowViewModel? _mainWindowViewModel; + // Default page + private string _currentPageName = "Overlays"; + #endregion + + #region CONSTRUCTORS + public MainTopMenuViewModel() + { + // Initialize navigation commands + NavigateToOverlaysPageCommand = ReactiveCommand.Create(() => { _mainWindowViewModel?.NavigateTo(new OverlaysViewModel()); CurrentPageName = "Overlays"; }); + NavigateToDataPageCommand = ReactiveCommand.Create(() => { _mainWindowViewModel?.NavigateTo(new DataViewModel()); CurrentPageName = "Data"; }); + NavigateToSetupsPageCommand = ReactiveCommand.Create(() => { _mainWindowViewModel?.NavigateTo(new SetupsViewModel()); CurrentPageName = "Setups"; }); + NavigateToLiveriesPageCommand = ReactiveCommand.Create(() => { _mainWindowViewModel?.NavigateTo(new LiveriesViewModel()); CurrentPageName = "Liveries"; }); + NavigateToToolsPageCommand = ReactiveCommand.Create(() => { _mainWindowViewModel?.NavigateTo(new ToolsViewModel()); CurrentPageName = "Tools"; }); + } + #endregion + + #region PUBIC PROPERTIES + public string CurrentPageName + { + get => _currentPageName; + private set => this.RaiseAndSetIfChanged(ref _currentPageName, value); + } + #endregion + + #region PUBLIC COMMANDS/METHODS + public bool IsCurrentPage(ViewModelBase page) + { + return _mainWindowViewModel?.CurrentPage == page; + } + + // Navigation commands + public ReactiveCommand NavigateToOverlaysPageCommand { get; } + public ReactiveCommand NavigateToDataPageCommand { get; } + public ReactiveCommand NavigateToSetupsPageCommand { get; } + public ReactiveCommand NavigateToLiveriesPageCommand { get; } + public ReactiveCommand NavigateToToolsPageCommand { get; } + + // Command to close the application + public static ReactiveCommand CloseApplicationCommand => ReactiveCommand.Create(() => { Environment.Exit(0); }); + + // Command to minimize the application + public static ReactiveCommand MinimizeApplicationCommand => ReactiveCommand.Create(() => + { + if (Avalonia.Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime) + { + desktopLifetime.MainWindow.WindowState = WindowState.Minimized; + } + }); + #endregion + + #region INTERNAL METHODS + internal void SetMainWindowViewModel(MainWindowViewModel mainWindowViewModel) + { + _mainWindowViewModel = mainWindowViewModel; + } + #endregion + + #region PRIVATE METHODS + #endregion } diff --git a/Race Element.UI/ViewModels/OverlaySettingViewModels/AccelerometerViewModel.cs b/Race Element.UI/ViewModels/OverlaySettingViewModels/AccelerometerViewModel.cs new file mode 100644 index 000000000..d4a9ee4b8 --- /dev/null +++ b/Race Element.UI/ViewModels/OverlaySettingViewModels/AccelerometerViewModel.cs @@ -0,0 +1,6 @@ +using ReactiveUI; + +namespace RaceElement.UI.ViewModels.OverlaySettingViewModels; +public class AccelerometerViewModel : OverlaySettingViewModelBase +{ +} diff --git a/Race Element.UI/ViewModels/OverlaySettingViewModels/AverageLaptimeViewModel.cs b/Race Element.UI/ViewModels/OverlaySettingViewModels/AverageLaptimeViewModel.cs new file mode 100644 index 000000000..a1cdfc1e5 --- /dev/null +++ b/Race Element.UI/ViewModels/OverlaySettingViewModels/AverageLaptimeViewModel.cs @@ -0,0 +1,7 @@ +using ReactiveUI; + +namespace RaceElement.UI.ViewModels.OverlaySettingViewModels; +public class AverageLaptimeViewModel : OverlaySettingViewModelBase +{ + +} diff --git a/Race Element.UI/ViewModels/OverlaySettingViewModels/ControlButtonsPanelViewModel.cs b/Race Element.UI/ViewModels/OverlaySettingViewModels/ControlButtonsPanelViewModel.cs new file mode 100644 index 000000000..853306d5f --- /dev/null +++ b/Race Element.UI/ViewModels/OverlaySettingViewModels/ControlButtonsPanelViewModel.cs @@ -0,0 +1,121 @@ +using Avalonia.Media; +using ReactiveUI; +using System; +using System.Reactive; +using System.Threading.Tasks; + +namespace RaceElement.UI.ViewModels.OverlaySettingViewModels; + +public class ControlButtonsPanelViewModel : ViewModelBase +{ + // Reference to the current overlay view model + private ViewModelBase _currentOverlayViewModel; + + // Commands for each button in the control panel + public ReactiveCommand ActivateCommand { get; } + public ReactiveCommand PreviewNowCommand { get; } + public ReactiveCommand AddFavoriteCommand { get; } + public ReactiveCommand ResetToDefaultCommand { get; } + public ReactiveCommand MoveResizeCommand { get; } + public ReactiveCommand SaveChangesCommand { get; } + + public ControlButtonsPanelViewModel() + { + // Initialize commands with their implementations + ActivateCommand = ReactiveCommand.CreateFromTask(OnActivateAsync); + PreviewNowCommand = ReactiveCommand.CreateFromTask(OnPreviewNowAsync); + AddFavoriteCommand = ReactiveCommand.CreateFromTask(OnAddFavoriteAsync); + ResetToDefaultCommand = ReactiveCommand.CreateFromTask(OnResetToDefaultAsync); + MoveResizeCommand = ReactiveCommand.CreateFromTask(OnMoveResizeAsync); + SaveChangesCommand = ReactiveCommand.CreateFromTask(OnSaveChangesAsync); + } + + // Property to determine the favorite icon's color + private IBrush _favoriteIconColor = Brushes.White; + public IBrush FavoriteIconColor + { + get => _favoriteIconColor; + private set => this.RaiseAndSetIfChanged(ref _favoriteIconColor, value); + } + + // Property to track if the current overlay is a favorite + private bool _isCurrentOverlayFavorite; + public bool IsCurrentOverlayFavorite + { + get => _isCurrentOverlayFavorite; + set + { + this.RaiseAndSetIfChanged(ref _isCurrentOverlayFavorite, value); + UpdateFavoriteIconColor(); + + // If the current overlay is any type of OverlaySettingViewModelBase, update its IsFavorite property + if (_currentOverlayViewModel is OverlaySettingViewModelBase accelerometerVM) + { + accelerometerVM.IsFavorite = value; + } + } + } + + public void SetCurrentOverlayViewModel(ViewModelBase viewModel) + { + _currentOverlayViewModel = viewModel; + + // Update favorite status based on the current view model + if (_currentOverlayViewModel is OverlaySettingViewModelBase accelerometerVM) + { + IsCurrentOverlayFavorite = accelerometerVM.IsFavorite; + + accelerometerVM.WhenAnyValue(vm => vm.IsFavorite) + .Subscribe(isFavorite => + { + IsCurrentOverlayFavorite = isFavorite; + }); + } + else + { + IsCurrentOverlayFavorite = false; + } + } + + private void UpdateFavoriteIconColor() + { + FavoriteIconColor = IsCurrentOverlayFavorite ? Brushes.Red : Brushes.White; + } + + private async Task OnActivateAsync() + { + // Implement the logic to activate the overlay + await Task.CompletedTask; + } + + private async Task OnPreviewNowAsync() + { + // Implement the logic to preview the overlay + await Task.CompletedTask; + } + + private async Task OnAddFavoriteAsync() + { + // Toggle the favorite status + IsCurrentOverlayFavorite = !IsCurrentOverlayFavorite; + await Task.CompletedTask; + } + + private async Task OnResetToDefaultAsync() + { + // Implement the logic to reset settings to default values + await Task.CompletedTask; + } + + private async Task OnMoveResizeAsync() + { + // Implement the logic to reset settings to default values + await Task.CompletedTask; + } + + private async Task OnSaveChangesAsync() + { + // Implement the logic to save the current settings + await Task.CompletedTask; + } +} diff --git a/Race Element.UI/ViewModels/OverlaySettingViewModels/FuelOverlayViewModel.cs b/Race Element.UI/ViewModels/OverlaySettingViewModels/FuelOverlayViewModel.cs new file mode 100644 index 000000000..ce9a141d7 --- /dev/null +++ b/Race Element.UI/ViewModels/OverlaySettingViewModels/FuelOverlayViewModel.cs @@ -0,0 +1,6 @@ +using ReactiveUI; + +namespace RaceElement.UI.ViewModels.OverlaySettingViewModels; +public class FuelOverlayViewModel : OverlaySettingViewModelBase +{ +} diff --git a/Race Element.UI/ViewModels/OverlaySettingViewModels/InputsOverlayViewModel.cs b/Race Element.UI/ViewModels/OverlaySettingViewModels/InputsOverlayViewModel.cs new file mode 100644 index 000000000..72535d796 --- /dev/null +++ b/Race Element.UI/ViewModels/OverlaySettingViewModels/InputsOverlayViewModel.cs @@ -0,0 +1,6 @@ +using ReactiveUI; + +namespace RaceElement.UI.ViewModels.OverlaySettingViewModels; +public class InputsOverlayViewModel : OverlaySettingViewModelBase +{ +} diff --git a/Race Element.UI/ViewModels/OverlaySettingViewModels/LaptimeOverlayViewModel.cs b/Race Element.UI/ViewModels/OverlaySettingViewModels/LaptimeOverlayViewModel.cs new file mode 100644 index 000000000..b3e757a8d --- /dev/null +++ b/Race Element.UI/ViewModels/OverlaySettingViewModels/LaptimeOverlayViewModel.cs @@ -0,0 +1,6 @@ +using ReactiveUI; + +namespace RaceElement.UI.ViewModels.OverlaySettingViewModels; +public class LaptimeOverlayViewModel : OverlaySettingViewModelBase +{ +} diff --git a/Race Element.UI/ViewModels/OverlaySettingViewModels/OverlaySettingViewModelBase.cs b/Race Element.UI/ViewModels/OverlaySettingViewModels/OverlaySettingViewModelBase.cs new file mode 100644 index 000000000..e2e556f50 --- /dev/null +++ b/Race Element.UI/ViewModels/OverlaySettingViewModels/OverlaySettingViewModelBase.cs @@ -0,0 +1,107 @@ +using Avalonia.Media; +using ReactiveUI; +using System.Collections.ObjectModel; + +namespace RaceElement.UI.ViewModels.OverlaySettingViewModels; +public class OverlaySettingViewModelBase : ViewModelBase +{ + private bool _isFavorite; + public bool IsFavorite + { + get => _isFavorite; + set => this.RaiseAndSetIfChanged(ref _isFavorite, value); + } + + // Display Settings + private bool _isEnabled = true; + public bool IsEnabled + { + get => _isEnabled; + set => this.RaiseAndSetIfChanged(ref _isEnabled, value); + } + + private double _size = 150; + public double Size + { + get => _size; + set => this.RaiseAndSetIfChanged(ref _size, value); + } + + private double _opacity = 0.8; + public double Opacity + { + get => _opacity; + set => this.RaiseAndSetIfChanged(ref _opacity, value); + } + + // Behavior Settings + private double _sensitivity = 1.0; + public double Sensitivity + { + get => _sensitivity; + set => this.RaiseAndSetIfChanged(ref _sensitivity, value); + } + + private double _smoothing = 3; + public double Smoothing + { + get => _smoothing; + set => this.RaiseAndSetIfChanged(ref _smoothing, value); + } + + // Position Settings + private int _selectedPositionIndex = 0; + public int SelectedPositionIndex + { + get => _selectedPositionIndex; + set => this.RaiseAndSetIfChanged(ref _selectedPositionIndex, value); + } + + public ObservableCollection PositionPresets { get; } = new ObservableCollection + { + "Center", "Top Left", "Top Right", "Bottom Left", "Bottom Right", "Custom" + }; + + private double _xPosition = 50; + public double XPosition + { + get => _xPosition; + set => this.RaiseAndSetIfChanged(ref _xPosition, value); + } + + private double _yPosition = 50; + public double YPosition + { + get => _yPosition; + set => this.RaiseAndSetIfChanged(ref _yPosition, value); + } + + private bool _alwaysOnTop = true; + public bool AlwaysOnTop + { + get => _alwaysOnTop; + set => this.RaiseAndSetIfChanged(ref _alwaysOnTop, value); + } + + // Appearance + private Color _backgroundColor = Colors.Transparent; + public Color BackgroundColor + { + get => _backgroundColor; + set => this.RaiseAndSetIfChanged(ref _backgroundColor, value); + } + + private Color _indicatorColor = Colors.Red; + public Color IndicatorColor + { + get => _indicatorColor; + set => this.RaiseAndSetIfChanged(ref _indicatorColor, value); + } + + private bool _showGridLines = true; + public bool ShowGridLines + { + get => _showGridLines; + set => this.RaiseAndSetIfChanged(ref _showGridLines, value); + } +} diff --git a/Race Element.UI/ViewModels/OverlaySettingViewModels/RelativesOverlayViewModel.cs b/Race Element.UI/ViewModels/OverlaySettingViewModels/RelativesOverlayViewModel.cs new file mode 100644 index 000000000..a23addd77 --- /dev/null +++ b/Race Element.UI/ViewModels/OverlaySettingViewModels/RelativesOverlayViewModel.cs @@ -0,0 +1,6 @@ +using ReactiveUI; + +namespace RaceElement.UI.ViewModels.OverlaySettingViewModels; +public class RelativesOverlayViewModel : OverlaySettingViewModelBase +{ +} diff --git a/Race Element.UI/ViewModels/OverlaySettingViewModels/SpotterOverlayViewModel.cs b/Race Element.UI/ViewModels/OverlaySettingViewModels/SpotterOverlayViewModel.cs new file mode 100644 index 000000000..9a23f859e --- /dev/null +++ b/Race Element.UI/ViewModels/OverlaySettingViewModels/SpotterOverlayViewModel.cs @@ -0,0 +1,6 @@ +using ReactiveUI; + +namespace RaceElement.UI.ViewModels.OverlaySettingViewModels; +public class SpotterOverlayViewModel : OverlaySettingViewModelBase +{ +} diff --git a/Race Element.UI/ViewModels/OverlaySettingViewModels/StandingsOverlayViewModel.cs b/Race Element.UI/ViewModels/OverlaySettingViewModels/StandingsOverlayViewModel.cs new file mode 100644 index 000000000..7c36806c8 --- /dev/null +++ b/Race Element.UI/ViewModels/OverlaySettingViewModels/StandingsOverlayViewModel.cs @@ -0,0 +1,6 @@ +using ReactiveUI; + +namespace RaceElement.UI.ViewModels.OverlaySettingViewModels; +public class StandingsOverlayViewModel : OverlaySettingViewModelBase +{ +} diff --git a/Race Element.UI/ViewModels/OverlaySettingViewModels/TrackMapOverlayViewModel.cs b/Race Element.UI/ViewModels/OverlaySettingViewModels/TrackMapOverlayViewModel.cs new file mode 100644 index 000000000..6126a730f --- /dev/null +++ b/Race Element.UI/ViewModels/OverlaySettingViewModels/TrackMapOverlayViewModel.cs @@ -0,0 +1,6 @@ +using ReactiveUI; + +namespace RaceElement.UI.ViewModels.OverlaySettingViewModels; +public class TrackMapOverlayViewModel : OverlaySettingViewModelBase +{ +} diff --git a/Race Element.UI/ViewModels/OverlaysViewModel.cs b/Race Element.UI/ViewModels/OverlaysViewModel.cs index f812d9552..35ecea594 100644 --- a/Race Element.UI/ViewModels/OverlaysViewModel.cs +++ b/Race Element.UI/ViewModels/OverlaysViewModel.cs @@ -1,5 +1,34 @@ -namespace RaceElement.UI.ViewModels; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using Avalonia.Input; +using Avalonia.Interactivity; +using RaceElement.UI.ViewModels.OverlaySettingViewModels; +using RaceElement.UI.Views.Pages.OverlaySettingPages; +using ReactiveUI; +using System.Collections.Generic; +using System.Reactive; -internal class OverlaysViewModel : ViewModelBase +namespace RaceElement.UI.ViewModels; + +public class OverlaysViewModel : ViewModelBase { + private int _selectedOverlayIndex; + public int SelectedOverlayIndex + { + get => _selectedOverlayIndex; + set => this.RaiseAndSetIfChanged(ref _selectedOverlayIndex, value); + } + + // You could optionally add a command if you need more complex logic + public ReactiveCommand SelectOverlayCommand { get; } + + public OverlaysViewModel() + { + // Initialize command + SelectOverlayCommand = ReactiveCommand.Create(index => + { + SelectedOverlayIndex = index; + // Any additional logic needed when selection changes + }); + } } \ No newline at end of file diff --git a/Race Element.UI/ViewModels/SetupsViewModel.cs b/Race Element.UI/ViewModels/SetupsViewModel.cs index 9aa1535ad..1ed68994d 100644 --- a/Race Element.UI/ViewModels/SetupsViewModel.cs +++ b/Race Element.UI/ViewModels/SetupsViewModel.cs @@ -1,5 +1,7 @@ -namespace RaceElement.UI.ViewModels; +using ReactiveUI; -internal class SetupsViewModel : ViewModelBase +namespace RaceElement.UI.ViewModels; + +public class SetupsViewModel : ViewModelBase { } \ No newline at end of file diff --git a/Race Element.UI/ViewModels/ToolsViewModel.cs b/Race Element.UI/ViewModels/ToolsViewModel.cs index a01899012..4f4586577 100644 --- a/Race Element.UI/ViewModels/ToolsViewModel.cs +++ b/Race Element.UI/ViewModels/ToolsViewModel.cs @@ -1,5 +1,7 @@ -namespace RaceElement.UI.ViewModels; +using ReactiveUI; -internal class ToolsViewModel : ViewModelBase +namespace RaceElement.UI.ViewModels; + +public class ToolsViewModel : ViewModelBase { } \ No newline at end of file diff --git a/Race Element.UI/ViewModels/ViewModelBase.cs b/Race Element.UI/ViewModels/ViewModelBase.cs index 0066683bf..4ec889023 100644 --- a/Race Element.UI/ViewModels/ViewModelBase.cs +++ b/Race Element.UI/ViewModels/ViewModelBase.cs @@ -1,7 +1,6 @@ using ReactiveUI; namespace RaceElement.UI.ViewModels; - public class ViewModelBase : ReactiveObject { } diff --git a/Race Element.UI/Views/MainTopMenuView.axaml b/Race Element.UI/Views/MainTopMenuView.axaml index 167b594e5..e6f6cfe69 100644 --- a/Race Element.UI/Views/MainTopMenuView.axaml +++ b/Race Element.UI/Views/MainTopMenuView.axaml @@ -6,6 +6,7 @@ xmlns:controls="clr-namespace:Avalonia.Themes.Neumorphism.Controls;assembly=Avalonia.Themes.Neumorphism" xmlns:assist="clr-namespace:Avalonia.Themes.Neumorphism.Assist;assembly=Avalonia.Themes.Neumorphism" xmlns:material="using:Material.Icons.Avalonia" + xmlns:icons="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" xmlns:vm="clr-namespace:RaceElement.UI.ViewModels" mc:Ignorable="d" d:DesignWidth="1280" d:DesignHeight="96" x:Class="RaceElement.UI.Views.MainTopMenuView" @@ -23,11 +24,6 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + @@ -77,11 +134,39 @@ xmlns:stylers="using:RaceElement.UI.Views.Stylers"> - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Race Element.UI/Views/Pages/OverlaysPageView.axaml.cs b/Race Element.UI/Views/Pages/OverlaysPageView.axaml.cs index f31925b24..7c95973cb 100644 --- a/Race Element.UI/Views/Pages/OverlaysPageView.axaml.cs +++ b/Race Element.UI/Views/Pages/OverlaysPageView.axaml.cs @@ -1,18 +1,31 @@ using Avalonia; using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Interactivity; using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; +using RaceElement.UI.ViewModels; +using ReactiveUI; namespace RaceElement.UI.Views.Pages; -public partial class OverlaysPageView : UserControl +public partial class OverlaysPageView : ReactiveUserControl { - public OverlaysPageView() - { - InitializeComponent(); - } + private ListBox OverlaysList => this.GetControl("OverlayItemsList"); - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } + public OverlaysPageView() + { + InitializeComponent(); + + // Set up additional bindings or event handlers in the WhenActivated method + this.WhenActivated(disposables => + { + // todo : Favorites can be checked + }); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } } diff --git a/Race Element.UI/Views/Pages/SetupsPageView.axaml.cs b/Race Element.UI/Views/Pages/SetupsPageView.axaml.cs index f30d580f4..b3178c3dd 100644 --- a/Race Element.UI/Views/Pages/SetupsPageView.axaml.cs +++ b/Race Element.UI/Views/Pages/SetupsPageView.axaml.cs @@ -1,10 +1,13 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; +using ReactiveUI; +using RaceElement.UI.ViewModels; namespace RaceElement.UI.Views.Pages; -public partial class SetupsPageView : UserControl +public partial class SetupsPageView : ReactiveUserControl { public SetupsPageView() { diff --git a/Race Element.UI/Views/Pages/ToolsPageView.axaml.cs b/Race Element.UI/Views/Pages/ToolsPageView.axaml.cs index cc522beeb..ae543d5d6 100644 --- a/Race Element.UI/Views/Pages/ToolsPageView.axaml.cs +++ b/Race Element.UI/Views/Pages/ToolsPageView.axaml.cs @@ -1,10 +1,12 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; +using RaceElement.UI.ViewModels; namespace RaceElement.UI.Views.Pages; -public partial class ToolsPageView : UserControl +public partial class ToolsPageView : ReactiveUserControl { public ToolsPageView() { diff --git a/Race Element.UI/Views/Stylers/ActiveButtonStyler.cs b/Race Element.UI/Views/Stylers/ActiveButtonStyler.cs index d843708c5..054cde78f 100644 --- a/Race Element.UI/Views/Stylers/ActiveButtonStyler.cs +++ b/Race Element.UI/Views/Stylers/ActiveButtonStyler.cs @@ -22,10 +22,10 @@ public object Convert(object value, Type targetType, object parameter, CultureIn // Return appropriate value based on property type if (targetType == typeof(Thickness)) - return isSelected ? new Thickness(2) : new Thickness(1); + return isSelected ? new Thickness(4) : new Thickness(1); if (targetType == typeof(IBrush)) - return isSelected ? new SolidColorBrush(Colors.DarkOrange) : new SolidColorBrush(Colors.Transparent); + return isSelected ? new SolidColorBrush(Colors.LightSteelBlue) : new SolidColorBrush(Colors.Transparent); return null; } From 65d75c154df1aab5386290b45b7dd2d2e4ed54d4 Mon Sep 17 00:00:00 2001 From: Tolga YILMAZ Date: Sat, 12 Apr 2025 22:13:07 +0200 Subject: [PATCH 4/9] Provide Game selection Icon change and also enable background logic execution if necessary --- Race Element.UI/Assets/LeMans-Logo.svg | 75 -------- Race Element.UI/Assets/acc-list-image.jpg | Bin 0 -> 6962 bytes Race Element.UI/Assets/acc.ico | Bin 0 -> 34494 bytes Race Element.UI/Assets/acevo-list-image.jpg | Bin 0 -> 8422 bytes Race Element.UI/Assets/acevo.ico | Bin 0 -> 140206 bytes Race Element.UI/Assets/iracing-list-image.jpg | Bin 0 -> 3208 bytes Race Element.UI/Assets/iracing-logo.png | Bin 34113 -> 0 bytes Race Element.UI/Assets/iracing.ico | Bin 0 -> 5182 bytes Race Element.UI/Assets/lmu-list-image.png | Bin 0 -> 12952 bytes Race Element.UI/Assets/lmu-logo.png | Bin 1661 -> 0 bytes Race Element.UI/Assets/lmu.ico | Bin 0 -> 67646 bytes .../Services/GameSelectionService.cs | 113 +++++++++++ .../ViewModels/MainTopMenuViewModel.cs | 31 +++ Race Element.UI/Views/MainTopMenuView.axaml | 92 ++++++++- .../Views/Stylers/GameSelectionIconStyler.cs | 46 +++++ .../Views/Stylers/MainWindowStyler.cs | 178 +++++++++++------- 16 files changed, 386 insertions(+), 149 deletions(-) delete mode 100644 Race Element.UI/Assets/LeMans-Logo.svg create mode 100644 Race Element.UI/Assets/acc-list-image.jpg create mode 100644 Race Element.UI/Assets/acc.ico create mode 100644 Race Element.UI/Assets/acevo-list-image.jpg create mode 100644 Race Element.UI/Assets/acevo.ico create mode 100644 Race Element.UI/Assets/iracing-list-image.jpg delete mode 100644 Race Element.UI/Assets/iracing-logo.png create mode 100644 Race Element.UI/Assets/iracing.ico create mode 100644 Race Element.UI/Assets/lmu-list-image.png delete mode 100644 Race Element.UI/Assets/lmu-logo.png create mode 100644 Race Element.UI/Assets/lmu.ico create mode 100644 Race Element.UI/Services/GameSelectionService.cs create mode 100644 Race Element.UI/Views/Stylers/GameSelectionIconStyler.cs diff --git a/Race Element.UI/Assets/LeMans-Logo.svg b/Race Element.UI/Assets/LeMans-Logo.svg deleted file mode 100644 index a5bc753ac..000000000 --- a/Race Element.UI/Assets/LeMans-Logo.svg +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Race Element.UI/Assets/acc-list-image.jpg b/Race Element.UI/Assets/acc-list-image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f158804315fa928c1677d270ba9d5ee301cce6f2 GIT binary patch literal 6962 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 R{V9dJ|2)7ye*IX1{|ASaUgrP+ literal 0 HcmV?d00001 diff --git a/Race Element.UI/Assets/acevo-list-image.jpg b/Race Element.UI/Assets/acevo-list-image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8b05333a17fcea0ed47a70bfac1f83a782254273 GIT binary patch literal 8422 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 literal 0 HcmV?d00001 diff --git a/Race Element.UI/Assets/acevo.ico b/Race Element.UI/Assets/acevo.ico new file mode 100644 index 0000000000000000000000000000000000000000..a4d130e1fa098ca5ea9cef31e0ab4ad1914a9a2a GIT binary patch literal 140206 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∋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%0AZ->dNpt)z848 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 P00000NkvXXu0mjfN}JKu diff --git a/Race Element.UI/Assets/iracing.ico b/Race Element.UI/Assets/iracing.ico new file mode 100644 index 0000000000000000000000000000000000000000..024add7494e7e489849874562631eb84c45d1ed3 GIT binary patch literal 5182 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 literal 0 HcmV?d00001 diff --git a/Race Element.UI/Services/GameSelectionService.cs b/Race Element.UI/Services/GameSelectionService.cs new file mode 100644 index 000000000..38156c13c --- /dev/null +++ b/Race Element.UI/Services/GameSelectionService.cs @@ -0,0 +1,113 @@ +// Create a new file: Race Element.UI/Services/GameSelectionService.cs +using ReactiveUI; +using System; +using System.Diagnostics; + +namespace RaceElement.UI.Services; + +public enum SupportedGame +{ + IRacing, + ACC, + ACEvo, + LMU +} + +/// +/// Provides application-wide access to the currently selected game +/// +public class GameSelectionService : ReactiveObject +{ + private static GameSelectionService? _instance; + + private string _selectedGame = "acc"; + + // Constructor is private to enforce singleton pattern + private GameSelectionService() { } + + /// + /// Gets the currently selected game + /// + public string SelectedGame => _selectedGame; + + public static GameSelectionService Instance => _instance ??= new GameSelectionService(); + // Helper methods to check for specific games + public bool IsIRacing => SelectedGame == "iracing"; + public bool IsACC => SelectedGame == "acc"; + public bool IsACEvo => SelectedGame == "acevo"; + public bool IsLMU => SelectedGame == "lmu"; + + /// + /// Updates the selected game (internal - only used by MainTopMenuViewModel) + /// + internal void UpdateSelectedGame(string game) + { + this.RaiseAndSetIfChanged(ref _selectedGame, game); + } + + /// + /// Updates the selected game and performs any game-specific initialization logic + /// + /// The game identifier + /// True if the selection was valid and processed, false otherwise + internal bool SelectGame(string selection) + { + string game = selection.ToLower(); + + // Skip if same game selected + if (_selectedGame == game) return false; + + // Update the selected game + this.RaiseAndSetIfChanged(ref _selectedGame, game); + + // Perform game-specific initialization + InitializeGameSpecificSettings(game); + + return true; + } + + /// + /// Initializes game-specific settings and configurations + /// + private void InitializeGameSpecificSettings(string game) + { + switch (game) + { + case "iracing": + // iRacing-specific initialization + InitializeIRacingSettings(); + break; + + case "acc": + // ACC-specific initialization + InitializeACCSettings(); + break; + + case "acevo": + // AC Evo-specific initialization + InitializeACEvoSettings(); + break; + + case "lmu": + // LMU-specific initialization + InitializeLMUSettings(); + break; + } + } + + private void InitializeIRacingSettings() + { + } + + private void InitializeACCSettings() + { + } + + private void InitializeACEvoSettings() + { + } + + private void InitializeLMUSettings() + { + } +} diff --git a/Race Element.UI/ViewModels/MainTopMenuViewModel.cs b/Race Element.UI/ViewModels/MainTopMenuViewModel.cs index 624ba6cca..bc07b3868 100644 --- a/Race Element.UI/ViewModels/MainTopMenuViewModel.cs +++ b/Race Element.UI/ViewModels/MainTopMenuViewModel.cs @@ -3,6 +3,8 @@ using ReactiveUI; using System; using System.Reactive; +using System.Diagnostics; +using RaceElement.UI.Services; namespace RaceElement.UI.ViewModels; public class MainTopMenuViewModel : ViewModelBase @@ -13,6 +15,8 @@ public class MainTopMenuViewModel : ViewModelBase private MainWindowViewModel? _mainWindowViewModel; // Default page private string _currentPageName = "Overlays"; + // Track the current game icon source + private string _currentGameIconSource; #endregion #region CONSTRUCTORS @@ -24,6 +28,9 @@ public MainTopMenuViewModel() NavigateToSetupsPageCommand = ReactiveCommand.Create(() => { _mainWindowViewModel?.NavigateTo(new SetupsViewModel()); CurrentPageName = "Setups"; }); NavigateToLiveriesPageCommand = ReactiveCommand.Create(() => { _mainWindowViewModel?.NavigateTo(new LiveriesViewModel()); CurrentPageName = "Liveries"; }); NavigateToToolsPageCommand = ReactiveCommand.Create(() => { _mainWindowViewModel?.NavigateTo(new ToolsViewModel()); CurrentPageName = "Tools"; }); + + // Initialize GameSelectionCommand + GameSelectionCommand = ReactiveCommand.Create(HandleGameSelection); } #endregion @@ -33,6 +40,14 @@ public string CurrentPageName get => _currentPageName; private set => this.RaiseAndSetIfChanged(ref _currentPageName, value); } + + public string SelectedGame + { + get => GameSelectionService.Instance.SelectedGame; + private set => GameSelectionService.Instance.UpdateSelectedGame(value); + } + + public string CurrentGameIconSource => $"avares://RaceElement.UI/Assets/{SelectedGame}.ico"; #endregion #region PUBLIC COMMANDS/METHODS @@ -48,6 +63,9 @@ public bool IsCurrentPage(ViewModelBase page) public ReactiveCommand NavigateToLiveriesPageCommand { get; } public ReactiveCommand NavigateToToolsPageCommand { get; } + // Command for game selection from dropdown + public ReactiveCommand GameSelectionCommand { get; } + // Command to close the application public static ReactiveCommand CloseApplicationCommand => ReactiveCommand.Create(() => { Environment.Exit(0); }); @@ -69,5 +87,18 @@ internal void SetMainWindowViewModel(MainWindowViewModel mainWindowViewModel) #endregion #region PRIVATE METHODS + /// + /// Handles the game selection from the dropdown menu. + /// + /// + private void HandleGameSelection(string selection) + { + // Let the service handle game selection and initialization + if (GameSelectionService.Instance.SelectGame(selection)) + { + // Update UI only if the game actually changed + this.RaisePropertyChanged(nameof(CurrentGameIconSource)); + } + } #endregion } diff --git a/Race Element.UI/Views/MainTopMenuView.axaml b/Race Element.UI/Views/MainTopMenuView.axaml index e6f6cfe69..29d405a1e 100644 --- a/Race Element.UI/Views/MainTopMenuView.axaml +++ b/Race Element.UI/Views/MainTopMenuView.axaml @@ -5,9 +5,11 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:controls="clr-namespace:Avalonia.Themes.Neumorphism.Controls;assembly=Avalonia.Themes.Neumorphism" xmlns:assist="clr-namespace:Avalonia.Themes.Neumorphism.Assist;assembly=Avalonia.Themes.Neumorphism" + xmlns:naming="clr-namespace:Avalonia.Themes.Neumorphism.Resources.Naming;assembly=Avalonia.Themes.Neumorphism" xmlns:material="using:Material.Icons.Avalonia" xmlns:icons="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" xmlns:vm="clr-namespace:RaceElement.UI.ViewModels" + xmlns:sys="using:System" mc:Ignorable="d" d:DesignWidth="1280" d:DesignHeight="96" x:Class="RaceElement.UI.Views.MainTopMenuView" x:DataType="vm:MainTopMenuViewModel" @@ -15,6 +17,9 @@ + + 128 + @@ -24,10 +29,10 @@ @@ -78,6 +83,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Race Element.UI/Views/Stylers/GameSelectionIconStyler.cs b/Race Element.UI/Views/Stylers/GameSelectionIconStyler.cs new file mode 100644 index 000000000..afa6bad01 --- /dev/null +++ b/Race Element.UI/Views/Stylers/GameSelectionIconStyler.cs @@ -0,0 +1,46 @@ +using Avalonia; +using Avalonia.Data.Converters; +using Avalonia.Media.Imaging; +using Avalonia.Platform; +using System; +using System.Globalization; +using System.IO; + +namespace RaceElement.UI.Views.Stylers; + +public class GameSelectionIconStyler : IValueConverter +{ + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is string imagePath) + { + try + { + // Handle asset paths + if (imagePath.StartsWith("avares://")) + { + var uri = new Uri(imagePath); + + using var stream = AssetLoader.Open(uri); + return new Bitmap(stream); + } + + // Handle local files + return new Bitmap(imagePath); + } + catch (Exception ex) + { + return null; + } + } + + return null; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotSupportedException(); + } +} + + diff --git a/Race Element.UI/Views/Stylers/MainWindowStyler.cs b/Race Element.UI/Views/Stylers/MainWindowStyler.cs index 34c7325dd..6a494c161 100644 --- a/Race Element.UI/Views/Stylers/MainWindowStyler.cs +++ b/Race Element.UI/Views/Stylers/MainWindowStyler.cs @@ -14,86 +14,124 @@ namespace RaceElement.UI.Views.Stylers; /// public readonly struct WindowSize(int width, int height) { - public readonly double DefaultWidth { get; } = width; - public readonly double DefaultHeight { get; } = height; + public readonly double DefaultWidth { get; } = width; + public readonly double DefaultHeight { get; } = height; } internal class MainWindowStyler { - public static void Decorate(Window window) - { - _mainWindow = window; - - // Initialize a WindowSize struct with 1200 and 768 values - _windowSize = new WindowSize(1200, 768); - - // Assign the values to the mainWindow attributes - _mainWindow.Width = _windowSize.DefaultWidth; - _mainWindow.Height = _windowSize.DefaultHeight; - _mainWindow.MinWidth = _windowSize.DefaultWidth; - _mainWindow.MinHeight = _windowSize.DefaultHeight; - - // Window configuration - _mainWindow.Background = Brushes.Transparent; - _mainWindow.ExtendClientAreaToDecorationsHint = true; - _mainWindow.ExtendClientAreaChromeHints = ExtendClientAreaChromeHints.NoChrome; - _mainWindow.ExtendClientAreaTitleBarHeightHint = -1; - _mainWindow.SystemDecorations = SystemDecorations.None; - _mainWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen; - - // To make mainwindow draggable - _mainWindow.Loaded += MainWindow_Loaded; - } - - private static void MainWindow_Loaded(object? sender, RoutedEventArgs e) - { - var TopMenuBar = _mainWindow.FindControl("TopMenuBar"); - // Access TopMenuBar directly by its generated field x:Name - if (TopMenuBar != null) + public static void Decorate(Window window) { - TopMenuBar.PointerPressed += (s, args) => - { - _isDragging = true; - _lastPosition = args.GetPosition(_mainWindow); - _mainWindow.PointerReleased += PointerReleasedHandler; - _mainWindow.PointerMoved += PointerMovedHandler; - }; + _mainWindow = window; + + // Initialize a WindowSize struct with 1200 and 768 values + _windowSize = new WindowSize(1200, 768); + + // Assign the values to the mainWindow attributes + _mainWindow.Width = _windowSize.DefaultWidth; + _mainWindow.Height = _windowSize.DefaultHeight; + _mainWindow.MinWidth = _windowSize.DefaultWidth; + _mainWindow.MinHeight = _windowSize.DefaultHeight; + + // Window configuration + _mainWindow.Background = Brushes.Transparent; + _mainWindow.ExtendClientAreaToDecorationsHint = true; + _mainWindow.ExtendClientAreaChromeHints = ExtendClientAreaChromeHints.NoChrome; + _mainWindow.ExtendClientAreaTitleBarHeightHint = -1; + _mainWindow.SystemDecorations = SystemDecorations.None; + _mainWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen; + + // To make mainwindow draggable + _mainWindow.Loaded += MainWindow_Loaded; + } + + private static void MainWindow_Loaded(object? sender, RoutedEventArgs e) + { + var TopMenuBar = _mainWindow.FindControl("TopMenuBar"); + // Access TopMenuBar directly by its generated field x:Name + if (TopMenuBar != null) + { + TopMenuBar.PointerPressed += (s, args) => + { + // Get the source of the event + // Temporary solution to game seleciton menu resulting triggers movement + if (args.Source is Control sourceControl) + { + // Check if the source or any of its ancestors is a MenuItem or part of game selector menu + bool isMenuItemOrGameSelector = IsPartOfGameSelectorMenu(sourceControl); + + if (isMenuItemOrGameSelector) + { + // Skip dragging if the click is on a menu item or the game selector + args.Handled = true; + return; + } + } + + _isDragging = true; + _lastPosition = args.GetPosition(_mainWindow); + _mainWindow.PointerReleased += PointerReleasedHandler; + _mainWindow.PointerMoved += PointerMovedHandler; + }; + } } - } - - private static void PointerReleasedHandler(object? sender, PointerReleasedEventArgs e) - { - _isDragging = false; - _mainWindow.PointerReleased -= PointerReleasedHandler; - _mainWindow.PointerMoved -= PointerMovedHandler; - } - - private static void PointerMovedHandler(object? sender, PointerEventArgs e) - { - if (_isDragging) + + // Temporary solution to game seleciton menu resulting triggers movement + private static bool IsPartOfGameSelectorMenu(Control control) { - var currentPoint = e.GetPosition(_mainWindow); - var offset = currentPoint - _lastPosition; - - // Fix: Use _mainWindow.Position to update the window's position - _mainWindow.Position = new PixelPoint( - _mainWindow.Position.X + (int)offset.X, - _mainWindow.Position.Y + (int)offset.Y - ); + // Check current control + if (control is MenuItem || control.Name == "GameSelectionMenu") + { + return true; + } + + // Check parent hierarchy + var parent = control.Parent as Control; + while (parent != null) + { + if (parent is MenuItem || parent.Name == "GameSelectionMenu") + { + return true; + } + parent = parent.Parent as Control; + } + + return false; + } + + private static void PointerReleasedHandler(object? sender, PointerReleasedEventArgs e) + { + _isDragging = false; + _mainWindow.PointerReleased -= PointerReleasedHandler; + _mainWindow.PointerMoved -= PointerMovedHandler; + } + + private static void PointerMovedHandler(object? sender, PointerEventArgs e) + { + if (_isDragging) + { + var currentPoint = e.GetPosition(_mainWindow); + var offset = currentPoint - _lastPosition; + + // Fix: Use _mainWindow.Position to update the window's position + _mainWindow.Position = new PixelPoint( + _mainWindow.Position.X + (int)offset.X, + _mainWindow.Position.Y + (int)offset.Y + ); + } } - } - /// ------------------------------------------------------------------------------ - /// Private Fields - /// ------------------------------------------------------------------------------ + /// ------------------------------------------------------------------------------ + /// Private Fields + /// ------------------------------------------------------------------------------ - // Fields to track the dragging state and last position of the pointer - private static bool _isDragging = false; - private static Point _lastPosition; + // Fields to track the dragging state and last position of the pointer + private static bool _isDragging = false; + private static Point _lastPosition; - // WindowSize struct to hold the default window size - private static WindowSize _windowSize; + // WindowSize struct to hold the default window size + private static WindowSize _windowSize; - // Reference to the main window - private static Window _mainWindow; + // Reference to the main window + private static Window _mainWindow; } From ecfbb52258c2c8209940d4093872cd4618afd073 Mon Sep 17 00:00:00 2001 From: Tolga YILMAZ Date: Sun, 13 Apr 2025 03:46:37 +0200 Subject: [PATCH 5/9] Settings popup --- .../ViewModels/MainTopMenuViewModel.cs | 45 +++++- .../ViewModels/SettingsMenuViewModel.cs | 128 ++++++++++++++++++ Race Element.UI/Views/MainTopMenuView.axaml | 3 +- Race Element.UI/Views/MainWindow.axaml.cs | 7 +- Race Element.UI/Views/SettingsMenuView.axaml | 86 ++++++++++++ .../Views/SettingsMenuView.axaml.cs | 40 ++++++ 6 files changed, 300 insertions(+), 9 deletions(-) create mode 100644 Race Element.UI/ViewModels/SettingsMenuViewModel.cs create mode 100644 Race Element.UI/Views/SettingsMenuView.axaml create mode 100644 Race Element.UI/Views/SettingsMenuView.axaml.cs diff --git a/Race Element.UI/ViewModels/MainTopMenuViewModel.cs b/Race Element.UI/ViewModels/MainTopMenuViewModel.cs index bc07b3868..8da059400 100644 --- a/Race Element.UI/ViewModels/MainTopMenuViewModel.cs +++ b/Race Element.UI/ViewModels/MainTopMenuViewModel.cs @@ -3,8 +3,13 @@ using ReactiveUI; using System; using System.Reactive; -using System.Diagnostics; using RaceElement.UI.Services; +using Avalonia.Themes.Neumorphism.Dialogs.Interfaces; +using System.Threading.Tasks; +using Avalonia.Themes.Neumorphism.Dialogs; +using Avalonia.Themes.Neumorphism.Dialogs.Bases; +using RaceElement.UI.Views; +using Avalonia.Themes.Neumorphism.Dialogs.Enums; namespace RaceElement.UI.ViewModels; public class MainTopMenuViewModel : ViewModelBase @@ -15,8 +20,6 @@ public class MainTopMenuViewModel : ViewModelBase private MainWindowViewModel? _mainWindowViewModel; // Default page private string _currentPageName = "Overlays"; - // Track the current game icon source - private string _currentGameIconSource; #endregion #region CONSTRUCTORS @@ -31,6 +34,14 @@ public MainTopMenuViewModel() // Initialize GameSelectionCommand GameSelectionCommand = ReactiveCommand.Create(HandleGameSelection); + + // Pop up settings dialog + OpenSettingsDialog = ReactiveCommand.CreateFromTask(async () => + { + await ShowSettingsDialogAsync(); + }); + + } #endregion @@ -66,6 +77,9 @@ public bool IsCurrentPage(ViewModelBase page) // Command for game selection from dropdown public ReactiveCommand GameSelectionCommand { get; } + // Command open settings dialog + public ReactiveCommand OpenSettingsDialog { get; } + // Command to close the application public static ReactiveCommand CloseApplicationCommand => ReactiveCommand.Create(() => { Environment.Exit(0); }); @@ -100,5 +114,30 @@ private void HandleGameSelection(string selection) this.RaisePropertyChanged(nameof(CurrentGameIconSource)); } } + + private async Task ShowSettingsDialogAsync() + { + // Get the main window from the application + if (Avalonia.Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop && + desktop.MainWindow is Window mainWindow) + { + // Initialize the settings view and view model if they don't exist yet + var settingsMenuView = new SettingsMenuView(); + var settingsViewModel = new SettingsMenuViewModel(settingsMenuView); + + settingsMenuView.DataContext = settingsViewModel; + + var dialog = new DialogWindowBase(settingsMenuView); + + // This makes it modal - the main window will be disabled until this dialog is closed + DialogResult result = await dialog.ShowDialog(mainWindow); + + // Dialog is about to close + if (result != null && result.GetResult == "ok") + { + } + } + } #endregion + } diff --git a/Race Element.UI/ViewModels/SettingsMenuViewModel.cs b/Race Element.UI/ViewModels/SettingsMenuViewModel.cs new file mode 100644 index 000000000..c36d89a56 --- /dev/null +++ b/Race Element.UI/ViewModels/SettingsMenuViewModel.cs @@ -0,0 +1,128 @@ +using Avalonia.Controls; +using Avalonia.Themes.Neumorphism.Dialogs; +using Avalonia.Themes.Neumorphism.Dialogs.Interfaces; +using Avalonia.Themes.Neumorphism.Dialogs.ViewModels; +using Avalonia.Themes.Neumorphism.Dialogs.ViewModels.Elements; +using ReactiveUI; + +namespace RaceElement.UI.ViewModels; + +/// +/// View model for the settings menu dialog it should derive from DialogWindowViewModel +/// to block mainwindow interaction during dialog open +/// +public class SettingsMenuViewModel : DialogWindowViewModel +{ + #region Private Fields + + /// + /// Reference to the dialog window + /// + private readonly Window _window; + + /// + /// OK button view model + /// + private ResultBasedDialogButtonViewModel? _buttonOk; + + /// + /// Cancel button view model + /// + private ResultBasedDialogButtonViewModel? _buttonCancel; + #endregion + + #region Public Properties + + /// + /// Gets or sets the OK button view model + /// + public ResultBasedDialogButtonViewModel ButtonOk + { + get { return _buttonOk; } + set + { + _buttonOk = value; + OnPropertyChanged(nameof(ButtonOk)); + } + } + + /// + /// Gets or sets the Cancel button view model + /// + public ResultBasedDialogButtonViewModel ButtonCancel + { + get { return _buttonCancel; } + set + { + _buttonCancel = value; + OnPropertyChanged(nameof(ButtonCancel)); + } + } + #endregion + + #region Constructor + + /// + /// Initializes a new instance of the class + /// + /// The dialog window + public SettingsMenuViewModel(Window window) : base(window) + { + _window = window; + + // Create ReactiveCommands that accept ResultBasedDialogButtonViewModel + var saveCommand = ReactiveCommand.Create(_ => + { + // Save settings here + HandleSave(); + }); + + var cancelCommand = ReactiveCommand.Create(_ => + { + // Maybe warn for changes will not be saved + HandleCancel(); + }); + + // Initialize the OK button + ButtonOk = new ResultBasedDialogButtonViewModel(this, "OK", "ok") + { + Content = "OK", + Command = saveCommand + }; + + // Initialize the Cancel button + ButtonCancel = new ResultBasedDialogButtonViewModel(this, "Cancel", "cancel") + { + Content = "Cancel", + Command = cancelCommand + }; + } + #endregion + + #region Private Methods + + /// + /// Persist all settings + /// + private void HandleSave() + { + // Set dialog result + DialogResult = new DialogResult("Ok"); + + // Close the window directly + _window.Close(); + } + + /// + /// Handles the cancel command execution + /// + private void HandleCancel() + { + // Set dialog result + DialogResult = new DialogResult("Cancel"); + + // Close the window directly + _window.Close(); + } + #endregion +} \ No newline at end of file diff --git a/Race Element.UI/Views/MainTopMenuView.axaml b/Race Element.UI/Views/MainTopMenuView.axaml index 29d405a1e..55e72ef21 100644 --- a/Race Element.UI/Views/MainTopMenuView.axaml +++ b/Race Element.UI/Views/MainTopMenuView.axaml @@ -163,7 +163,8 @@ + Background="LightSteelBlue" BorderBrush="White" BorderThickness="3" + Command="{Binding OpenSettingsDialog}"> diff --git a/Race Element.UI/Views/MainWindow.axaml.cs b/Race Element.UI/Views/MainWindow.axaml.cs index c7d86a2e2..9e7f87218 100644 --- a/Race Element.UI/Views/MainWindow.axaml.cs +++ b/Race Element.UI/Views/MainWindow.axaml.cs @@ -1,11 +1,8 @@ using Avalonia; using Avalonia.Controls; -using RaceElement.UI.ViewModels; -using Avalonia.Input; -using Avalonia.Interactivity; +using Avalonia.Styling; using RaceElement.UI.Views.Stylers; -using Avalonia.Styling; namespace RaceElement.UI.Views; @@ -17,7 +14,7 @@ public MainWindow() // Style the main window and set the default size MainWindowStyler.Decorate(this); - Application.Current.SetValue( + Application.Current?.SetValue( ThemeVariantScope.ActualThemeVariantProperty, ThemeVariant.Light); } diff --git a/Race Element.UI/Views/SettingsMenuView.axaml b/Race Element.UI/Views/SettingsMenuView.axaml new file mode 100644 index 000000000..d1b4bb6bc --- /dev/null +++ b/Race Element.UI/Views/SettingsMenuView.axaml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Race Element.UI/Views/SettingsMenuView.axaml.cs b/Race Element.UI/Views/SettingsMenuView.axaml.cs new file mode 100644 index 000000000..ca51c13cc --- /dev/null +++ b/Race Element.UI/Views/SettingsMenuView.axaml.cs @@ -0,0 +1,40 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Themes.Neumorphism.Dialogs.Interfaces; +using Avalonia.Themes.Neumorphism.Dialogs; +using RaceElement.UI.ViewModels; +using Avalonia.Markup.Xaml; + +namespace RaceElement.UI.Views; + +public partial class SettingsMenuView : Window, IDialogWindowResult, IHasNegativeResult +{ + + /// + /// Initializes a new instance of the class. + /// + public SettingsMenuView() + { + AvaloniaXamlLoader.Load(this); + WindowStartupLocation = WindowStartupLocation.CenterOwner; + SystemDecorations = SystemDecorations.None; + ExtendClientAreaToDecorationsHint = true; + } + + /// + /// Gets the result of the dialog. + /// + /// + public DialogResult GetResult() => (DataContext as SettingsMenuViewModel)?.DialogResult; + + /// + /// Ensures that even if the user closes the dialog without explicitly clicking one of the buttons, + /// dialog returns a meaningful result. + /// + /// + public void SetNegativeResult(DialogResult result) + { + if (DataContext is SettingsMenuViewModel viewModel) + viewModel.DialogResult = result; + } +} From eb172a0a04ec8042537a7af6f8cf2afccd9a137e Mon Sep 17 00:00:00 2001 From: Tolga YILMAZ Date: Sun, 13 Apr 2025 16:42:53 +0200 Subject: [PATCH 6/9] Keep overlay control buttons from sliding with the overlay setting view. Based on selected game load different Overlay settings view. Refactor game selection and UI components - Refactored `GameSelectionService` to use a singleton pattern with `Lazy`, added `GameChanged` event, and improved game selection methods. - Cleaned up using directives in `MainTopMenuViewModel` and defined an asynchronous command for opening settings. - Updated `ControlButtonsPanelViewModel` to manage favorite icon color and overlay status, with improved command initialization. - Enhanced `OverlaysViewModel` to handle game-specific view models and respond to game changes. - Modified several XAML files to remove `ControlButtonsPanelView` and reorganize UI layout for better structure. - Updated `OverlaysPageView.axaml` to include a new column for global control buttons and adjusted code-behind for initialization. --- .../Services/GameSelectionService.cs | 84 +++++++++----- .../ViewModels/MainTopMenuViewModel.cs | 18 ++- .../ControlButtonsPanelViewModel.cs | 44 ++++--- .../ViewModels/OverlaysViewModel.cs | 109 +++++++++++++++--- Race Element.UI/Views/MainTopMenuView.axaml | 4 +- .../AccelerometerView.axaml | 3 - .../AverageLaptimeView.axaml | 3 - .../OverlaySettingPages/FuelOverlayView.axaml | 3 - .../InputsOverlayView.axaml | 3 - .../LaptimeOverlayView.axaml | 3 - .../RelativesOverlayView.axaml | 3 - .../SpotterOverlayView.axaml | 2 - .../StandingsOverlayView.axaml | 3 - .../TrackMapOverlayView.axaml | 3 - .../Views/Pages/OverlaysPageView.axaml | 17 ++- .../Views/Pages/OverlaysPageView.axaml.cs | 39 ++++++- 16 files changed, 231 insertions(+), 110 deletions(-) diff --git a/Race Element.UI/Services/GameSelectionService.cs b/Race Element.UI/Services/GameSelectionService.cs index 38156c13c..119006aa5 100644 --- a/Race Element.UI/Services/GameSelectionService.cs +++ b/Race Element.UI/Services/GameSelectionService.cs @@ -18,53 +18,79 @@ public enum SupportedGame /// public class GameSelectionService : ReactiveObject { - private static GameSelectionService? _instance; + #region Singleton + private static readonly Lazy _instance = + new Lazy(() => new GameSelectionService()); - private string _selectedGame = "acc"; + public static GameSelectionService Instance => _instance.Value; + #endregion - // Constructor is private to enforce singleton pattern - private GameSelectionService() { } + #region Events + public event Action GameChanged; + #endregion + + #region Properties + private string _selectedGame = "acc"; // Default game - /// - /// Gets the currently selected game - /// public string SelectedGame => _selectedGame; + #endregion - public static GameSelectionService Instance => _instance ??= new GameSelectionService(); - // Helper methods to check for specific games - public bool IsIRacing => SelectedGame == "iracing"; - public bool IsACC => SelectedGame == "acc"; - public bool IsACEvo => SelectedGame == "acevo"; - public bool IsLMU => SelectedGame == "lmu"; + #region Constructor + private GameSelectionService() + { + // Private constructor for singleton + } + #endregion + + #region Public Methods /// - /// Updates the selected game (internal - only used by MainTopMenuViewModel) + /// Updates the selected game and performs any game-specific initialization logic /// - internal void UpdateSelectedGame(string game) + /// The game identifier + /// True if the selection was valid and processed, false otherwise + public bool SelectGame(string game) { - this.RaiseAndSetIfChanged(ref _selectedGame, game); + if (game == _selectedGame) + return false; + + _selectedGame = game; + GameChanged?.Invoke(game); + return true; } /// - /// Updates the selected game and performs any game-specific initialization logic + /// Updates the selected game (internal - only used by MainTopMenuViewModel) /// - /// The game identifier - /// True if the selection was valid and processed, false otherwise - internal bool SelectGame(string selection) + public void UpdateSelectedGame(string game) { - string game = selection.ToLower(); + _selectedGame = game; + } - // Skip if same game selected - if (_selectedGame == game) return false; + // Helper methods to check for specific games + public bool IsIRacing => SelectedGame == "iracing"; + public bool IsACC => SelectedGame == "acc"; + public bool IsACEvo => SelectedGame == "acevo"; + public bool IsLMU => SelectedGame == "lmu"; + #endregion - // Update the selected game - this.RaiseAndSetIfChanged(ref _selectedGame, game); - // Perform game-specific initialization - InitializeGameSpecificSettings(game); - return true; - } + //internal bool SelectGame(string selection) + //{ + // string game = selection.ToLower(); + + // // Skip if same game selected + // if (_selectedGame == game) return false; + + // // Update the selected game + // this.RaiseAndSetIfChanged(ref _selectedGame, game); + + // // Perform game-specific initialization + // InitializeGameSpecificSettings(game); + + // return true; + //} /// /// Initializes game-specific settings and configurations diff --git a/Race Element.UI/ViewModels/MainTopMenuViewModel.cs b/Race Element.UI/ViewModels/MainTopMenuViewModel.cs index 8da059400..2e21d1771 100644 --- a/Race Element.UI/ViewModels/MainTopMenuViewModel.cs +++ b/Race Element.UI/ViewModels/MainTopMenuViewModel.cs @@ -1,15 +1,15 @@ -using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.Controls; -using ReactiveUI; -using System; -using System.Reactive; -using RaceElement.UI.Services; -using Avalonia.Themes.Neumorphism.Dialogs.Interfaces; +using System; using System.Threading.Tasks; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Controls; using Avalonia.Themes.Neumorphism.Dialogs; using Avalonia.Themes.Neumorphism.Dialogs.Bases; + +using System.Reactive; +using ReactiveUI; + +using RaceElement.UI.Services; using RaceElement.UI.Views; -using Avalonia.Themes.Neumorphism.Dialogs.Enums; namespace RaceElement.UI.ViewModels; public class MainTopMenuViewModel : ViewModelBase @@ -40,8 +40,6 @@ public MainTopMenuViewModel() { await ShowSettingsDialogAsync(); }); - - } #endregion diff --git a/Race Element.UI/ViewModels/OverlaySettingViewModels/ControlButtonsPanelViewModel.cs b/Race Element.UI/ViewModels/OverlaySettingViewModels/ControlButtonsPanelViewModel.cs index 853306d5f..03e7ab8f9 100644 --- a/Race Element.UI/ViewModels/OverlaySettingViewModels/ControlButtonsPanelViewModel.cs +++ b/Race Element.UI/ViewModels/OverlaySettingViewModels/ControlButtonsPanelViewModel.cs @@ -8,17 +8,18 @@ namespace RaceElement.UI.ViewModels.OverlaySettingViewModels; public class ControlButtonsPanelViewModel : ViewModelBase { + #region Private Fields // Reference to the current overlay view model private ViewModelBase _currentOverlayViewModel; - // Commands for each button in the control panel - public ReactiveCommand ActivateCommand { get; } - public ReactiveCommand PreviewNowCommand { get; } - public ReactiveCommand AddFavoriteCommand { get; } - public ReactiveCommand ResetToDefaultCommand { get; } - public ReactiveCommand MoveResizeCommand { get; } - public ReactiveCommand SaveChangesCommand { get; } + // Property to determine the favorite icon's color + private IBrush _favoriteIconColor = Brushes.White; + // Property to track if the current overlay is a favorite + private bool _isCurrentOverlayFavorite; + #endregion + + #region Constructor public ControlButtonsPanelViewModel() { // Initialize commands with their implementations @@ -28,18 +29,24 @@ public ControlButtonsPanelViewModel() ResetToDefaultCommand = ReactiveCommand.CreateFromTask(OnResetToDefaultAsync); MoveResizeCommand = ReactiveCommand.CreateFromTask(OnMoveResizeAsync); SaveChangesCommand = ReactiveCommand.CreateFromTask(OnSaveChangesAsync); - } + } + #endregion + + #region Public Methods + // Commands for each button in the control panel + public ReactiveCommand ActivateCommand { get; } + public ReactiveCommand PreviewNowCommand { get; } + public ReactiveCommand AddFavoriteCommand { get; } + public ReactiveCommand ResetToDefaultCommand { get; } + public ReactiveCommand MoveResizeCommand { get; } + public ReactiveCommand SaveChangesCommand { get; } - // Property to determine the favorite icon's color - private IBrush _favoriteIconColor = Brushes.White; public IBrush FavoriteIconColor { get => _favoriteIconColor; private set => this.RaiseAndSetIfChanged(ref _favoriteIconColor, value); } - // Property to track if the current overlay is a favorite - private bool _isCurrentOverlayFavorite; public bool IsCurrentOverlayFavorite { get => _isCurrentOverlayFavorite; @@ -61,11 +68,11 @@ public void SetCurrentOverlayViewModel(ViewModelBase viewModel) _currentOverlayViewModel = viewModel; // Update favorite status based on the current view model - if (_currentOverlayViewModel is OverlaySettingViewModelBase accelerometerVM) + if (_currentOverlayViewModel is OverlaySettingViewModelBase overlaySettingVM) { - IsCurrentOverlayFavorite = accelerometerVM.IsFavorite; + IsCurrentOverlayFavorite = overlaySettingVM.IsFavorite; - accelerometerVM.WhenAnyValue(vm => vm.IsFavorite) + overlaySettingVM.WhenAnyValue(vm => vm.IsFavorite) .Subscribe(isFavorite => { IsCurrentOverlayFavorite = isFavorite; @@ -75,8 +82,10 @@ public void SetCurrentOverlayViewModel(ViewModelBase viewModel) { IsCurrentOverlayFavorite = false; } - } + } + #endregion + #region Private Methods private void UpdateFavoriteIconColor() { FavoriteIconColor = IsCurrentOverlayFavorite ? Brushes.Red : Brushes.White; @@ -117,5 +126,6 @@ private async Task OnSaveChangesAsync() { // Implement the logic to save the current settings await Task.CompletedTask; - } + } + #endregion } diff --git a/Race Element.UI/ViewModels/OverlaysViewModel.cs b/Race Element.UI/ViewModels/OverlaysViewModel.cs index 35ecea594..54278dda9 100644 --- a/Race Element.UI/ViewModels/OverlaysViewModel.cs +++ b/Race Element.UI/ViewModels/OverlaysViewModel.cs @@ -1,34 +1,113 @@ -using Avalonia.Controls; -using Avalonia.Controls.Primitives; -using Avalonia.Input; -using Avalonia.Interactivity; -using RaceElement.UI.ViewModels.OverlaySettingViewModels; -using RaceElement.UI.Views.Pages.OverlaySettingPages; -using ReactiveUI; +using System; using System.Collections.Generic; using System.Reactive; +using ReactiveUI; + +using RaceElement.UI.Services; +using RaceElement.UI.ViewModels.OverlaySettingViewModels; namespace RaceElement.UI.ViewModels; public class OverlaysViewModel : ViewModelBase { + #region Private Fields + // Index of the currently selected overlay private int _selectedOverlayIndex; + + // Dictionary to hold game-specific view models + private readonly Dictionary> _gameSpecificViewModels = []; + + // The current game selected in the application + private string _currentGame; + #endregion + + public OverlaysViewModel() + { + // Initialize empty view model collections for each supported game + _gameSpecificViewModels["iracing"] = new Dictionary(); + _gameSpecificViewModels["acc"] = new Dictionary(); + _gameSpecificViewModels["acevo"] = new Dictionary(); + _gameSpecificViewModels["lmu"] = new Dictionary(); + + // Initialize with the current game from the service + _currentGame = GameSelectionService.Instance.SelectedGame; + + // Subscribe to game changes + GameSelectionService.Instance.GameChanged += OnGameChanged; + + // When the selected index changes, notify the CurrentOverlayViewModel property + this.WhenAnyValue(x => x.SelectedOverlayIndex) + .Subscribe(_ => this.RaisePropertyChanged(nameof(CurrentOverlayViewModel))); + } + + #region Public Properties + // Command to have additional logic public int SelectedOverlayIndex { get => _selectedOverlayIndex; set => this.RaiseAndSetIfChanged(ref _selectedOverlayIndex, value); } - // You could optionally add a command if you need more complex logic - public ReactiveCommand SelectOverlayCommand { get; } + public ViewModelBase CurrentOverlayViewModel => GetOrCreateViewModel(_selectedOverlayIndex); + #endregion - public OverlaysViewModel() + #region Private Methods + + ////////////////////////////////////////////////////////////////////////////////////////////// + /// HANDLE SELECTED GAME CHANGES /// + ////////////////////////////////////////////////////////////////////////////////////////////// + private void OnGameChanged(string newGame) + { + // Store current game + _currentGame = newGame; + + // Force refresh of current view model + this.RaisePropertyChanged(nameof(CurrentOverlayViewModel)); + } + + private ViewModelBase GetOrCreateViewModel(int index) { - // Initialize command - SelectOverlayCommand = ReactiveCommand.Create(index => + // Get the current game's view models + var gameViewModels = _gameSpecificViewModels[_currentGame]; + + // If we already have a view model for this index and game, return it + if (gameViewModels.TryGetValue(index, out var existingViewModel)) { - SelectedOverlayIndex = index; - // Any additional logic needed when selection changes - }); + return existingViewModel; + } + + // Otherwise, create a new one + var newViewModel = CreateViewModelForIndex(index); + gameViewModels[index] = newViewModel; + return newViewModel; + } + + private ViewModelBase CreateViewModelForIndex(int index) + { + // Create the appropriate view model based on index + return index switch + { + 0 => new InputsOverlayViewModel(), + 1 => new StandingsOverlayViewModel(), + 2 => new RelativesOverlayViewModel(), + 3 => new LaptimeOverlayViewModel(), + 4 => new FuelOverlayViewModel(), + 5 => new TrackMapOverlayViewModel(), + 6 => new SpotterOverlayViewModel(), + 7 => new AccelerometerViewModel(), + 8 => new AverageLaptimeViewModel(), + //9 => new BoostGaugeViewModel(), + //10 => new BrakePressureViewModel(), + _ => new InputsOverlayViewModel() // Default + }; + } + #endregion + + #region Cleanup + public void Dispose() + { + // Unsubscribe from game changed event + GameSelectionService.Instance.GameChanged -= OnGameChanged; } + #endregion } \ No newline at end of file diff --git a/Race Element.UI/Views/MainTopMenuView.axaml b/Race Element.UI/Views/MainTopMenuView.axaml index 55e72ef21..8eb953f88 100644 --- a/Race Element.UI/Views/MainTopMenuView.axaml +++ b/Race Element.UI/Views/MainTopMenuView.axaml @@ -92,7 +92,7 @@ assist:MenuAssist.PopupHorizontalOffset="-140" assist:MenuAssist.PopupVerticalOffset="10"> - + @@ -108,7 +108,7 @@ BorderBrush="{DynamicResource MaterialDesignToolBackground}" BorderThickness="1" ClipToBounds="False"> diff --git a/Race Element.UI/Views/Pages/OverlaySettingPages/AccelerometerView.axaml b/Race Element.UI/Views/Pages/OverlaySettingPages/AccelerometerView.axaml index 117926cad..811f01931 100644 --- a/Race Element.UI/Views/Pages/OverlaySettingPages/AccelerometerView.axaml +++ b/Race Element.UI/Views/Pages/OverlaySettingPages/AccelerometerView.axaml @@ -6,15 +6,12 @@ xmlns:assist="clr-namespace:Avalonia.Themes.Neumorphism.Assist;assembly=Avalonia.Themes.Neumorphism" xmlns:icons="using:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - xmlns:controlbuttons="using:RaceElement.UI.Views.OverlaySettingsPages" x:Class="RaceElement.UI.Views.Pages.OverlaySettingPages.AccelerometerView" xmlns:vm="using:RaceElement.UI.ViewModels.OverlaySettingViewModels" x:DataType="vm:AccelerometerViewModel"> - - diff --git a/Race Element.UI/Views/Pages/OverlaySettingPages/AverageLaptimeView.axaml b/Race Element.UI/Views/Pages/OverlaySettingPages/AverageLaptimeView.axaml index 6d9388e47..12db01a00 100644 --- a/Race Element.UI/Views/Pages/OverlaySettingPages/AverageLaptimeView.axaml +++ b/Race Element.UI/Views/Pages/OverlaySettingPages/AverageLaptimeView.axaml @@ -5,14 +5,11 @@ xmlns:controls="clr-namespace:Avalonia.Themes.Neumorphism.Controls;assembly=Avalonia.Themes.Neumorphism" xmlns:assist="clr-namespace:Avalonia.Themes.Neumorphism.Assist;assembly=Avalonia.Themes.Neumorphism" xmlns:icons="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" - xmlns:controlbuttons="using:RaceElement.UI.Views.OverlaySettingsPages" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="RaceElement.UI.Views.Pages.OverlaySettingPages.AverageLaptimeView"> - - diff --git a/Race Element.UI/Views/Pages/OverlaySettingPages/FuelOverlayView.axaml b/Race Element.UI/Views/Pages/OverlaySettingPages/FuelOverlayView.axaml index bbb8618d9..3ed3654f9 100644 --- a/Race Element.UI/Views/Pages/OverlaySettingPages/FuelOverlayView.axaml +++ b/Race Element.UI/Views/Pages/OverlaySettingPages/FuelOverlayView.axaml @@ -6,15 +6,12 @@ xmlns:assist="clr-namespace:Avalonia.Themes.Neumorphism.Assist;assembly=Avalonia.Themes.Neumorphism" xmlns:icons="using:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - xmlns:controlbuttons="using:RaceElement.UI.Views.OverlaySettingsPages" x:Class="RaceElement.UI.Views.Pages.OverlaySettingPages.FuelOverlayView" xmlns:vm="using:RaceElement.UI.ViewModels.OverlaySettingViewModels" x:DataType="vm:FuelOverlayViewModel"> - - diff --git a/Race Element.UI/Views/Pages/OverlaySettingPages/InputsOverlayView.axaml b/Race Element.UI/Views/Pages/OverlaySettingPages/InputsOverlayView.axaml index cce31015c..fd46c784e 100644 --- a/Race Element.UI/Views/Pages/OverlaySettingPages/InputsOverlayView.axaml +++ b/Race Element.UI/Views/Pages/OverlaySettingPages/InputsOverlayView.axaml @@ -6,15 +6,12 @@ xmlns:assist="clr-namespace:Avalonia.Themes.Neumorphism.Assist;assembly=Avalonia.Themes.Neumorphism" xmlns:icons="using:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - xmlns:controlbuttons="using:RaceElement.UI.Views.OverlaySettingsPages" x:Class="RaceElement.UI.Views.Pages.OverlaySettingPages.InputsOverlayView" xmlns:vm="using:RaceElement.UI.ViewModels.OverlaySettingViewModels" x:DataType="vm:InputsOverlayViewModel"> - - diff --git a/Race Element.UI/Views/Pages/OverlaySettingPages/LaptimeOverlayView.axaml b/Race Element.UI/Views/Pages/OverlaySettingPages/LaptimeOverlayView.axaml index 33f371bd0..8f69abd27 100644 --- a/Race Element.UI/Views/Pages/OverlaySettingPages/LaptimeOverlayView.axaml +++ b/Race Element.UI/Views/Pages/OverlaySettingPages/LaptimeOverlayView.axaml @@ -6,15 +6,12 @@ xmlns:assist="clr-namespace:Avalonia.Themes.Neumorphism.Assist;assembly=Avalonia.Themes.Neumorphism" xmlns:icons="using:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - xmlns:controlbuttons="using:RaceElement.UI.Views.OverlaySettingsPages" x:Class="RaceElement.UI.Views.Pages.OverlaySettingPages.LaptimeOverlayView" xmlns:vm="using:RaceElement.UI.ViewModels.OverlaySettingViewModels" x:DataType="vm:LaptimeOverlayViewModel"> - - diff --git a/Race Element.UI/Views/Pages/OverlaySettingPages/RelativesOverlayView.axaml b/Race Element.UI/Views/Pages/OverlaySettingPages/RelativesOverlayView.axaml index 1b5e17eff..03762d34a 100644 --- a/Race Element.UI/Views/Pages/OverlaySettingPages/RelativesOverlayView.axaml +++ b/Race Element.UI/Views/Pages/OverlaySettingPages/RelativesOverlayView.axaml @@ -6,15 +6,12 @@ xmlns:assist="clr-namespace:Avalonia.Themes.Neumorphism.Assist;assembly=Avalonia.Themes.Neumorphism" xmlns:icons="using:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - xmlns:controlbuttons="using:RaceElement.UI.Views.OverlaySettingsPages" x:Class="RaceElement.UI.Views.Pages.OverlaySettingPages.RelativesOverlayView" xmlns:vm="using:RaceElement.UI.ViewModels.OverlaySettingViewModels" x:DataType="vm:RelativesOverlayViewModel"> - - diff --git a/Race Element.UI/Views/Pages/OverlaySettingPages/SpotterOverlayView.axaml b/Race Element.UI/Views/Pages/OverlaySettingPages/SpotterOverlayView.axaml index a4252cb2e..49c2b7e86 100644 --- a/Race Element.UI/Views/Pages/OverlaySettingPages/SpotterOverlayView.axaml +++ b/Race Element.UI/Views/Pages/OverlaySettingPages/SpotterOverlayView.axaml @@ -13,8 +13,6 @@ - - diff --git a/Race Element.UI/Views/Pages/OverlaySettingPages/StandingsOverlayView.axaml b/Race Element.UI/Views/Pages/OverlaySettingPages/StandingsOverlayView.axaml index 8d6538470..d1ae82cc6 100644 --- a/Race Element.UI/Views/Pages/OverlaySettingPages/StandingsOverlayView.axaml +++ b/Race Element.UI/Views/Pages/OverlaySettingPages/StandingsOverlayView.axaml @@ -6,15 +6,12 @@ xmlns:assist="clr-namespace:Avalonia.Themes.Neumorphism.Assist;assembly=Avalonia.Themes.Neumorphism" xmlns:icons="using:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - xmlns:controlbuttons="using:RaceElement.UI.Views.OverlaySettingsPages" x:Class="RaceElement.UI.Views.Pages.OverlaySettingPages.StandingsOverlayView" xmlns:vm="using:RaceElement.UI.ViewModels.OverlaySettingViewModels" x:DataType="vm:StandingsOverlayViewModel"> - - diff --git a/Race Element.UI/Views/Pages/OverlaySettingPages/TrackMapOverlayView.axaml b/Race Element.UI/Views/Pages/OverlaySettingPages/TrackMapOverlayView.axaml index d20a72692..3d2ea9f02 100644 --- a/Race Element.UI/Views/Pages/OverlaySettingPages/TrackMapOverlayView.axaml +++ b/Race Element.UI/Views/Pages/OverlaySettingPages/TrackMapOverlayView.axaml @@ -6,15 +6,12 @@ xmlns:assist="clr-namespace:Avalonia.Themes.Neumorphism.Assist;assembly=Avalonia.Themes.Neumorphism" xmlns:icons="using:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - xmlns:controlbuttons="using:RaceElement.UI.Views.OverlaySettingsPages" x:Class="RaceElement.UI.Views.Pages.OverlaySettingPages.TrackMapOverlayView" xmlns:vm="using:RaceElement.UI.ViewModels.OverlaySettingViewModels" x:DataType="vm:TrackMapOverlayViewModel"> - - diff --git a/Race Element.UI/Views/Pages/OverlaysPageView.axaml b/Race Element.UI/Views/Pages/OverlaysPageView.axaml index fd1c6bc83..3fa95cb03 100644 --- a/Race Element.UI/Views/Pages/OverlaysPageView.axaml +++ b/Race Element.UI/Views/Pages/OverlaysPageView.axaml @@ -9,6 +9,7 @@ xmlns:icons="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalo xmlns:vm="using:RaceElement.UI.ViewModels" xmlns:overlayvm="using:RaceElement.UI.ViewModels.OverlaySettingViewModels" xmlns:overlay="using:RaceElement.UI.Views.Pages.OverlaySettingPages" +xmlns:controlbuttons="using:RaceElement.UI.Views.OverlaySettingsPages" x:DataType="vm:OverlaysViewModel" mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="688" x:Class="RaceElement.UI.Views.Pages.OverlaysPageView" @@ -22,6 +23,7 @@ xmlns:stylers="using:RaceElement.UI.Views.Stylers"> + @@ -134,11 +136,9 @@ xmlns:stylers="using:RaceElement.UI.Views.Stylers"> - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + @@ -138,7 +97,7 @@ xmlns:stylers="using:RaceElement.UI.Views.Stylers"> + SelectedIndex="{Binding SelectedOverlayItem.Type, Converter={StaticResource EnumToIndexConverter}, Mode=TwoWay}"> - - + @@ -165,6 +123,10 @@ xmlns:stylers="using:RaceElement.UI.Views.Stylers"> + diff --git a/Race Element.UI/Views/Pages/OverlaysPageView.axaml.cs b/Race Element.UI/Views/Pages/OverlaysPageView.axaml.cs index 796b81fa0..a1104a933 100644 --- a/Race Element.UI/Views/Pages/OverlaysPageView.axaml.cs +++ b/Race Element.UI/Views/Pages/OverlaysPageView.axaml.cs @@ -10,6 +10,7 @@ using Avalonia.ReactiveUI; using ReactiveUI; +using RaceElement.UI.Services; using RaceElement.UI.ViewModels; using RaceElement.UI.ViewModels.OverlaySettingViewModels; using RaceElement.UI.Views.OverlaySettingsPages; @@ -35,10 +36,10 @@ public OverlaysPageView() .Subscribe(viewModel => { // Initial setup when ViewModel is set - UpdateControlButtons(viewModel.SelectedOverlayIndex); + UpdateControlButtons(viewModel.SelectedOverlayType); // Subscribe to changes in SelectedOverlayIndex - viewModel.WhenAnyValue(vm => vm.SelectedOverlayIndex) + viewModel.WhenAnyValue(vm => vm.SelectedOverlayType) .Subscribe(UpdateControlButtons) .DisposeWith(disposables); }) @@ -46,7 +47,7 @@ public OverlaysPageView() }); } - private void UpdateControlButtons(int index) + private void UpdateControlButtons(OverlayType index) { // Update the control buttons based on the selected overlay index if (_controlButtonsPanelView?.DataContext is ControlButtonsPanelViewModel controlButtonsVM && diff --git a/Race Element.UI/Views/Stylers/EnumToIndexConverter.cs b/Race Element.UI/Views/Stylers/EnumToIndexConverter.cs new file mode 100644 index 000000000..4df2e6431 --- /dev/null +++ b/Race Element.UI/Views/Stylers/EnumToIndexConverter.cs @@ -0,0 +1,37 @@ +using Avalonia; +using Avalonia.Data; +using Avalonia.Data.Converters; +using Avalonia.Media; +using System; +using System.Globalization; + +using RaceElement.UI.Services; + +namespace RaceElement.UI.Views.Stylers; + +public class EnumToIndexConverter : IValueConverter +{ + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is OverlayType overlayType) + return (int)overlayType; + return 0; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + // Check if the value is a valid index + if (value is int index) + { + // Handle special case: -1 (no selection) should return a default value + if (index == -1) + return OverlayType.Inputs; + + // Check if it's a valid enum value + if (Enum.IsDefined(typeof(OverlayType), index)) + return (OverlayType)index; + } + + return OverlayType.Inputs; + } +} From 0745ae5a873cd8ddd70dbe89dc37d9522226225b Mon Sep 17 00:00:00 2001 From: Tolga YILMAZ Date: Sun, 13 Apr 2025 21:44:15 +0200 Subject: [PATCH 8/9] adds Boost gauge and brake pressure overlay items --- .../BoostGaugeViewModel.cs | 6 ++ .../BrakePressureViewModel.cs | 6 ++ .../OverlaySettingViewModelBase.cs | 26 ++------- .../ViewModels/OverlaysViewModel.cs | 32 +++-------- .../OverlaySettingPages/BoostGaugeView.axaml | 18 ++++++ .../BoostGaugeView.axaml.cs | 55 +++++++++++++++++++ .../BrakePressureView.axaml | 18 ++++++ .../BrakePressureView.axaml.cs | 55 +++++++++++++++++++ .../Views/Pages/OverlaysPageView.axaml | 6 +- 9 files changed, 175 insertions(+), 47 deletions(-) create mode 100644 Race Element.UI/ViewModels/OverlaySettingViewModels/BoostGaugeViewModel.cs create mode 100644 Race Element.UI/ViewModels/OverlaySettingViewModels/BrakePressureViewModel.cs create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/BoostGaugeView.axaml create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/BoostGaugeView.axaml.cs create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/BrakePressureView.axaml create mode 100644 Race Element.UI/Views/Pages/OverlaySettingPages/BrakePressureView.axaml.cs diff --git a/Race Element.UI/ViewModels/OverlaySettingViewModels/BoostGaugeViewModel.cs b/Race Element.UI/ViewModels/OverlaySettingViewModels/BoostGaugeViewModel.cs new file mode 100644 index 000000000..16167fae6 --- /dev/null +++ b/Race Element.UI/ViewModels/OverlaySettingViewModels/BoostGaugeViewModel.cs @@ -0,0 +1,6 @@ +using ReactiveUI; + +namespace RaceElement.UI.ViewModels.OverlaySettingViewModels; +public class BoostGaugeViewModel : OverlaySettingViewModelBase +{ +} diff --git a/Race Element.UI/ViewModels/OverlaySettingViewModels/BrakePressureViewModel.cs b/Race Element.UI/ViewModels/OverlaySettingViewModels/BrakePressureViewModel.cs new file mode 100644 index 000000000..ccb1eddc9 --- /dev/null +++ b/Race Element.UI/ViewModels/OverlaySettingViewModels/BrakePressureViewModel.cs @@ -0,0 +1,6 @@ +using ReactiveUI; + +namespace RaceElement.UI.ViewModels.OverlaySettingViewModels; +public class BrakePressureViewModel : OverlaySettingViewModelBase +{ +} diff --git a/Race Element.UI/ViewModels/OverlaySettingViewModels/OverlaySettingViewModelBase.cs b/Race Element.UI/ViewModels/OverlaySettingViewModels/OverlaySettingViewModelBase.cs index 8f38e9fe7..ceb489aac 100644 --- a/Race Element.UI/ViewModels/OverlaySettingViewModels/OverlaySettingViewModelBase.cs +++ b/Race Element.UI/ViewModels/OverlaySettingViewModels/OverlaySettingViewModelBase.cs @@ -8,22 +8,20 @@ namespace RaceElement.UI.ViewModels.OverlaySettingViewModels; public class OverlaySettingViewModelBase : ViewModelBase { - private bool _isFavorite; - private OverlayType _type; - private string _name; - private MaterialIconKind _iconKind; + private bool _isFavorite = false; + private OverlayType _type = OverlayType.Inputs; + private string _name = ""; + private MaterialIconKind _iconKind = MaterialIconKind.QuestionMark; public OverlaySettingViewModelBase() { - // Subscribe to game changes to update availability - GameSelectionService.Instance.GameChanged += OnGameChanged; } - /// /// Indicates if this overlay is available for the currently selected game /// - public bool IsAvailable => OverlaySelectionService.Instance.IsOverlayAvailableForGame(Type, GameSelectionService.Instance.SelectedGame); + public bool IsAvailable => OverlaySelectionService.Instance.IsOverlayAvailableForGame( + Type, GameSelectionService.Instance.SelectedGame); /// /// Indicates if this overlay is a favorite @@ -68,16 +66,4 @@ public bool IsEnabled get => _isEnabled; set => this.RaiseAndSetIfChanged(ref _isEnabled, value); } - - private void OnGameChanged(string newGame) - { - // Notify UI that IsAvailable property might have changed - this.RaisePropertyChanged(nameof(IsAvailable)); - } - - // Clean up event subscriptions - public void Dispose() - { - GameSelectionService.Instance.GameChanged -= OnGameChanged; - } } diff --git a/Race Element.UI/ViewModels/OverlaysViewModel.cs b/Race Element.UI/ViewModels/OverlaysViewModel.cs index 1e8fb8709..d231099ec 100644 --- a/Race Element.UI/ViewModels/OverlaysViewModel.cs +++ b/Race Element.UI/ViewModels/OverlaysViewModel.cs @@ -22,20 +22,7 @@ public class OverlaysViewModel : ViewModelBase private readonly Dictionary> _gameSpecificViewModels = []; // The current game selected in the application - private string _currentGame; - - // Properties to expose overlay availability status - public bool IsInputsAvailable => IsOverlayAvailable(OverlayType.Inputs); - public bool IsStandingsAvailable => IsOverlayAvailable(OverlayType.Standings); - public bool IsRelativesAvailable => IsOverlayAvailable(OverlayType.Relatives); - public bool IsLaptimesAvailable => IsOverlayAvailable(OverlayType.Laptimes); - public bool IsFuelAvailable => IsOverlayAvailable(OverlayType.Fuel); - public bool IsTrackMapAvailable => IsOverlayAvailable(OverlayType.TrackMap); - public bool IsSpotterAvailable => IsOverlayAvailable(OverlayType.Spotter); - public bool IsAccelerometerAvailable => IsOverlayAvailable(OverlayType.Accelerometer); - public bool IsAverageLaptimeAvailable => IsOverlayAvailable(OverlayType.AverageLaptime); - public bool IsBoostGaugeAvailable => IsOverlayAvailable(OverlayType.BoostGauge); - public bool IsBrakePressureAvailable => IsOverlayAvailable(OverlayType.BrakePressure); + private string _currentGame = "acc"; #endregion public OverlaysViewModel() @@ -53,16 +40,13 @@ public OverlaysViewModel() UpdateAvailableOverlays(); // Initialize the selected item - if (AvailableOverlays.Count > 0) - { - _selectedOverlayItem = AvailableOverlays.First(); - _selectedOverlayType = _selectedOverlayItem.Type; - } + _selectedOverlayItem = AvailableOverlays.First(); + _selectedOverlayType = _selectedOverlayItem.Type; // Subscribe to game changes GameSelectionService.Instance.GameChanged += OnGameChanged; - // When the selected index changes, notify the CurrentOverlayViewModel property + // When the selected overlay menu changes, notify the CurrentOverlayViewModel property this.WhenAnyValue(x => x._selectedOverlayType) .Subscribe(_ => this.RaisePropertyChanged(nameof(CurrentOverlayViewModel))); } @@ -156,13 +140,13 @@ private void OnGameChanged(string newGame) // Find the corresponding item in the available overlays SelectedOverlayItem = AvailableOverlays.FirstOrDefault(o => o.Type == firstAvailable) ?? - (AvailableOverlays.Count > 0 ? AvailableOverlays[0] : null); + (AvailableOverlays.Count > 0 ? AvailableOverlays[0] : null)!; } else { // If still available, find the item in the new collection SelectedOverlayItem = AvailableOverlays.FirstOrDefault(o => o.Type == _selectedOverlayType) ?? - (AvailableOverlays.Count > 0 ? AvailableOverlays[0] : null); + (AvailableOverlays.Count > 0 ? AvailableOverlays[0] : null)!; } } @@ -197,8 +181,8 @@ private ViewModelBase CreateViewModelForIndex(OverlayType type) OverlayType.Spotter => new SpotterOverlayViewModel(), OverlayType.Accelerometer => new AccelerometerViewModel(), OverlayType.AverageLaptime => new AverageLaptimeViewModel(), - //OverlayType.BoostGauge => new BoostGaugeViewModel(), - //OverlayType.BrakePressure => new BrakePressureViewModel(), + OverlayType.BoostGauge => new BoostGaugeViewModel(), + OverlayType.BrakePressure => new BrakePressureViewModel(), }; } #endregion diff --git a/Race Element.UI/Views/Pages/OverlaySettingPages/BoostGaugeView.axaml b/Race Element.UI/Views/Pages/OverlaySettingPages/BoostGaugeView.axaml new file mode 100644 index 000000000..dd9ba0af1 --- /dev/null +++ b/Race Element.UI/Views/Pages/OverlaySettingPages/BoostGaugeView.axaml @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/Race Element.UI/Views/Pages/OverlaySettingPages/BoostGaugeView.axaml.cs b/Race Element.UI/Views/Pages/OverlaySettingPages/BoostGaugeView.axaml.cs new file mode 100644 index 000000000..2c1be68ab --- /dev/null +++ b/Race Element.UI/Views/Pages/OverlaySettingPages/BoostGaugeView.axaml.cs @@ -0,0 +1,55 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; +using RaceElement.UI.ViewModels.OverlaySettingViewModels; +using RaceElement.UI.Views.OverlaySettingsPages; +using ReactiveUI; + +namespace RaceElement.UI.Views.Pages.OverlaySettingPages; + +public partial class BoostGaugeView : ReactiveUserControl +{ + private ControlButtonsPanelView? _controlButtonsPanelView; + public BoostGaugeView() + { + InitializeComponent(); + + if (DataContext == null) + { + DataContext = new BoostGaugeViewModel(); + } + + this.WhenActivated(disposables => + { + // Find the ControlButtonsPanelView + _controlButtonsPanelView = this.FindControl("ControlButtons"); + + if (_controlButtonsPanelView != null && DataContext is BoostGaugeViewModel viewModel) + { + // Set the current overlay view model on the control buttons panel + if (_controlButtonsPanelView.DataContext is ControlButtonsPanelViewModel controlButtonsVM) + { + controlButtonsVM.SetCurrentOverlayViewModel(viewModel); + } + } + }); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + + // Find the control buttons panel once the view is loaded + _controlButtonsPanelView = this.FindControl("ControlButtons"); + + if (_controlButtonsPanelView != null && DataContext is BoostGaugeViewModel viewModel) + { + // Set the current overlay view model on the control buttons panel + if (_controlButtonsPanelView.DataContext is ControlButtonsPanelViewModel controlButtonsVM) + { + controlButtonsVM.SetCurrentOverlayViewModel(viewModel); + } + } + } +} \ No newline at end of file diff --git a/Race Element.UI/Views/Pages/OverlaySettingPages/BrakePressureView.axaml b/Race Element.UI/Views/Pages/OverlaySettingPages/BrakePressureView.axaml new file mode 100644 index 000000000..272f91963 --- /dev/null +++ b/Race Element.UI/Views/Pages/OverlaySettingPages/BrakePressureView.axaml @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/Race Element.UI/Views/Pages/OverlaySettingPages/BrakePressureView.axaml.cs b/Race Element.UI/Views/Pages/OverlaySettingPages/BrakePressureView.axaml.cs new file mode 100644 index 000000000..817aa07a6 --- /dev/null +++ b/Race Element.UI/Views/Pages/OverlaySettingPages/BrakePressureView.axaml.cs @@ -0,0 +1,55 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; +using RaceElement.UI.ViewModels.OverlaySettingViewModels; +using RaceElement.UI.Views.OverlaySettingsPages; +using ReactiveUI; + +namespace RaceElement.UI.Views.Pages.OverlaySettingPages; + +public partial class BrakePressureView : ReactiveUserControl +{ + private ControlButtonsPanelView? _controlButtonsPanelView; + public BrakePressureView() + { + InitializeComponent(); + + if (DataContext == null) + { + DataContext = new BrakePressureViewModel(); + } + + this.WhenActivated(disposables => + { + // Find the ControlButtonsPanelView + _controlButtonsPanelView = this.FindControl("ControlButtons"); + + if (_controlButtonsPanelView != null && DataContext is BrakePressureViewModel viewModel) + { + // Set the current overlay view model on the control buttons panel + if (_controlButtonsPanelView.DataContext is ControlButtonsPanelViewModel controlButtonsVM) + { + controlButtonsVM.SetCurrentOverlayViewModel(viewModel); + } + } + }); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + + // Find the control buttons panel once the view is loaded + _controlButtonsPanelView = this.FindControl("ControlButtons"); + + if (_controlButtonsPanelView != null && DataContext is BrakePressureViewModel viewModel) + { + // Set the current overlay view model on the control buttons panel + if (_controlButtonsPanelView.DataContext is ControlButtonsPanelViewModel controlButtonsVM) + { + controlButtonsVM.SetCurrentOverlayViewModel(viewModel); + } + } + } +} \ No newline at end of file diff --git a/Race Element.UI/Views/Pages/OverlaysPageView.axaml b/Race Element.UI/Views/Pages/OverlaysPageView.axaml index 7f08ebb92..afa582055 100644 --- a/Race Element.UI/Views/Pages/OverlaysPageView.axaml +++ b/Race Element.UI/Views/Pages/OverlaysPageView.axaml @@ -123,10 +123,10 @@ xmlns:stylers="using:RaceElement.UI.Views.Stylers"> - - --> + + From 08391b54a57edb7c1cd6f201d94a243466185f19 Mon Sep 17 00:00:00 2001 From: Tolga YILMAZ Date: Sun, 13 Apr 2025 22:05:11 +0200 Subject: [PATCH 9/9] Instead string game names use enumarations. --- .../Services/GameSelectionService.cs | 21 ++++++------ .../Services/OverlaySelectionService.cs | 32 ++++++------------- .../ViewModels/MainTopMenuViewModel.cs | 10 +++--- .../ViewModels/OverlaysViewModel.cs | 14 ++++---- Race Element.UI/Views/MainTopMenuView.axaml | 9 +++--- .../Views/MainTopMenuView.axaml.cs | 7 +--- 6 files changed, 37 insertions(+), 56 deletions(-) diff --git a/Race Element.UI/Services/GameSelectionService.cs b/Race Element.UI/Services/GameSelectionService.cs index d7f3b4d9b..f3888e9f2 100644 --- a/Race Element.UI/Services/GameSelectionService.cs +++ b/Race Element.UI/Services/GameSelectionService.cs @@ -26,13 +26,13 @@ public class GameSelectionService : ReactiveObject #endregion #region Events - public event Action? GameChanged; + public event Action? GameChanged; #endregion #region Properties - private string _selectedGame = "acc"; // Default game + private SupportedGame _selectedGame = SupportedGame.ACC; // Default game - public string SelectedGame => _selectedGame; + public SupportedGame SelectedGame => _selectedGame; #endregion #region Constructor @@ -49,28 +49,27 @@ private GameSelectionService() /// /// The game identifier /// True if the selection was valid and processed, false otherwise - public bool SelectGame(string game) + public bool SelectGame(SupportedGame game) { if (game == _selectedGame) return false; _selectedGame = game; - GameChanged?.Invoke(game); + GameChanged?.Invoke(game); // Convert SupportedGame enum to string return true; } - /// /// Updates the selected game (internal - only used by MainTopMenuViewModel) /// - public void UpdateSelectedGame(string game) + public void UpdateSelectedGame(SupportedGame game) { _selectedGame = game; } // Helper methods to check for specific games - public bool IsIRacing => SelectedGame == "iracing"; - public bool IsACC => SelectedGame == "acc"; - public bool IsACEvo => SelectedGame == "acevo"; - public bool IsLMU => SelectedGame == "lmu"; + public bool IsIRacing => SelectedGame == SupportedGame.IRacing; + public bool IsACC => SelectedGame == SupportedGame.ACC; + public bool IsACEvo => SelectedGame == SupportedGame.ACEvo; + public bool IsLMU => SelectedGame == SupportedGame.LMU; #endregion } diff --git a/Race Element.UI/Services/OverlaySelectionService.cs b/Race Element.UI/Services/OverlaySelectionService.cs index d21f03e53..aafb1d808 100644 --- a/Race Element.UI/Services/OverlaySelectionService.cs +++ b/Race Element.UI/Services/OverlaySelectionService.cs @@ -73,17 +73,17 @@ public class OverlaySelectionService #region Game-Specific Overlay Availability // Define which overlays are available for each game - private readonly Dictionary> _gameOverlayAvailability; + private readonly Dictionary> _gameOverlayAvailability; #endregion #region Constructor private OverlaySelectionService() { // Initialize availability mappings - _gameOverlayAvailability = new Dictionary> + _gameOverlayAvailability = new Dictionary> { // iRacing supports all overlays - ["iracing"] = new HashSet + [SupportedGame.IRacing] = new HashSet { OverlayType.Inputs, OverlayType.Standings, @@ -99,7 +99,7 @@ private OverlaySelectionService() }, // ACC doesn't support BoostGauge and BrakePressure - ["acc"] = new HashSet + [SupportedGame.ACC] = new HashSet { OverlayType.Inputs, OverlayType.Standings, @@ -112,7 +112,7 @@ private OverlaySelectionService() }, // AC Evo doesn't support Spotter - ["acevo"] = new HashSet + [SupportedGame.ACEvo] = new HashSet { OverlayType.Inputs, OverlayType.Standings, @@ -127,7 +127,7 @@ private OverlaySelectionService() }, // LMU has limited overlay support - ["lmu"] = new HashSet + [SupportedGame.LMU] = new HashSet { OverlayType.Inputs, OverlayType.Standings, @@ -146,7 +146,7 @@ private OverlaySelectionService() /// The overlay type to check /// The game identifier /// True if the overlay is available, false otherwise - public bool IsOverlayAvailableForGame(OverlayType overlayType, string game) + public bool IsOverlayAvailableForGame(OverlayType overlayType, SupportedGame game) { if (_gameOverlayAvailability.TryGetValue(game, out var availableItems)) { @@ -160,7 +160,7 @@ public bool IsOverlayAvailableForGame(OverlayType overlayType, string game) /// /// The game identifier /// An enumerable of available overlay types - public IEnumerable GetAvailableOverlaysForGame(string game) + public IEnumerable GetAvailableOverlaysForGame(SupportedGame game) { if (_gameOverlayAvailability.TryGetValue(game, out var availableItems)) { @@ -169,26 +169,12 @@ public IEnumerable GetAvailableOverlaysForGame(string game) return Enumerable.Empty(); } - /// - /// Gets the overlay type with the specified index - /// - /// The numeric index of the overlay - /// The corresponding overlay type - public OverlayType GetOverlayTypeFromIndex(int index) - { - if (Enum.IsDefined(typeof(OverlayType), index)) - { - return (OverlayType)index; - } - return OverlayType.Inputs; // Default to Inputs if invalid - } - /// /// Finds the first available overlay for the specified game /// /// The game identifier /// The first available overlay type - public OverlayType FindFirstAvailableOverlay(string game) + public OverlayType FindFirstAvailableOverlay(SupportedGame game) { return GetAvailableOverlaysForGame(game).FirstOrDefault(); } diff --git a/Race Element.UI/ViewModels/MainTopMenuViewModel.cs b/Race Element.UI/ViewModels/MainTopMenuViewModel.cs index 2e21d1771..d46f5af51 100644 --- a/Race Element.UI/ViewModels/MainTopMenuViewModel.cs +++ b/Race Element.UI/ViewModels/MainTopMenuViewModel.cs @@ -33,7 +33,7 @@ public MainTopMenuViewModel() NavigateToToolsPageCommand = ReactiveCommand.Create(() => { _mainWindowViewModel?.NavigateTo(new ToolsViewModel()); CurrentPageName = "Tools"; }); // Initialize GameSelectionCommand - GameSelectionCommand = ReactiveCommand.Create(HandleGameSelection); + GameSelectionCommand = ReactiveCommand.Create(HandleGameSelection); // Pop up settings dialog OpenSettingsDialog = ReactiveCommand.CreateFromTask(async () => @@ -50,13 +50,13 @@ public string CurrentPageName private set => this.RaiseAndSetIfChanged(ref _currentPageName, value); } - public string SelectedGame + public SupportedGame SelectedGame { get => GameSelectionService.Instance.SelectedGame; private set => GameSelectionService.Instance.UpdateSelectedGame(value); } - public string CurrentGameIconSource => $"avares://RaceElement.UI/Assets/{SelectedGame}.ico"; + public string CurrentGameIconSource => $"avares://RaceElement.UI/Assets/{SelectedGame.ToString().ToLower()}.ico"; #endregion #region PUBLIC COMMANDS/METHODS @@ -73,7 +73,7 @@ public bool IsCurrentPage(ViewModelBase page) public ReactiveCommand NavigateToToolsPageCommand { get; } // Command for game selection from dropdown - public ReactiveCommand GameSelectionCommand { get; } + public ReactiveCommand GameSelectionCommand { get; } // Command open settings dialog public ReactiveCommand OpenSettingsDialog { get; } @@ -103,7 +103,7 @@ internal void SetMainWindowViewModel(MainWindowViewModel mainWindowViewModel) /// Handles the game selection from the dropdown menu. /// /// - private void HandleGameSelection(string selection) + private void HandleGameSelection(SupportedGame selection) { // Let the service handle game selection and initialization if (GameSelectionService.Instance.SelectGame(selection)) diff --git a/Race Element.UI/ViewModels/OverlaysViewModel.cs b/Race Element.UI/ViewModels/OverlaysViewModel.cs index d231099ec..3bc0eb29a 100644 --- a/Race Element.UI/ViewModels/OverlaysViewModel.cs +++ b/Race Element.UI/ViewModels/OverlaysViewModel.cs @@ -19,19 +19,19 @@ public class OverlaysViewModel : ViewModelBase private OverlaySettingViewModelBase _selectedOverlayItem; // Dictionary to hold game-specific view models - private readonly Dictionary> _gameSpecificViewModels = []; + private readonly Dictionary> _gameSpecificViewModels = []; // The current game selected in the application - private string _currentGame = "acc"; + private SupportedGame _currentGame = GameSelectionService.Instance.SelectedGame; #endregion public OverlaysViewModel() { // Initialize empty view model collections for each supported game - _gameSpecificViewModels["iracing"] = new Dictionary(); - _gameSpecificViewModels["acc"] = new Dictionary(); - _gameSpecificViewModels["acevo"] = new Dictionary(); - _gameSpecificViewModels["lmu"] = new Dictionary(); + _gameSpecificViewModels[SupportedGame.IRacing] = new Dictionary(); + _gameSpecificViewModels[SupportedGame.ACC] = new Dictionary(); + _gameSpecificViewModels[SupportedGame.ACEvo] = new Dictionary(); + _gameSpecificViewModels[SupportedGame.LMU] = new Dictionary(); // Initialize with the current game from the service _currentGame = GameSelectionService.Instance.SelectedGame; @@ -120,7 +120,7 @@ private bool IsOverlayAvailable(OverlayType overlayType) ////////////////////////////////////////////////////////////////////////////////////////////// /// HANDLE SELECTED GAME CHANGES /// ////////////////////////////////////////////////////////////////////////////////////////////// - private void OnGameChanged(string newGame) + private void OnGameChanged(SupportedGame newGame) { // Store current game _currentGame = newGame; diff --git a/Race Element.UI/Views/MainTopMenuView.axaml b/Race Element.UI/Views/MainTopMenuView.axaml index 8eb953f88..346239834 100644 --- a/Race Element.UI/Views/MainTopMenuView.axaml +++ b/Race Element.UI/Views/MainTopMenuView.axaml @@ -12,6 +12,7 @@ xmlns:sys="using:System" mc:Ignorable="d" d:DesignWidth="1280" d:DesignHeight="96" x:Class="RaceElement.UI.Views.MainTopMenuView" + xmlns:services="using:RaceElement.UI.Services" x:DataType="vm:MainTopMenuViewModel" xmlns:stylers="using:RaceElement.UI.Views.Stylers"> @@ -132,28 +133,28 @@ - + - + - + - + diff --git a/Race Element.UI/Views/MainTopMenuView.axaml.cs b/Race Element.UI/Views/MainTopMenuView.axaml.cs index bcbf4bc11..05a0119d4 100644 --- a/Race Element.UI/Views/MainTopMenuView.axaml.cs +++ b/Race Element.UI/Views/MainTopMenuView.axaml.cs @@ -5,13 +5,8 @@ namespace RaceElement.UI.Views; public partial class MainTopMenuView : UserControl { - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } - public MainTopMenuView() { - InitializeComponent(); + AvaloniaXamlLoader.Load(this); } } \ No newline at end of file