Further work on ui-redesign and implemented dependency injection

This commit is contained in:
Enrico Ludwig 2024-09-02 20:35:36 +02:00
parent b42d313bff
commit 4ac3a44cef
13 changed files with 89 additions and 17 deletions

View File

@ -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<ITwitchDataService, TwitchDataService>();
_services.AddTransient<MainWindowViewModel>();
_services.AddTransient<AboutWindowViewModel>();
_provider = _services.BuildServiceProvider();
}
public static void InitTwitchClient(bool overrideToken = false)
@ -132,14 +150,25 @@ public partial class App : Application
public override void OnFrameworkInitializationCompleted()
{
BindingPlugins.DataValidators.RemoveAt(0);
var vm = _provider?.GetRequiredService<MainWindowViewModel>();
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
};
}

View File

@ -27,6 +27,7 @@
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.1.0" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="TwitchLib" Version="3.5.3" />
</ItemGroup>
</Project>

View File

@ -1,11 +1,22 @@
using Avalonia;
using Avalonia.Controls;
using Microsoft.Extensions.DependencyInjection;
namespace BetterRaid.Extensions;
public static class DataContextExtensions
{
public static T? GetDataContextAs<T>(this T obj) where T : Window
public static T? GetDataContextAs<T>(this T obj) where T : StyledElement
{
return obj.DataContext as T;
}
public static void InjectDataContext<T>(this StyledElement e) where T : class
{
if (Application.Current is not App { Provider: not null } app)
return;
var vm = app.Provider.GetRequiredService<T>();
e.DataContext = vm;
}
}

View File

@ -1,7 +1,6 @@
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Avalonia.Threading;
namespace BetterRaid.Models;

View File

@ -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()

View File

@ -1,6 +1,6 @@
namespace BetterRaid.Services;
public class TwitchDataService
public interface ITwitchDataService
{
}

View File

@ -0,0 +1,6 @@
namespace BetterRaid.Services;
public class TwitchDataService : ITwitchDataService
{
}

View File

@ -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");
}
}

View File

@ -1,6 +1,11 @@
using System;
namespace BetterRaid.ViewModels;
public class AddChannelWindowViewModel : ViewModelBase
{
public AddChannelWindowViewModel()
{
Console.WriteLine("[DEBUG] AddChannelWindowViewModel created");
}
}

View File

@ -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<AboutWindowViewModel>();
about.ShowDialog(owner);
about.CenterToOwner();
}

View File

@ -4,4 +4,5 @@ namespace BetterRaid.ViewModels;
public class ViewModelBase : ObservableObject
{
}

View File

@ -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"

View File

@ -1,10 +1,10 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:BetterRaid.ViewModels"
xmlns:br="using:BetterRaid"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ai="using:AsyncImageLoader"
xmlns:betterRaid="clr-namespace:BetterRaid"
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="800"
Width="600"
Height="800"
@ -118,7 +118,7 @@
<ai:AdvancedImage Grid.Column="0"
Grid.Row="0"
Source="{Binding ThumbnailUrl, TargetNullValue={x:Static betterRaid:App.ChannelPlaceholderImageUrl}}" />
Source="{Binding ThumbnailUrl, TargetNullValue={x:Static br:App.ChannelPlaceholderImageUrl}}" />
<Border Grid.Column="0"
Grid.Row="0"