Lots of performance optimization; Added category to RaidButton; Added AboutWindow

This commit is contained in:
Enrico Ludwig 2024-08-27 19:51:23 +02:00
parent 4311bfb43f
commit d0662351d7
11 changed files with 218 additions and 79 deletions

View File

@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.002.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BetterRaid", "BetterRaid.csproj", "{5F90F02B-A28E-4B50-9821-1F0D7226936C}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BetterRaid", "BetterRaid.csproj", "{6BE742A5-079D-4617-BDC1-2933274CDCB7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -11,10 +11,10 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5F90F02B-A28E-4B50-9821-1F0D7226936C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5F90F02B-A28E-4B50-9821-1F0D7226936C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5F90F02B-A28E-4B50-9821-1F0D7226936C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5F90F02B-A28E-4B50-9821-1F0D7226936C}.Release|Any CPU.Build.0 = Release|Any CPU
{6BE742A5-079D-4617-BDC1-2933274CDCB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6BE742A5-079D-4617-BDC1-2933274CDCB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6BE742A5-079D-4617-BDC1-2933274CDCB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6BE742A5-079D-4617-BDC1-2933274CDCB7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -57,14 +57,17 @@
Orientation="Vertical">
<Label HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
Content="{Binding Channel.DisplayName}" />
Content="{Binding Channel.DisplayName, FallbackValue=...}" />
<Label HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
Content="{Binding Channel.Category, TargetNullValue=-, FallbackValue=...}" />
<Label HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
Foreground="{Binding ViewerCountColor}"
Content="{Binding Channel.ViewerCount}" />
Content="{Binding Channel.ViewerCount, TargetNullValue=(Offline), FallbackValue=...}" />
<Label HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
Content="{Binding LastRaided, TargetNullValue=Never Raided}" />
Content="{Binding LastRaided, TargetNullValue=Never Raided, FallbackValue=...}" />
</StackPanel>
</Grid>

View File

@ -0,0 +1,19 @@
using Avalonia.Controls;
namespace BetterRaid.Extensions;
public static class WindowExtensions
{
public static void CenterToOwner(this Window window)
{
var owner = window.Owner as Window;
if (owner == null)
return;
window.Position = new Avalonia.PixelPoint(
(int)(owner.Position.X + owner.Width / 2 - window.Width / 2),
(int)(owner.Position.Y + owner.Height / 2 - window.Height / 2)
);
}
}

View File

@ -6,11 +6,12 @@ namespace BetterRaid.Models;
public class TwitchChannel : INotifyPropertyChanged
{
private string? viewerCount;
private bool isLive;
private string? name;
private string? displayName;
private string? thumbnailUrl;
private string? _viewerCount;
private bool _isLive;
private string? _name;
private string? _displayName;
private string? _thumbnailUrl;
private string? _category;
public string? BroadcasterId
{
@ -19,63 +20,76 @@ public class TwitchChannel : INotifyPropertyChanged
}
public string? Name
{
get => name;
get => _name;
set
{
if (value == name)
if (value == _name)
return;
name = value;
_name = value;
OnPropertyChanged();
}
}
public bool IsLive
{
get => isLive;
get => _isLive;
set
{
if (value == isLive)
if (value == _isLive)
return;
isLive = value;
_isLive = value;
OnPropertyChanged();
}
}
public string? ViewerCount
{
get => viewerCount;
get => _viewerCount;
set
{
if (value == viewerCount)
if (value == _viewerCount)
return;
viewerCount = value;
_viewerCount = value;
OnPropertyChanged();
}
}
public string? ThumbnailUrl
{
get => thumbnailUrl;
get => _thumbnailUrl;
set
{
if (value == thumbnailUrl)
if (value == _thumbnailUrl)
return;
thumbnailUrl = value;
_thumbnailUrl = value;
OnPropertyChanged();
}
}
public string? DisplayName
{
get => displayName;
get => _displayName;
set
{
if (value == displayName)
if (value == _displayName)
return;
displayName = value;
_displayName = value;
OnPropertyChanged();
}
}
public string? Category
{
get => _category;
set
{
if (value == _category)
return;
_category = value;
OnPropertyChanged();
}
}

View File

@ -1,6 +1,9 @@
using System;
using Avalonia;
using Avalonia.Controls;
using BetterRaid.Extensions;
using BetterRaid.Models;
using BetterRaid.Views;
namespace BetterRaid.ViewModels;
@ -27,4 +30,11 @@ public partial class MainWindowViewModel : ViewModelBase
//TODO polish later
Environment.Exit(0);
}
public void ShowAboutWindow(Window owner)
{
var about = new AboutWindow();
about.ShowDialog(owner);
about.CenterToOwner();
}
}

View File

@ -3,6 +3,7 @@ using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Media;
using Avalonia.Threading;
using BetterRaid.Models;
using TwitchLib.Api.Helix.Models.Raids.StartRaid;
using TwitchLib.Api.Helix.Models.Search;
@ -15,13 +16,13 @@ public class RaidButtonViewModel : ViewModelBase
private TwitchChannel? _channel;
private SolidColorBrush _viewerCountColor = new SolidColorBrush(Color.FromRgb(byte.MaxValue, byte.MaxValue, byte.MaxValue));
public required string ChannelName
public string ChannelName
{
get;
set;
}
public TwitchChannel Channel => _channel ?? new TwitchChannel(ChannelName);
public TwitchChannel? Channel => _channel ?? new TwitchChannel(ChannelName);
public SolidColorBrush ViewerCountColor
{
@ -33,13 +34,14 @@ public class RaidButtonViewModel : ViewModelBase
public DateTime? LastRaided => MainVm?.Database?.GetLastRaided(ChannelName);
public RaidButtonViewModel(string channelName)
{
ChannelName = channelName;
}
public async Task<bool> GetOrUpdateChannelAsync()
{
if (_channel == null)
{
_channel = new TwitchChannel(ChannelName);
_channel.PropertyChanged += OnChannelDataChanged;
}
Console.WriteLine("[DEBUG] Updating channel '{0}' ...", ChannelName);
var currentChannelData = await GetChannelAsync(ChannelName);
@ -48,24 +50,42 @@ public class RaidButtonViewModel : ViewModelBase
var currentStreamData = await GetStreamAsync(currentChannelData);
_channel.BroadcasterId = currentChannelData.Id;
_channel.Name = ChannelName;
_channel.DisplayName = currentChannelData.DisplayName;
_channel.IsLive = currentChannelData.IsLive;
_channel.ThumbnailUrl = currentChannelData.ThumbnailUrl;
_channel.ViewerCount = currentStreamData?.ViewerCount == null
var swapChannel = new TwitchChannel(ChannelName)
{
BroadcasterId = currentChannelData.Id,
Name = ChannelName,
DisplayName = currentChannelData.DisplayName,
IsLive = currentChannelData.IsLive,
ThumbnailUrl = currentChannelData.ThumbnailUrl,
ViewerCount = currentStreamData?.ViewerCount == null
? "(Offline)"
: $"{currentStreamData?.ViewerCount} Viewers";
: $"{currentStreamData?.ViewerCount} Viewers",
Category = currentStreamData?.GameName
};
if (_channel.IsLive)
if (_channel != null)
{
ViewerCountColor = new SolidColorBrush(Color.FromRgb(0, byte.MaxValue, 0));
_channel.PropertyChanged -= OnChannelDataChanged;
}
else
Dispatcher.UIThread.Invoke(() => {
ViewerCountColor = new SolidColorBrush(Color.FromRgb(
r: swapChannel.IsLive ? (byte) 0 : byte.MaxValue,
g: swapChannel.IsLive ? byte.MaxValue : (byte) 0,
b: 0)
);
_channel = swapChannel;
OnPropertyChanged(nameof(Channel));
});
if (_channel != null)
{
ViewerCountColor = new SolidColorBrush(Color.FromRgb(byte.MaxValue, 0, 0));
_channel.PropertyChanged += OnChannelDataChanged;
}
Console.WriteLine("[DEBUG] DONE Updating channel '{0}'", ChannelName);
return true;
}
@ -102,6 +122,9 @@ public class RaidButtonViewModel : ViewModelBase
if (App.TwitchAPI == null)
return;
if (Channel == null)
return;
StartRaidResponse? raid = null;
try

57
Views/AboutWindow.axaml Normal file
View File

@ -0,0 +1,57 @@
<Window xmlns="https://github.com/avaloniaui"
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"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="BetterRaid.Views.AboutWindow"
Title="About"
MaxWidth="300"
MinWidth="300"
Height="200"
Background="DarkSlateGray">
<ScrollViewer>
<StackPanel Orientation="Vertical">
<Label HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
Content="About BetterRaid"
Margin="0, 10, 0, -10"
FontSize="28"
FontWeight="ExtraLight" />
<Label HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
Content="v0.0.1"
Margin="0"
FontSize="12"
FontWeight="Light" />
<Separator Margin="0, 5, 0, 5" />
<TextBlock HorizontalAlignment="Left"
Text="Programming"
FontSize="14"
Margin="5, 5, 0, 5"
TextDecorations="Underline" />
<TextBlock HorizontalAlignment="Left"
Text="- Enrico Ludwig &lt;hi@zion-networks.de&gt;"
FontSize="12"
Margin="15, 0, 0, 0" />
<TextBlock HorizontalAlignment="Left"
Text="Graphics"
FontSize="14"
Margin="5, 5, 0, 5"
TextDecorations="Underline" />
<TextBlock HorizontalAlignment="Left"
Text="- UNKNOWN ARTIST"
FontSize="12"
Margin="15, 0, 0, 0" />
</StackPanel>
</ScrollViewer>
</Window>

View File

@ -0,0 +1,13 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace BetterRaid.Views;
public partial class AboutWindow : Window
{
public AboutWindow()
{
InitializeComponent();
}
}

View File

@ -10,8 +10,7 @@
x:DataType="vm:MainWindowViewModel"
Icon="/Assets/avalonia-logo.ico"
Title="BetterRaid"
Background="DarkSlateGray"
WindowStartupLocation="CenterScreen">
Background="DarkSlateGray">
<Design.DataContext>
<vm:MainWindowViewModel/>
@ -35,7 +34,12 @@
Grid.Row="0">
<MenuItem Header="File">
<MenuItem Header="Exit" Command="{Binding ExitApplication}" />
<MenuItem Header="About"
CommandParameter="{Binding $parent[Window]}"
Command="{Binding ShowAboutWindow}" />
<Separator />
<MenuItem Header="Exit"
Command="{Binding ExitApplication}" />
</MenuItem>
</Menu>

View File

@ -6,6 +6,7 @@ using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Threading;
using BetterRaid.Extensions;
using BetterRaid.Models;
using BetterRaid.ViewModels;
@ -25,13 +26,14 @@ public partial class MainWindow : Window
InitializeComponent();
_autoUpdater.WorkerSupportsCancellation = true;
_autoUpdater.DoWork += UpdateAllTiles;
_autoUpdater.RunWorkerAsync();
}
private void OnDatabaseChanged(object? sender, PropertyChangedEventArgs e)
{
InitializeRaidChannels();
// TODO: Only if new channel was added or existing were removed
// InitializeRaidChannels();
GenerateRaidGrid();
}
@ -60,9 +62,14 @@ public partial class MainWindow : Window
private void InitializeRaidChannels()
{
if (_autoUpdater?.IsBusy == false)
{
_autoUpdater?.CancelAsync();
}
foreach (var rbvm in _raidButtonVMs)
{
rbvm.PropertyChanged -= OnChannelDataChanged;
rbvm.PropertyChanged -= OnRaidButtonViewModelChanged;
}
_raidButtonVMs.Clear();
@ -77,26 +84,25 @@ public partial class MainWindow : Window
if (string.IsNullOrEmpty(channel))
continue;
var rbvm = new RaidButtonViewModel
var rbvm = new RaidButtonViewModel(channel)
{
ChannelName = channel,
MainVm = vm
};
rbvm.PropertyChanged += OnChannelDataChanged;
rbvm.PropertyChanged += OnRaidButtonViewModelChanged;
_raidButtonVMs.Add(rbvm);
}
UpdateChannelData();
if (_autoUpdater?.IsBusy == false)
{
_autoUpdater?.RunWorkerAsync();
}
}
private void OnChannelDataChanged(object? sender, PropertyChangedEventArgs e)
private void OnRaidButtonViewModelChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(RaidButtonViewModel.Channel))
{
GenerateRaidGrid();
}
}
private void GenerateRaidGrid()
@ -129,13 +135,15 @@ public partial class MainWindow : Window
}
}
if (vm.Database.OnlyOnline && channel.Channel.IsLive == false)
if (vm.Database.OnlyOnline && channel.Channel?.IsLive == false)
{
visible = false;
}
return visible;
}).ToList();
}).OrderByDescending(c => c.Channel?.IsLive).ToList();
var rows = (int)Math.Ceiling((visibleChannels.Count + 1) / 3.0);
for (var i = 0; i < rows; i++)
@ -163,11 +171,6 @@ public partial class MainWindow : Window
colIndex = 0;
rowIndex++;
}
if (btn.DataContext is RaidButtonViewModel rbvm)
{
Dispatcher.UIThread.InvokeAsync(rbvm.GetOrUpdateChannelAsync);
}
}
var addButton = new Button
@ -193,10 +196,7 @@ public partial class MainWindow : Window
private void OnAddChannelButtonClicked(object? sender, RoutedEventArgs e)
{
var dialog = new AddChannelWindow();
dialog.Position = new Avalonia.PixelPoint(
(int)(Position.X + Width / 2 - dialog.Width / 2),
(int)(Position.Y + Height / 2 - dialog.Height / 2)
);
dialog.CenterToOwner();
var vm = DataContext as MainWindowViewModel;
@ -225,11 +225,7 @@ public partial class MainWindow : Window
{
foreach (var vm in _raidButtonVMs)
{
Dispatcher.UIThread.InvokeAsync(async () =>
{
await vm.GetOrUpdateChannelAsync();
}
);
Task.Run(vm.GetOrUpdateChannelAsync);
}
}
@ -237,8 +233,8 @@ public partial class MainWindow : Window
{
while (e.Cancel == false)
{
Task.Delay(App.AutoUpdateDelay).Wait();
UpdateChannelData();
Task.Delay(App.AutoUpdateDelay).Wait();
}
}
}

View File

@ -1 +1 @@
{"LastRaided":{"Cedricun":null,"ZanTal":null,"PropzMaster":null,"Artimus83":null,"HyperonsLive":null,"theshroomlife":null,"Robocraft999":null,"sllikson":null,"Aron_dc":null,"AIEsports":null,"TobinatorLP":null,"Lordabgrund":null,"GronkhTV":null},"OnlyOnline":false,"Channels":["Cedricun","ZanTal","PropzMaster","Artimus83","HyperonsLive","theshroomlife","Robocraft999","sllikson","Aron_dc","AIEsports","TobinatorLP","Lordabgrund","GronkhTV"],"AutoSave":true}
{"LastRaided":{"Cedricun":null,"ZanTal":null,"PropzMaster":null,"Artimus83":null,"HyperonsLive":null,"theshroomlife":null,"Robocraft999":null,"sllikson":null,"Aron_dc":null,"AIEsports":null,"TobinatorLP":null,"Lordabgrund":null,"GronkhTV":null,"Bounty2Cooki":null,"ichdasFaultier":null,"codingPurpurTentakel":null,"DerMorzi":null},"OnlyOnline":false,"Channels":["Cedricun","ZanTal","PropzMaster","Artimus83","HyperonsLive","theshroomlife","Robocraft999","sllikson","Aron_dc","AIEsports","TobinatorLP","Lordabgrund","GronkhTV","Bounty2Cooki","ichdasFaultier","codingPurpurTentakel","DerMorzi"],"AutoSave":true}