diff --git a/App.axaml.cs b/App.axaml.cs index f8b0b4a..03a7cfa 100644 --- a/App.axaml.cs +++ b/App.axaml.cs @@ -5,14 +5,19 @@ using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Data.Core.Plugins; using Avalonia.Markup.Xaml; +using BetterRaid.Services; using BetterRaid.ViewModels; using BetterRaid.Views; +using Microsoft.Extensions.DependencyInjection; using TwitchLib.Api; namespace BetterRaid; public partial class App : Application { + private readonly ServiceCollection _services = []; + private ServiceProvider? _provider; + internal static TwitchAPI? TwitchApi = null; internal static int AutoUpdateDelay = 10_000; internal static bool HasUserZnSubbed = false; @@ -33,10 +38,14 @@ public partial class App : Application + $"&response_type={TwitchOAuthResponseType}" + $"&scope={string.Join("+", TwitchOAuthScopes)}"; - internal static readonly string ChannelPlaceholderImageUrl = "https://cdn.pixabay.com/photo/2018/11/13/22/01/avatar-3814081_1280.png"; + public const string ChannelPlaceholderImageUrl = "https://cdn.pixabay.com/photo/2018/11/13/22/01/avatar-3814081_1280.png"; + public IServiceProvider? Provider => _provider; + public override void Initialize() { + InitializeServices(); + var userHomeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); switch (Environment.OSVersion.Platform) @@ -63,7 +72,16 @@ public partial class App : Application InitTwitchClient(); } - AvaloniaXamlLoader.Load(this); + AvaloniaXamlLoader.Load(_provider, this); + } + + private void InitializeServices() + { + _services.AddSingleton(); + _services.AddTransient(); + _services.AddTransient(); + + _provider = _services.BuildServiceProvider(); } public static void InitTwitchClient(bool overrideToken = false) @@ -132,17 +150,28 @@ public partial class App : Application public override void OnFrameworkInitializationCompleted() { + BindingPlugins.DataValidators.RemoveAt(0); + + var vm = _provider?.GetRequiredService(); + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { // Line below is needed to remove Avalonia data validation. // Without this line you will get duplicate validations from both Avalonia and CT - BindingPlugins.DataValidators.RemoveAt(0); + desktop.MainWindow = new MainWindow { - //DataContext = new MainWindowViewModel() + DataContext = vm }; } - + else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform) + { + singleViewPlatform.MainView = new MainWindow + { + DataContext = vm + }; + } + base.OnFrameworkInitializationCompleted(); } } \ No newline at end of file diff --git a/BetterRaid.csproj b/BetterRaid.csproj index 2ba6c9b..6fdc464 100644 --- a/BetterRaid.csproj +++ b/BetterRaid.csproj @@ -27,6 +27,7 @@ + diff --git a/Extensions/DataContextExtensions.cs b/Extensions/DataContextExtensions.cs index c87e81b..0237d51 100644 --- a/Extensions/DataContextExtensions.cs +++ b/Extensions/DataContextExtensions.cs @@ -1,11 +1,22 @@ +using Avalonia; using Avalonia.Controls; +using Microsoft.Extensions.DependencyInjection; namespace BetterRaid.Extensions; public static class DataContextExtensions { - public static T? GetDataContextAs(this T obj) where T : Window + public static T? GetDataContextAs(this T obj) where T : StyledElement { return obj.DataContext as T; } + + public static void InjectDataContext(this StyledElement e) where T : class + { + if (Application.Current is not App { Provider: not null } app) + return; + + var vm = app.Provider.GetRequiredService(); + e.DataContext = vm; + } } \ No newline at end of file diff --git a/Models/TwitchChannel.cs b/Models/TwitchChannel.cs index ca60254..5a04dcf 100644 --- a/Models/TwitchChannel.cs +++ b/Models/TwitchChannel.cs @@ -1,7 +1,6 @@ using System; using System.ComponentModel; using System.Runtime.CompilerServices; -using Avalonia.Threading; namespace BetterRaid.Models; diff --git a/Program.cs b/Program.cs index dc223ea..672a903 100644 --- a/Program.cs +++ b/Program.cs @@ -9,8 +9,9 @@ sealed class Program // 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); + public static void Main(string[] args) => + BuildAvaloniaApp() + .StartWithClassicDesktopLifetime(args); // Avalonia configuration, don't remove; also used by visual designer. public static AppBuilder BuildAvaloniaApp() diff --git a/Services/TwitchDataService.cs b/Services/ITwitchDataService.cs similarity index 51% rename from Services/TwitchDataService.cs rename to Services/ITwitchDataService.cs index d56609d..a3ec8db 100644 --- a/Services/TwitchDataService.cs +++ b/Services/ITwitchDataService.cs @@ -1,6 +1,6 @@ namespace BetterRaid.Services; -public class TwitchDataService +public interface ITwitchDataService { } \ No newline at end of file diff --git a/Services/Implementations/TwitchDataService.cs b/Services/Implementations/TwitchDataService.cs new file mode 100644 index 0000000..d5f0f81 --- /dev/null +++ b/Services/Implementations/TwitchDataService.cs @@ -0,0 +1,6 @@ +namespace BetterRaid.Services; + +public class TwitchDataService : ITwitchDataService +{ + +} \ No newline at end of file diff --git a/ViewModels/AboutWindowViewModel.cs b/ViewModels/AboutWindowViewModel.cs new file mode 100644 index 0000000..ef4cda8 --- /dev/null +++ b/ViewModels/AboutWindowViewModel.cs @@ -0,0 +1,13 @@ +using System; +using BetterRaid.Services; + +namespace BetterRaid.ViewModels; + +public class AboutWindowViewModel : ViewModelBase +{ + public AboutWindowViewModel(ITwitchDataService s) + { + Console.WriteLine(s); + Console.WriteLine("[DEBUG] AboutWindowViewModel created"); + } +} \ No newline at end of file diff --git a/ViewModels/AddChannelWindowViewModel.cs b/ViewModels/AddChannelWindowViewModel.cs index e2c33f4..ba02f68 100644 --- a/ViewModels/AddChannelWindowViewModel.cs +++ b/ViewModels/AddChannelWindowViewModel.cs @@ -1,6 +1,11 @@ +using System; + namespace BetterRaid.ViewModels; public class AddChannelWindowViewModel : ViewModelBase { - + public AddChannelWindowViewModel() + { + Console.WriteLine("[DEBUG] AddChannelWindowViewModel created"); + } } \ No newline at end of file diff --git a/ViewModels/MainWindowViewModel.cs b/ViewModels/MainWindowViewModel.cs index 566e402..7888c0e 100644 --- a/ViewModels/MainWindowViewModel.cs +++ b/ViewModels/MainWindowViewModel.cs @@ -1,15 +1,12 @@ using System; using System.Collections.ObjectModel; -using System.Collections.Specialized; -using System.ComponentModel; using System.Linq; using System.Threading; -using System.Threading.Tasks; using Avalonia.Controls; -using Avalonia.Threading; using BetterRaid.Extensions; using BetterRaid.Misc; using BetterRaid.Models; +using BetterRaid.Services; using BetterRaid.Views; namespace BetterRaid.ViewModels; @@ -46,6 +43,12 @@ public partial class MainWindowViewModel : ViewModelBase public bool IsLoggedIn => App.TwitchApi != null; + public MainWindowViewModel(ITwitchDataService t) + { + Console.WriteLine(t); + Console.WriteLine("[DEBUG] MainWindowViewModel created"); + } + public void ExitApplication() { //TODO polish later @@ -55,6 +58,7 @@ public partial class MainWindowViewModel : ViewModelBase public void ShowAboutWindow(Window owner) { var about = new AboutWindow(); + about.InjectDataContext(); about.ShowDialog(owner); about.CenterToOwner(); } diff --git a/ViewModels/ViewModelBase.cs b/ViewModels/ViewModelBase.cs index dd785e5..b67d0c1 100644 --- a/ViewModels/ViewModelBase.cs +++ b/ViewModels/ViewModelBase.cs @@ -4,4 +4,5 @@ namespace BetterRaid.ViewModels; public class ViewModelBase : ObservableObject { + } diff --git a/Views/AboutWindow.axaml b/Views/AboutWindow.axaml index d120a76..cf4345c 100644 --- a/Views/AboutWindow.axaml +++ b/Views/AboutWindow.axaml @@ -2,8 +2,10 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:vm="clr-namespace:BetterRaid.ViewModels" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="BetterRaid.Views.AboutWindow" + x:DataType="vm:AboutWindowViewModel" Title="About" MaxWidth="300" MinWidth="300" diff --git a/Views/MainWindow.axaml b/Views/MainWindow.axaml index 74661c5..d36ccdc 100644 --- a/Views/MainWindow.axaml +++ b/Views/MainWindow.axaml @@ -1,10 +1,10 @@ + Source="{Binding ThumbnailUrl, TargetNullValue={x:Static br:App.ChannelPlaceholderImageUrl}}" />