diff --git a/App.axaml.cs b/App.axaml.cs index 03afbe7..e136622 100644 --- a/App.axaml.cs +++ b/App.axaml.cs @@ -6,6 +6,7 @@ using Avalonia.Data.Core.Plugins; using Avalonia.Markup.Xaml; using BetterRaid.ViewModels; using BetterRaid.Views; +using TwitchLib.Api; using TwitchLib.Client; using TwitchLib.Client.Events; using TwitchLib.Client.Models; @@ -20,6 +21,8 @@ public partial class App : Application public static string TokenClientId = ""; public static string TokenClientSecret = ""; public static string TokenClientAccess = ""; + public static TwitchClient? TwitchClient = null; + public static TwitchAPI? TwitchAPI = null; public override void Initialize() { @@ -48,14 +51,18 @@ public partial class App : Application }; var customClient = new WebSocketClient(clientOptions); - var client = new TwitchClient(customClient); + TwitchClient = new TwitchClient(customClient); - client.Initialize(creds, TwitchChannelName); - client.OnMessageReceived += OnMessageReceived; - client.OnConnected += OnConnected; - client.OnConnectionError += OnConnectionError; + TwitchClient.Initialize(creds, TwitchChannelName); + TwitchClient.OnMessageReceived += OnMessageReceived; + TwitchClient.OnConnected += OnConnected; + TwitchClient.OnConnectionError += OnConnectionError; - client.Connect(); + TwitchClient.Connect(); + + TwitchAPI = new TwitchAPI(); + TwitchAPI.Settings.ClientId = TokenClientId; + TwitchAPI.Settings.AccessToken = TokenClientAccess; AvaloniaXamlLoader.Load(this); } diff --git a/BetterRaid.csproj b/BetterRaid.csproj index a2bb39b..ef46a50 100644 --- a/BetterRaid.csproj +++ b/BetterRaid.csproj @@ -14,6 +14,7 @@ + diff --git a/BetterRaid.generated.sln b/BetterRaid.generated.sln index 826f431..e1c46b5 100644 --- a/BetterRaid.generated.sln +++ b/BetterRaid.generated.sln @@ -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", "{25B567E7-5B84-4DF8-BAB4-1B802DC11876}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BetterRaid", "BetterRaid.csproj", "{050F930D-FE73-4FA8-A05B-E659A4A0CEEA}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -11,10 +11,10 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {25B567E7-5B84-4DF8-BAB4-1B802DC11876}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {25B567E7-5B84-4DF8-BAB4-1B802DC11876}.Debug|Any CPU.Build.0 = Debug|Any CPU - {25B567E7-5B84-4DF8-BAB4-1B802DC11876}.Release|Any CPU.ActiveCfg = Release|Any CPU - {25B567E7-5B84-4DF8-BAB4-1B802DC11876}.Release|Any CPU.Build.0 = Release|Any CPU + {050F930D-FE73-4FA8-A05B-E659A4A0CEEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {050F930D-FE73-4FA8-A05B-E659A4A0CEEA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {050F930D-FE73-4FA8-A05B-E659A4A0CEEA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {050F930D-FE73-4FA8-A05B-E659A4A0CEEA}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Models/TwitchChannel.cs b/Models/TwitchChannel.cs new file mode 100644 index 0000000..20bdff9 --- /dev/null +++ b/Models/TwitchChannel.cs @@ -0,0 +1,14 @@ +namespace BetterRaid.Models; + +public class TwitchChannel +{ + public string? BroadcasterId { get; set; } + public string Name { get; set; } + public bool IsLive { get; set; } + public int ViewerCount { get; set; } + + public TwitchChannel(string channelName) + { + Name = channelName; + } +} \ No newline at end of file diff --git a/ViewModels/MainWindowViewModel.cs b/ViewModels/MainWindowViewModel.cs index 7c5b6c2..58589dc 100644 --- a/ViewModels/MainWindowViewModel.cs +++ b/ViewModels/MainWindowViewModel.cs @@ -2,7 +2,5 @@ public partial class MainWindowViewModel : ViewModelBase { -#pragma warning disable CA1822 // Mark members as static - public string Greeting => "Welcome to Avalonia!"; -#pragma warning restore CA1822 // Mark members as static + } diff --git a/Views/MainWindow.axaml b/Views/MainWindow.axaml index 624437f..d7ae223 100644 --- a/Views/MainWindow.axaml +++ b/Views/MainWindow.axaml @@ -3,18 +3,29 @@ xmlns:vm="using:BetterRaid.ViewModels" 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" + mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="450" + Width="600" + Height="800" x:Class="BetterRaid.Views.MainWindow" x:DataType="vm:MainWindowViewModel" Icon="/Assets/avalonia-logo.ico" Title="BetterRaid"> - - + + + + + + + + + diff --git a/Views/MainWindow.axaml.cs b/Views/MainWindow.axaml.cs index 3535110..6fc9b5b 100644 --- a/Views/MainWindow.axaml.cs +++ b/Views/MainWindow.axaml.cs @@ -1,11 +1,134 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using AsyncImageLoader; +using Avalonia; using Avalonia.Controls; +using Avalonia.Data; +using Avalonia.Media; +using Avalonia.Media.Imaging; +using Avalonia.Threading; +using BetterRaid.Models; +using BetterRaid.ViewModels; +using TwitchLib.Client.Events; namespace BetterRaid.Views; public partial class MainWindow : Window { + private string[] _channelNames = [ + "Cedricun", // Ehrenbruder + "ZanTal", // Ehrenschwester + "PropzMaster", + "Artimus83", + "HyperonsLive", + "theshroomlife", + "Robocraft999", + "sllikson", + "Aron_dc", + "AIEsports" + ]; + public MainWindow() { InitializeComponent(); + PrepareRaidGrid(); + ConnectToTwitch(); + } + + private void PrepareRaidGrid() + { + var rows = (int)Math.Ceiling(_channelNames.Length / 3.0); + + for (var i = 0; i < rows; i++) + { + raidGrid.RowDefinitions.Add(new RowDefinition(GridLength.Parse("200"))); + } + + var colIndex = 0; + var rowIndex = 0; + foreach (var channel in _channelNames) + { + var btn = new Button + { + Content = channel, + DataContext = new TwitchChannel(channel), + Margin = Thickness.Parse("5"), + HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Stretch, + VerticalAlignment = Avalonia.Layout.VerticalAlignment.Stretch, + HorizontalContentAlignment = Avalonia.Layout.HorizontalAlignment.Center, + VerticalContentAlignment = Avalonia.Layout.VerticalAlignment.Center + }; + + Grid.SetColumn(btn, colIndex); + Grid.SetRow(btn, rowIndex); + + raidGrid.Children.Add(btn); + + colIndex++; + if (colIndex % 3 == 0) + { + colIndex = 0; + rowIndex++; + } + } + } + + private void ConnectToTwitch() + { + if (App.TwitchClient != null && App.TwitchAPI != null) + { + foreach (var c in raidGrid.Children) + { + if (c is Button btn) + { + var channel = (btn.DataContext as TwitchChannel)?.Name; + + if (string.IsNullOrEmpty(channel) == false) + { + var channels = App.TwitchAPI.Helix.Search.SearchChannelsAsync(channel).Result; + var exactChannel = channels.Channels.FirstOrDefault(c => c.BroadcasterLogin.ToLower() == channel.ToLower()); + + Dispatcher.UIThread.Invoke(() => + { + if (exactChannel != null) + { + if (btn.DataContext is TwitchChannel ctx) + { + ctx.BroadcasterId = exactChannel.Id; + var ib = new ImageBrush(); + ImageBrushLoader.SetSource(ib, exactChannel.ThumbnailUrl); + btn.Background = ib; + + var streamInfo = App.TwitchAPI.Helix.Streams.GetStreamsAsync(userLogins: new List([channel])).Result; + var exactStreamInfo = streamInfo.Streams.FirstOrDefault(s => s.UserLogin.ToLower() == channel.ToLower()); + + if (exactStreamInfo != null) + { + if (exactChannel.IsLive) + { + btn.Foreground = new SolidColorBrush(new Color(byte.MaxValue, 0, byte.MaxValue, 0)); + btn.Content = $"{exactChannel.DisplayName} ({exactStreamInfo.ViewerCount})"; + } + else + { + btn.Foreground = new SolidColorBrush(new Color(byte.MaxValue, byte.MaxValue, 0, 0)); + btn.Content = $"{exactChannel.DisplayName} (Offline)"; + } + + ctx.ViewerCount = exactStreamInfo.ViewerCount; + } + else + { + btn.Foreground = new SolidColorBrush(new Color(byte.MaxValue, byte.MaxValue, 0, 0)); + btn.Content = $"{exactChannel.DisplayName} (Offline)"; + } + } + } + }); + } + } + } + } } } \ No newline at end of file