diff --git a/AVALONIA_MIGRATION.md b/AVALONIA_MIGRATION.md new file mode 100644 index 000000000..49304ba68 --- /dev/null +++ b/AVALONIA_MIGRATION.md @@ -0,0 +1,200 @@ +# Avalonia UI Migration Documentation + +## Overview + +This document describes the migration from WPF to Avalonia UI for the Algoloop application. The Avalonia UI project provides a cross-platform alternative to the existing WPF application. + +## What Changed + +### New Project: Algoloop.Avalonia + +A new Avalonia UI project has been added to the solution targeting .NET 8.0. This project: +- Uses Avalonia 11.2.2 for cross-platform UI +- Implements a minimal main window with menu and tabbed interface +- Provides standalone ViewModels without WPF dependencies +- Includes the FluentTheme for modern UI styling + +### Project Structure + +``` +Algoloop.Avalonia/ +├── Algoloop.Avalonia.csproj # Project file +├── Program.cs # Application entry point +├── App.axaml # Application definition +├── App.axaml.cs # Application code-behind +├── MainWindow.axaml # Main window XAML +├── MainWindow.axaml.cs # Main window code-behind +├── Styles.axaml # Application styles +├── ViewModels/ +│ └── MainViewModel.cs # Main view model +└── Resources/ + └── AlgoloopIcon.ico # Application icon +``` + +### Key Components + +#### Program.cs +The entry point that configures and starts the Avalonia application with classic desktop lifetime. + +#### App.axaml / App.axaml.cs +The main application class that: +- Loads the FluentTheme +- Initializes the application styles +- Creates and shows the main window + +#### MainWindow.axaml / MainWindow.axaml.cs +The main application window featuring: +- File menu with Save and Exit commands +- Help menu +- Status bar +- Tabbed interface with: + - Markets (placeholder) + - Strategies (placeholder) + - Research (placeholder) + - Log (DataGrid with sample data) + +#### ViewModels +Simplified ViewModels created specifically for Avalonia: +- **MainViewModel**: Main application view model with Save and Exit commands +- **LogViewModel**: Log view model with sample log entries + +### Dependencies + +The Avalonia project uses the following NuGet packages: +- Avalonia 11.2.2 +- Avalonia.Desktop 11.2.2 +- Avalonia.Controls.DataGrid 11.2.2 +- Avalonia.Themes.Fluent 11.2.2 +- Avalonia.Diagnostics 11.2.2 (Debug only) +- CommunityToolkit.Mvvm 8.4.0 + +## How to Build and Run + +### Prerequisites +- .NET 8.0 SDK or later +- Platform-specific requirements: + - Windows: No additional requirements + - Linux: See [Avalonia Linux setup](https://docs.avaloniaui.net/docs/get-started/set-up-an-editor/linux) + - macOS: See [Avalonia macOS setup](https://docs.avaloniaui.net/docs/get-started/set-up-an-editor/macos) + +### Build Instructions + +#### Build the Avalonia project: +```bash +dotnet build Algoloop.Avalonia/Algoloop.Avalonia.csproj +``` + +#### Build the entire solution: +```bash +dotnet build Algoloop.sln +``` + +### Run Instructions + +#### Run the Avalonia UI application: +```bash +dotnet run --project Algoloop.Avalonia +``` + +#### On Windows, you can also run the executable directly: +```bash +.\Algoloop.Avalonia\bin\Debug\net8.0\Algoloop.Avalonia.exe +``` + +## Known Limitations + +### Current Implementation Status + +1. **Minimal UI Implementation** + - The current implementation provides a basic window structure + - Only the Log tab has a functional DataGrid with sample data + - Markets, Strategies, and Research tabs show placeholders + +2. **ViewModels** + - Simplified ViewModels created specifically for Avalonia + - No integration with existing WPF ViewModels (which have WPF dependencies) + - Business logic from Algoloop core projects needs to be integrated + +3. **Missing Features** + - No integration with QuantConnect Lean engine + - No data loading or persistence + - No charts or visualizations + - No strategy/market management + - No settings or configuration UI + +4. **Platform-Specific Limitations** + - The original WPF ViewModels use System.Windows which is Windows-specific + - Some features may require platform-specific implementations + +### WPF Project Status + +- The WPF project (Algoloop.Wpf) remains unchanged and fully functional +- Both WPF and Avalonia projects can coexist in the solution +- WPF is still the primary/recommended UI for production use + +## Next Steps for Full Migration + +To achieve feature parity with the WPF version, the following work is needed: + +1. **Refactor ViewModels** + - Extract business logic from WPF-specific ViewModels + - Create platform-agnostic ViewModels or shared view model library + - Implement proper MVVM patterns without WPF dependencies + +2. **Implement Core Features** + - Markets management UI + - Strategies management UI + - Research/Jupyter notebook integration + - Settings and configuration + - Chart visualizations (using OxyPlot.Avalonia or similar) + +3. **Integrate Business Logic** + - Connect to QuantConnect Lean engine + - Implement data loading and persistence + - Add backtesting capabilities + - Integrate market data providers + +4. **Testing and Validation** + - Cross-platform testing (Windows, Linux, macOS) + - UI/UX refinement + - Performance optimization + +5. **Documentation** + - User guide for Avalonia version + - Developer documentation + - Migration guide for contributors + +## Architecture Notes + +### Separation of Concerns + +The Avalonia implementation intentionally avoids direct references to WPF projects to maintain cross-platform compatibility. Future development should: +- Keep UI code platform-agnostic where possible +- Use dependency injection for platform-specific services +- Share business logic through non-UI projects + +### Recommended Approach + +For a production-ready Avalonia migration: +1. Create shared ViewModel library (no WPF/Avalonia dependencies) +2. Use interfaces for platform-specific services +3. Implement proper dependency injection +4. Use platform-specific view implementations (WPF/Avalonia) + +## References + +- [Avalonia Documentation](https://docs.avaloniaui.net/) +- [Avalonia Samples](https://github.com/AvaloniaUI/Avalonia.Samples) +- [MVVM Toolkit](https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/) +- [WPF to Avalonia Migration Guide](https://docs.avaloniaui.net/docs/guides/platforms/wpf-migration) + +## Support + +For questions or issues related to the Avalonia migration: +1. Check existing documentation +2. Review Avalonia samples and documentation +3. Create an issue in the repository with "Avalonia" label + +## License + +The Avalonia project follows the same license as the main Algoloop project. diff --git a/Algoloop.Avalonia/Algoloop.Avalonia.csproj b/Algoloop.Avalonia/Algoloop.Avalonia.csproj new file mode 100644 index 000000000..902263960 --- /dev/null +++ b/Algoloop.Avalonia/Algoloop.Avalonia.csproj @@ -0,0 +1,24 @@ + + + WinExe + net8.0 + enable + true + Resources\AlgoloopIcon.ico + false + + + + + + + + + + + + + + + + diff --git a/Algoloop.Avalonia/App.axaml b/Algoloop.Avalonia/App.axaml new file mode 100644 index 000000000..90538a0c9 --- /dev/null +++ b/Algoloop.Avalonia/App.axaml @@ -0,0 +1,9 @@ + + + + + + diff --git a/Algoloop.Avalonia/App.axaml.cs b/Algoloop.Avalonia/App.axaml.cs new file mode 100644 index 000000000..3b1cd83b1 --- /dev/null +++ b/Algoloop.Avalonia/App.axaml.cs @@ -0,0 +1,27 @@ +using Algoloop.Avalonia.ViewModels; +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Markup.Xaml; + +namespace Algoloop.Avalonia; + +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 MainViewModel() + }; + } + + base.OnFrameworkInitializationCompleted(); + } +} diff --git a/Algoloop.Avalonia/MainWindow.axaml b/Algoloop.Avalonia/MainWindow.axaml new file mode 100644 index 000000000..4dd7127af --- /dev/null +++ b/Algoloop.Avalonia/MainWindow.axaml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Algoloop.Avalonia/MainWindow.axaml.cs b/Algoloop.Avalonia/MainWindow.axaml.cs new file mode 100644 index 000000000..94d99a7a3 --- /dev/null +++ b/Algoloop.Avalonia/MainWindow.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; + +namespace Algoloop.Avalonia; + +public partial class MainWindow : Window +{ + public MainWindow() + { + InitializeComponent(); + } +} diff --git a/Algoloop.Avalonia/Program.cs b/Algoloop.Avalonia/Program.cs new file mode 100644 index 000000000..2c74e152f --- /dev/null +++ b/Algoloop.Avalonia/Program.cs @@ -0,0 +1,20 @@ +using Avalonia; +using System; + +namespace Algoloop.Avalonia; + +class Program +{ + // Initialization code. Don't use any Avalonia, third-party APIs or any + // SynchronizationContext-reliant code before AppMain is called: things aren't initialized + // yet and stuff might break. + [STAThread] + public static void Main(string[] args) => BuildAvaloniaApp() + .StartWithClassicDesktopLifetime(args); + + // Avalonia configuration, don't remove; also used by visual designer. + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .UsePlatformDetect() + .LogToTrace(); +} diff --git a/Algoloop.Avalonia/README.md b/Algoloop.Avalonia/README.md new file mode 100644 index 000000000..e94143bba --- /dev/null +++ b/Algoloop.Avalonia/README.md @@ -0,0 +1,66 @@ +# Algoloop Avalonia UI + +This is the cross-platform Avalonia UI implementation for Algoloop. + +## Quick Start + +### Prerequisites +- .NET 8.0 SDK or later + +### Build +```bash +dotnet build +``` + +### Run +```bash +dotnet run +``` + +## Project Structure + +- **Program.cs** - Application entry point +- **App.axaml** / **App.axaml.cs** - Application configuration with FluentTheme +- **MainWindow.axaml** / **MainWindow.axaml.cs** - Main application window +- **ViewModels/** - MVVM view models +- **Styles.axaml** - Application-wide styles +- **Resources/** - Application resources (icons, etc.) + +## Features + +### Current Implementation +- ✅ Cross-platform desktop application (Windows, Linux, macOS) +- ✅ FluentTheme UI +- ✅ Main window with menu and tabs +- ✅ DataGrid in Log tab +- ✅ MVVM architecture using CommunityToolkit.Mvvm + +### Planned Features +- ⏳ Markets management +- ⏳ Strategies configuration +- ⏳ Research/Jupyter integration +- ⏳ Chart visualizations +- ⏳ QuantConnect Lean engine integration +- ⏳ Data persistence +- ⏳ Backtesting capabilities + +## Development + +### Adding New Views +1. Create `.axaml` and `.axaml.cs` files in the appropriate folder +2. Create corresponding ViewModel in `ViewModels/` +3. Wire up DataContext in code-behind or XAML + +### Styling +Application-wide styles are defined in `Styles.axaml`. The project uses the FluentTheme from Avalonia. + +### Debugging +The project includes Avalonia.Diagnostics for development builds. Press F12 in the running application to open the DevTools. + +## Documentation + +For comprehensive migration information, see [AVALONIA_MIGRATION.md](../AVALONIA_MIGRATION.md) in the repository root. + +## License + +Same license as the main Algoloop project. diff --git a/Algoloop.Avalonia/Resources/AlgoloopIcon.ico b/Algoloop.Avalonia/Resources/AlgoloopIcon.ico new file mode 100644 index 000000000..c1ca3ca54 Binary files /dev/null and b/Algoloop.Avalonia/Resources/AlgoloopIcon.ico differ diff --git a/Algoloop.Avalonia/Styles.axaml b/Algoloop.Avalonia/Styles.axaml new file mode 100644 index 000000000..50b9ae1ac --- /dev/null +++ b/Algoloop.Avalonia/Styles.axaml @@ -0,0 +1,18 @@ + + + + + + + + + diff --git a/Algoloop.Avalonia/ViewModels/MainViewModel.cs b/Algoloop.Avalonia/ViewModels/MainViewModel.cs new file mode 100644 index 000000000..a6b5ce27f --- /dev/null +++ b/Algoloop.Avalonia/ViewModels/MainViewModel.cs @@ -0,0 +1,68 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using System.Collections.ObjectModel; + +namespace Algoloop.Avalonia.ViewModels; + +public class LogItem +{ + public string Time { get; set; } = string.Empty; + public string Level { get; set; } = string.Empty; + public string Message { get; set; } = string.Empty; +} + +public class LogViewModel : ObservableObject +{ + public ObservableCollection Logs { get; } = new(); + + public LogViewModel() + { + // Add some sample log items + Logs.Add(new LogItem { Time = System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), Level = "INFO", Message = "Application started" }); + } +} + +public class MainViewModel : ObservableObject +{ + private bool _isBusy; + private string _statusMessage = "Ready"; + + public MainViewModel() + { + SaveCommand = new RelayCommand(SaveConfig, () => !IsBusy); + ExitCommand = new RelayCommand(DoExit); + LogViewModel = new LogViewModel(); + } + + public static string Title => "Algoloop Avalonia (Preview)"; + + public bool IsBusy + { + get => _isBusy; + set => SetProperty(ref _isBusy, value); + } + + public string StatusMessage + { + get => _statusMessage; + set => SetProperty(ref _statusMessage, value); + } + + public LogViewModel LogViewModel { get; } + + public RelayCommand SaveCommand { get; } + public RelayCommand ExitCommand { get; } + + private void SaveConfig() + { + StatusMessage = "Configuration saved"; + } + + private void DoExit(object? window) + { + if (window is global::Avalonia.Controls.Window w) + { + w.Close(); + } + } +} diff --git a/Algoloop.sln b/Algoloop.sln index 7335e4160..ac1fd9bed 100644 --- a/Algoloop.sln +++ b/Algoloop.sln @@ -63,6 +63,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Algoloop", "Algoloop\Algolo EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuantConnect.DownloaderDataProvider.Launcher", "DownloaderDataProvider\QuantConnect.DownloaderDataProvider.Launcher.csproj", "{387365D5-6937-4211-AA79-CBE46CCB3961}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Algoloop.Avalonia", "Algoloop.Avalonia\Algoloop.Avalonia.csproj", "{8E55E25D-F304-469F-B676-431E6779ECE1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -667,6 +669,26 @@ Global {387365D5-6937-4211-AA79-CBE46CCB3961}.Release|x64.Build.0 = Release|Any CPU {387365D5-6937-4211-AA79-CBE46CCB3961}.Release|x86.ActiveCfg = Release|Any CPU {387365D5-6937-4211-AA79-CBE46CCB3961}.Release|x86.Build.0 = Release|Any CPU + {8E55E25D-F304-469F-B676-431E6779ECE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8E55E25D-F304-469F-B676-431E6779ECE1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8E55E25D-F304-469F-B676-431E6779ECE1}.Debug|ARM.ActiveCfg = Debug|Any CPU + {8E55E25D-F304-469F-B676-431E6779ECE1}.Debug|ARM.Build.0 = Debug|Any CPU + {8E55E25D-F304-469F-B676-431E6779ECE1}.Debug|arm64.ActiveCfg = Debug|Any CPU + {8E55E25D-F304-469F-B676-431E6779ECE1}.Debug|arm64.Build.0 = Debug|Any CPU + {8E55E25D-F304-469F-B676-431E6779ECE1}.Debug|x64.ActiveCfg = Debug|Any CPU + {8E55E25D-F304-469F-B676-431E6779ECE1}.Debug|x64.Build.0 = Debug|Any CPU + {8E55E25D-F304-469F-B676-431E6779ECE1}.Debug|x86.ActiveCfg = Debug|Any CPU + {8E55E25D-F304-469F-B676-431E6779ECE1}.Debug|x86.Build.0 = Debug|Any CPU + {8E55E25D-F304-469F-B676-431E6779ECE1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8E55E25D-F304-469F-B676-431E6779ECE1}.Release|Any CPU.Build.0 = Release|Any CPU + {8E55E25D-F304-469F-B676-431E6779ECE1}.Release|ARM.ActiveCfg = Release|Any CPU + {8E55E25D-F304-469F-B676-431E6779ECE1}.Release|ARM.Build.0 = Release|Any CPU + {8E55E25D-F304-469F-B676-431E6779ECE1}.Release|arm64.ActiveCfg = Release|Any CPU + {8E55E25D-F304-469F-B676-431E6779ECE1}.Release|arm64.Build.0 = Release|Any CPU + {8E55E25D-F304-469F-B676-431E6779ECE1}.Release|x64.ActiveCfg = Release|Any CPU + {8E55E25D-F304-469F-B676-431E6779ECE1}.Release|x64.Build.0 = Release|Any CPU + {8E55E25D-F304-469F-B676-431E6779ECE1}.Release|x86.ActiveCfg = Release|Any CPU + {8E55E25D-F304-469F-B676-431E6779ECE1}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE